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://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/configuration.md
Configuration and Optimization Guide
Guide for configuring mewt and optimizing mutation testing performance before running a campaign.
Goal
Configure mewt so the user can run mewt run with optimal settings that balance thoroughness and execution time.
Configuration Workflow
Phase 1: Initialize and Validate Targets
Entry: User has a codebase and wants to configure mutation testing.
Actions:
Initialize mewt:
mewt init # Creates mewt.toml and mewt.sqliteNote: If working with a config in a non-standard location, use
--config path/to/mewt.toml. The parent directory of the config file becomes the working directory, and relative paths in the config resolve from there.Examples use mewt 4.x. Check the installed tool's
--helpbefore using unfamiliar flags. For muton, use its command name and configuration filename.Review auto-generated configuration:
mewt print configVerify target patterns:
Include patterns should match only source code:
src/,lib/,contracts/Ignore patterns should exclude tests, dependencies, generated code
Note: Ignore patterns use substring matching (e.g.,
"test"matchestests/,test_utils.rs)
Edit
mewt.tomlif needed to fix target patterns:[targets] include = ["src/**/*.rs"] # Specific source directories only ignore = ["test", "mock"] # Exclude test/mock files within src/
Exit: mewt.toml contains valid target patterns that match intended source files.
Phase 2: Generate Mutants and Assess Scope
Entry: Phase 1 exit criteria met (valid mewt.toml exists).
Actions:
Generate mutants:
mewt mutate src/Note: Output shows per-target summaries with severity breakdown (high/medium/low). Use
--verboseto see individual mutants.Check mutant count and distribution:
mewt status # View total mutant count mewt print targets # Pretty table showing which files were mutatedTime the test command:
time <test-command-from-config> # e.g., time cargo testNote the baseline test duration.
Calculate worst-case campaign duration:
Formula:
mutant_count × test_durationExample: 500 mutants × 10s = ~1.4 hours
Actual runtime typically faster (tests catch mutants quickly, skipping reduces load)
Exit: Know the mutant count, test duration, and estimated campaign time.
Phase 3: Decide on Optimization Strategy
Entry: Phase 2 exit criteria met (mutant count and time estimate known).
Decision Tree:
Estimated campaign duration?
|
+-- < 1 hour
| └─> Proceed to Phase 4 (no optimization needed)
|
+-- 1-16 hours
| └─> Consult user: Acceptable? Run overnight/end-of-day?
| +-- User accepts --> Proceed to Phase 4
| +-- User declines --> Apply optimization (see Optimization Strategies below)
|
+-- > 16 hours
└─> Explore optimization options (see Optimization Strategies below)Actions (if optimization needed):
Read references/optimization-strategies.md for detailed strategies and examples. Then:
Verify target selection (most common issue — check
mewt print targetsfor unintended files)Analyze project structure (
mewt print mutants --target 'src/component/**'per component)Present options to user with time estimates (full campaign / target critical components / high-severity only / two-phase)
Apply chosen optimization to
mewt.tomlIf
[targets]or[run].mutationschanged, update the database and recalculate duration: Purging deletes saved mutants and outcomes. Preserve results that need to be retained and confirm that discarding the affected campaign data is authorized before purging.Target scope narrowed (Option B): purge removed targets, then mutate any newly included files:
mewt purge # removes targets no longer in [targets].include/ignore mewt mutate src/ # adds mutants for any newly included files mewt status # verify reduced mutant countMutation types restricted (Option C): full regeneration required since existing mutants may no longer be valid:
mewt purge --all mewt mutate src/ mewt status # verify reduced mutant count
Update the duration estimate before proceeding to Phase 4.
Exit: Either campaign duration is acceptable, or mewt.toml has been optimized, the database updated, and the new duration estimate confirmed.
Phase 4: Validate Test Command and Timeout
Entry: Phase 3 exit criteria met (optimization applied if needed).
Actions:
If test configuration was modified in Phase 3, verify it works:
<test-command-from-config> # Should succeed without errorsSkip this step if Phase 2's timing already validated the unmodified command.
Check if timeout adjustment needed:
Default: Mewt auto-calculates timeout (baseline test time × 2), which accounts for incremental recompilation in most cases.
Exception: For compiled languages where recompilation of dependents dominates test time (Solidity/Foundry):
# Test with warm cache time forge test # e.g., 0.8s # Simulate mutation: touch source file to trigger dependent recompilation touch src/Contract.sol # Test again (includes recompilation) time forge test # e.g., 5.2s # If drastically different, set manual timeout in mewt.tomlIf recompilation time >> test time:
[test] cmd = "forge test" timeout = 11 # Based on: 5.2s × 2 = 10.4s, round upOtherwise, omit
timeoutand let mewt auto-calculate.
Exit: Test command verified working (if modified), timeout appropriately set (auto or manual).
Phase 5: Final Validation
Entry: Phase 4 exit criteria met (test command works if modified, timeout set).
Actions:
Run through the validation checklist to verify all prior phases completed successfully:
[ ]
mewt print config— Configuration syntax valid, no errors[ ]
mewt status— Mutant count matches expected count (Phase 2 count if no optimization applied; lower post-optimization count if[targets]or[run].mutationswas narrowed)[ ]
mewt print targets— Only intended files mutated (no tests, mocks, dependencies)[ ] Test command verified — Already validated in Phase 2 (and Phase 4 if modified)
[ ] Timeout set — Auto-calculated or manually set for recompilation-heavy languages
[ ] Scope acceptable — Duration estimate from Phase 2 acceptable to user
Exit: Ready to run mewt run.
Configuration Reference
File Structure
db = "mewt.sqlite"
[log]
level = "info" # trace, debug, info, warn, error
[targets]
# BE SPECIFIC: Source code only, never tests/dependencies
include = ["src/**/*.js", "lib/**/*.js"]
ignore = ["test", "mock"] # substring matches, not globs
[run]
# Optional: Restrict mutation types (omit to test all)
# mutations = ["ER", "CR", "IF", "IT"]
[test]
cmd = "npm test"
# timeout = 30 # Optional: auto-calculated if omitted (2× baseline)
# Per-target rules (first match wins)
[[per_target]]
glob = "src/core/*.js"
test.cmd = "npm test -- core"
test.timeout = 20Use top-level [[per_target]] rules with test.cmd and test.timeout. Run mewt print config after editing to catch invalid TOML and confirm the effective settings.
Target Configuration Examples
Important: Restrictive include patterns exclude most unwanted files. Only add ignore patterns for items within included paths.
# Rust project
[targets]
include = ["src/**/*.rs"]
ignore = ["test", "mock", "generated"]
# Solidity project
[targets]
include = ["contracts/**/*.sol"]
ignore = ["test", "interfaces", "mocks"]
# Go project
[targets]
include = ["**/*.go"]
ignore = ["test", "mock", "generated"]
# JavaScript/TypeScript
[targets]
include = ["src/**/*.ts", "lib/**/*.ts"]
ignore = ["test", "spec", "mock"]Test Configuration
Timeout Calculation:
Mutants trigger incremental recompilation (only mutated file + dependents). Mewt's auto-calculated timeout (2× baseline) usually accounts for this.
Edge case: In some compiled languages (Solidity/Foundry), recompiling dependent files takes much longer than running tests. Verify by timing tests, touching a file, and timing again. If drastically different, set manual timeout based on the slower measurement.
# Option 1: Auto-calculate (recommended for most languages)
[test]
cmd = "cargo test"
# Omit timeout — mewt measures baseline and applies 2× multiplier
# Option 2: Explicit timeout (for recompilation-heavy languages)
[test]
cmd = "forge test"
timeout = 11 # Based on: touch file, time test (5.2s), × 2Troubleshooting
No Mutants Generated
Check language support:
mewt print mutations --language rustVerify patterns:
mewt print config
find src -name '*.rs' | head # Do source files exist where include points?find, not ls src/**/*.rs. Whether ** recurses depends on the shell: zsh expands it, bash does not unless globstar is set, and the bash 3.2 that macOS ships has no globstar option to set. So the ls form degrades to src/*/*.rs under bash — given src/top.rs, src/a/one.rs, and src/a/b/two.rs it lists only src/a/one.rs — while the same line is correct under zsh. A diagnostic that under-reports on some machines and not others is worse than none: the files it drops read as "the include pattern doesn't match," sending you to edit a pattern that was already right. find behaves identically in every shell and exits 0 when nothing matches, instead of erroring. Keep the ** in mewt.toml, where mewt expands it rather than the shell.
Common causes:
Include pattern doesn't match files
Ignore pattern too broad (e.g.,
"test"matchestest_utils.rs)Unsupported language
Test Command Fails
Run command manually:
pytest # Should work from project directory without errorsFind correct command:
Check:
Makefile,justfile,package.json,README.mdIn monorepos, may need to run from workspace subdirectory
Configuration Validation
Before running mewt run, complete Phase 5's validation checklist above. If any item fails, return to the relevant phase to fix it.
Campaign Execution Timing
Recommend timing based on estimated duration:
< 1 hour: Run anytime
1-16 hours: Start end-of-day, results by morning
16-48 hours: Start Friday evening, results Monday
Two-phase: Phase 1 overnight, Phase 2 next day
Configuration Principles
Configure via
mewt.toml— Not CLI flags (version control the config)Target source code specifically — Exclude tests, dependencies, generated code
Prefer limiting files over mutation types — Better to assess critical code thoroughly
Verify test commands — Run manually before campaign
Trust auto-calculated timeouts — 2× baseline accounts for incremental recompilation in most cases
Measure before optimizing — Profile actual test times before applying per-target config
Document decisions — Commit
mewt.tomlwith comments explaining configuration choices
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 or Trail of Bits.
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download mutation-testing.zip