Skip to main content

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.

License: Apache 2.0 Python 3.11+ Status: alpha

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

  1. Scope. Ruinator resolves your include/exclude globs, parses # ruinator: skip annotations, and (optionally) drops uncovered lines using your coverage.py / lcov report.
  2. Candidates. tree-sitter parses each file and queries the AST for candidate nodes per mutator category (conditions, comparisons, boundaries).
  3. Sample. A seeded RNG samples N candidates per category per file, up to your budget.
  4. Mutate. Built-in mutators (or your plugins) propose a mutation. A creative slot reserved for LLM-proposed bugs is planned for v0.2.
  5. Apply. Each mutation lives in its own git worktree under .ruinator/worktrees/<id>/. Your working tree is never touched.
  6. Test. Your test_command runs in the worktree with a timeout. Exit code 0 = survived; non-zero = killed.
  7. Rerun survivors. Survivors run N more times (default 3) to rule out flaky-pass.
  8. 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.3 security, 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 worktree per 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

License

Apache 2.0. See LICENSE.

Project details


Download files

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

Source Distribution

ruinator-0.1.0.tar.gz (231.2 kB view details)

Uploaded Source

Built Distribution

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

ruinator-0.1.0-py3-none-any.whl (56.8 kB view details)

Uploaded Python 3

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

Hashes for ruinator-0.1.0.tar.gz
Algorithm Hash digest
SHA256 3e513a2104713619f314d60874136a2e2983eb6120f42e47bb16166b03316760
MD5 51d2bb9e9ef64907a52f4b07011547be
BLAKE2b-256 e63186a77e365760b4175b8744c0eecb8b3f195012ed83f5b7e3cfce144f6b41

See more details on using hashes here.

Provenance

The following attestation bundles were made for ruinator-0.1.0.tar.gz:

Publisher: release.yml on nauski/ruinator

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

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

Hashes for ruinator-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 e874551adfd290e4fb7c620d2669d2b9f0793226cbaf68d71b2390aae072a062
MD5 da3157f228345017b41f63977660c89b
BLAKE2b-256 d327d7580dd8895889bf59debcb4c5bea0edd649dfe38693ec58c9454acd7e02

See more details on using hashes here.

Provenance

The following attestation bundles were made for ruinator-0.1.0-py3-none-any.whl:

Publisher: release.yml on nauski/ruinator

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

Supported by

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