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

In generated governed projects, "full-auto" is not a separate protocol mode. It is a project-policy posture: routine gates are marked credentialed: false, the QA ship gate also requires verification pass evidence, and approval_policy contains explicit rules for the routine boundaries that may close without an operator.

If you need repo-local automation after a human-approved gate succeeds, that is a different feature. See Gate Actions. Approval policy decides whether a human pause is required; gate actions decide what runs after approval.

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 publishing to npm, deploying to production, or any other external credentialed action.

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,
"credentialed_gate": false
}
},
{
"from_phase": "qa",
"to_phase": "release",
"action": "require_human"
}
]
},
"run_completion": {
"action": "auto_approve",
"when": {
"gate_passed": true,
"all_phases_visited": true,
"credentialed_gate": false
}
}
}
}

Routine gates opt into policy eligibility with credentialed: false:

agentxchain.json
{
"gates": {
"qa_ship_verdict": {
"requires_files": [
".planning/acceptance-matrix.md",
".planning/ship-verdict.md",
".planning/RELEASE_NOTES.md"
],
"requires_human_approval": true,
"requires_verification_pass": true,
"credentialed": false
},
"publish_release": {
"requires_human_approval": true,
"credentialed": 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.
credentialed_gatefalseRequires the current gate to be non-credentialed. true is rejected because credentialed gates are hard-stopped before rule matching.

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.
credentialed_gatefalseRequires the completion gate to be non-credentialed.

Invariants

  1. Only applies to requires_human_approval gates. Gates without that flag already auto-advance — the policy does not affect them.
  2. Credentialed gates hard-stop. A gate with credentialed: true always requires human approval. A catch-all auto_approve rule cannot override it.
  3. --auto-approve overrides policy entirely. The CLI flag is an operator override, not a project policy. It approves everything regardless of policy rules and is not equivalent to full-auto policy defaults.
  4. Absent policy = today's behavior. If approval_policy is not configured, all requires_human_approval gates pause for human approval.
  5. Pure evaluation. Policy decisions are deterministic: (gateResult, state, config) → "auto_approve" | "require_human".
  6. 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-auto policy posture with safety conditions

{
"gates": {
"planning_signoff": {
"requires_human_approval": true,
"credentialed": false
},
"qa_ship_verdict": {
"requires_human_approval": true,
"requires_verification_pass": true,
"credentialed": false
},
"publish_release": {
"requires_human_approval": true,
"credentialed": true
}
},
"approval_policy": {
"phase_transitions": {
"default": "require_human",
"rules": [
{
"from_phase": "planning",
"to_phase": "implementation",
"action": "auto_approve",
"when": {
"gate_passed": true,
"credentialed_gate": false
}
}
]
},
"run_completion": {
"action": "auto_approve",
"when": {
"gate_passed": true,
"all_phases_visited": true,
"credentialed_gate": false
}
}
}
}

This is the tester-shaped routine case: QA records 38/38 acceptance criteria as passing, smoke evidence exits 0, qa_ship_verdict is non-credentialed, and the run completion gate closes by policy. If the same gate is changed to credentialed: true, the run pauses and agentxchain approve-completion --dry-run shows the pending human approval boundary.

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
Gate ActionsPost-approval repo-local automationAdjacent but separate — gate actions run from human approval commands; gates with release/deploy actions should be credentialed: true so policy cannot bypass them
HooksExternal commands/endpointsIndependent — hooks fire on lifecycle events, not on gate approval decisions
--auto-approveCLI flagOverrides approval policy — approves everything