Tests your agent can't game.
The most common failure in agentic development isn't broken code. It's an agent quietly bending the tests to fit what it built. 2119 makes plans become requirements, requirements become tests, and tests get judged by a reviewer that didn't write them. Enforced, not requested.
$ npx rfc2119 initHow it works
Context
Prompt the agent to read the relevant context and prepare to discuss the feature.
Spec
The plan is stored as an RFC 2119 spec: numbered requirements with stable IDs, exactly one keyword each. 2119 lint enforces the format.
Build
Every MUST needs at least one test carrying that requirement’s ID in a comment. 2119 cover fails on any gap, in either direction.
Judge
A fresh-context reviewer that didn’t write the code reads each requirement and its tests, and answers one question: would these tests fail if this requirement were violated? Verdicts are recorded, committed, and gate 2119 check.
Artifact
The words in the plan decide how it gets tested.
Specs are plain markdown with every line addressable. Tests declare which requirement they exist for in a comment, so the mapping works in any language.
file · specs/session-handling.md
# REQ-001: Session Handling### REQ-001.1: Timeouts1. Sessions MUST expire after 30 minutes of inactivity.2. Expired sessions MUST NOT be resumable with a stale token.3. The docs SHOULD explain the timeout rationale. [review: docs/**]// in any language, a covering test declares its requirement:// 2119: REQ-001.1.2it("rejects a stale token after expiry", async () => { ... });
Why it holds
Approvals expire the moment content changes.
Every verdict is keyed to a SHA-256 of the requirement's text plus the full content of its covering tests. Edit a test, or reword the requirement, and the old approval silently stops counting. Verdicts are committed JSON with a written justification, so every review decision is visible in the PR diff.
verdict hashing
requirement text ─┐├─▶ sha256 ─▶ REQ-001.1.2--9f2c41ab07de ─▶ verdict: passcovering tests ──┘# ...then the agent edits a covering test...requirement text ─┐├─▶ sha256 ─▶ REQ-001.1.2--e07d5512c9aa ─▶ no verdict; check failscovering tests* ──┘
Stated honestly: no local tool can physically stop an agent from approving its own work, because the agent controls the shell. The mitigations are layered. Committed verdicts make self-approval visible, hash invalidation makes it short-lived, and CI re-runs the same check with no agent in the loop, so nothing merges without the full gate.
It works on its author. Building 2119 with 2119, the first review round returned six failing verdicts, every one a genuine defect.
Quickstart
One command, any repo, any agent.
terminal
$ npx rfc2119 init # specs/, config, AGENTS.md section$ npx rfc2119 check # lint + cover + review, one exit code
On agents with lifecycle hooks (Claude Code, Codex CLI, Gemini CLI), npx rfc2119 init --agent claude adds write-time lint feedback and a stop gate that blocks “done” while check fails. Everywhere else the same gate runs through AGENTS.md, a pre-commit hook, and CI. It composes with DeepWork: DeepReviews is the general engine for custom review rules; 2119 is the portable distillation of this one loop.