A single binary that mutates your source code and runs your tests. If tests pass β your coverage has gaps. No plugins, no config files, no dependencies.
docker pull ghcr.io/fibegg/muti:latest
Ruby, Go, Python, JavaScript, TypeScript out of the box. Uses tree-sitter AST parsing β no language-specific plugins needed.
Boolean swaps, equality negation, arithmetic flips, guard clause removal, error handler deletion, and more. Real mutations, not toy examples.
Mutates files directly in your repo, runs your test suite, then resets via git checkout. Fast, simple, no overhead.
One binary, zero runtime dependencies (except git). Download, run, done. Also available as a Docker image.
Every mutation is emitted as JSON. Pipe it to echo, curl, a webhook, a file β integrate with anything.
Run forever with --forever for ongoing mutation coverage in CI or background. Randomized mutations each round.
muti parses your source with tree-sitter and applies random AST mutations (swap booleans, negate conditions, etc.)
Your test suite β the probe command β runs against the mutated code. Any shell command works.
Tests fail? Mutation killed β β good coverage. Tests pass? Mutation survived β coverage gap found.
Results stream as JSON to your configured tool β stdout, a webhook, a file, or any command.
Everything after -- is your probe command β typically your test suite. If the probe exits non-zero, the mutation is killed (your tests caught it). If it exits zero, the mutation survived.
# The probe is your test suite muti --dirs app -- bundle exec rspec --fail-fast muti --dirs src -- pytest -x muti --dirs src -- npm test
Each mutation result is serialized as JSON and piped to the tool's stdin. Default is echo (prints to stdout). Use it to send results anywhere.
# Print to terminal (default) muti --tool echo -- make test # Save to file muti --tool 'tee -a mutations.jsonl' -- make test # Send to a webhook muti --tool 'curl -s -X POST ...' -- make test
Each round applies one or more mutations, runs the probe, then resets. Control the batch size with --mutations (fixed) or --mru (random up to N).
# 20 rounds, 3 mutations each muti --rounds 20 --mutations 3 -- make test # Random 1-7 mutations per round, forever muti --forever --mru 7 -- make test # 4 parallel workers muti --parallel 4 --rounds 100 -- make test
Point at your app directory and use RSpec or Minitest as the probe.
# Mutate app/ directory, use RSpec muti --dirs app -- bundle exec rspec --fail-fast # Mutate specific directories muti --dirs app/models,app/services -- bundle exec rspec --fail-fast # Run forever in CI with random 1-10 mutations muti --dirs app --forever --mru 10 -- bundle exec rspec --fail-fast # With Minitest muti --dirs app -- bundle exec rails test
Works with pytest, unittest, or any test runner.
# Mutate src/ directory, use pytest muti --dirs src -- pytest -x --tb=short # Django project muti --dirs myapp -- python manage.py test --failfast # Only .py files in a mixed-language project muti --dirs src --extensions py -- pytest -x # With coverage threshold check muti --dirs src -- pytest -x --cov=src --cov-fail-under=80
Supports .js, .jsx, .mjs, .cjs, .ts, .tsx files. Use any test runner.
# Mutate src/ directory, use Jest muti --dirs src -- npx jest --bail # Vitest muti --dirs src -- npx vitest run # TypeScript only muti --dirs src --extensions ts,tsx -- npm test # Mocha muti --dirs lib -- npx mocha --bail
Go test is the natural probe. Use -count=1 to prevent caching.
# Mutate current directory muti -- go test -count=1 ./... # Mutate specific packages muti --dirs internal -- go test -count=1 ./...
| Operator | What it does |
|---|---|
| swap_boolean | true β false |
| negate_equality | == β != |
| swap_logical | && β ||, and β or |
| flip_conditional | Swap if/else branches |
| swap_comparison | > β <, >= β <= |
| swap_arithmetic | + β -, * β / |
| swap_integer | 0 β 1 |
| empty_string | Replace string literal with "" |
| null_return | return expr β return nil |
| inject_early_return | Insert return nil at function start |
| remove_statement | Remove a random statement from a function body |
| remove_guard_clause | Remove early-return guard clauses |
| remove_error_handler | Remove rescue / except / catch blocks |
| replace_arg_with_null | Replace a method argument with nil |
Pre-built for Linux and macOS (amd64 + arm64)
curl -sL https://github.com/fibegg/muti/releases/latest/download/muti_*_linux_amd64.tar.gz | tar xz sudo mv muti /usr/local/bin/
Multi-arch image (linux/amd64, linux/arm64)
docker pull ghcr.io/fibegg/muti:latest docker run --rm -v "$(pwd):/workspace" \ ghcr.io/fibegg/muti:latest \ --dirs src -- make test
Requires Go 1.23+, git, and a C compiler
go install github.com/fibegg/muti/cmd/muti@latest
# or clone and build
git clone https://github.com/fibegg/muti.git
cd muti && make build