mutineer · git:20261025.ba9e0ef · 2026-10-25 · sha256 6f3b6d646e4f2415
mutineer git:20261025.ba9e0efA
Immutable. This exact content never changes and is served at /api/v1/blob/6f3b6d646e4f2415.
--- name: mutineer description: Mutation testing for Ruby (Prism + stdlib, zero deps). Mutates source one change at a time, runs the suite against each mutant, and reports the mutants tests fail to catch, with a versioned JSON contract and CI/agent gating. Use when checking whether a Ruby test suite would catch a change, finding weak or missing tests, gating CI on a mutation score, or acting on mutineer's JSON report. --- # Mutineer Mutation testing for Ruby, built for CI gates and AI coding agents. Line coverage tells you which code *ran*; mutation testing tells you whether your tests would *notice if it broke*. ## Install ```sh gem install mutineer ``` ## Run ```sh mutineer run <source...> --test <test> [--test <test>...] [options] ``` Example — mutate `lib/calculator.rb`, gate CI below 90%: ```sh mutineer run lib/calculator.rb --test test/calculator_test.rb --threshold 90 ``` ## Agent loop 1. Edit code and tests on a branch. Fetch `origin/main` before using it below. 2. Run diff-scoped, as JSON: ```sh mutineer run app/ --since origin/main --threshold 90 --format json --output .mutineer/run.json ``` 3. Parse `survivors[]` — each carries a `diff` and an `id`. File moves, renames, project-root changes, and changes to repeated-name or repeated-mutation order can change ids; see [Mutant ids](https://github.com/davidteren/mutineer#mutant-ids). Review each change against the intended behaviour. If review finds a test gap, write or strengthen a test that fails under that change. 4. Re-run. Accept the result only when this run exits `0`, `summary.score` is not `null`, and `summary.score >= 90`. If every scored mutant must be killed, also require `summary.survived == 0`. Mutineer 1.7.0 and earlier gate on the rounded score, so a run just below the threshold can still exit `0`. On those versions, also require `summary.killed * 100 >= 90 * (summary.killed + summary.survived)`. Stop after a few unsuccessful attempts and ask a person to review the survivor. Failed attempts do not prove that a mutant is equivalent. To suppress it, `mutineer triage .mutineer/run.json --reason TEXT --id ID` prints an `ignore:` entry for `.mutineer.yml` (Mutineer 1.7 or later reads it). See [Suppressing equivalent mutants](https://github.com/davidteren/mutineer#suppressing-equivalent-mutants). Keep `fail_fast` disabled (the default). If the active `.mutineer.yml` sets it to `true`, temporarily change that value to `false` for the loop. Restore the original value when the loop ends, before committing. A fail-fast run is partial, and its score and exit code do not cover the full scope. Zero survivors alone is not success: an empty or fully suppressed scope, or a run with no usable verdicts, also has zero survivors. If the score is null, stop and report “no score”. Check `no_coverage[]` for test gaps and `no_verdict[]` for harness failures, and fix them before starting a new run. A positive threshold fails when nothing can be scored and something broke, or when more than one mutant has no verdict and they exceed 10% of those attempted; it does not require zero errors. Set the threshold to your target. An empty run (`summary.total` is 0) exits 0 in 1.x and prints a warning on stderr. Treat it as "no score". Pass `--allow-empty` only when an empty run is expected. A `--since` run whose changes hold no mutable code says "nothing to test in the changes since REF"; that is a valid success. Warnings that start with `mutineer:` or `[mutineer]` also go to stderr: the empty-run warning, "did you mean" hints, notes about Mutineer 2.0, the count of errored mutants, and a notice that a `PARALLEL_WORKERS` value you set was replaced with 1. ## Exit codes <!-- contract:exit-codes --> | Code | Meaning | |------|---------| | `0` | Score ≥ threshold (or no gate) **and** no baseline regression. | | `1` | Score below `--threshold`, OR nothing could be scored and something broke, or more than one mutant produced no verdict and they exceed 10% of those attempted, OR a `--baseline` regression, OR a runtime error, including a boot, source or `require:` file that raises while loading. | | `2` | Usage / invalid-flag error, including a mistyped flag, a bad path (such as a missing `--boot` or `require:` file), or an unreadable baseline. | <!-- /contract:exit-codes --> ## References - Docs: https://davidteren.github.io/mutineer/ - Agent & CI guide: https://davidteren.github.io/mutineer/agentic-coding.html - JSON schema: https://davidteren.github.io/mutineer/json-schema.html - Ruby API: https://davidteren.github.io/mutineer/api/ - Source: https://github.com/davidteren/mutineer