2.**Git hooks** from `.githooks/`, copied into `.git/hooks` by `npm install` (`scripts/install-hooks.sh`). `pre-push` rejects any push that would update `main`, however it's spelled. `pre-commit` / `pre-merge-commit` refuse ordinary and merge commits while `main` is checked out; cherry-pick, revert and fast-forwards skip them, but pre-push still stops the result leaving the machine. The hooks are copied, not linked with `core.hooksPath`, because Claude Code's sandbox can't write inside `.git/`: a sandboxed command can't rewrite the installed hooks, which matters because `git commit` / `git push` run outside the sandbox. Anyone can still skip them with `--no-verify`.
3.**Claude Code deny rules** in `.claude/settings.json` for `git push … main`: a quick early stop, but they match command text, so they're easy to get around.