Turn a spec into a frozen acceptance harness enforced via Claude Code Stop hook.
Project description
specgate
Turn a spec into a frozen acceptance harness, then enforce it as a Claude Code Stop hook — so the agent literally cannot end its turn until every criterion passes.
Core invariant
The agent that writes the code must never be able to alter the harness that grades it.
The harness is generated and human-approved before implementation begins, then frozen by a SHA-256 hash. The Stop-hook gate re-verifies that hash on every run. A hash mismatch is a hard block — the agent cannot weaken its own test.
Install
pipx install specgate
Requires Python 3.11+. No runtime dependencies.
The generate → freeze → enforce flow
1. Init (once per repo)
cd my-repo
specgate init
Creates .specgate/ and merges a Stop-hook entry into .claude/settings.json. Existing hooks are preserved.
2. Write a spec
Write a spec file with concrete, measurable requirements:
# Feature: Password Reset
1. POST /password-reset with a valid email returns HTTP 202 and enqueues one email.
2. A reset token is single-use; a second attempt returns HTTP 400.
3. Tokens expire after exactly 24 hours.
Vague specs are rejected by specgate generate. Clarify first.
3. Generate the harness
specgate generate issues/password-reset.md
Calls claude -p to extract acceptance criteria and emit pytest check files into .specgate/harness/. Prints a summary of every criterion for review. manifest.json is written with approved: false.
4. Review and freeze (human sign-off)
Read the summary. Inspect the generated checks in .specgate/harness/. Edit them if needed. When satisfied:
specgate freeze
This computes a SHA-256 hash over the harness directory, stores it in manifest.json, and sets approved: true. From this point, the harness is the definition of done.
5. Implement
Tell the agent to implement the feature. The Stop hook fires at the end of every reply:
- If the harness passes → the turn ends normally.
- If any criterion fails → the agent receives a specific, actionable block reason naming the failing criteria and is forced to continue.
- If the hash has changed → hard block: the agent is told to restore the harness. It cannot bypass this.
- After 5 consecutive blocks → the agent is instructed to summarize its attempts and ask the human for guidance (before the 8-block Claude Code cap).
Debug manually
specgate check # same code path as the hook — prints pass/fail per criterion
specgate status # show approval state, hash match, block count
Gate protocol (Stop hook)
The hook receives JSON on stdin and writes to stdout:
- Block:
{"decision": "block", "reason": "<specific failing criteria + hint>"}, exit 0. - Pass: no output, exit 0.
- Loop guard: if
stop_hook_activeis true, exit 0 immediately — prevents infinite loops.
.specgate/ layout
.specgate/
harness/ ← generated pytest checks (frozen by hash)
manifest.json ← criteria, check map, hash, approval flag
state.json ← block counter, last run (written by gate, never committed)
Commit .specgate/harness/ and .specgate/manifest.json. Do not commit state.json.
Configuration
| Env var | Default | Purpose |
|---|---|---|
SPECGATE_ESCALATION |
5 |
Block count before "ask the human" escalation |
SPECGATE_TIMEOUT |
120 |
Wall-clock budget (seconds) for the harness run |
SPECGATE_BACKEND_TIMEOUT |
120 |
Timeout for claude -p generation calls |
Constraints
- Standard library only — no runtime dependencies.
- Generation backend:
claude -p(Claude Code CLI) — reuses your existing auth. - Generated harness may use the target repo's test framework (default: pytest).
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file specgate_cli-0.2.1.tar.gz.
File metadata
- Download URL: specgate_cli-0.2.1.tar.gz
- Upload date:
- Size: 19.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c5e26479d46bcda79f2e6d1b166f3bdb967aab0ecc5ae31d97d7475ef462cd98
|
|
| MD5 |
579c30301aad75906be8e309c9e2832b
|
|
| BLAKE2b-256 |
5b13197347bd81d4f5787863ca83e5471c6dbe20bb70b3e55ececf53d614eb0e
|
File details
Details for the file specgate_cli-0.2.1-py3-none-any.whl.
File metadata
- Download URL: specgate_cli-0.2.1-py3-none-any.whl
- Upload date:
- Size: 17.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b4f9316bea396341fbdecc6d86b59c5f9b6cf2ca043e02178a4b83e59884c949
|
|
| MD5 |
93d6ce886773f0d82618a460eedb3194
|
|
| BLAKE2b-256 |
32253b25e84bb6a3732a12d0f3668cfef4beea8b7ef4ddf5c11b48b4d2ad76b0
|