Documentation
¶
Overview ¶
Command gate is the small binary claude's PreToolUse hook invokes before every Bash tool call. It reads a JSON envelope from stdin, decides allow/block via the gate matcher, logs the decision to the shared commands.jsonl, and signals claude via stdout JSON.
Block contract (per Claude Code docs):
exit 0, no stdout JSON → allow exit 0, stdout JSON with hookSpecificOutput .permissionDecision="deny" → block (claude cancels the tool call)
Note: exit 2 alone is NOT a block — claude ignores any stdout JSON when the exit code is non-zero, so the tool would still run. We always exit 0 from this binary.
The binary ships per-app as `<app>-gate[.exe]` (e.g. `myapp-gate` for a project initialized with `wick init myapp`).
Configuration is loaded from the shared spec at ~/.<app>/agents/gate/spec.json — the gate binary derives `<app>` from its own executable filename via gate.AppName() (strip `-gate[.exe]` suffix). No env var, no ldflag injection.
Fail-safe: if anything goes wrong (spec missing, parse failure, timeout reading stdin), we BLOCK + log. Better to refuse a real command than let an unverified one through.