Gate Actions
gate_actions let a human-approved gate run repo-local automation before the approval is finalized. This is the narrow bridge between "the gate is approved" and "the repo actually did the governed follow-up work."
Use it for explicit, post-approval actions such as release wrappers, deploy wrappers, or repo-owned verification scripts that should run only after a human signs off.
This is not a second workflow-kit config tree. The contract lives directly on the gate definition itself under gates.<gate_id>.
Config shape
{
"gates": {
"qa_ship_verdict": {
"requires_human_approval": true,
"gate_actions": [
{
"label": "publish npm package",
"run": "bash scripts/release/publish-npm-if-needed.sh",
"timeout_ms": 900000
},
{
"label": "sync homebrew formula",
"run": "bash scripts/release/sync-homebrew-if-needed.sh",
"timeout_ms": 900000
}
]
}
}
}
Real validation rules
gate_actionsis valid only ongates.<gate_id>.- The gate must set
requires_human_approval: true. gate_actionsmust be a non-empty array when present.- Every action needs a non-empty
runstring. labelis optional, but when present it must be a non-empty string.timeout_msis optional, but when present it must be an integer between1000and3600000.
If you put gate_actions on a non-human gate, config validation rejects it. That is intentional. The shipped feature is a post-approval boundary, not a general automation runner.
Execution model
When an operator runs agentxchain approve-transition or agentxchain approve-completion, the runtime applies this order:
- The pending human gate is identified.
before_gatehooks run first.- Gate actions execute sequentially in the repo root via
/bin/sh -lc. - Each action uses its configured
timeout_ms, or the runtime default of900000ms(15 minutes) when no override is provided. - The approval finalizes only after all gate actions succeed.
That last point matters. AgentXchain does not mark the gate complete and then hope the automation worked. If a gate action fails, the approval is not finalized.
Workspace boundary
Gate actions run in the real repo root with normal workspace write access. They are not isolated in a scratch checkout or temp directory.
That is deliberate. Release and deploy wrappers often need the real repo state, tags, build outputs, or generated metadata. A generic dirty-workspace ban would break valid post-approval automation.
The burden moves to the operator instead:
- treat workspace writes as part of the approval boundary
- make those writes intentional and rerunnable
- prefer repo-owned wrappers that can detect already-completed work and exit cleanly on retry
If a gate action writes files you did not intend to carry forward, that is not a runtime mystery. It is a weak gate-action contract.
Timeout boundary
Hung gate actions are not acceptable. Every action gets a per-action timeout:
- explicit
timeout_mswhen you set it - otherwise the runtime default of
900000ms(15 minutes)
If an action exceeds that limit, AgentXchain treats it as a failed gate action, blocks the run, preserves the pending gate, and records timeout evidence in .agentxchain/decision-ledger.jsonl.
For release or deploy wrappers, set an explicit timeout instead of relying on the default when you know the expected duration:
{
"gates": {
"release_publish": {
"requires_human_approval": true,
"gate_actions": [
{
"label": "deploy docs",
"run": "bash scripts/release/deploy-docs-if-needed.sh",
"timeout_ms": 1800000
}
]
}
}
}
Dry-run
Both approval commands support preview mode:
agentxchain approve-transition --dry-run
agentxchain approve-completion --dry-run
--dry-run shows the planned gate actions without executing hooks, actions, or state mutation. Use it when you want to inspect the exact release/deploy follow-up before crossing the approval boundary.
Failure and retry model
If any action fails:
- the run becomes
blocked typed_reasonbecomesgate_action_failed- the pending gate stays intact
- the recovery path remains the same approval command
That means the configured commands must be rerunnable. Do not treat raw one-shot commands as safe defaults. npm version patch, ad hoc git tag, or other non-idempotent shell snippets are bad examples because a partial execution makes retry behavior ambiguous.
Prefer repo-owned wrapper scripts that can detect already-completed steps and exit cleanly on rerun:
bash scripts/release/publish-npm-if-needed.sh
bash scripts/release/sync-homebrew-if-needed.sh
bash scripts/release/deploy-docs-if-needed.sh
If your automation cannot answer "what happens when I run the same approval command again after a partial failure?", the contract is too weak.
Environment available to actions
AgentXchain exposes these environment variables to each gate-action command:
AGENTXCHAIN_GATE_IDAGENTXCHAIN_GATE_TYPEAGENTXCHAIN_PHASEAGENTXCHAIN_REQUESTED_BY_TURNAGENTXCHAIN_TRIGGER_COMMAND
Use them in repo-owned wrappers when the script needs to log gate context or branch on approval type.
Evidence surface
Every executed action appends a type: "gate_action" entry to .agentxchain/decision-ledger.jsonl.
Recorded evidence includes:
- gate id and gate type
- phase and requesting turn
- approval attempt id
- action index and label
- command
- timeout configuration
- status
- exit code or signal
- stdout/stderr tail
- timestamp
That evidence is then surfaced through:
agentxchain status— latest gate-action attempt for the pending gateagentxchain report— gate-action evidence in the governed reportagentxchain audit— gate-action evidence in the live audit surface
Worked example: release approval gate
This is the right shape for a release gate:
{
"gates": {
"release_publish": {
"requires_human_approval": true,
"gate_actions": [
{
"label": "publish npm if this version is not live",
"run": "bash scripts/release/publish-npm-if-needed.sh",
"timeout_ms": 900000
},
{
"label": "sync homebrew if formula lags",
"run": "bash scripts/release/sync-homebrew-if-needed.sh",
"timeout_ms": 900000
}
]
}
}
}
Then the operator flow is:
agentxchain status
agentxchain approve-completion --dry-run
agentxchain approve-completion
The approval does not complete unless both wrapper scripts succeed. If sync-homebrew-if-needed.sh fails, the run blocks with gate_action_failed, the pending completion gate remains, and the operator reruns agentxchain approve-completion after fixing the script or environment.
What gate actions are not
| Mechanism | What it does | How it differs from gate actions |
|---|---|---|
| Approval Policy | Auto-approves some human gates when conditions match | Approval policy decides whether the human pause can be skipped; gate actions decide what runs after a human-approved gate |
| Policies | Declarative turn-acceptance rules | Policies govern turn acceptance, not post-approval automation |
| Notifications | Best-effort delivery to external channels | Notification failures do not block approval; gate-action failures do |
Current boundary
The shipped feature is repo-local only. It does not yet provide coordinator-level gate actions or a hosted action runner. That boundary is deliberate. Retry safety and evidence semantics need to stay battle-tested at the repo gate first.
For command syntax, see CLI Reference. For blocked recovery after a failed action, see Recovery.