Gates (enforcement)
SpecForge’s differentiator is that human approval is enforced by a hook, not left to the model’s goodwill.
The hooks
Section titled “The hooks”plugins/specforge/hooks/hooks.json wires four events to scripts (referenced with
${CLAUDE_PLUGIN_ROOT} because installed plugins run from a cache copy):
| Event | Script | Purpose |
|---|---|---|
PreToolUse (Edit/Write/MultiEdit/NotebookEdit) |
gate-check.sh |
Block code edits until spec+plan approved |
UserPromptSubmit |
inject-state.sh |
Inject current feature + gate status as context |
SessionStart |
bootstrap.sh |
Announce the workspace + gate at session start |
Stop |
validate-artifacts.sh |
Non-blocking artifact consistency check |
The gate decision
Section titled “The gate decision”gate-check.sh reads the PreToolUse JSON and decides, in order:
- No
specforge/workspace? → allow (inert on unrelated projects). - Editing a file inside
specforge/? → allow (that’s how specs get written). fasttrack: on? → allow (audited escape hatch).- Active feature’s
specifyandplanareapproved? → allow (gate OPEN). - Otherwise → deny with an explanation telling Claude to finish/approve the plan or run
/specforge:quick.
It fails open on any parse ambiguity, so it never wrongly blocks you — enforcement kicks in only when it can positively confirm an unapproved code edit.
Why a hook and not a prompt
Section titled “Why a hook and not a prompt”A skill can say “don’t code before approval,” but nothing stops a model from ignoring it. A
PreToolUse hook is executed by the Claude Code harness and can return a hard deny — the edit never
happens. That turns “AI proposes, human approves” from a hope into an invariant.
Scope: an honest workflow, not a hostile-agent defense
Section titled “Scope: an honest workflow, not a hostile-agent defense”The gate is an in-repo control: its scripts live in files a coding agent with file-write access
can, in principle, read and edit — an agent could disable the PreToolUse block in hooks.json, or
edit the gate’s own scripts. .specforge/ (and the Copilot and Cursor bundles’ own .specforge/
directories) is intentionally always-editable, precisely so SpecForge can self-update. The git pre-commit backstop
is what catches that regardless: a tampered or disabled hook that still lets an unapproved edit
through gets caught the moment the change is staged, no matter which agent (or human) made it. The
model here is keep an honest workflow honest, not defend against an actively adversarial agent.
Tested
Section titled “Tested”The gate isn’t just asserted — it’s verified in CI. The repo ships 28 tests, including the full deny → approve → allow → fast-track transition and fail-open behavior. See the test suite.
Trying it
Section titled “Trying it”/specforge:init# ask Claude to edit a source file → DENIED/specforge:specify "…" → /specforge:plan → /specforge:approve specify → /specforge:approve plan# the same edit is now ALLOWED