Mutation Testing
Trail of BitsOfficialPublished by Trail of Bits
- Skill
- Tool integration
- Software development
- CC-BY-SA-4.0
- No issues found
AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
This skill provides a structured approach to mutation testing using the mewt or muton tools. It guides users through the entire lifecycle of a mutation testing campaign, from initial configuration and execution to the analysis of surviving mutants. By systematically injecting faults into source code and observing test behavior, it helps developers distinguish between equivalent mutants and genuine testing gaps, ultimately revealing bugs that standard coverage metrics might miss.
What it does
- Configures and executes mutation testing campaigns via mewt or muton.
- Provides commands to filter, inspect, and re-test specific mutants.
- Categorizes mutation results into caught, uncaught, timeout, or skipped outcomes.
- Offers a framework for identifying equivalent mutants to reduce false positives.
- Prioritizes investigation based on mutation severity and language-specific patterns.
- Supports advanced analysis for blockchain-specific constructs like Solidity and Move.
When to use it
- When you need to validate the effectiveness of your existing test suite.
- When you want to identify untested code paths or weak assertions.
- When you need to analyze why specific mutants survived your test execution.
- When you are working on a project that requires high-assurance testing, such as blockchain smart contracts.
Advantages
- Uncovers subtle bugs that traditional line coverage metrics fail to detect.
- Provides a clear, actionable workflow for triaging and resolving surviving mutants.
- Reduces noise by helping developers identify and ignore semantically equivalent mutants.
- Enables targeted re-testing of specific code segments to verify fixes.
Usage examples
- “Run a mutation testing campaign on the src/auth directory.”
- The agent will execute the mutation campaign specifically targeting the auth module and provide a summary of the results.
- “Show me all uncaught mutants in the current project.”
- The agent will list the surviving mutants, allowing you to investigate potential testing gaps.
- “How do I investigate a high-severity surviving mutant?”
- The agent will guide you through inspecting the mutated code and suggest how to write a test to catch it.
- “Is this mutant equivalent to the original code?”
- The agent will apply the verification procedure to help you determine if the mutation is semantically identical or a genuine testing gap.
Install
Download the skill as a ZIP:
https://mp-staging.autogineer.com/agent-skills/trailofbits/mutation-testing/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip mutation-testing.zip -d .agents/skills
Documentation by Trail of Bits
Mutation Testing (mewt/muton)
Routes to the right mutation testing workflow and loads the references that workflow needs.
Note: muton and mewt share identical interfaces. Examples use
mewt; substitutemutonand its file names (muton.toml,muton.sqlite) for muton projects.
mewt --help and mewt <subcommand> --help are the source of truth for command-line behavior. Examples below reflect the mewt 4.x API; run --help when a flag looks unfamiliar or a command fails.
When to Use
Use this skill when the user:
Mentions "mewt", "muton", or "mutation testing"
Wants to configure, scope, or speed up a mutation testing campaign
Wants to analyze mutation results — surviving/uncaught mutants, equivalent mutants, kill rate
Wants to use mutation results to find bugs in the source code
When NOT to Use
Do not use this skill when the user asks about tests or line coverage without any mutation testing context.
Routing
Pick the workflow, then load it together with the references listed for it. Workflows and references do not load each other — that decision belongs here.
Setting up, scoping, or speeding up a campaign → workflows/configuration.md → Also load references/optimization-strategies.md when the campaign estimate is long enough to need trimming, or the user asks to make it faster.
Campaign finished, hunting for bugs in untested code → workflows/bug-hunter.md
Turning results into a formal analysis report → workflows/analyzing-results.md, plus:
references/equivalent-mutants.md — equivalence catalog and verification procedure
references/severity-classification.md — severity tier criteria
references/report-template.md — report structure
references/blockchain-patterns.md — only for Solidity, Move, FunC/Tolk, Cairo, or Solana Rust targets
references/input-formats.md — unless the results came from mewt or muton. Foreign tool output may not be self-describing; this covers the parsing anchors for slither-mutate, mull, and dextool-mutate
Anything else → run mewt --help or mewt <subcommand> --help, then assist directly.
Essential Commands
# Set up and run
mewt init # Create config and database
mewt mutate [paths] # Generate mutants without testing them
mewt run [paths] # Generate mutants and run the campaign
# Read results
mewt status # Overview with per-file breakdown
mewt results # Uncaught mutants (default view)
mewt results --all # Every outcome, not just uncaught
mewt results --format json # json | sarif | ids | table
# Narrow down (these filters work on both `results` and `print mutants`)
mewt results --target 'src/auth/**' # Quote globs so the shell does not expand them
mewt results --severity high,medium
mewt results --mutation-types ER,CR
mewt results --status Uncaught # Uncaught | TestFail | Skipped | Timeout
mewt results --line 42
# Investigate and re-test
mewt print mutant --id [id] # View the mutated code
mewt test --ids [ids] # Re-test specific mutants
mewt test --ids-file uncaught_ids.txt # Re-test IDs from a file, or '-' for stdin
# Inspect configuration
mewt print config # Effective config
mewt print targets # Files actually mutated
mewt print mutations --language [lang] # Mutations and severities for a languageLanguage labels are canonical family or family/dialect values in mewt 4.x — for example rust, javascript/ts, move/sui, move/iota.
What Results Mean
Caught/TestFail: tests detected the mutation (good)
Uncaught: tests did not detect the change. Inspect the code to distinguish a testing gap from an equivalent mutation.
Timeout: tests took too long — inconclusive, not evidence of coverage
Skipped: a less severe mutant was skipped because a more severe mutant on the same line was uncaught
Interpreting Mutation Types
mewt print mutations --language [lang] lists every mutation slug, description, and severity for a language, and is authoritative — the operator set grows with each release. What that output does not tell you is what a survivor means, which is where prioritization comes from:
| Severity | Representative slugs | What an uncaught mutant tells you |
|---|---|---|
| High | ER (Error Replacement) | Tests tolerate the injected error. Investigate whether the path executes, whether error handling masks the change, and whether assertions check the outcome. |
| Medium | CR (Comment Replacement) | Removing the statement does not fail the tests. Check whether its effects matter and whether assertions observe them. |
| Medium | IF/IT (If False/True), NR (Negation Removal) | Tests do not distinguish the changed condition. Both constant replacements surviving can indicate an unexecuted condition or weak assertions on the branch outcomes. |
| Low | Operator shuffles (AOS, COS, LOS, BOS, shift/assignment variants), BL, AS, LC, WF | Check boundary inputs, arithmetic assertions, and semantic equivalence. The mutation result alone does not establish whether the code executed. |
Severity ranks the mutation, not the risk. A low-severity survivor in a fee calculation matters more than a high-severity survivor in a log line — weigh what the mutated code does. Filter with --severity to work through the results in priority order.
Files
- ATTRIBUTION.mdAdded by AutoGineer942 B
- LICENSELicence file added by AutoGineer19.7 KiB
- SKILL.md6.1 KiB
- agents/openai.yaml243 B
- assets/trail-of-bits-mark.svg3.0 KiB
- references/blockchain-patterns.md4.8 KiB
- references/equivalent-mutants.md7.0 KiB
- references/input-formats.md2.4 KiB
- references/optimization-strategies.md8.7 KiB
- references/report-template.md4.3 KiB
- references/severity-classification.md5.9 KiB
- workflows/analyzing-results.md6.7 KiB
- workflows/bug-hunter.md7.4 KiB
- workflows/configuration.md11.3 KiB
workflows/analyzing-results.md
Analyzing Mutation Testing Results
Analyzes mutation testing campaign results to identify testing gaps, classify surviving mutants by severity, filter equivalent mutants, and produce a structured report.
This workflow is tool-agnostic and language-agnostic. It is used together with the equivalence catalog, severity guide, and report template loaded alongside it; those files hold the criteria, this file holds the procedure.
When to Use
The user provides mutation testing results (surviving mutants with file paths, line numbers, and code changes)
The user wants to know which survivors are real testing gaps versus equivalent mutants
The user wants a structured report prioritizing which tests to improve
When NOT to Use
Running mutation testing tools (this workflow analyzes results, it does not generate them)
Writing or modifying test code (it recommends improvements, it does not implement them)
Choosing which mutation testing tool to use
Coverage analysis without mutation data, or code review and vulnerability discovery (use audit-context-building or wilson)
Rationalizations to Reject
"The kill rate is above 80%, so the test suite is adequate." Aggregate metrics hide individual critical gaps. One survivor in access control matters more than a hundred killed mutants in logging.
"This is probably an equivalent mutant." Equivalence is proven from the type system and control flow, never assumed. Absence of a distinguishing test is not proof.
"Boundary changes like > to >= are always equivalent." They are equivalent only when the boundary value is provably unreachable. A reachable boundary is a real finding.
"The test suite catches this in practice even though the mutant survived." If the mutant survived, the suite does not catch it. That is what surviving means.
"Only the top tier is worth reporting." Lower tiers are still concrete, actionable test improvements. Even event-emission survivors reveal missing assertions that matter for monitoring and integration.
"I can classify this without reading the source." Severity depends on what the mutated code does, and equivalence depends on types and reachability. Both require the source at the mutation site.
Workflow
Phase 1: Parse Input
Entry: The user has provided mutation testing results.
Read the input and identify its format. Most tools (mewt/muton, mutmut, cargo-mutants, mutahunter) produce JSON or CSV that parses directly from field names; when the structure is not obvious, read the first 50 lines before proceeding. The input-formats reference covers the tools whose output is not self-describing.
Confirm it is mutation testing output — expect file paths, line numbers, and a status field.
Extract each surviving mutant: file path, line number, original code, mutated code, mutation operator if available. Filter to surviving/uncaught status only.
For mewt/muton projects, mewt results --format json gives uncaught mutants directly.
Exit: Structured list of surviving mutants.
Phase 2: Gather Context
Entry: Phase 1 complete.
Group mutants by source file to batch Read calls, then read each mutation site and establish: what the code does, the types involved, whether the code is reachable, and whether it is security-sensitive, financial, business logic, or observability.
Exit: Context gathered for every mutant.
Phase 3: Filter Equivalent Mutants
Entry: Phase 2 complete.
Apply the five-check verification procedure from the equivalence catalog to each mutant: type context, reachability, downstream consumption, semantic comparison, and a distinguishing-test attempt. Classify identical behavior as equivalent and an observable difference missed by tests as a testing gap. Keep uncertain cases unresolved and describe the missing evidence.
The catalog also lists the patterns that look equivalent but are not — treat those as real findings.
Exit: Each mutant classified as equivalent, a testing gap, or unresolved.
Phase 4: Classify Severity
Entry: Phase 3 complete.
Assign each confirmed testing gap a priority tier using the criteria in the severity guide, based on what the mutated code does. Explain uncertain impact instead of automatically raising the tier. These tiers prioritize testing work and do not establish vulnerability severity in the original program.
Exit: Every real mutant has a tier.
Phase 5: Analyze Test Gaps
Entry: Phase 4 complete.
For each real survivor:
Find the responsible test file. Most ecosystems follow a convention (
src/x.rs→tests/x.rsor an in-file#[cfg(test)]module,x.py→test_x.py,x.go→x_test.go,X.sol→X.t.sol). When the convention does not hold, Grep for imports of the mutated module.Read the tests that exercise the mutated code and identify which case should have caught the mutation.
Explain why it did not — missing assertion, uncovered branch, missing edge case, insufficient input variety, or a test that exercises the code without verifying its output.
State concretely how to close the gap: which assertion to add, which input to use, which branch to cover.
If no test touches the mutated code at all, say so — that is a stronger finding than a weak assertion.
Exit: Every real mutant has a test file, a gap explanation, and a recommendation.
Phase 6: Report
Entry: Phase 5 complete.
Write the report to mutation-testing-report.md in the working directory, following the structure in the report template.
Compute every statistic from the parsed data. State the denominator for each rate and account for skipped, timed-out, and unresolved cases separately. Report raw and equivalence-adjusted rates only when the supplied data supports them. A rate summarizes this campaign and does not establish overall test adequacy.
Match report length to the number of findings. Each finding needs its context, gap explanation, and recommendation; it does not need restating in a summary section, and tiers with no findings can be omitted rather than padded.
Exit: Report written.
Analysis Requirements
Every surviving mutant is analyzed individually — no skipping, summarizing, or batching. Each one gets context, an equivalence check, a severity tier, a test gap, and a recommendation.
Work in severity order (Tier 1 and 2 first) so the highest-value analysis is complete if context runs short.
Save intermediate progress if the session may end before the analysis does.
Write in formal, objective, third-person voice, active voice, present tense. Use inline code formatting for paths, function names, and snippets. Describe recommended test changes in prose rather than writing out test code.
Requirements and compatibility
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta
“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.
Needs: Declares allowed tools
Security
No issues found by our static scan· No issues found
A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.
Attribution and licence
- Published by
- Trail of Bits
- Publisher
- Trail of Bits (Official)
- Source
- trailofbits/skills · plugins/mutation-testing/skills/mutation-testing · commit e4dd0bb
- Licence
- Creative Commons Attribution-ShareAlike 4.0 International (redistribution allowed)
- LICENSE (added by AutoGineer from LICENSE)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
AutoGineer is not affiliated with or endorsed by Trail of Bits.
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download mutation-testing.zip