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 prompt string to re-engage the AI if the reviewer rejects
  • A max_attempts integer to limit retry cycles
  • A capture_response boolean 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:

  1. Message dispatch – Builds a human-readable string (⏸ **Approval required**: …) and sends it via safeSendMessage through the platform adapter.
  2. Event emission – Fires an approval_requested event (lines 2320-2325) so UI clients can render approval buttons or dedicated review views.
  3. 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 ApprovalNodeSchema in packages/workflows/src/schemas/dag-node.ts, requiring a message and optional on_reject policy.
  • Persistence: The pauseWorkflowRun function in packages/workflows/src/store.ts creates a durable pause record with type "approval".
  • Execution: The executeDagWorkflow logic in packages/workflows/src/dag-executor.ts handles pausing, emits approval_requested events, and manages resumption via isApprovalContext.
  • Rejection Handling: Configurable on_reject prompts allow the AI to retry generation up to max_attempts before workflow cancellation.
  • CLI Integration: Reviewers use archon workflow approve or reject commands 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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →