npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

mutant-bounty

v0.1.1

Published

Adversarial mutation gate for AI-written tests: proves whether a green suite notices broken logic, and refuses to let a coding agent stop until it does.

Readme

Mutant Bounty is an adversarial mutation gate for AI-written tests. It breaks your code on purpose, runs your test suite against each break, and shows you every break the suite failed to notice. Installed as a Stop hook, it refuses to let Claude Code or Codex say "done" while those breaks survive.

No dependencies. One Node script. Your working tree is never modified.

Quick install from npm — run these in the repository you want to protect:

npm install --save-dev mutant-bounty
npx mutant-bounty-install --claude --codex

Choose --claude, --codex, or both. First audit and agent setup.


The problem

Your agent implements canDelete(), writes a test, runs it. Green. Ship it.

test("canDelete returns a boolean", () => {
  const result = canDelete({ id: 1, isAdmin: true }, { ownerId: 2 });
  assert.ok(result !== undefined);
  assert.equal(typeof result, "boolean");
});

That test passes if canDelete returns true for everyone. It passes if it returns false for everyone. It passes if the admin check is replaced with if (true). Coverage reports 100%. The test proves nothing.

This is the oracle problem, and it is the default output of vibe-coding: the same model wrote the code and the test, so the test agrees with the code by construction. Green means "consistent with itself", not "correct".

What Mutant Bounty does about it

  1. Finds what changed. Production lines from git diff, plus untracked files. Tests, fixtures, snapshots and generated code are never touched.
  2. Breaks each line on purpose, one mutant at a time. >= becomes <. if (user.isAdmin) becomes if (true). a || b becomes a && b. return total * 0.9 becomes return 0.
  3. Runs your real test command against every mutant in a throwaway copy of the repository.
  4. Reports every mutant that stayed green. Each survivor is a bug your suite would ship, listed with the file, the line, the exact edit, and the assertion that is missing.
  5. Blocks the agent. As a Stop hook it reads the latest report and refuses the stop while the audit is missing, stale, inconclusive, or has survivors. The refusal tells the agent exactly what to run and what to fix.

See it

The demo repository has an uncommitted canDelete implementation and the type-only test above. npm test is green.

The agent adds four behavioral cases: admin allowed, owner allowed, stranger denied, locked document never deletable. Same eight mutants:

Every survivor also lands in a self-contained HTML report with a repair hint per mutant:

The part no other mutation tool does

Mutation testing has existed for decades. What is new is the enforcement point: the moment an agent decides it is finished.

This is a real transcript from a headless Claude Code session in the demo repository. The prompt was "add one line to README.md and finish". The Stop hook answered:

Mutant Bounty stop gate: BLOCKED (1/3) - no Mutant Bounty report exists for the changed production files.
Changed files: src/auth.mjs
Expected report: .mutant-bounty/latest.json

Do not claim the change is done or ready for a PR. Required next step:
  node ".../mutant-bounty.mjs" --root "..." --test-command "npm test" --max-mutants 8 --json ".mutant-bounty/latest.json" --html ".mutant-bounty/latest.html"
Then resolve every survivor with a behavioral assertion (green original, red mutant), rerun the exact command, and stop again.

Claude did not stop. It ran the audit, found 7 survivors, rewrote the test with four behavioral cases, reran the audit, killed 8 of 8, and only then was allowed to finish. Eleven turns, fifty seconds. Codex, given the same repository and prompt, did the same and closed with the markdown dashboard below.

| Harness | Hook file | Verified | |---|---|---| | Claude Code 2.1 | .claude/settings.json | Headless run: blocked, audited, repaired, allowed | | Codex CLI 0.153 | .codex/hooks.json | Headless run: blocked, audited, repaired, allowed |

The gate never runs your suite itself. It checks SHA-256 fingerprints of the audited source and the copied repository inputs, including tests, fixtures, manifests, lockfiles and configuration. Changed, added or deleted inputs invalidate a report. A new run replaces the previous report before it starts; failed or interrupted audits cannot reuse an old success. A loop guard yields after three consecutive blocks on the same state, so a stuck agent is never trapped.

Install

Node 20 or newer and Git are required. Run the commands from the JavaScript or TypeScript repository you want to audit.

Try one audit

With a green test suite and staged, unstaged or untracked production changes:

npx mutant-bounty --root . --test-command "npm test"

The default scope is your changes relative to HEAD. In a clean checkout, or a repository without its first commit, name an existing source file explicitly:

npx mutant-bounty --root . --file src/pricing.ts --test-command "npm test"

Replace src/pricing.ts with a file in your repository and npm test with your real test command. A clean checkout without --file has nothing to audit and exits with code 2.

Audits save JSON evidence to .mutant-bounty/latest.json by default, including a failed baseline. Use --json to choose another path and --html .mutant-bounty/latest.html for the visual report.

Install the agent hook

Install the published mutant-bounty package as a project dependency, then run its installer:

npm install --save-dev mutant-bounty
npx mutant-bounty-install --claude --codex

Choose --claude, --codex, or both. mutant-bounty-install is a binary included in the mutant-bounty package, not a separate npm package; the install command above makes it available to npx. The gate path points into the project's installed dependency, so it remains available after the npm cache is cleared. After moving the checkout to a different path, rerun the installer.

For a one-off installer check without a local dependency, select the package explicitly:

npx --package=mutant-bounty mutant-bounty-install --check

The installer detects the test command from package.json, writes .claude/settings.json and .codex/hooks.json with the absolute path of the gate, preserves other hooks, checks Node, Git and the harness CLIs, and probes the gate. Malformed existing settings stop installation without overwriting either target. Pass --test-command "pnpm test" or --check-command "npm run typecheck" when needed.

Codex only: on the first turn in that repository, accept the two prompts that trust the project's .codex layer and the hook command. Until both are accepted the hook silently never runs.

Optional named skill commands

The npm package already contains SKILL.md, which the hook points the agent to. To also register /mutant-bounty in Claude Code or $mutant-bounty in Codex, clone into the appropriate skill directory:

# Claude Code
git clone https://github.com/ahmtsahin/mutant-bounty ~/.claude/skills/mutant-bounty

# Codex
git clone https://github.com/ahmtsahin/mutant-bounty ~/.codex/skills/mutant-bounty

If you use a clone instead of npm for the hook, run its installer from your target repository: node ~/.claude/skills/mutant-bounty/hooks/install.mjs --claude or node ~/.codex/skills/mutant-bounty/hooks/install.mjs --codex.

Use it by hand

With the optional skill registered, type /mutant-bounty in Claude Code or $mutant-bounty in Codex. You can also run the npm CLI directly and save evidence for the hook:

npx mutant-bounty \
  --root . \
  --test-command "npm test" \
  --json .mutant-bounty/latest.json \
  --html .mutant-bounty/latest.html

Add --check-command "npm run typecheck" when the repository has a compile step, --file src/pricing.ts to audit a file Git cannot infer, and --max-mutants 20 for a deeper pass.

What you get

In the terminal: the live dashboard shown above. When stdout is not a terminal the same run prints a stable plain-text report, which is what the agent reads and what the tests assert on. --color always|never overrides the detection.

In the chat: the skill instructs the agent to summarize every run in one fixed shape, so a reader can scan it in a chat window:

☠ NOT READY — 7 / 8 mutants survived · mutation score 13% · 5.2 s

| | Location | Mutation | Missing assertion | |---|---|---|---| | ☠ | src/auth.mjs:4 | if (user.isAdmin \|\| user.id === doc.ownerId) → if (true) | canDelete({id:3,isAdmin:false}, {ownerId:2}) must be false | | ☠ | src/auth.mjs:4 | \|\| → && | admin who is not the owner must still get true | | ☠ | src/auth.mjs:3 | if (doc.locked) → if (false) | locked document must be denied even for an admin | | ✅ | src/auth.mjs:5 | return true → return 0 | — |

Baseline npm test PASS · scope src/auth.mjs (changed lines) · invalid 0 · report .mutant-bounty/latest.html

As files: latest.json (schema-versioned, for the Stop hook and CI) and latest.html (the report above, no external resources). Both live in .mutant-bounty/, which git-ignores itself.

JSON schema 3 records whether the run is RUNNING, FAILED or COMPLETED. The gate requires a completed, current audit. After updating from schema 1 or 2, rerun the audit once; those older reports do not fingerprint test inputs.

Statuses and exit codes

| Status | Meaning | |---|---| | SURVIVED | The suite passed with the mutant in place. Blocking until reviewed. | | KILLED_BY_COMMAND | The suite failed. Inspect the failure; an assertion is stronger evidence than a crash. | | INVALID | The mutant never reached the tests: rejected by the syntax preflight, by --check-command, or the test output was a compile error naming the mutated file. Reported, not counted; the next candidate is tried instead. | | INCONCLUSIVE | Timeout or crash. Never treated as a pass. |

Exit 0 when every executed mutant was killed, 1 when any survived, 2 when the result is not gateable: red baseline, no candidate, no executable mutant, or an inconclusive run.

Why not just run Stryker?

You can, and for a full-suite score you should. Mutant Bounty is built for a different moment.

| | Stryker / PIT / mutmut | Mutant Bounty | |---|---|---| | Scope | Whole project, or incremental cache | The lines the agent just changed | | Runtime | Minutes | Seconds (5.2 s on the demo above) | | Where it runs | CI, or when you remember | The instant the agent tries to stop | | Who reads the output | You | The agent, in a format it can act on | | Setup | Config file, plugin per runner | One command, any test command | | Dependencies | Many | None | | False kills | Handled by AST-level mutators | Masking, whitespace-delimited comparators, syntax preflight, compile-error detection |

It is not a replacement for a nightly full mutation run. It is the thing that stops "all 10 tests pass ✅" from being the last message before a PR.

Honest limitations

  • JavaScript and TypeScript only. Five operator families: condition, comparator, logical, return value, boolean literal.
  • Mutations are textual, per line, on a masked copy that ignores strings and comments. Bare < and > are only mutated with whitespace on both sides, so a>b yields no comparator mutant. Generics and JSX are never touched.
  • Each mutant runs in a fresh copy of the repository (minus node_modules, which is linked). On a 3,000-file tree that costs about 20 seconds for eight mutants. A single-workspace mode is the next planned change.
  • Input fingerprints cover files copied into the workspace. .git, .mutant-bounty, node_modules, coverage and the chosen report files are excluded. External services, environment variables and installed dependency contents are outside this fingerprint; use a fresh audit when they change. Keep gate state in .mutant-bounty/.
  • Symbolic links and junctions in copied source or test inputs are rejected before tests run. The linked root node_modules directory is the deliberate exception.
  • INVALID detection from test output is a heuristic. It is deliberately biased toward demoting a doubtful kill to invalid, because a false kill is the dangerous direction.

Development

npm test

Thirty-four tests cover the auditor, source isolation, stale test/config inputs, failed and malformed reports, Unicode paths, installer preservation and target selection, and a fresh npm package installation. The package smoke test packs the current source, installs it offline into a project whose path contains spaces, runs both installed bins, and verifies block → audit → allow through the generated hook. Run the suite with npm test; it supplies the npm CLI used by that smoke test. CI runs it on Windows and Linux with Node 20 and 22.

SKILL.md                     skill entry point for Claude Code and Codex
agents/openai.yaml           Codex skill metadata
scripts/mutant-bounty.mjs    the auditor: diff scope, mutants, isolation, reports
hooks/stop-gate.mjs          the Stop hook for both harnesses
hooks/install.mjs            installer and doctor
references/mutation-policy.md  survivor triage and repair patterns for the agent
references/mvp-design.md     design, acceptance criteria, hook contract
tests/                       node:test suites

License

MIT © Ahmet Sahin