Skip to main content

Shrink Ray

Shrink Ray is a modern multiformat test-case reducer.

What is test-case reduction?

Test-case reduction is the process of automatically taking a test case and reducing it to something close to a minimal reproducible example.

That is, you have some file that has some interesting property (usually that it triggers a bug in some software), but it is large and complicated and as a result you can't figure out what about the file actually matters. You want to be able to trigger the bug with a small, simple, version of it that contains only the features of interest.

For example, the following is some Python code that triggered a bug in libcst:

() if 0 else(lambda:())

This was extracted from a large Python file (probably several thousand lines of code) and systematically reduced down to this example.

You would obtain this by running shrinkray breakslibcst.py mytestcase.py, where breakslibcst.py looks something like this:

import libcst
import sys

if __name__  == '__main__':
    try:
        libcst.parse_module(sys.stdin.read())
    except TypeError:
        sys.exit(0)
    sys.exit(1)

This script exits with 0 if the code passed to it on standard input triggers the relevant bug (that libcst raises a TypeError when parsing this code), and with a non-zero exit code otherwise.

shrinkray (or any other test-case reducer) then systematically tries smaller and simpler variants of your original source file until it reduces it to something as small as it can manage.

While it runs, you will see the following user interface:

Shrink Ray demo

(This is a toy example based on reducing a ridiculously bad version of hello world)

When it finishes you will be left with the reduced test case in mytestcase.py.

Test-case reducers are useful for any tools that handle files with complex formats that can trigger bugs in them. Historically this has been particularly useful for compilers and other programming tools, but in principle it can be used for anything.

Most test-case reducers only work well on a few formats. Shrink Ray is designed to be able to support a wide variety of formats, including binary ones, although it's currently best tuned for "things that look like programming languages".

What makes Shrink Ray distinctive?

It's designed to be highly parallel, and work with a very wide variety of formats, through a mix of good generic algorithms and format-specific reduction passes.

Versioning and Releases

Shrink Ray uses calendar versioning (calver) in the format YY.M.D.N (e.g., 25.12.26.0 for the first release on December 26, 2025, 25.12.26.1 for the second, etc.).

New releases are published automatically when changes are pushed to main if there are any changes to the source code or pyproject.toml since the previous release.

Shrinkray makes no particularly strong backwards compatibility guarantees. I aim to keep its behaviour relatively stable between releases, but for example will not be particularly shy about dropping old versions of Python or adding new dependencies. The basic workflow of running a simple reduction will rarely, if ever, change, but the UI is likely to be continuously evolving for some time.

Installation

Shrink Ray requires Python 3.12 or later, and can be installed using pip or uv like any other python package.

You can install the latest release from PyPI or run directly from the main branch:

pipx install shrinkray
# or
pipx install git+https://github.com/DRMacIver/shrinkray.git

(if you don't have or want pipx you could also do this with pip or uv pip and it would work fine)

Shrink Ray requires Python 3.12 or later and won't work on earlier versions. If everything is working correctly, it should refuse to install on versions it's incompatible with. If you do not have Python 3.12 installed, I recommend pyenv for managing Python installs.

If you want to use it from the git repo directly, you can do the following:

git clone https://github.com/DRMacIver/shrinkray.git
cd shrinkray
python -m venv .venv
.venv/bin/pip install -e .

You will now have a shrinkray executable in .venv/bin, which you can also put on your path by running source .venv/bin/activate.

Usage

Shrink Ray is run as follows:

shrinkray is_interesting.sh my-test-case

Where my-test-case is some file you want to reduce and is_interesting.sh can be any executable that exits with 0 when a test case passed to it is interesting and non-zero otherwise.

Variant test cases are passed to the interestingness test both on STDIN and as a file name passed as an argument. Additionally for creduce compatibility, the file has the same base name as the original test case and is in the current working directory the script is run with. This behaviour can be customised with the --input-type argument.

shrinkray --help will give more usage instructions.

LLM mode

Shrink Ray uses a language model, running locally in-process, to propose smaller test cases alongside its normal reduction passes. This is enabled by default: once the ordinary passes stop making progress, the model is asked for smaller rewrites of the whole test case. The first use downloads the default model (Qwen3.5-4B, about 2.7GB) from Hugging Face — in the background, while the ordinary passes get on with reducing; the LLM passes join in once it's ready. The model runs on CPU, or with GPU acceleration where llama-cpp-python supports it (e.g. Metal on Apple Silicon).

Model suggestions are just candidates like any others: they're only accepted if your interestingness test still passes, so a bad model costs time but never correctness.

When a reduction would download the model (or a tree-sitter grammar for the input's language), Shrink Ray tells you first rather than fetching silently: the interactive UI shows a startup dialog listing each pending download with a checkbox to skip it, and the basic UI prints the list. Reduction starts right away behind the dialog on the ordinary passes, and each download's extra passes join in when it finishes.

To turn it off, pass --no-llm (or set SHRINKRAY_LLM=0 in the environment, useful on shared machines and CI). --llm-model selects a different model — either a path to a local .gguf file or a Hugging Face repo:filename reference — and --llm-only disables all of the non-LLM passes so the model does the whole reduction. On platforms where llama-cpp-python cannot load, shrink ray warns and reduces without the LLM passes.

Supported formats

Shrink Ray is fully generic in the sense that it will work with literally any file you give it in any format. However, some formats will work a lot better than others.

It has a generic reduction algorithm that should work pretty well with any textual format, and an architecture that is designed to make it easy to add specialised support for specific formats as needed.

Additionally, Shrink Ray has special support for the following formats:

  • C and C++
  • Python
  • JSON
  • Dimacs CNF format for SAT problems

Most of this support is quite basic and is just designed to deal with specific cases that the generic logic is known not to handle well, but it's easy to extend with additional transformations. It is also fairly easy to add support for new formats as needed.

If you run into a test case and interestingness test that you care about that shrink ray handles badly please let me know and I'll likely see about improving its handling of that format.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

shrinkray-26.7.7.3.tar.gz (464.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

shrinkray-26.7.7.3-py3-none-any.whl (170.6 kB view details)

Uploaded Python 3

File details

Details for the file shrinkray-26.7.7.3.tar.gz.

File metadata

  • Download URL: shrinkray-26.7.7.3.tar.gz
  • Upload date:
  • Size: 464.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for shrinkray-26.7.7.3.tar.gz
Algorithm Hash digest
SHA256 f8abd7c7cc532c5c277cd5ded6c140eec2f812c6c4a623f0a1e4471e63853511
MD5 3e6f257372f22139c9707448529a7d22
BLAKE2b-256 cf3eb7d703992f2cb86cdb0d50976fc937a10e5156ab45cfe9eece2fd4199373

See more details on using hashes here.

Provenance

The following attestation bundles were made for shrinkray-26.7.7.3.tar.gz:

Publisher: ci.yml on DRMacIver/shrinkray

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file shrinkray-26.7.7.3-py3-none-any.whl.

File metadata

  • Download URL: shrinkray-26.7.7.3-py3-none-any.whl
  • Upload date:
  • Size: 170.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for shrinkray-26.7.7.3-py3-none-any.whl
Algorithm Hash digest
SHA256 35c60826ae9d1a3ad9382de5f227e73eaa1e093152ef0a69284bc15eb48cf0a2
MD5 a788fe21369b01d1bd5e04cb113e15d2
BLAKE2b-256 4ad29d5d5df3e828e3e30d2f87200567b9d1f7979a05f0f4e01a1d37f0c72ee8

See more details on using hashes here.

Provenance

The following attestation bundles were made for shrinkray-26.7.7.3-py3-none-any.whl:

Publisher: ci.yml on DRMacIver/shrinkray

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

26.7.8.0

2 files

26.7.7.4

2 files

This release

26.7.7.3 This release

2 files

26.7.7.2

2 files

26.7.7.1

2 files

26.7.7.0

2 files

26.7.6.1

2 files

26.7.6.0

2 files

26.7.5.7

2 files

26.7.5.6

2 files

26.7.5.5

2 files

26.7.5.4

2 files

26.7.5.3

2 files

26.7.5.2

2 files

26.7.5.1

2 files

26.7.5.0

2 files

26.7.3.1

2 files

26.7.3.0

2 files

26.4.14.0

2 files

26.4.10.0

2 files

26.3.17.0

2 files

26.2.20.0

2 files

26.2.4.1

2 files

26.2.4.0

2 files

26.1.1.0

2 files

25.12.29.0

2 files

25.12.28.0

2 files

25.12.27.3

2 files

25.12.27.2

2 files

25.12.27.1

2 files

25.12.27.0

2 files

25.12.26.2

2 files

25.12.26.1

2 files

25.12.26

3 files

0.0.2

1 file

0.0.1

1 file

0.0.0

1 file

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page