How the no-mistakes Pipeline Handles Parked Runs for Approval Requests
The no-mistakes pipeline marks runs as parked by writing a Unix timestamp to the awaiting_agent_since column in SQLite, exposing this state through IPC to enable polling by external agents, and clears the marker once the agent responds.
The no-mistakes pipeline implements a robust mechanism for handling approval gates by parking runs and signaling their awaiting-agent state. When a step requires human or automated approval, the executor stores a persistent marker in the database that survives crashes and remains queryable via the IPC protocol. This design allows external tools to poll for approval status without accessing the executor's internal memory.
Setting the Parked Marker in SQLite
When the executor encounters an approval gate, it immediately persists the awaiting-agent state to disk before blocking. This ensures that even if the daemon crashes, the parked status remains recoverable.
The SetRunAwaitingAgent Mechanism
Inside internal/pipeline/executor.go, the executor calls SetRunAwaitingAgent before entering the wait state:
// internal/pipeline/executor.go
if dbErr := e.db.SetRunAwaitingAgent(run.ID); dbErr != nil {
slog.Warn("failed to set awaiting-agent marker in db", …)
}
The SetRunAwaitingAgent function in internal/db/run.go writes the current Unix timestamp into the awaiting_agent_since column:
// internal/db/run.go
func (d *DB) SetRunAwaitingAgent(id string) error {
ts := now()
_, err := d.sql.Exec(`UPDATE runs SET awaiting_agent_since = ?, updated_at = ? WHERE id = ?`,
ts, ts, id)
return err
}
A nil value in awaiting_agent_since indicates the run is not parked, while any timestamp indicates active waiting.
Blocking While Awaiting Agent Response
After marking the run as parked, the executor blocks on waitForApproval, which suspends execution until the agent sends an axi respond command or the context is cancelled.
During this blocked state:
- The executor consumes no CPU cycles while waiting
- The
awaiting_agent_sincetimestamp remains set in the database - External observers can query how long the run has been parked by calculating the delta between the current time and the stored timestamp
Clearing the Parked Marker
Once waitForApproval returns—whether through agent response, cancellation, or error—the executor immediately clears the marker:
// internal/pipeline/executor.go (after wait returns)
if dbErr := e.db.ClearRunAwaitingAgent(run.ID); dbErr != nil {
slog.Warn("failed to clear awaiting-agent marker in db", …)
}
The ClearRunAwaitingAgent function in internal/db/run.go sets the column back to NULL:
// internal/db/run.go
func (d *DB) ClearRunAwaitingAgent(id string) error {
_, err := d.sql.Exec(`UPDATE runs SET awaiting_agent_since = NULL, updated_at = ? WHERE id = ?`,
now(), id)
return err
}
This atomic transition ensures the run never appears parked once processing resumes.
Exposing Parked State via IPC Protocol
The pipeline exposes the awaiting-agent signal through the IPC layer defined in internal/ipc/protocol.go. The RunInfo struct carries two relevant fields:
// internal/ipc/protocol.go
type RunInfo struct {
AwaitingAgent bool `json:"awaiting_agent,omitempty"`
AwaitingAgentSince *int64 `json:"awaiting_agent_since,omitempty"`
// ... other fields
}
When the daemon broadcasts run_updated events, it populates these fields from the database row. Clients receive the parked status in a single RPC call, eliminating the need for repeated polling of the executor's internal state.
Rendering the Awaiting-Agent Signal in CLI
The axi status command formats the parked state for human consumption in internal/cli/axi_render.go. The renderer checks for non-nil timestamps on non-terminal runs:
// internal/cli/axi_render.go
if rv.AwaitingAgentSince != nil && !terminalStatus(rv.Status) {
fields = append(fields, toon.Field{
Key: "awaiting_agent",
Value: formatParkedFor(*rv.AwaitingAgentSince),
})
}
The formatParkedFor helper converts the Unix timestamp into a human-readable duration, producing output like "parked 2m30s". This makes the awaiting-agent signal instantly visible to operators monitoring pipeline status.
Recovering from Daemon Crashes
To handle crashes while a run is parked, the RecoverStaleRuns function in internal/db/run.go executes during daemon startup. It clears any lingering awaiting_agent_since values for runs that are being marked as failed, ensuring that a crashed and restarted daemon never reports a dead run as still awaiting an agent.
Testing the Parked Signal
The codebase validates the awaiting-agent signal through three distinct test layers:
- Executor-level tests (
internal/pipeline/executor_approval_test.go) verify thatSetRunAwaitingAgentpopulates the database field and thatClearRunAwaitingAgentsets it back to nil - CLI rendering tests (
internal/cli/axi_test.go) assert that formatted output containsawaiting_agent: parked …only while the run remains in the parked state - End-to-end tests (
internal/e2e/axi_journey_test.go) confirm that a singleaxi statuscall reports the parked signal and that the field disappears after the run finishes
Summary
- The no-mistakes pipeline uses the
awaiting_agent_sincecolumn in SQLite to create a durable, queryable parked state for approval requests - Setting and clearing the marker occurs in
internal/db/run.gothroughSetRunAwaitingAgentandClearRunAwaitingAgent - IPC exposure in
internal/ipc/protocol.goallows external agents to poll for status via theRunInfostruct without accessing executor internals - CLI rendering in
internal/cli/axi_render.goconverts the Unix timestamp into human-readable durations like "parked 2m30s" - Crash recovery via
RecoverStaleRunsprevents stale parked signals from persisting after daemon restarts
Frequently Asked Questions
How does the no-mistakes pipeline prevent stale parked signals after a crash?
The daemon calls RecoverStaleRuns during startup in internal/db/run.go, which clears the awaiting_agent_since field for any runs being marked as failed. This ensures that a crashed daemon that restarts cannot leave runs in a false awaiting-agent state.
Can external tools poll for approval status without accessing the executor directly?
Yes. The daemon exposes the parked state through the IPC protocol in internal/ipc/protocol.go via the RunInfo struct fields AwaitingAgent and AwaitingAgentSince. Clients receive these values in run_updated events or through status queries, enabling observation without direct executor access.
What happens to the database record while the executor is waiting for approval?
The awaiting_agent_since column contains a Unix timestamp indicating when the run entered the approval gate. This non-null value signals that the run is parked, while the updated_at column refreshes to maintain liveness information. The executor blocks on waitForApproval but leaves the database row in this marked state until the agent responds.
How does the CLI display the duration a run has been parked?
The formatParkedFor function in internal/cli/axi_render.go calculates the delta between the current time and the awaiting_agent_since timestamp, formatting it as a human-readable string like "parked 2m30s". This field only appears in axi status output when AwaitingAgentSince is non-nil and the run has not reached a terminal status.
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 →