|
| 1 | +# With AI coding agents |
| 2 | + |
| 3 | +A coding agent commits more often than a person, and when a hook rejects a |
| 4 | +commit it can reach for `git commit --no-verify` to get past it. Three layers |
| 5 | +keep the policy in place, cheapest first. Only the last one cannot be skipped. |
| 6 | + |
| 7 | +## Tell the agent |
| 8 | + |
| 9 | +Put the rule where agents read their instructions. `AGENTS.md` at the |
| 10 | +repository root is read by Codex, Cursor, Jules, Devin, the Copilot coding |
| 11 | +agent and [many others](https://agents.md/). Claude Code reads it too when the |
| 12 | +repository has no `CLAUDE.md`; if it has one, add `@AGENTS.md` to it. |
| 13 | + |
| 14 | +```markdown title="AGENTS.md" |
| 15 | +## Commits |
| 16 | + |
| 17 | +Commit messages and branch names follow `cchk.toml`. When the commit-check |
| 18 | +hook fails, fix the message and commit again. Never pass `--no-verify` to |
| 19 | +`git commit` or `git push`, or `-n` to `git commit`. |
| 20 | +``` |
| 21 | + |
| 22 | +With the [MCP server](mcp.md) the agent can check the message before it |
| 23 | +commits; [Make the agent use it](mcp.md#make-the-agent-use-it) has the line to |
| 24 | +add for that. |
| 25 | + |
| 26 | +An instruction is read, not enforced: the agent can still decide to skip the |
| 27 | +hook. |
| 28 | + |
| 29 | +## Block it in Claude Code |
| 30 | + |
| 31 | +Claude Code runs a [PreToolUse hook](https://code.claude.com/docs/en/hooks) |
| 32 | +before each shell command, and a hook that exits with code 2 stops the command |
| 33 | +and tells Claude why. This one stops `--no-verify`, and `-n` on `git commit`: |
| 34 | + |
| 35 | +```bash title=".claude/hooks/no-verify.sh" |
| 36 | +#!/usr/bin/env bash |
| 37 | +# Stop `git commit` and `git push` from skipping the hooks. Quoted text |
| 38 | +# is dropped first, so a commit message that mentions -n still passes. |
| 39 | +command=$(jq -r '.tool_input.command' | sed -E "s/\"[^\"]*\"//g; s/'[^']*'//g") |
| 40 | +skips='--no-verify|git( +-C +[^ ]+)* +commit[^;&|]* +-[a-zA-Z]*n' |
| 41 | + |
| 42 | +if grep -Eq -e "$skips" <<<"$command"; then |
| 43 | + echo "Do not skip the hooks (--no-verify, -n)." \ |
| 44 | + "Fix what Commit Check reported and commit again." >&2 |
| 45 | + exit 2 |
| 46 | +fi |
| 47 | +``` |
| 48 | + |
| 49 | +```json title=".claude/settings.json" |
| 50 | +{ |
| 51 | + "hooks": { |
| 52 | + "PreToolUse": [ |
| 53 | + { |
| 54 | + "matcher": "Bash", |
| 55 | + "hooks": [ |
| 56 | + { |
| 57 | + "type": "command", |
| 58 | + "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/no-verify.sh", |
| 59 | + "args": [] |
| 60 | + } |
| 61 | + ] |
| 62 | + } |
| 63 | + ] |
| 64 | + } |
| 65 | +} |
| 66 | +``` |
| 67 | + |
| 68 | +Make the script executable, install [jq](https://jqlang.org/), and commit both |
| 69 | +files, so everyone who works in the repository with Claude Code gets the hook. |
| 70 | +It reads the command as written and does not catch every way around a hook, |
| 71 | +pre-commit's `SKIP` variable for one. |
| 72 | + |
| 73 | +## Check the pull request |
| 74 | + |
| 75 | +Agents that work in the cloud, such as the Copilot coding agent, Codex, Jules |
| 76 | +and Devin, commit in their own sandbox, where no hook runs unless their setup |
| 77 | +installs one. The check that holds for every agent is the one on the pull |
| 78 | +request. The [GitHub App](github-app.md) needs no workflow file and also |
| 79 | +checks the agents that commit as an app |
| 80 | +([which ones](github-app.md#bots-re-runs-and-commits-checked-twice)); the |
| 81 | +[Action](github-actions.md) does the same job in CI. Make **Commit Check** a |
| 82 | +[required check](github-app.md#enforcing-it), and a commit that skipped the |
| 83 | +hook still cannot merge. |
0 commit comments