Gates
A rule that matters becomes a gate. Enforcement sits at the tool level — a hook, a permission, a test case — so the model is not asked to remember it.
| Component | Count | What it is |
|---|---|---|
| Agents | 12 | Thin triggers — who owns a domain and when they fire |
| Skills | 39 | The method, written once, applied by whoever needs it |
| Commands | 10 | /crew-brainstorm · /crew-plan · /crew-review · /crew-ship · /crew-handoff · /crew-update · /crew-doctor · /crew-gates · /crew-skill · /crew-studio |
| Hooks | 12 | The gates, plus session measurement and routing |
| Discipline | 1 | Principles, workflow, Definition of Done, prohibitions — imported by your CLAUDE.md |
All 12 hooks
Section titled “All 12 hooks”| Hook | Role |
|---|---|
route-hint.sh |
Names the owning agent alongside every prompt, so specialists run without you asking |
guard-bash.sh |
Tool-level command gate: commit/push approval, review-before-commit, destructive ops, remote-code-exec, hook tampering |
guard-write.sh |
The same protection on the Write/Edit side — a gate you can silently delete is not a gate. It normalises the target path before matching it, so a gate file cannot be reached under a different spelling. |
guard-commit-scan.sh |
Runs the real trace and secret scanners from PreToolUse, so the commit gate works where core.hooksPath cannot be set |
context-usage.sh |
Reads the real token count from the transcript and injects it every turn |
session-guard.sh |
Warns once at 75% context fill and once at 90% — never blocks a turn |
session-rehydrate.sh |
Re-surfaces the handover after /compact or /clear, and tells a session which language the project was installed in |
skill-trust.sh |
Names any skill or agent Crewforth never shipped and you never accepted |
session-stats.sh |
Reports what the session actually did — failing tool loops, repeated prompts, interrupts. reflect and handoff read it, so a retrospective rests on the record rather than on recollection |
session-update-check.sh |
Asks once, when a session opens, whether to update when a newer version is published — each edition compared against the channel that will deliver it. The lookup runs detached and at most daily, so an offline or proxied machine costs the session opening nothing; CREW_NO_UPDATE_CHECK=1 turns it off |
The other two hooks serve an experimental feature and do nothing until a repository switches it on.
Two git hooks — pre-commit and commit-msg — run the trace, secret, repo-bloat and private-path scans. The last one exists because a path that only lives on your machine reaches a shared repo by being pasted, not by being typed: it blocks your own $HOME automatically, and the internal project, client and host names only you can recognise come from a gitignored .private-terms.txt (.private-allowlist.txt is the escape). The plugin edition ships all of these except skill-trust.sh, which decides what Crewforth owns from the kit-manifest.txt an installer writes and the plugin never creates.
Rule → gate
Section titled “Rule → gate”Left is the rule; right is the thing that refuses to let it slide.
| Rule | Enforced by |
|---|---|
| Commit and push need your approval, in every permission mode; staging and creating a branch are free | guard-bash.sh raises a prompt only you can answer. Fails closed under bypassPermissions |
| A commit needs a clean review of the diff it is actually about | guard-bash.sh compares git’s object id of the staged diff, and the HEAD it was reviewed against, with what crew-review-agent recorded when it cleared the change. A review of another diff — or of this one on another base — does not count, and there is no size exemption |
Destructive ops: reset --hard, checkout -- ., force push, rm -rf, clean -f, --no-verify, amend |
guard-bash.sh, blocked at the tool level |
Remote code execution and permission nukes: curl…|bash, world-writable chmod, dd of= |
guard-bash.sh, hard-blocked in every mode |
Disarming a gate — redirecting core.hooksPath, editing or deleting a hook, or rewriting the discipline the gates enforce |
guard-bash.sh (shell) + guard-write.sh (file edits). Both match the resolved path, so .. segments, doubled slashes, Windows separators and a symlinked parent all reach the same verdict as the plain spelling |
| No API key, token or private key reaches a commit | pre-commit secret scan; every pattern carries its own test case |
| No machine-private path or internal name reaches a commit | pre-commit private-path scan: your own $HOME automatically, plus a gitignored .private-terms.txt |
No credential is read into the context — ~/.ssh/id_rsa, ~/.aws/credentials, *.pem, kubeconfig |
settings.json read-deny + guard-bash.sh |
| No AI-authorship trace or vendor template name in a commit | pre-commit + commit-msg git hooks |
| No build artifact, vendored tree or oversized blob gets staged | pre-commit repo-bloat scan |
No commit quietly lowers the quality bar: a checker switched off where it fired, a test skipped or deleted, assertions taken out of a test that stays, a stub or an empty catch where the work should be |
pre-commit floor guard, across the supported stacks. Generated files and documentation are exempt; a genuine exception is a line in .floor-allowlist.txt, in the same commit, where review sees it |
An unvetted skill or agent appearing in .claude/ is named, with a scanner verdict |
skill-trust.sh at session start |
| Always-on context stays lean | smoke-test.sh byte budget per component |
| A running session never follows stale rules after an update | context-usage.sh version comparison |
Every rule carries cases for both halves: that it blocks what it must, and that it does not block its neighbours — chmod 755, rm -rf build, git checkout -- src/app.js. A gate nobody proved is not a gate, and a gate that fires on routine work gets worked around.
The gates stop accidents, not determined attempts. On a command line there is always a way around a pattern; if you need a real boundary, run Claude Code in a devcontainer or a VM. /crew-doctor tells you whether you have one.
Watching a gate fire
Section titled “Watching a gate fire”The Bash guard appends a line to .claude/gate-log.tsv for each block, approval prompt and CLAUDE_GIT_OK pre-authorisation (BLOCK / ASK / ALLOW), and the gate-file write guard one for each block, with the section and the rule; the command is recorded only with CREW_GATE_LOG_CMD=1. It is on by default when the project’s .claude/ directory exists and the file is git-ignored or the project is not a repo; CREW_GATE_LOG=<path> sends it elsewhere and /dev/null turns it off. The commit scan refuses without writing a line. It is write-only and written after the verdict, so it cannot change one. Useful when you need to know whether a gate stopped something or the model simply never went there — those two leave identical traces.
Enforced rules (40)
Section titled “Enforced rules (40)”Read from the hooks when the site is built — the same inventory gate-report.sh derives — so a rule added to a hook appears here without anyone editing this page.
| Rule |
|---|
| CLAUDE_GIT_OK pre-authorised session |
| approval key set inside the command |
| commit/push approval prompt |
| commit/push under a mode that cannot prompt |
| PowerShell disk-level destructive command |
| PowerShell download-and-execute (… | iex) |
| PowerShell recursive force delete (Remove-Item -Recurse -Force) |
| PowerShell world-writable ACL (icacls /grant Everyone:F) |
| chmod world-writable (777/1777/666/o+w …) |
| cluster teardown (kubectl delete / helm uninstall) |
| dd of= (disk overwrite) |
| destructive rm -rf |
| disk-level destructive command |
| forced git branch (-D / -f / -M / -C) |
| git -c core.hooksPath (disarms the git hooks) |
| git clean -f |
| git commit –amend |
| git config core.hooksPath (disarms the git hooks) |
| git filter-branch/filter-repo |
| git rebase |
| git reset –hard |
| git update-index –add (bypasses .gitignore, same as git add -f) |
| hook skip (–no-verify) |
| in-place edit of a gate file |
| indirected write to a gate path (variable + redirect) |
| infrastructure destroy (removes every managed resource) |
| lockfile deletion |
| pipe-to-shell (curl|bash RCE) |
| reading a .env secret via the Bash tool |
| reading a private key / credential file via the Bash tool |
| redirect over a gate file |
| symlink pointing at the config directory (a gate path in two steps) |
| unattended infrastructure apply (skips the tool’s only confirmation) |
| whole-tree revert (git checkout/restore over everything) |
| write/tamper of a gate file (hook/settings/.git-hooks) |
| commit redirected at another worktree |
| commit takes content from the working tree |
| no review-pass record |
| review-pass does not match this diff |
| review-pass matches the staged diff |