Skip to main content

Approval Policy

The approval policy is the conditional auto-approval layer for governed gates. It sits between the gate evaluator and the state machine, providing a middle ground between two extremes:

ModeBehavior
requires_human_approval: true (no policy)Always pauses for human approval
--auto-approve on agentxchain runBypasses ALL approval gates
Approval policyAuto-approves specific gates when evidence conditions are met

For lights-out operation, operators need conditional approval — rules that auto-approve low-risk transitions when structural predicates pass, while still requiring human approval for high-risk transitions like qa → release.

Config shape

The approval_policy is an optional top-level section in agentxchain.json:

agentxchain.json
{
"approval_policy": {
"phase_transitions": {
"default": "require_human",
"rules": [
{
"from_phase": "planning",
"to_phase": "implementation",
"action": "auto_approve",
"when": {
"gate_passed": true
}
},
{
"from_phase": "qa",
"to_phase": "release",
"action": "require_human"
}
]
},
"run_completion": {
"action": "auto_approve",
"when": {
"gate_passed": true,
"all_phases_visited": true
}
}
}
}

How it works

The approval policy only evaluates when a gate returns awaiting_human_approval. It cannot override gate failures — it can only relax the human-approval requirement when all structural predicates (files, verification, ownership) have already passed.

Gate evaluator returns 'awaiting_human_approval'
→ Approval policy evaluates rules
→ 'auto_approve': gate advances automatically
→ 'require_human': gate pauses for human approval

This means:

  • Gate predicates are ALWAYS evaluated first
  • Approval policy can only relax, never override failures
  • The gate evaluator itself remains pure and unchanged

Phase transition rules

phase_transitions.default

Fallback action when no rule matches. One of "require_human" (default) or "auto_approve".

phase_transitions.rules

Ordered list of rules. First match wins.

FieldTypeRequiredDescription
from_phasestringNoSource phase. Omit to match any source.
to_phasestringNoTarget phase. Omit to match any target.
actionstringYes"auto_approve" or "require_human"
whenobjectNoAdditional conditions. All must be true for auto-approval.

Conditions (when)

ConditionTypeDescription
gate_passedbooleanGate structural predicates must have passed. In practice this is defense-in-depth, because the policy only evaluates after the gate already returned awaiting_human_approval.
roles_participatedstring[]These role IDs must have at least one accepted turn in the current phase. The evaluator sees history after the just-accepted turn is appended, so the current accepted turn counts.

Run completion

Controls auto-approval for the final run completion gate.

FieldTypeRequiredDescription
actionstringYes"auto_approve" or "require_human"
whenobjectNoConditions for auto-approval.

Run completion conditions

ConditionTypeDescription
gate_passedbooleanCompletion gate must have passed. This is also defense-in-depth for the same reason as phase transitions.
all_phases_visitedbooleanEvery phase declared in routing must have been active at least once. This is strict: if you declare an optional phase in routing and never visit it, completion will still require human approval.

Invariants

  1. Only applies to requires_human_approval gates. Gates without that flag already auto-advance — the policy does not affect them.
  2. --auto-approve overrides policy entirely. The CLI flag is a superset — it approves everything regardless of policy rules. Backwards compatible.
  3. Absent policy = today's behavior. If approval_policy is not configured, all requires_human_approval gates pause for human approval.
  4. Pure evaluation. Policy decisions are deterministic: (gateResult, state, config) → "auto_approve" | "require_human".
  5. Auditable. Every auto-approval decision is recorded in the decision ledger with type: "approval_policy", the matched rule, and the gate context.

Examples

Auto-approve everything except release

{
"approval_policy": {
"phase_transitions": {
"default": "auto_approve",
"rules": [
{
"from_phase": "qa",
"to_phase": "release",
"action": "require_human"
}
]
},
"run_completion": {
"action": "require_human"
}
}
}

Auto-approve only after QA participation

{
"approval_policy": {
"phase_transitions": {
"rules": [
{
"from_phase": "qa",
"action": "auto_approve",
"when": {
"gate_passed": true,
"roles_participated": ["qa_engineer"]
}
}
]
}
}
}

Full lights-out with safety conditions

{
"approval_policy": {
"phase_transitions": {
"default": "auto_approve",
"rules": [
{
"action": "auto_approve",
"when": { "gate_passed": true }
}
]
},
"run_completion": {
"action": "auto_approve",
"when": {
"gate_passed": true,
"all_phases_visited": true
}
}
}
}

Relationship to other mechanisms

MechanismScopeApproval policy interaction
PoliciesTurn acceptance rulesIndependent — policies evaluate on acceptance, approval policy evaluates on gate transitions
GatesArtifact and approval checksApproval policy sits downstream — only evaluates after gate returns awaiting_human_approval
HooksExternal commands/endpointsIndependent — hooks fire on lifecycle events, not on gate approval decisions
--auto-approveCLI flagOverrides approval policy — approves everything