How to Implement Approval Gates with Human Review in Archon Workflows
Archon implements approval gates with human review by modeling them as special DAG nodes that pause execution via the pauseWorkflowRun method, emit an approval_requested event to UI clients, and resume only after a reviewer invokes approve or reject commands via the CLI.
Archon’s workflow engine represents every step as a node in a directed-acyclic graph (DAG). When you need to inject human oversight into an automated sequence, you configure an approval node—a specialized DAG node defined in packages/workflows/src/schemas/dag-node.ts that halts the executor until manual validation is received.
Schema Definition for Approval Nodes
The shape of an approval node is enforced by the ApprovalNodeSchema in packages/workflows/src/schemas/dag-node.ts (lines 247-259). This Zod schema requires a message string to display to the reviewer and optionally accepts an on_reject sub-object.
The on_reject configuration includes:
- A
promptstring to re-engage the AI if the reviewer rejects - A
max_attemptsinteger to limit retry cycles - A
capture_responseboolean to persist the reviewer’s comment as node output
Persistence and Pause Handling
When the DAG executor encounters an approval node, it invokes pauseWorkflowRun from packages/workflows/src/store.ts (lines 55-58). This method writes a pause record to the workflow-run store, capturing the node ID, type "approval", and metadata such as whether to capture the response or how to handle rejections.
The workflow remains in a paused state until external intervention, with the executor returning early and preserving the current execution context in the store.
Execution Flow in the DAG Executor
The core logic resides in packages/workflows/src/dag-executor.ts, specifically within the executeDagWorkflow function (lines 2310-2339). The executor performs three critical actions when handling approval nodes:
- Message dispatch – Builds a human-readable string (
⏸ **Approval required**: …) and sends it viasafeSendMessagethrough the platform adapter. - Event emission – Fires an
approval_requestedevent (lines 2320-2325) so UI clients can render approval buttons or dedicated review views. - Metadata marking – Tags the run with
{ type: "approval", nodeId, captureResponse, onReject… }.
Upon re-entry, the isApprovalContext guard (lines 2210-2225) validates the resume context. If the user approves, the metadata clears and execution continues. If capture_response is true, the reviewer’s comment is stored as $nodeId.output for downstream consumption.
If the reviewer rejects and an on_reject block exists, the executor re-prompts the AI using the configured on_reject.prompt, increments the attempt counter, and aborts with a cancellation event after exceeding max_attempts.
Practical Configuration Examples
Minimal Approval Node
Define a basic gate that captures the reviewer’s comment:
# .archon/workflows/example-approval.yaml
name: example-approval
nodes:
- id: generate-plan
prompt: |
Write a short plan to add a logging utility.
- id: human‑review
approval:
message: "Please review the plan above and type **approve** or **reject**."
capture_response: true
- id: implement
bash: |
# Use the plan stored in $generate-plan.output
echo "Implementing..."
Approval with Rejection Handling
Configure automatic retries when reviewers request changes:
name: approval‑with‑reject
nodes:
- id: draft
prompt: "Draft a README for the new feature."
- id: review
approval:
message: "Does the draft look good?"
capture_response: true
on_reject:
prompt: "Please rewrite the README based on the reviewer’s feedback."
max_attempts: 2
- id: commit
bash: |
git add README.md
git commit -m "Add updated README"
Resuming Workflows from the CLI
Reviewers interact with paused runs using the Archon CLI:
# List runs that are waiting for approval
archon workflow list --status paused
# Approve a specific run (the reviewer’s comment will be stored as $review.output)
archon workflow approve <run-id> "Looks fine, proceed."
# Or reject with a custom reason (triggers the on_reject prompt)
archon workflow reject <run-id> "Missing section on installation."
Summary
- Schema: Approval nodes are defined by
ApprovalNodeSchemainpackages/workflows/src/schemas/dag-node.ts, requiring amessageand optionalon_rejectpolicy. - Persistence: The
pauseWorkflowRunfunction inpackages/workflows/src/store.tscreates a durable pause record with type"approval". - Execution: The
executeDagWorkflowlogic inpackages/workflows/src/dag-executor.tshandles pausing, emitsapproval_requestedevents, and manages resumption viaisApprovalContext. - Rejection Handling: Configurable
on_rejectprompts allow the AI to retry generation up tomax_attemptsbefore workflow cancellation. - CLI Integration: Reviewers use
archon workflow approveorrejectcommands to resume execution and optionally provide feedback captured as node output.
Frequently Asked Questions
What happens when a workflow reaches an approval node?
The DAG executor pauses the run by calling pauseWorkflowRun, which persists the pause state to the workflow-run store with type "approval". The executor then emits an approval_requested event and returns early, leaving the workflow in a paused state until human intervention occurs.
How does Archon store reviewer feedback?
If the capture_response flag is set to true in the approval node schema, the reviewer’s comment from the approve or reject command is stored as $nodeId.output in the workflow context. Downstream nodes can reference this value using the node ID variable syntax.
Can I limit the number of rejection retries?
Yes. The on_reject configuration accepts a max_attempts integer. When a reviewer rejects and provides feedback, the executor re-prompts the AI with the on_reject.prompt text up to the specified limit before aborting the workflow with a cancellation event.
How do I resume a paused workflow?
Use the Archon CLI commands archon workflow approve <run-id> to continue execution or archon workflow reject <run-id> to trigger rejection handling. Both commands accept an optional comment argument that becomes node output when capture_response is enabled.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →