governance

Human approval gates for AI agents

A human approval gate is a point in an AI agent's process where the work stops until a named person says yes, and the check is made by the system, not by the agent. In Claude Code you get gates from permission ask rules and hooks. Across sessions and teams you need a workflow engine.

the route

8 sections · 10 min

  1. What a gate is
  2. Prompt rules are not gates
  3. Kinds of gates
  4. Gates in Claude Code
  5. Where gates go
  6. Gates in ConvOps
  7. When the approver says no
  8. Removing gates over time
01What a gate is

What is a human approval gate for an AI agent?

A point where the agent's work stops until a person approves, enforced by something outside the agent. The agent can ask for approval, but text in the conversation is not the approval: the yes has to arrive through the mechanism the gate checks, and the record shows whose account sent it.

Three properties separate a real gate from a polite request: the check runs in code the agent does not control, the work actually waits (minutes or days), and the record shows who moved it on.

Gates are one form of human-in-the-loop control. The other common form is review after the fact: the agent acts, a person checks the result. Both are useful. Gates belong where undoing the action is expensive or impossible, review belongs everywhere else.

  1. Enforced outside the model: a permission layer, a hook, a platform or an engine.
  2. The work waits, and resumes from the same place after the yes.
  3. The approval leaves a record you can read later.
agent works
asks to advance
gateapproval
moves onafter the yes
fig 1 The work waits until a person says yes.
02Prompt rules are not gates

Why is "ask me before you deploy" in a prompt not a gate?

Because the model decides whether the instruction applies. Anthropic's Claude Code docs say instruction files are treated "as context, not enforced configuration", and recommend a hook to block an action regardless of what Claude decides.

A prompt rule usually works. It fails in the cases that matter: long sessions, conflicting instructions, a task that does not look like a deploy, or text from a file or web page that tells the agent something else. A gate does not read the situation; it checks a condition.

This matters most for agents that read untrusted input: issues, emails, web pages, documents from customers. Text in that input can tell the agent the change was already approved, or that this case is an exception. A gate checked by code does not read that text at all.

sourcesClaude Code docs: memoryClaude Code docs: hooks

in the prompt read by the AI

"wait for approval"

Shipped. Nobody said yes.

as a gate checked by the engine

Waiting for you.

fig 2 Ask me first, as a sentence and as a gate.
03Kinds of gates

What kinds of approval gates are there?

Gates differ in where they live and how long they can wait. Pick the one whose scope matches the risk. Dedicated approval services are another option; see how ConvOps compares with HumanLayer.

Approval mechanisms for AI agents, as of October 2026.
GateWhere it livesCan it wait for days?Example
Prompt instructionThe model's contextNo, and it is not enforced"Ask me before pushing"
Permission ask ruleClaude Code settingsOnly while the session is openask: Bash(git push *)
Hook decisionYour script, before the tool runsOnly while the session is openPreToolUse returns ask or deny
Platform approvalCI or deploy platformYesGitHub environment required reviewers
Workflow engine gateA process engine outside the agentYesConvOps requires_approval on a step
Structural conditionA process engineYesWait until child tasks are complete
Promptnot enforced
Permission asklive session only
Engine gatewaits for days
fig 3 Where the gate lives decides how long it can wait.
04Gates in Claude Code

How do I add approval gates in Claude Code today?

Use permission rules for command patterns and PreToolUse hooks for anything that needs logic. Both run outside the model. Rules evaluate deny first, then ask, then allow, and a hook's decision cannot override a deny or ask rule.

Commit .claude/settings.json to the repo so every teammate and every session gets the same ask and deny rules. Personal overrides go in .claude/settings.local.json, which stays out of git.

  1. 1

    Ask before risky commands

    Add ask rules to .claude/settings.json in the repo so the whole team gets them. Deny what must never happen.

    {
      "permissions": {
        "ask": ["Bash(git push *)", "Bash(npm publish *)"],
        "deny": ["Bash(git push --force *)", "Read(./.env)"]
      }
    }
  2. 2

    Ask on a condition

    A PreToolUse hook can inspect the call and return an ask decision with a reason, for example when a migration touches a production schema.

    {
      "hookSpecificOutput": {
        "hookEventName": "PreToolUse",
        "permissionDecision": "ask",
        "permissionDecisionReason": "Migration touches production tables. Confirm."
      }
    }
  3. 3

    Know what happens unattended

    In claude -p with nobody attached, an ask cannot be answered, so it is denied. That fails safe, but the work stops instead of waiting. Claude Code Routines run without stopping for approval, and Anthropic notes the fired prompt cannot act as approval or consent. Dynamic workflows have no mid-run user input.

  4. 4

    Gate the deploy on the platform

    For deploys, a CI platform gate also works: GitHub environments can require a reviewer and prevent self-review. As of October 2026, GitHub documents required reviewers on private repositories only for Enterprise plans.

sourcesClaude Code docs: permissionsClaude Code docs: hooksClaude Code docs: headless modeClaude Code docs: RoutinesClaude Code docs: Dynamic workflowsGitHub docs: deployment environments

tool call
deny?
askapproval
runs
fig 4 Deny first, then ask, then allow.
05Where gates go

Where should approval gates go in an agent's process?

Where a wrong move is expensive or hard to undo, and nowhere else. Too many gates train people to click yes without reading, which is worse than no gate.

Give the approver what they need to decide in one screen: the diff or the draft, the test results, and what happens if they say yes. A gate that asks "Ship it?" next to a clear summary gets read. A generic "Continue?" gets clicked.

Gate hereUsually no gate
Publishing anything outside the companyDrafting, research, reading code
Merging to main or deployingRunning tests, lint, local builds
Changing production data or schemasChanges on a branch under review
Spending money or sending messages to customersInternal notes and summaries
Changing permissions, secrets or accessReading configuration
  1. Put the gate on the step, not on the tool, when the risk depends on context.
  2. Write what the approver should check in the gate prompt.
  3. Review the list every few weeks. Remove gates that never catch anything.
Publish, merge, deploygate
Spend, access, prod datagate
Draft, test, readno gate
fig 5 Gate the consequence, not the activity.
06Gates in ConvOps

How do approval gates work in ConvOps?

A gate is part of the workflow step, not of the prompt. Claude Code, or any MCP client, works the current step and asks to advance. The engine evaluates the gate on every advance against real state. If it is not met, the cursor stays put and the agent is told exactly what is missing.

Approval has to be passed explicitly on the advance call; it is never inferred from chat text. The advance that passes the gate writes an audit row with field-level before and after on the task and the workflow instance, with two identities: the agent label the caller declares, and the person the server verified from the credential. There is no separate approver field, so the record shows the account behind the advance. Unattended runs stop at the gate and wait for a person.

Not every gate needs a person. wait_for_children holds a parent until its child tasks finish, and require_context will not close a step without a recorded why. Combine a structural condition with requires_approval and a person is asked only once the work is actually ready, which keeps each approval meaningful.

  1. 1

    Put the gate on the step

    requires_approval holds the step for a person. Structural keys hold it for real state: wait_for_children, sequential_children, task_status and require_context.

    {
      "id": "approve",
      "gate": {
        "requires_approval": true,
        "wait_for_children": true,
        "prompt": "Ship it?"
      }
    }
  2. 2

    Let the agent try

    An early advance is refused with the unmet conditions, verbatim.

    workflow_advance(task_id="…")
    
    {
      "current_step": { "id": "review" },
      "unmet_conditions": [
        "Requires explicit user approval",
        "1 of 1 child tasks are not completed"
      ]
    }
  3. 3

    Approve

    You review the work and advance with your approval. The next step arrives; the audit keeps the agent label and your signed-in account.

Audit · exampletask history
changeagentperson
statusin reviewdoneimplementerdeclared by the clientdana@example.com from the verified sign-in
fig 6 Example row. The agent declares a label; the person comes from the verified sign-in.
07When the approver says no

What happens when the approver says no?

The work should go back to a named step, not stall. A well-designed gate defines the no path as carefully as the yes path: which step rejected work returns to, and what the approver has to see before deciding.

In Claude Code, denying an ask blocks that one tool call; the model is told the call was rejected and chooses what to try next in the same session. Nothing records where the work should go after a no.

In ConvOps, a step can name an on_rejected target, any step of the same workflow. Rejecting the advance moves the run straight to that step, for example from approve-draft back to revise-draft, and the task takes that step's status. The step history keeps a rejected row and the audit marks the verdict. A step with no on_rejected target refuses the rejection, so the run stays at the gate.

Anatomy of an approval gate.
PartQuestion it answersIn ConvOps
TriggerWhich step needs a yes?requires_approval on the step
ContextWhat does the approver check?The gate prompt and the work on the task
Yes pathWhere does approved work go?The next step of the workflow
No pathWhere does rejected work go?The step named in on_rejected
WaitingHow long can the work wait?Until someone answers; every step is persisted
RecordWho moved it on?Audit row with the agent label and the verified account
a gate with a no path
{
  "id": "approve-draft",
  "on_rejected": "revise-draft",
  "gate": { "requires_approval": true, "prompt": "Publish this draft?" }
}

workflow_advance(task_id="…", approved=false)
→ current_step: "revise-draft"
08Removing gates over time

How do I remove gates as trust grows?

Start with approvals on every step. As trust grows, let the work run on its own. Remove a gate when the record shows it never changes the outcome, and keep it where the consequence is high.

StageGatesEvidence to move on
StartOn every stepSteps approved without changes
Trusted stepsOnly on publish, merge and spendRuns finish without blocked tasks
UnattendedGates where consequence is high; runs wait thereAudit and run records you review weekly
every stepwaiting for you
high stakes onlyapproval
runs on its ownstops where it matters
fig 7 Start with approvals on every step. As trust grows, let the work run on its own.

Frequently asked questions

What is the difference between a gate and a policy?

A policy is a rule the agent is given to follow. A gate is a condition the system checks before the work can move on. Policies inform; gates block. Use a gate where a mistake is costly.

Is an approval gate the same as human-in-the-loop?

An approval gate is one kind of human-in-the-loop control: the work stops before an action until a person approves. Review after the fact is another kind. Use gates where an action is costly or hard to undo.

Can Claude Code wait for my approval?

In an open session, yes: a permission ask rule or a hook ask decision prompts you. In headless runs nobody can answer, so the call is denied and the work stops. Waiting for days needs state outside the session.

How many approval gates should an agent workflow have?

Start with one on every step while you learn the process. Then keep gates where a wrong move is expensive or hard to undo: publishing, merging, deploying, spending, and changing access.

What happens to the work when I reject it in ConvOps?

If the step names an on_rejected target, the run moves straight to that step, such as a revise step, and the history records the rejection. If the step has no on_rejected target, the rejection is refused and the run stays at the gate.

How do I know who approved a step in ConvOps?

The advance that passes the gate is written to the audit with the agent's label and the verified account the call ran under. There is no separate approver field, so the record shows the account behind the advance.

Do approval gates work with tools other than Claude Code?

ConvOps gates live in the workflow, so they apply to any MCP client that works the task: Claude Code, Codex, Cursor, ChatGPT, OpenCode and others. Claude Code permission rules and hooks apply only inside Claude Code.