Parked/Awaiting-Agent Signal Mechanism in no-mistakes: Enabling Reliable Agent Supervision

The parked/awaiting-agent signal is a durable boolean flag paired with a Unix timestamp that marks a pipeline run as paused at an agent gate, enabling external supervisors to detect when human or AI intervention is required.

The no-mistakes repository orchestrates complex automation pipelines through sequential steps such as rebase, lint, test, and CI. When a step encounters a gate requiring approval from an external agent—whether Claude, Codex, or a human reviewer—the pipeline enters a parked state. This state is communicated system-wide through a lightweight but persistent signal mechanism that ensures observability survives daemon restarts and crashes.

How the Signal is Produced and Cleared

The executor manages the lifecycle of the awaiting-agent marker. Immediately before entering a gate that requires external input, the executor sets the parked flag in the database.

In internal/pipeline/executor.go, the marker is established:

if dbErr := e.db.SetRunAwaitingAgent(run.ID); dbErr != nil {
    // handle error
}

Once the agent responds or the run aborts, the executor clears the marker:

if dbErr := e.db.ClearRunAwaitingAgent(run.ID); dbErr != nil {
    // handle error
}

This simple set/clear contract ensures that the awaiting-agent signal is only active during the exact window when the pipeline is blocked on external input.

Persistent Storage in SQLite

Durability is critical for supervision. The parked state survives process restarts because it is stored in the runs table as awaiting_agent_since, a nullable Unix-seconds timestamp.

In internal/db/run.go, the schema definition appears as:

// Run.AwaitingAgentSince is the unix-seconds timestamp at which the run parked.
AwaitingAgentSince *int64

The database layer exposes two helper methods for manipulating this column:

  • SetRunAwaitingAgent(id string) error – Writes the current epoch seconds to the column.
  • ClearRunAwaitingAgent(id string) error – Sets the column to NULL, effectively unparking the run.

This storage strategy guarantees that even if the no-mistakes daemon crashes and restarts, the recovery logic (RecoverStaleRuns) can correctly restore or clear the parked state without leaving runs in an ambiguous limbo.

Propagation to Clients and CLI

The signal propagates from the database through the IPC layer to end-user interfaces. When the daemon communicates run status over internal channels, it includes the parked metadata in the protocol defined in internal/ipc/protocol.go:

AwaitingAgent      bool   `json:"awaiting_agent,omitempty"`
AwaitingAgentSince *int64 `json:"awaiting_agent_since,omitempty"`

The CLI tool (axi) renders this information for human consumption. In internal/cli/axi_render.go, the output formatter checks for the timestamp and appends a human-readable field:

if rv.AwaitingAgentSince != nil && !terminalStatus(rv.Status) {
    fields = append(fields,
        toon.Field{Key: "awaiting_agent", Value: formatParkedFor(*rv.AwaitingAgentSince)})
}

The helper function formatParkedFor converts the Unix timestamp into a duration string (e.g., "parked 5m"), making it immediately obvious that the pipeline is awaiting intervention.

Practical Code Examples

Checking Parked State via CLI

Supervisors can poll the daemon to detect parked runs using the axi command-line tool:


# Query the daemon for run status (JSON output)

axi status --run $RUN_ID | jq '.awaiting_agent, .awaiting_agent_since'

A parked run returns:

true
1627896543

After the agent responds, the fields revert to:

false
null

Implementing Custom Gate Logic

When building custom steps that require agent approval, respect the parked flag by explicitly setting and clearing the marker:

func (s *MyStep) Run(ctx context.Context, runID string) error {
    // ... perform step work ...
    
    // Park the run before awaiting agent input
    if err := db.SetRunAwaitingAgent(runID); err != nil {
        return err
    }
    
    // Block until agent responds via IPC, webhook, or channel
    <-agentResponseChan
    
    // Unpark after receiving response
    return db.ClearRunAwaitingAgent(runID)
}

Rendering Parked Status in Custom UIs

For custom dashboards or monitoring tools, interpret the timestamp to display status:

if run.AwaitingAgentSince != nil {
    parkedTime := time.Unix(*run.AwaitingAgentSince, 0)
    fmt.Printf("⏸️  Run parked awaiting agent since %s\n", 
        parkedTime.Format(time.RFC822))
}

Testing and Reliability Guarantees

The no-mistakes codebase enforces the parked/awaiting-agent signal mechanism through comprehensive tests that prevent regressions:

  • Executor-gate interaction: TestExecutor_AwaitingAgentMarkerSetOnGateClearedOnRespond verifies the marker is set upon gate entry and cleared after the agent responds.
  • Database integrity: TestRunAwaitingAgentSetAndClear confirms the timestamp is correctly recorded and removed at the storage layer.
  • Crash recovery: TestRecoverStaleRunsClearsAwaitingAgent ensures that recovery logic never leaves orphaned parked states after a daemon restart.
  • CLI rendering: TestRunObjectRendersAwaitingAgent validates that the UI only displays the "awaiting_agent" field while the run is actively parked.
  • End-to-end supervision: TestAxiParkedAwaitingAgentSignal in internal/e2e/axi_journey_test.go confirms that axi status JSON correctly reports awaiting_agent: true with a non-nil timestamp during gate pauses, and that both fields disappear post-response.

These tests guarantee that the signal mechanism remains reliable across daemon restarts, database migrations, and UI changes.

Summary

  • The parked/awaiting-agent signal uses a nullable Unix timestamp (AwaitingAgentSince) stored in SQLite to mark runs paused at agent gates.
  • The executor sets the marker before gate entry and clears it after agent response via SetRunAwaitingAgent and ClearRunAwaitingAgent.
  • The signal propagates through IPC (internal/ipc/protocol.go) to the CLI (axi), where it renders as a human-readable "awaiting_agent" field.
  • Durability is ensured through database persistence and recovery logic that handles stale parked states after crashes.
  • Comprehensive test coverage verifies the contract across the executor, database, rendering, and end-to-end user journeys.

Frequently Asked Questions

How does no-mistakes handle parked runs if the daemon crashes?

The parked state persists in the SQLite database via the awaiting_agent_since column. When the daemon restarts, the RecoverStaleRuns logic examines this column and clears any stale markers, ensuring runs do not remain stuck in a parked state indefinitely.

Can external automation detect when a run is awaiting an agent?

Yes. External scripts and CI systems can poll axi status --run $RUN_ID and inspect the awaiting_agent boolean field. When true, the run is parked at a gate and requires intervention. The accompanying awaiting_agent_since timestamp indicates how long the run has been waiting.

What is the difference between a parked run and a failed run?

A parked run has awaiting_agent: true and an active awaiting_agent_since timestamp, indicating it is paused waiting for external input but has not terminated. A failed run has reached a terminal error state and would not show the awaiting-agent flag unless it failed specifically during the gate transition before the marker was cleared.

Which source files define the awaiting-agent behavior?

The core logic resides in four key locations: internal/pipeline/executor.go manages the set/clear lifecycle, internal/db/run.go defines the schema and database helpers, internal/ipc/protocol.go structures the IPC payload, and internal/cli/axi_render.go handles the human-readable CLI output.

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 →