Don't ask your agent to run the tests.
Force it.

Verification for coding agents. Krites runs your checks itself and blocks the stop until they pass.

$claude plugin install krites@anthropic-plugin-directory
No setup for cargo, npm, pnpm, yarn, pytest or go testsRequires Node 20 or laterClaude Code · free · Apache-2.0READMETelemetry is opt-in
The plugin is free. Pro has 100 founding seats.

What goes wrong.

What happens
Says the tests pass, never ran them.RUNKrites runs them itself and reads the exit codes.
Hook times out, agent proceeds.HELDAn internal deadline blocks first, below Claude Code's own timeout.
Edit tool writes outside the repo.DENIEDWith a krites.toml, denied on the resolved real path, symlinks included.
Second stop attempt skips the gate.RERUNThe gate runs on every stop.
Runs git commit before the checks pass.GATEDWith checks in krites.toml, held unless the last run passed on the work as it stands and the commit carries all of it.
exit 2 leaks hook paths to the model.SCRUBBEDJSON block, relative paths only.
What the gate proves

Which commands ran, with which exit codes, on which diff, at which commit. Signed.

Krites runs the checks itself. With a krites.toml, the edit tools are denied on protected paths, and a protected path changed any other way refutes the next stop. The receipt is signed. It does not prove your tests are good; it proves they ran.

How it works

Three steps. None of them trust the agent.

Protect

With a krites.toml, the edit tools are denied on the paths you name there, and on anything outside the repo, before the write lands.

Blocked: docs/SPEC.md is protected.

Gate

When the agent tries to stop, Krites runs your checks itself, or your repo's test command until there is a krites.toml. The first failure blocks the stop, up to three times in a row by default, and hands the agent the command and its last 60 lines.

waiting for the agent to stopcargo test · exit 101 · refuted · stop blockedcargo test · exit 0 · passed · stop allowed

Receipt

/krites:receipt signs the last run: commands, exit codes, diff and commit. Anyone can verify it offline with one dependency-free file.

receipts/…4a10c564.json · ed25519
ProIN DEVELOPMENT

The same gate on Codex and OpenCode.
Then routing by what passes.

For anyone paying for more than one agent plan.

Works with Claude Code today. Codex and OpenCode adapters are next, free, with the same protected paths, stop gate and signed receipts. After that, Pro: a switcher that tracks headroom on each plan and moves a task to whichever has room, and routes by first-try pass rate on your own runs. No cost claims until the ledger backs them.

Not a screenshot
passed
TASKfix retry backoff in queue.rs
ROUTEclaude · planheadroom 7 of 10
GATEcargo testexit 101REFUTED
ROUTEcodex · planwhy: refuted, next plan with room
GATEcargo testexit 0PASSED
RECEIPTsigned · 2 routes · 1 refutation
Controlspinveto

The plugin is free. Pro has 100 founding seats.

Per seat · no usage fees
Free$0 · Apache-2.0

The Claude Code plugin: protected paths, the stop and commit gates, signed receipts, and the verifier. That's all that exists today, and it's all free.

Install the plugin
Founding seat100 seats
$99 / year, lockedPro planned at $240/yr

Pro is in development: the switcher and routing by first-try pass rate on your own runs. Your year starts the day Pro ships, not today.

Claim a founding seat · $99Full refund any time before Pro ships, and without asking if it hasn't shipped by the date you pick at checkout.

Krites never holds a vendor credential and never meters a token. License keys verify offline; if you stop paying, the version you have keeps working.

Every gate leaves a receipt.

Commands, exit codes, durations, and the diff stat, exported with /krites:receipt as signed JSON and Markdown. Attach one to the pull request and stop answering "did you run the tests?"

View a real receipt on GitHub
receipts/2026-09-25T17-42-54Z-4a10c564.jsonkrites.receipt/0.3
{
  "checks": [
    {
      "command": "cargo fmt --check",
      "duration_ms": 144,
      "exit_code": 0,
      "tail": ""
    },
    {
      "command": "cargo clippy --all-targets -- -D warnings",
      "duration_ms": 275,
      "exit_code": 0,
      "tail": "    Checking krites-fixture v0.1.0 (.)\n    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.15s\n"
    },
    {
      "command": "cargo doc --no-deps",
      "duration_ms": 353,
      "exit_code": 0,
      "tail": " Documenting krites-fixture v0.1.0 (.)\n    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.28s\n   Generated .\\target\\doc\\krites_fixture\\index.html\n"
    },
    {
      "command": "cargo test",
      "duration_ms": 473,
      "exit_code": 0,
      "tail": "   Compiling krites-fixture v0.1.0 (.)\n    Finished `test` profile [unoptimized + debuginfo] target(s) in 0.23s\n     Running unittests src\\lib.rs (target\\debug\\deps\\krites_fixture-b47e9f1eb22c7040.exe)\n\nrunning 0 tests\n\ntest result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s\n\n     Running tests\\total.rs (target\\debug\\deps\\total-ab1a7d6bba047f68.exe)\n\nrunning 1 test\ntest total_sums_the_values ... ok\n\ntest result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s\n\n   Doc-tests krites_fixture\n\nrunning 0 tests\n\ntest result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s\n\n"
    }
  ],
  "commands": [
    [
      "cargo",
      "fmt",
      "--check"
    ],
    [
      "cargo",
      "clippy",
      "--all-targets",
      "--",
      "-D",
      "warnings"
    ],
    [
      "cargo",
      "doc",
      "--no-deps"
    ],
    [
      "cargo",
      "test"
    ]
  ],
  "config_hash": "50e61df90d9e313abca94bada59ee30e521603d6e4ba7db8fa39a0575afd4d08",
  "created_at": "2026-09-25T17:42:54Z",
  "diff": {
    "deletions": 1,
    "files": [
      "src/lib.rs"
    ],
    "files_changed": 1,
    "insertions": 1
  },
  "env": [],
  "not_run": [],
  "plugin_version": "0.2.1",
  "reason": null,
  "repo": {
    "dirty": true,
    "head": "4a10c564f522ead66cf069aca370672c504bda50",
    "root_hash": "9c2440ea07f025e3e4a34406566f5a317fdf58930d7f6f18994aa602c2b9b8e7"
  },
  "schema": "krites.receipt/0.3",
  "session_id": "v0-sample",
  "signature": {
    "alg": "ed25519",
    "public_key": "S8B0by11nSvB+iMlF9ElY2jp7eOuRP8Afkz4CM7kiz8=",
    "sig": "SDznZXsm7jH5hyJOVeII+VPQxXo7ZAAihWp5b/dlfbhKmZn4e+5c5a1mMUdv0p0X6HmORoTuK7cT2TKnwnveDQ=="
  },
  "slow": [],
  "tree_fingerprint": "a61a51dfc41fa265fbc40da20e825f697c5676842377c74d69aaa66f7da33bb7",
  "verdict": "passed"
}
$ node verify-receipt.js --key 6b11164d362ea9b5 receipts/2026-09-25T17-42-54Z-4a10c564.json
valid: signed by 6b11164d362ea9b5c7711d8f5465d76c7d6da068a55f9b4253bd697171978bfa, verdict passed
VerbatimThe exact command Krites ran, its exit code, and how long it took. Nothing summarized by the agent.
The diff, at a commitFiles changed, insertions, deletions, HEAD, and the hash of the krites.toml that governed the run.
Tamper-evidentSigned with a per-install ed25519 key. Pin a teammate's key once and any edit to their receipts fails verification.
YoursWritten to receipts/ in the repo. No account, no upload, no model call.

Tell me about the last time your agent lied about tests.

Book 20 minutes