LLM-augmented mutation-testing framework: inject realistic bugs, see if your tests catch them.
Project description
Ruinator
LLM-augmented mutation-testing framework. Inject realistic bugs into your code, see if your tests catch them.
Ruinator is a mutation-testing framework for people who want to know whether their test suite actually catches bugs. It analyzes your source code, introduces realistic bugs (logic errors, off-by-one mistakes, missing guards), and reruns your tests against each mutation. Surviving mutants reveal gaps in your coverage.
Unlike classical rule-based mutation testers (Stryker, PIT, Mutmut), ruinator is plugin-extensible, LLM-augmented, reproducible via seeds + manifests, and CI-native.
Status
Alpha (v0.1). APIs will change. v0.1 ships rule-based mutation with a heuristic equivalence filter; the LLM equivalence judge and creative-mutant slot are scaffolded but not wired into the default pipeline yet.
Quick look
# ruinator.toml
[ruinator]
test_command = "pytest -q"
timeout_seconds = 60
seed = 1
survivor_reruns = 3
[ruinator.scope]
include = ["src/**/*.py"]
exclude = []
# coverage_file = ".coverage" # optional; when set, only covered lines mutate
[ruinator.selection]
categories = ["logic", "boundary"]
languages = ["python"]
max_mutants = 100
per_file_per_category = 4
[ruinator.llm]
provider = "none" # "claude" and "litellm" also supported (unused in v0.1 pipeline)
ruinator init # scaffold ruinator.toml
ruinator run --config ruinator.toml # run a mutation campaign
ruinator run --report html --report json # emit reports alongside the manifest
ruinator run --report markdown --report sarif # PR-comment + code-scanning outputs
ruinator report .ruinator/runs/latest.json # re-render reports from a manifest
ruinator replay .ruinator/runs/latest.json # rerun the same mutants at HEAD
GitHub Action
# .github/workflows/ruinator.yml
name: Mutation testing
on:
pull_request:
permissions:
contents: read
pull-requests: write # for the PR comment
security-events: write # for SARIF upload to Code Scanning
jobs:
ruinator:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: nauski/ruinator@v0.1.0
with:
config: ruinator.toml
fail-under: '0.80'
The action installs ruinator from PyPI, runs it with your config, emits
markdown + SARIF, posts (or updates) a PR comment with the summary, uploads
the SARIF to GitHub Code Scanning, and attaches all reports as workflow
artifacts. See action.yml for the full input list.
Why ruinator?
| Classical tools (Stryker, PIT) | Mutahunter | LLMorpheus | Ruinator | |
|---|---|---|---|---|
| Cross-language | per-tool | yes | JS only | tree-sitter (many) |
| LLM-augmented | no | yes | yes | yes (Claude + BYO) |
| Bug taxonomy | mech operators | none | none | categorized |
| Reproducible (seed+manifest) | partial | no | no | yes |
| Plugin framework | per-tool | weak | no | declarative + code |
| CI baseline-then-diff | no | no | no | yes (v0.2) |
| Web UI | Stryker only | no | no | v0.2 |
| MCP server | no | no | no | v0.2 |
How it works
- Scope. Ruinator resolves your
include/excludeglobs, parses# ruinator: skipannotations, and (optionally) drops uncovered lines using yourcoverage.py/lcovreport. - Candidates. tree-sitter parses each file and queries the AST for candidate nodes per mutator category (conditions, comparisons, boundaries).
- Sample. A seeded RNG samples N candidates per category per file, up to your budget.
- Mutate. Built-in mutators (or your plugins) propose a mutation. A creative slot reserved for LLM-proposed bugs is planned for v0.2.
- Apply. Each mutation lives in its own
git worktreeunder.ruinator/worktrees/<id>/. Your working tree is never touched. - Test. Your
test_commandruns in the worktree with a timeout. Exit code 0 = survived; non-zero = killed. - Rerun survivors. Survivors run N more times (default 3) to rule out flaky-pass.
- Report. JSON manifest (canonical) + HTML report (browser-friendly).
Differentiators
- Plugin framework — declarative YAML mutators (
query + prompt template + category) or code mutators (Python class). Discovered via entry-points. - Bug taxonomy — every mutation carries a category (
logic,boundary, and in v0.3security,concurrency). Budgets allocate per category. - Reproducibility — mutation IDs are
sha256(file, node_range, mutator_id, seed). Replay a manifest and get the same mutant set every time. - Worktree isolation — one
git worktreeper mutant. Safe for parallel execution and for security mutants that look like exploit code. - Cost control — token budget enforced hard. Prompt caching + Haiku/Sonnet model tiering cut token spend aggressively.
- Claude-ready — Anthropic SDK adapter with prompt caching + model tiering, plus LiteLLM for BYO providers. Pipeline defaults to rule-based mutation in v0.1; LLM judging/creation land in v0.2.
Roadmap
- v0.1 (current) — Python + JS, logic + boundary categories, CLI, JSON/HTML reports, heuristic equivalence filter, worktree isolation, manifest cache.
- v0.2 — LLM equivalence judge wired into the pipeline, creative-mutant slot (Claude/LiteLLM proposing realistic bugs), Web UI, MCP server, GitHub Action, SARIF + Markdown reporters, local LLM provider.
- v0.3 — Security + concurrency mutators, multi-file mutations, Go/Rust/TS/Java adapters.
- v0.4 — Auto-test-writer agent (writes tests that kill survivors).
- v1.0 — Stable plugin API (semver), docs site, hosted SaaS beta.
See ROADMAP.md for details.
Contributing
PRs welcome. See CONTRIBUTING.md and CODE_OF_CONDUCT.md.
Development install:
git clone https://github.com/nauski/ruinator
cd ruinator
uv sync --extra dev
uv run pytest
uv run ruinator --help
Prior art & inspiration
- Mutahunter — language-agnostic LLM mutation testing; closest existing tool.
- LLMorpheus — GitHub Next research, JS-only placeholder approach.
- Meta ACH — multi-agent mutation + test generation at industrial scale.
- Stryker, PIT, Mutmut, Cosmic Ray — classical rule-based tools.
- honnibal/claude-skills #mutation-testing — Matthew Honnibal's manual Claude skill; the conceptual starting point.
License
Apache 2.0. See LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file ruinator-0.1.0.tar.gz.
File metadata
- Download URL: ruinator-0.1.0.tar.gz
- Upload date:
- Size: 231.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3e513a2104713619f314d60874136a2e2983eb6120f42e47bb16166b03316760
|
|
| MD5 |
51d2bb9e9ef64907a52f4b07011547be
|
|
| BLAKE2b-256 |
e63186a77e365760b4175b8744c0eecb8b3f195012ed83f5b7e3cfce144f6b41
|
Provenance
The following attestation bundles were made for ruinator-0.1.0.tar.gz:
Publisher:
release.yml on nauski/ruinator
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ruinator-0.1.0.tar.gz -
Subject digest:
3e513a2104713619f314d60874136a2e2983eb6120f42e47bb16166b03316760 - Sigstore transparency entry: 1339559401
- Sigstore integration time:
-
Permalink:
nauski/ruinator@c63d6ad77facd85ee4c6355a2c4dc3ea679dd15b -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/nauski
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@c63d6ad77facd85ee4c6355a2c4dc3ea679dd15b -
Trigger Event:
push
-
Statement type:
File details
Details for the file ruinator-0.1.0-py3-none-any.whl.
File metadata
- Download URL: ruinator-0.1.0-py3-none-any.whl
- Upload date:
- Size: 56.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e874551adfd290e4fb7c620d2669d2b9f0793226cbaf68d71b2390aae072a062
|
|
| MD5 |
da3157f228345017b41f63977660c89b
|
|
| BLAKE2b-256 |
d327d7580dd8895889bf59debcb4c5bea0edd649dfe38693ec58c9454acd7e02
|
Provenance
The following attestation bundles were made for ruinator-0.1.0-py3-none-any.whl:
Publisher:
release.yml on nauski/ruinator
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ruinator-0.1.0-py3-none-any.whl -
Subject digest:
e874551adfd290e4fb7c620d2669d2b9f0793226cbaf68d71b2390aae072a062 - Sigstore transparency entry: 1339559402
- Sigstore integration time:
-
Permalink:
nauski/ruinator@c63d6ad77facd85ee4c6355a2c4dc3ea679dd15b -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/nauski
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@c63d6ad77facd85ee4c6355a2c4dc3ea679dd15b -
Trigger Event:
push
-
Statement type: