Changes reach `main` only through a PR that a human merges. Three layers, strongest first:
1.**Gitea branch protection** on `main` (set in the repo settings on code.westerkam.org): the only layer that can't be bypassed from a clone.
2.**Git hooks** in `.githooks/` (enabled by `npm install`): `pre-push` rejects any push that would update `main`, however it's spelled; `pre-commit` / `pre-merge-commit` refuse commits while `main` is checked out. `--no-verify` skips them.
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.