# How the no-mistakes Pipeline Handles Parked Runs for Approval Requests

> Learn how the no-mistakes pipeline manages parked runs for approval requests by writing timestamps to SQLite and enabling external agent polling. Approve faster with this efficient system.

- Repository: [Kun Chen/no-mistakes](https://github.com/kunchenguid/no-mistakes)
- Tags: how-to-guide
- Published: 2026-07-18

---

**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`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/pipeline/executor.go), the executor calls `SetRunAwaitingAgent` before entering the wait state:

```go
// 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`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/db/run.go) writes the current Unix timestamp into the `awaiting_agent_since` column:

```go
// 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_since` timestamp 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:

```go
// 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`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/db/run.go) sets the column back to **NULL**:

```go
// 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`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/ipc/protocol.go). The `RunInfo` struct carries two relevant fields:

```go
// 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`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/cli/axi_render.go). The renderer checks for non-nil timestamps on non-terminal runs:

```go
// 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`](https://github.com/kunchenguid/no-mistakes/blob/main/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:

1. **Executor-level tests** ([`internal/pipeline/executor_approval_test.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/pipeline/executor_approval_test.go)) verify that `SetRunAwaitingAgent` populates the database field and that `ClearRunAwaitingAgent` sets it back to nil
2. **CLI rendering tests** ([`internal/cli/axi_test.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/cli/axi_test.go)) assert that formatted output contains `awaiting_agent: parked …` only while the run remains in the parked state
3. **End-to-end tests** ([`internal/e2e/axi_journey_test.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/e2e/axi_journey_test.go)) confirm that a single `axi status` call reports the parked signal and that the field disappears after the run finishes

## Summary

- **The no-mistakes pipeline** uses the `awaiting_agent_since` column in SQLite to create a durable, queryable parked state for approval requests
- **Setting and clearing** the marker occurs in [`internal/db/run.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/db/run.go) through `SetRunAwaitingAgent` and `ClearRunAwaitingAgent`
- **IPC exposure** in [`internal/ipc/protocol.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/ipc/protocol.go) allows external agents to poll for status via the `RunInfo` struct without accessing executor internals
- **CLI rendering** in [`internal/cli/axi_render.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/cli/axi_render.go) converts the Unix timestamp into human-readable durations like "parked 2m30s"
- **Crash recovery** via `RecoverStaleRuns` prevents 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`](https://github.com/kunchenguid/no-mistakes/blob/main/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`](https://github.com/kunchenguid/no-mistakes/blob/main/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`](https://github.com/kunchenguid/no-mistakes/blob/main/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.