Skip to main content

specwarden 🪨

Every code change traces back to a written spec. Enforced by hooks, not vibes.

demo

bash <(curl -fsSL https://raw.githubusercontent.com/ameyxd/specwarden/main/install.sh)

The problem

AI agents start editing the moment you say go. Silent assumptions get baked in, adjacent files get touched, and by the time you review the diff the decisions are already made. The Karpathy CLAUDE.md named the failure modes — silent assumptions, hidden confusion, scope creep — and proposed behavioral rules as the cure. Rules work until the agent ignores them.

The fix in 30 seconds

A typical session with specwarden active:

You:    add JWT auth to the Flask API

Claude: [Edit on src/auth/middleware.py]
        -> specwarden: no active spec. Run `/spec <slug>` first to define
           what you're building before editing files.

You:    specwarden new "add jwt auth"
        # then you fill in the four sections yourself, in your editor
        specwarden activate 2026-05-06_add-jwt-auth

        # if you activate it while the template is still untouched:
        # -> specwarden: spec 2026-05-06_add-jwt-auth still has unwritten
        #    sections: Assumptions, Scope, Non-goals, Success criteria.
        #    An empty template is not a spec.

Claude: [edits src/auth/middleware.py]
        [creates src/auth/jwt.py]

# .claude/decisions/2026-05-06_add-jwt-auth.md now contains:
## 2026-05-06T14:32:18+00:00
- File: src/auth/jwt.py
- Lines: 1-87 (created)
- Summary: Write on src/auth/jwt.py
- Tool: Write

No edit tool call lands until a written spec is active, and every one that does is logged.

Two things this deliberately does not show, because they are not true:

  • The agent does not draft the spec. You write the four sections. A spec generated by the agent it is meant to constrain is that agent's assumptions wearing a human's authority.
  • There is no ready handshake. The skill asks the model to pause for your confirmation, and that is a behavioural convention only — nothing in the hooks checks it. What the hooks check is that the spec exists, is active, and has all four sections written.

The Summary line is mechanical (<tool> on <path>). Producing a real semantic summary without asking the agent to describe its own edit is an open problem; the richer entries under examples/ are the target, not the output.

What the gate does and does not cover

The PreToolUse hook matches Edit|Write|MultiEdit|NotebookEdit. That is the whole of its reach, and it is worth being blunt about the consequence:

  • Covered. Claude Code's file-editing tools. With no active spec, the call is denied and the model is told why.
  • Not covered. Shell commands. An agent that writes a file with cat > file, sed -i, or tee walks straight past the gate, and PostToolUse does not log it either. Verified, not theorised: with hooks live and no active spec, "append to calc.py using a Bash heredoc" succeeded on the first try.

Adding Bash to the matcher would deny every shell command without a spec — including ls, grep, and the test run — so specwarden does not do it. Treat the gate as a guardrail against an agent that drifts, not as a sandbox against one that is trying to get around it.

Benchmark numbers

Four arms, five fixture tasks, one trial per cell (20 cells). The measured claim is narrow and it is about the gate:

With hooks active, 20 of 20 edit attempts were blocked. Without them, 0 of 27 were.

Edit attempts Blocked Files changed
No hooks 27 0 16
Hooks wired 20 20 0

That is the whole of what this benchmark establishes. What it does not establish, stated plainly:

  • "0 files changed" is not tidiness, it is zero work. No spec was active in the gated cells, so the gate refused every edit and no task got done. It shows the gate holds. It says nothing about diff quality.
  • Out-of-scope edits are still unmeasured. The harness counts changed files; nothing compares them against a declared in-scope set.
  • The gate covers tool calls, not the filesystem. See the section above — a cat > walks past it.
  • n=1 per cell. Five tasks, single trial, no variance estimate.

An earlier run of this benchmark reported a 75–87% reduction in files modified and concluded the skill text was doing the work. That run passed --bare to every arm, which disables hooks, so it never tested enforcement at all; its file counter also ignored created files. Its behavioural finding did not reproduce here — no spec file was written in any cell of this run, and the skill-only arm changed 7 files against the control's 9. Treat the old numbers as withdrawn. Total run cost: $10.47.

Full methodology, scorecard, and the reproduction gap: evals/results/2026-07-25.md. Superseded run, kept for the record: evals/results/2026-05-11.md. Reproduce with make eval (~46 min, ~$10.50 in API tokens), or make eval-enforcement for just the arm A vs arm D contrast.

Install and first spec

macOS / Linux / WSL:

bash <(curl -fsSL https://raw.githubusercontent.com/ameyxd/specwarden/main/install.sh)

Windows PowerShell:

irm https://raw.githubusercontent.com/ameyxd/specwarden/main/install.ps1 | iex

Both installers run pipx install specwarden and specwarden init in the current directory. If you prefer to do it manually:

pipx install specwarden
cd your-repo
specwarden init      # creates .claude/specs/, wires hooks into .claude/settings.json

Create your first spec:

specwarden new "add jwt auth"
# opens .claude/specs/2026-05-06_add-jwt-auth.md in $EDITOR
# fill in the four sections, then:
specwarden activate 2026-05-06_add-jwt-auth

Now open Claude Code. The PreToolUse hook is live; no Edit or Write call lands until the spec is active and its four sections are written. Shell commands are not gated — see above.


Architecture

Three pieces: a CLI that manages spec state, hooks that intercept every edit, and a skill that loads the four-slash-command interface into the model's context. Removing the skill leaves enforcement intact; removing the hooks leaves advisory guidance intact; the CLI manages the .claude/specs/active file that both read. Full detail: docs/ARCHITECTURE.md.

What specwarden is not

Pulled from the project spec and the philosophy doc:

  • Not a project management tool. No assignees, priorities, due dates, or status boards.
  • Not a multi-user collaboration tool. Single-developer workflow only in v1.
  • Not a spec generator. The human writes the spec; that is the forcing function.
  • Not an integration layer. No GitHub Issues, Linear, Jira, or other trackers.
  • Not a migration tool. No importer for existing .cursorrules or CLAUDE.md rules.
  • Not a web UI. Everything is markdown files in git.

Comparison

Advisory text Edit enforcement Decisions log Coverage report Portable
github/spec-kit yes (templates) no no no many agent hosts
Karpathy CLAUDE.md yes no no no any host
Cursor .cursorrules yes no no no Cursor only
MCP server — no no no yes
specwarden yes yes yes yes Claude Code +

specwarden is complementary to spec-kit: use spec-kit's templates to write the spec, install specwarden so the hook layer enforces it during editing. Long-form comparison with tradeoffs: docs/COMPARISONS.md.

FAQ

Doesn't this slow me down? It adds one step — writing a four-section spec — before code lands. That step is roughly three to five minutes for a focused change. The bet is that surfacing assumptions and scope before editing saves more time in review and debugging than the spec took to write. For cases where it genuinely is overhead (typo fix, dependency bump), set SPECWARDEN_QUICKFIX=1 to bypass the check.

What about quick fixes? SPECWARDEN_QUICKFIX=1 claude skips the PreToolUse check entirely. The decisions log is not populated and the commit will appear as uncovered in specwarden coverage output. Use it for edits where a spec would be absurd; accept the uncovered commit.

Why not just use GitHub Issues? Issues track what you want to do. Specs record what you assumed, what was explicitly out of scope, and how you knew you were done — before the code was written, not after. The decisions log records what the agent actually did and why. That chain is what lets you audit a commit six months later without reading every line of diff. An issue link in a commit message does not give you that.

Does it work with Cursor or Codex CLI? The SKILL.md format and behavioral text load correctly in any agent host that supports skill injection or system-prompt files. Without Claude Code's hook support the enforcement layer is absent and you get advisory behaviour only, which is arm B in the benchmark — and arm B changed 7 files against the control's 9, with 16 edit attempts and none blocked. So on those hosts you are getting the spec template and the habit, not a gate. That is worth having, but do not mistake it for enforcement.

Contributing

The most useful contribution is a new eval fixture: a small self-contained coding task with a starting_state/ directory and a prompt.md. See evals/README.md for the fixture format and the submission checklist. Bug fixes and tests follow the same path: open an issue, reference it in a spec, submit a PR. Commits follow Conventional Commits (feat:, fix:, docs:, test:, chore:, refactor:); subject under 72 characters; no emoji.

License

MIT — see LICENSE.

Metadata

Release files for specwarden 0.2.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for specwarden 0.2.1
File Size Uploaded Provenance
specwarden-0.2.1.tar.gz 111.5 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for specwarden 0.2.1
File Interpreter ABI Platform
specwarden-0.2.1-py3-none-any.whl Python 3 none any Details

Total release size: 130.1 kB

Release files / specwarden-0.2.1.tar.gz

Download URL specwarden-0.2.1.tar.gz
Size 111.5 kB
Tags Source
SHA-256 checksum
How to use checksums
dbe23a98b8d132c9b280d4473e86a0c42c0b4ecdea139a6826923c2b7d2690b7
BLAKE2b-256 checksum
How to use checksums
a1832af6bf65c456b1ea46959cc763073be50b1f024617ef1b759da72193c91b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 26, 2026.

Transparency log

Release files / specwarden-0.2.1-py3-none-any.whl

Download URL specwarden-0.2.1-py3-none-any.whl
Size 18.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
abb2fc69f61c20e05df1d1ffa37f06b512f27809bde4a6c57e43176b654492ac
BLAKE2b-256 checksum
How to use checksums
97e0bbeceabeb3004132389bf8c6f59df90dfdbb3762e9229cac825238890236
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 26, 2026.

Transparency log

Security for specwarden 0.2.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for specwarden-0.2.1.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 26, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page