
Genotoxic
FreeStreamline mutation testing triage with graph analysis.
Free · Opens the source repo
What Genotoxic does
Genotoxic is a powerful skill designed for developers and testers who need to enhance their mutation testing processes. By integrating mutation testing with necessist and code graph analysis, Genotoxic helps users triage findings into actionable categories. This includes identifying false positives, pinpointing missing unit tests, and discovering potential fuzzing targets. The skill leverages data flow context to prioritize test improvements, ensuring that developers focus their efforts where they will have the most significant impact on code quality.
The workflow begins with the parsing of the codebase using Trailmark, which builds a comprehensive code graph. This graph is crucial for understanding the relationships and dependencies within the code, which informs the mutation testing process. After running the mutation tests, Genotoxic analyzes the results, filtering out harmless mutants and highlighting those that require attention. This systematic approach not only streamlines the triage process but also enhances overall test coverage and robustness.
Genotoxic is particularly beneficial in scenarios where mutation testing has already revealed survived mutants that need further investigation. It is ideal for teams looking to strengthen their testing strategies by identifying weak spots in their unit tests or functions that may benefit more from fuzz testing than traditional unit tests. By utilizing Genotoxic, developers can ensure their testing efforts are data-driven and focused on the most critical areas of their codebase.
However, it is essential to note that Genotoxic is not suitable for codebases lacking an existing test suite or for trivial scripts where mutation testing may not provide substantial insights. Users should ensure they have the necessary prerequisites installed, including Trailmark and a mutation testing framework, to fully leverage the capabilities of this skill.
When to use it
Use Genotoxic after conducting mutation testing to analyze survived mutants and improve test coverage.
When not to use it
Avoid using Genotoxic if there is no existing test suite or if working with simple scripts that do not require mutation testing.
What you can build with it
Enhancing Test Coverage
After running mutation tests, use Genotoxic to identify areas lacking sufficient test coverage and prioritize writing new unit tests.
Identifying Fuzzing Targets
Utilize Genotoxic to find functions that would benefit more from fuzz testing rather than traditional unit tests, improving overall robustness.
Reducing False Positives
Leverage Genotoxic to analyze survived mutants and filter out false positives, streamlining the testing process and focusing on critical issues.
How to install Genotoxic
View source1. Install with the skills CLI
npx skills add trailofbits/skills/genotoxic --agent claude-code2. Or install it manually
Download the skill folder and drop it into ~/.claude/skills/ for all projects, or .claude/skills/ to scope it to one repo. Restart Claude Code so it picks up the new skill.
Anthropic's agentic coding CLI, and the reference implementation of Agent Skills. Drop a skill folder into ~/.claude/skills and Claude Code loads it automatically whenever a task matches the skill's description. Claude Code docs
Inside SKILL.md
Written by trailofbitsGenotoxic
Combines mutation testing and necessist (test statement removal) with code graph analysis to triage findings into actionable categories: false positives, missing unit tests, and fuzzing targets.
When to Use
- After mutation testing reveals survived mutants that need triage
- Identifying where unit tests would have the highest impact
- Finding functions that need fuzz harnesses instead of unit tests
- Prioritizing test improvements using data flow context
- Filtering out harmless mutants from actionable ones
- Finding unnecessary test statements that indicate weak assertions (necessist)
When NOT to Use
- Codebase has no existing test suite (write tests first)
- Pure documentation or configuration changes
- Single-file scripts with trivial logic
Prerequisites
- trailmark installed — if
uv run trailmarkfails, run:
DO NOT fall back to "manual verification" or "manual analysis" as a substitute for running trailmark. Install it first. If installation fails, report the error instead of switching to manual analysis.uv pip install trailmark - A mutation testing framework for the target language — if the framework command fails (not found, not installed), install it using the instructions in references/mutation-frameworks.md. DO NOT fall back to "manual mutation analysis" or skip mutation testing. Install the framework first. If installation fails, report the error instead of switching to manual mutation analysis.
- necessist (optional, recommended) — if the target language is
supported (Go, Rust, Solidity/Foundry, TypeScript/Hardhat,
TypeScript/Vitest, Rust/Anchor), install with
cargo install necessist. See references/mutation-frameworks.md for details. - An existing test suite that passes
- macOS environment: Run
ulimit -n 1024before anymull-runnerinvocation. macOS Tahoe (26+) sets unlimited file descriptors by default, which crashes Mull's subprocess spawning. See references/mutation-frameworks.md for details.
Rationalizations to Reject
| Rationalization | Why It's Wrong | Required Action |
|---|---|---|
| "All survived mutants need tests" | Many are harmless or equivalent | Triage before writing tests |
| "Mutation testing is too noisy" | Noise means you're not triaging | Use graph data to filter |
| "Unit tests cover everything" | Complex data flows need fuzzing | Check entrypoint reachability |
| "Dead code mutants don't matter" | Dead code should be removed | Flag for cleanup |
| "Low complexity = low risk" | Boundary bugs hide in simple code | Check mutant location |
| "Tool isn't installed, I'll do it manually" | Manual analysis misses what tooling catches | Install the tool first |
| "Necessist isn't mutation testing, skip it" | Necessist finds what mutation testing misses: weak tests | Run both when the language supports it |
Quick Start
# 1. Build the code graph
uv run trailmark analyze --language auto --summary {targetDir}
# 2. Run mutation testing (language-dependent)
# Python:
uv run mutmut run --paths-to-mutate {targetDir}/src
uv run mutmut results
# 2b. Run necessist (if language supported)
necessist
# 3. Analyze results with this skill's workflow (Phase 3)
Workflow Overview
Phase 1: Graph Build → Parse codebase with trailmark
↓
Phase 2: Mutation Run → Execute mutation testing framework
Phase 2b: Necessist Run → Remove test statements (optional, parallel)
↓
Phase 3: Triage → Classify findings using graph data
↓
Output: Categorized Report
├── Corroborated (both tools flag same function — highest value)
├── False Positives (harmless, skip)
├── Missing Tests (write unit tests)
└── Fuzzing Targets (set up fuzz harnesses)
Decision Tree
├─ Need to set up mutation testing for a language?
│ └─ Read: references/mutation-frameworks.md
│
├─ Need to set up necessist or find weak test statements?
│ └─ Read: references/mutation-frameworks.md (Necessist section)
│
├─ Need to understand the triage criteria in depth?
│ └─ Read: references/triage-methodology.md
│
├─ Need to understand how graph data informs triage?
│ └─ Read: references/graph-analysis.md
│
└─ Already have results + graph? Use Phase 3 below.
Phase 1: Build Code Graph and Run Pre-Analysis
Parse the target codebase with trailmark and run pre-analysis before mutation testing. Pre-analysis computes blast radius, entry points, privilege boundaries, and taint propagation, which Phase 3 uses for triage.
uv run trailmark analyze --language auto --summary {targetDir}
Use the QueryEngine API to build the graph and run pre-analysis:
QueryEngine.from_directory("{targetDir}", language="auto")- Call
engine.preanalysis()— mandatory before triage - Export with
engine.to_json()for cross-referencing with mutation results
If auto-detection is wrong for the target, rerun with an explicit language or
comma-separated list such as python,rust.
See references/graph-analysis.md for the full API: node mapping, reachability queries, blast radius, and pre-analysis subgraph lookups.
Phase 2: Run Mutation Testing
Select and run the appropriate framework. See references/mutation-frameworks.md for language-specific setup.
Capture survived mutants. Each framework reports differently, but extract these fields per mutant:
| Field | Description |
|---|---|
| File path | Source file containing the mutant |
| Line number | Line where mutation was applied |
| Mutation type | What was changed (operator, value, etc.) |
| Status | survived, killed, timeout, error |
Filter to survived mutants only for Phase 3.
Phase 2b: Run Necessist (Optional)
If the target language is supported (Go, Rust, Solidity/Foundry, TypeScript/Hardhat, TypeScript/Vitest, Rust/Anchor), run necessist to find unnecessary test statements. This runs independently of Phase 2 and can execute in parallel.
# Auto-detect framework
necessist
# Or target specific test files
necessist tests/test_parser.rs
# Export results
necessist --dump
Filter to findings where the test passed after removal. See references/mutation-frameworks.md for framework-specific configuration and the normalized record format.
Map each removal to a production function using the algorithm in references/graph-analysis.md.
Phase 3: Triage Findings
For each survived mutant and each necessist removal, determine its triage bucket using graph data. Necessist removals must first be mapped to a production function (see references/graph-analysis.md).
Quick Classification (Mutation Testing)
| Signal | Bucket | Reasoning |
|---|---|---|
| No callers in graph | False Positive | Dead code, mutant is unreachable |
| Only test callers | False Positive | Test infrastructure, not production |
| Logging/display string | False Positive | Cosmetic, no behavioral impact |
| Equivalent mutant | False Positive | Behavior unchanged despite mutation |
| Simple function, low CC, no entrypoint path | Missing Tests | Unit test is straightforward |
| Error handling path | Missing Tests | Should have negative test cases |
| Boundary condition (off-by-one) | Missing Tests | Property-based test candidate |
| Pure function, deterministic | Missing Tests | Easy to test, high value |
| High CC (>10), entrypoint reachable | Fuzzing Target | Complex + exposed = fuzz it |
| Parser/validator/deserializer | Fuzzing Target | Structured input handling |
| Many callers (>10) + moderate CC | Fuzzing Target | High blast radius |
| Binary/wire protocol handling | Fuzzing Target | Fuzzers excel at format testing |
Quick Classification (Necessist)
| Signal | Bucket | Reasoning |
|---|---|---|
| Redundant setup or debug call | False Positive | Statement genuinely unnecessary |
| Cannot map to production function | False Positive | No graph context for triage |
| Call removed, no assertion checks its effect | Missing Tests | Test has weak assertions |
| Assertion removed, test still passes | Missing Tests | Redundant or insufficient coverage |
| Maps to high-CC entrypoint-reachable function | Fuzzing Target | Complex + exposed + weak test |
When both mutation testing and necessist flag the same production function, mark as corroborated — highest confidence finding.
For detailed criteria, see references/triage-methodology.md.
Graph Queries for Triage
For each mutant, map it to its containing graph node and use pre-analysis subgraphs (tainted, high_blast_radius, privilege_boundary) from Phase 1 to classify it. The classification logic checks: no callers → false positive, privilege boundary → fuzzing, high CC + tainted → fuzzing, high blast radius → fuzzing, otherwise → missing tests.
See references/graph-analysis.md for
the batch_triage implementation and node mapping functions.
Output Format
Generate a markdown report:
# Genotoxic Triage Report
## Summary
- Total survived mutants: N
- Total necessist removals: N
- Corroborated findings: N
- False positives: N (N%)
- Missing test coverage: N (N%)
- Fuzzing targets: N (N%)
## Corroborated Findings
| File | Line | Function | Mutation Signal | Necessist Signal | Action |
|------|------|----------|----------------|------------------|--------|
## False Positives
| File | Line | Mutation | Reason | Source |
|------|------|----------|--------|--------|
## Missing Test Coverage
| File | Line | Function | CC | Callers | Suggested Test | Source |
|------|------|----------|----|---------|----------------|--------|
## Fuzzing Targets
| File | Line | Function | CC | Entrypoint Path | Blast Radius | Source |
|------|------|----------|----|-----------------|--------------|--------|
The Source column is mutation, necessist, or corroborated.
Write the report to GENOTOXIC_REPORT.md in the working directory.
Quality Checklist
Before delivering:
- Trailmark graph built for target language
- Mutation framework ran to completion
- Necessist ran (if language supported) or noted as not applicable
- All survived mutants triaged (none unclassified)
- All necessist removals triaged (if applicable)
- Corroborated findings identified (if both tools ran)
- False positives have clear justifications
- Missing test items include suggested test type
- Fuzzing targets include entrypoint paths and blast radius
- Report file written to
GENOTOXIC_REPORT.md - User notified with summary statistics
Integration
trailmark skill:
- Phase 1: Build code graph, query complexity and entrypoints
- Phase 3: Caller analysis, reachability, blast radius
property-based-testing skill:
- Missing test coverage items involving boundary conditions
- Roundtrip/idempotence properties for serialization mutants
testing-handbook-skills (fuzzing):
- Fuzzing target items: use
harness-writing,cargo-fuzz,atheris
Supporting Documentation
- references/mutation-frameworks.md - Language-specific framework setup, output parsing, and necessist configuration
- references/triage-methodology.md - Detailed triage criteria, edge cases, and worked examples for both mutation testing and necessist
- references/graph-analysis.md - Graph query patterns, test-to-production mapping, and result merging
First-time users: Start with Phase 1 (graph build), then run mutations, then use the Quick Classification table in Phase 3.
Experienced users: Jump to Phase 3 and use the Decision Tree to load specific reference material.
Frequently asked questions about Genotoxic
Similar skills
Quality Playbook Generator
Run comprehensive quality audits on any codebase.
PR Draft Summary
Automate PR summary generation for openai-agents-python.
Final Release Review
Streamline your release candidate audits with ease.
Unit Test Vue Pinia
Efficiently write and review unit tests for Vue 3 applications.
Slang Shader Expert
Optimize and integrate Slang shaders with ease.
Telemetry Standards
Ensure consistent event tracking in Supabase Studio.
