Skip to content
All posts
7 min readBrian McManus

Gates for coding agents: where to stop an agent before push, PR and deploy

Checks in the hook path have microseconds of budget. Checks at push, pull request and deploy can wait. A stage map of deterministic gates for coding agents, with the sequence policies that make a cheap check smarter than it looks.

policygatescoding-agentsgovernance

A gate for a coding agent is a deterministic check that one action cannot pass until a condition holds. Put gates where the action happens, and pick the place by what the check needs: the hook path for decisions that must not wait on a network round trip, the push, pull request and deploy boundaries for checks that can take seconds or minutes.

Two speeds, four places

Where the gate runsTime it may takeWhat it can checkWhat it cannot do
Hook path, per tool callMicroseconds to low millisecondsPatterns, policy-as-code, session stateCall a model or the network
PushUnder a second locally, seconds on the serverBranch, commit, review stateSee anything that happened before the push
Pull requestMinutesBuilds, tests, SAST, human reviewStop a direct push on a branch that does not require a PR
DeployMinutesRelease policy, environment approvalFix a bad commit before it merges

The hook path

A hook fires on every tool call in an agentic loop, and one session can make a few hundred of them. That budget rules out anything that waits: no model call, no cloud policy service, no remote allowlist. What fits is deterministic work in the process: matching on the tool name and arguments, policy-as-code compiled from Lyra or OPA, and a small run-state automaton that remembers what happened earlier in the session. All of it works offline, which matters on a plane and matters more on a build machine with no route out.

Three vendor examples, with their real limits.

Claude Code reads PreToolUse hooks from .claude/settings.json, ~/.claude/settings.json, or managed settings. A handler returns permissionDecision: "deny" with a reason, or exits 0 and says nothing. The optional if field narrows a handler to something like Bash(git *), and the docs say plainly that if is best-effort and that a hard allow or deny belongs in the permission system rather than a hook. allowManagedHooksOnly in managed settings restricts which hooks may run (hooks reference).

Cursor reads .cursor/hooks.json at project level, ~/.cursor/hooks.json at user level, and enterprise hooks from /Library/Application Support/Cursor/hooks.json on macOS, /etc/cursor/hooks.json on Linux and C:\ProgramData\Cursor\hooks.json on Windows. beforeShellExecution and beforeMCPExecution can return permission: "deny", and exit code 2 blocks. A crash, a timeout or any other non-zero exit fails open unless the hook sets failClosed: true (hooks reference).

Codex pauses according to approval_policy in ~/.codex/config.toml and limits filesystem and network reach with sandbox_mode, which OpenAI documents as OS-level enforcement, with no network by default and writes confined to the workspace. Administrators can constrain both from requirements.toml, so a managed machine cannot be set to approval_policy = "never" or danger-full-access (config basics, managed configuration).

Read those together and the shape is clear. Claude Code and Cursor give you a hook whose failure behaviour you have to choose. Codex gives you an OS-enforced sandbox plus an approval policy, with a managed file that can restrict both. Each is configured per vendor, so three agents mean three configurations, and none of them gives you one policy across three agents out of the box. The decisions land in that vendor's own record unless you export them.

Sequence policies are why a cheap check is not a dumb one

A stateless check has to be conservative, because it knows nothing about the session. A run-state automaton makes the same cheap check much smarter. Keep a handful of flags per session: read a secret, fetched from the web, review passed, wrote outside the task's files, previous deny. Then a rule is a lookup on the event and the state, evaluated in memory, in constant time. No model and no network involved.

RuleState it readsDecision
After reading a file matching **/.env*, do not allow network egressread_secretDeny egress for the rest of the session
After a web fetch, do not allow git pushweb_fetch and no review_passedDeny the push
Before github.pr.create, ask whether the diff is in scopeNoneHold for approval
After a policy deny, do not allow the same tool call with modified argumentsdeniedDeny

The last row is the one people forget. An agent that gets denied tends to retry with slightly different arguments, and a check that only looks at the current call will let the third attempt through.

Alyria publishes five worked examples in this shape, each with what happened, what was decided and why, on semantic policy examples. Lyra compiles the same rules into the local policy service and evaluates them on the endpoint (Lyra policy as code).

Push

git push is the first action that publishes the work to a shared remote. A hook at .git/hooks/pre-push receives the refs on stdin and can exit non-zero to abort, and git push --no-verify skips it (githooks). Any push gate that has to hold therefore lives on the server, as a ruleset that requires a pull request and required status checks, or as a policy on the receiving side.

Gates written as sentences:

  • After a dependency install from an unpinned source, do not allow a push to main.
  • After any write under .github/workflows/, do not allow a push until someone with workflow permissions has reviewed it.
  • Before a force push to a protected branch, deny. This is not an approval case, because there is no good version of the action.

Pull request

The pull request is where the expensive checks belong, because only the merge is waiting. Required status checks cover the build, the unit tests, SAST, secret scanning and license review. Required review covers the second pair of eyes, which for an agent means someone other than the person who started the session.

Two rules that are specific to agents:

  • After the agent opens a pull request, do not allow the agent to approve it.
  • After review approved a revision, do not allow further commits to that branch without a fresh review.

The second one is the agent-era version of reviewing the thing that ships, and it is the rule that survives an agent that is helpful and keeps fixing things after the review.

Deploy

The deploy boundary is the last gate and the least ambiguous one. Environments with required reviewers, deployment protection rules and a wait timer cover the release. OIDC keeps the workflow from holding a stored cloud key (managing environments).

  • Before a deploy to production, require an approval from the service owner.
  • Before a deploy, do not allow a revision that did not pass the pull request gate.
  • After a deploy, do not allow the agent to change the feature flag that turns the change on without an approval.

The third rule matters when the agent can reach the flag API, because a deploy is not the only way a change reaches customers.

What a gate is not

A gate is not a line in a prompt. "Do not push to main" in an AGENTS.md is advice the model may follow. A gate is a decision taken outside the model, by something that will not be talked out of it. A gate with no record is a future argument, so log the rule id, the decision, the mode and the revision it applied to.

The order to build them in

Two or three rules with no false positives first: secrets, force push, production deploy. Run them in monitor mode for a week and count what they would have stopped. Promote one category at a time, and keep the rule text in the repository, so a change to policy is a reviewable diff like any other.

That is the gate layer of governing agents across the SDLC. The other two parts cover the evidence to keep and how approvals fit without causing fatigue. The vendor behaviour described here comes from the Claude Code hooks reference, the Cursor hooks reference and the Codex configuration docs, read in November 2026, and the fail-open defaults are worth re-reading against the versions you run.

How is your team using AI agents?

Pick your function and answer 20 questions on agent workflows and controls. Your result appears on the page.

Governed AI agents for the work your teams do.