Agents in this repo can still run git and gh commands that the rules forbid: gh pr merge, git push <src>:<dst>, force pushes, pushes to main, and commits on main. Today only the written rules stop them. On #900 a coordinator ran git push HEAD:<other branch>; GitHub then read the PR as merged and deleted its branch.
Add one PreToolUse hook script that both Claude Code (.claude/settings.json) and Codex (.codex/hooks.json) run before every Bash call. It blocks those commands, explains what to run instead, and is covered by a table test that runs in CI.
Acceptance:
- Blocks
gh pr merge (and the gh api .../pulls/N/merge equivalent), explicit src:dst and + refspecs, --force/-f/--mirror/--all, any push to main, and git commit while main is checked out.
- Allows
git push, git push -u origin <current-branch>, and every non-git command.
- Follows command chains,
cd X && ..., git -C, env prefixes and bash -c. It finds the branch in the directory where the command runs, and blocks git commands it cannot parse.
- Handles each harness's real stdin payload. Exit 2 blocks the call and shows stderr to the agent.
- One line in AGENTS.md "Git / PR workflow" names the guard.
Agents in this repo can still run git and gh commands that the rules forbid:
gh pr merge,git push <src>:<dst>, force pushes, pushes tomain, and commits onmain. Today only the written rules stop them. On #900 a coordinator rangit push HEAD:<other branch>; GitHub then read the PR as merged and deleted its branch.Add one PreToolUse hook script that both Claude Code (
.claude/settings.json) and Codex (.codex/hooks.json) run before every Bash call. It blocks those commands, explains what to run instead, and is covered by a table test that runs in CI.Acceptance:
gh pr merge(and thegh api .../pulls/N/mergeequivalent), explicitsrc:dstand+refspecs,--force/-f/--mirror/--all, any push tomain, andgit commitwhilemainis checked out.git push,git push -u origin <current-branch>, and every non-git command.cd X && ...,git -C, env prefixes andbash -c. It finds the branch in the directory where the command runs, and blocks git commands it cannot parse.