Episode 4
Guardrails
Clicking loads the video from YouTube (youtube-nocookie.com). Nothing is sent to YouTube before that. Privacy policy
In this episode (≈ 40 min of hands-on work)
- You know which hooks really block and which only check.
- Three task files that tell every session where you stand.
- Your project, backed up in a private GitHub repo.
Your step
Paste this into Claude Code in your project folder. Claude checks the guardrails with you.
Check the guardrails in this project with me. I am not a developer, so explain everything in plain words. 1. Read .claude/settings.json (if it lists no hooks, also ~/.claude/settings.json) and tell me which hooks are registered and which of them really block. The table is in ~/ailoopwise-blueprint/course/04-guardrails.md. 2. Test one guard. If a .env already exists here, skip the test and tell me. Otherwise try to create a file .env containing TEST=1 and tell me the exact message you got. If the file got created anyway, say so plainly. 3. Compare tasks/current.md, tasks/lessons.md and tasks/todo.md with the filled examples in ~/ailoopwise-blueprint/course/examples/. Tell me what mine are missing, above all an "Exact Next Action" a fresh session could follow without asking me. 4. Check that .gitignore contains the lines .claude/settings.local.json, .mcp.json and .env. Show me what is missing and add it only after I say yes. 5. Change nothing outside this folder. Never show the contents of .env or .mcp.json. Never run git commit or git push unless I ask, and never print a password, key or token.
Files for this episode
Questions about this episode? Just email us: hello@ailoopwise.com
Step-by-step guide
What this episode is about
Once your project is set up with the blueprint, the AI works inside fixed guardrails. Scripts (hooks) run automatically at fixed points; the AI cannot skip them. Three text files keep the context small, so a fresh session knows where things stand within seconds. Finally you back everything up to a private GitHub repo.
The wall: writing the guardrails is the work nobody sees. For us it took months.
What you need
- Your project from episode 2 (with
.claude/hooks/and.claude/settings.json) - jq: without it, the safety hooks block edits and writes until it is installed (the command guard still works): https://jqlang.org/download/
- Git: https://git-scm.com/downloads · a GitHub account: https://github.com
- For reference: hooks reference https://code.claude.com/docs/en/hooks
What the hooks actually do
The scripts live in blueprint/hooks/, registered in .claude/settings.json:
| Script | When | What it does | Effect |
|---|---|---|---|
block-dangerous-commands.sh | before every shell command | stops rm -rf on root, home and project paths, git reset --hard, git clean -fd, force push, git checkout/git restore of files, DROP TABLE and friends, mass deletion via find, commands that could expose secrets (cat .env, printenv), npm/yarn/pnpm publish | blocks, Claude sees why |
protect-sensitive-files.sh | before every write | locks .env files (templates like .env.example allowed), lockfiles, .git/, node_modules/, .ssh/, .aws/, credentials, .pem, .key | blocks |
detect-secrets-in-code.sh | before every write | looks for AWS, GitHub, Stripe, Slack and sk- keys, private keys, database URLs with passwords (skips .md, templates, test fixtures) | blocks |
format-and-lint.sh | after every JS/TS write | eslint --fix if there is a package.json | fixes silently |
owasp-check.sh | after every code write | warns on SQL injection, innerHTML, eval, shell=True and similar | warning only |
audit-dependencies.sh | after npm/pnpm/yarn/bun install | runs the package manager's security audit | warning only |
quality-check.sh | when Claude finishes | typecheck, lint, format check and, if code changed, tests (JS/TS, Python, Go, Rust) | blocks the stop once when types or tests fail; everything else is a warning only |
session-start.sh | at session start | warns if jq is missing and points to tasks/current.md and tasks/lessons.md | goes into context |
Honestly: the three guards before the step really block, and quality-check.sh blocks the stop exactly once when the typecheck or the tests fail (Claude sees the reason and fixes it; the second attempt goes through so nothing hangs forever). The remaining checks exit with code 0, and per the hooks reference their output then goes to the debug log only: "Claude never sees it." That Claude tests after every task and fixes its own errors comes from the "Mandatory Quality Checks" rule in your CLAUDE.md. That is context, not a lock. The docs put it this way: Claude treats CLAUDE.md "as context, not enforced configuration" (source). So ask which check actually ran.
Step by step
- Open your project and type
/hooks. You see the entries under PreToolUse, PostToolUse, Stop and SessionStart with the source Project Settings. - Trigger a guard on purpose:
Expected: Claude reports
Create a file .env in the project folder containing TEST=1.BLOCKED: Protected file patternand creates nothing. If a.envshows up anyway, the guard isn't running: see "If something goes wrong". Delete the file yourself. - Start every session with the line from
blueprint/MASTER-BLUEPRINT.md:Read tasks/current.md and tasks/lessons.md. Summarize where we left off.current.mdis where things stand,lessons.mdthe mistakes already made,todo.mdwhat's next. - End every task with:
Which checks (typecheck, lint, tests, build) did you just run? Give the command and the result. Say explicitly what did not run. - Create a private repo at https://github.com/new, without README, licence or
.gitignore. - Add a
.gitignoreto the project. The first three lines come from/new-project;.envis added:To back up your working state too, remove the.claude/settings.local.json .mcp.json tasks/current.md .envtasks/current.mdline..mcp.jsonand.envstay out; tokens live there. - In the project terminal (
Ctrl+`in VS Code):git init -b main git add . git commit -m "First setup" git remote add origin <YOUR-REPO-URL> git push -u origin main
Example to copy
Filled task files for the newsletter example: examples/current.md · examples/lessons.md · examples/todo.md. The key section is "Exact Next Action" in current.md:
## Exact Next Action
Create src/routes/unsubscribe.ts with GET /unsubscribe?token=... . Verify the token with
verifyToken from src/lib/tokens.ts; on success set the subscriber's status to "unsubscribed"
[...] Done when npm test passes.
Before the next episode
Open your repo on github.com and check: it is private, and .mcp.json and .env are not in it.
If something goes wrong
- The
.envgot created, or you seeFailed with non-blocking status code: a hook couldn't start, and then the action simply goes ahead. Check that the hooks are in~/.claude/hooks/(or.claude/hooks/in the project) and listed in~/.claude/settings.json; otherwise runbootstrap.shagain. If jq is missing you see "safety hooks need jq" instead, and the edit is blocked. Source: https://code.claude.com/docs/en/hooks#other-exit-codes - Claude says "tests pass" but you saw no run: only type and test failures block; the lint and format warnings from
quality-check.shgo to the debug log only. Start withclaude --debugand read~/.claude/debug/<session-id>.txt, or have Claude runnpm testvisibly. Source: https://code.claude.com/docs/en/hooks#debug-hooks git pushasks for a password and fails: GitHub no longer accepts passwords. Enter a personal access token or use Git Credential Manager. Source: https://docs.github.com/en/get-started/git-basics/about-remote-repositoriesgit pushis rejected: the repo was created on GitHub with a README or licence. Create it empty. Source: https://docs.github.com/en/migrations/importing-source-code/using-the-command-line-to-import-source-code/adding-locally-hosted-code-to-github
Free by email
New guides by email, plus the complete Blueprint package
With every new video you get the full guide with the ready-to-paste AI brief. Once you confirm your address, the complete Blueprint package is the first thing we send you.
Free. Unsubscribe any time.