The problem
A small internal software team gets Claude Code installed and then argues about it. One developer lets it run anything. Another bans it. Nobody can say what it did last Tuesday. IT's questions are fair: can it read our .env files, can it push to main, what is it running?
I wanted to show the setup and coaching work with evidence, not a slide deck.
What I built
A drop-in kit for the fictional Tallgrass Precision Components software team, installed in a small Node and SQLite gauge-calibration tracker:
CLAUDE.mdwith commands, conventions and a "do not touch" list..claude/settings.jsonwith an allow-list, deny rules and hooks.- Three plain-Node hooks: a PreToolUse guard, an append-only audit log, and a Stop hook that runs the tests.
- Three team skills and two subagents (a read-only reviewer, a test writer).
- A read-only SQLite MCP server, about 100 lines, no SDK.
- A one-page onboarding guide and a two-week rollout plan.
Then I recorded real headless Claude Code runs on throwaway copies of the repo and counted what happened.
How it works
Each layer catches what the one before it misses. The guard returns a reason the model can act on, such as "read .env.example instead", so it adapts instead of looping. The Stop hook runs npm test when files changed. If tests fail it sends the output back, up to three times, then stops and says so.
Security and control
- The guard blocks secret files,
rm -rfoutside the repo, force push, writes inside.git, printing the environment, network tools to anything but localhost,sudoandnpm publish. It fails closed on malformed input. - The audit log stores time, tool, an argument hash and the decision. Never command text, file contents or secrets.
- All
.envvalues are fake. Every run was in a temp copy, without--dangerously-skip-permissions. - The guard is a guardrail, not a sandbox. The real boundary is the OS account, network policy and permission rules.
Results
Measured on 2026-10-13 (UTC):
- 124 of 124 automated kit tests pass: 87 guard cases (58 must block, 28 must allow), 11 Stop hook, 10 MCP server, 9 settings, 6 audit log, 1 install check.
- 12 recorded real runs (
claude-sonnet-5-5, Claude Code 2.1.296): 50 tool calls, 186 seconds, $0.88. - The guard blocked 3 model-issued calls in 2 runs: an
.envread, and withCLAUDE.mdremoved,envand.env. - 6 calls were refused by permission settings (4 not on the allow-list, 2 deny rules, including
rm -rf node_modules && npm ci). - In 2 runs
CLAUDE.mdalone was enough: the model declined.envand a force push with no hook firing. - The Stop hook ran 7 times. In one run it failed the suite twice, sent the output back, then gave up on attempt three.
- The reviewer subagent found a SQL injection I planted, read-only.
One mistake: my first Stop hook only watched Edit and Write, so a sed -i change skipped the tests. I found it in a recording, fixed it with a git fingerprint, added tests and re-recorded. The original run is kept.
Stack
Claude Code 2.1.296 (settings, hooks, skills, subagents, MCP), Node 22 with built-in node:sqlite and node:test, Express, plain-JS hooks, Playwright for screenshots.
What I'd do for your company
Over two weeks: pilot with two developers, review permissions line by line with your IT contact, run two coaching sessions on a real ticket, turn your three most repeated tasks into skills, and hand over a team lead who can change a hook, add a deny rule with its test, and read the audit log.
Tallgrass Precision Components is a fictional company used for this demo.






