How no-mistakes Ensures Non-Blocking Pipelines: A Deep Dive into the Executor Logic

The no-mistakes pipeline executor guarantees non-blocking execution by automatically continuing past steps that generate info-only findings, while parking only individual runs that require explicit human approval via a pollable database flag that does not impede other pipeline executions.

In the kunchenguid/no-mistakes repository, pipelines execute sequences of steps—such as lint, test, and CI operations—that may produce findings of varying severity. Understanding how the system distinguishes between blocking and non-blocking execution paths is essential for teams running automated workflows. The implementation centers on the executor loop in internal/pipeline/executor.go, which evaluates step outcomes to determine whether the pipeline should proceed or pause.

The Core Non-Blocking Logic in the Executor

The executor’s primary responsibility is to evaluate each step’s outcome and decide whether to continue execution or wait for human intervention. This decision happens in a tight loop that checks specific flags indicating the severity and nature of findings.

Distinguishing Between Blocking and Non-Blocking Findings

After a step completes, the executor evaluates whether the findings require the pipeline to stop. According to the source code in internal/pipeline/executor.go (lines 43-48), the logic follows this pattern:

if !outcome.NeedsApproval && !hasAskUserFindingsJSON(outcome.Findings) {
    // Any remaining info-only or non‑blocking findings are acceptable
    // and don't block the pipeline.
    skipRemaining = outcome.SkipRemaining
    stepSkipped   = outcome.Skipped
    break
}

This conditional block ensures that info-only and non-blocking findings never stop the pipeline. The evaluation depends on two critical checks:

  • outcome.NeedsApproval: Returns true only when findings exist that mandate human review, such as those with "error" or "warning" severity.
  • hasAskUserFindingsJSON(outcome.Findings): Detects whether any findings request a user decision through the "ask-user" gate mechanism.

When both return false, the executor immediately proceeds to the next step, even if the previous step reported style warnings or informational messages.

The Approval Gate Check

When a step does require approval, the system transitions into an observable parking state rather than a hard block. The executor updates the database to mark the run as awaiting agent interaction (lines 76-82 of executor.go):

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

This creates a pollable flag in the runs table—specifically the awaiting_agent_since field defined in internal/db/schema.go—that indicates the run is paused. Crucially, this pause applies only to the current run; the executor continues scheduling and executing other pipelines without impediment.

Auto-Fix Execution Before Blocking Checks

Before the executor evaluates whether to block, it attempts to resolve findings automatically. The auto-fix logic runs prior to the blocking check, ensuring that machine-correctable issues do not trigger unnecessary human intervention.

As implemented in lines 13-41 of internal/pipeline/executor.go:

if outcome.AutoFixable && autoFixLimit > 0 && autoFixAttempts < autoFixLimit {
    // auto‑fix logic …
}

This preemptive resolution means that auto-fixable findings—including those with "info" severity—are corrected automatically. If an auto-fix succeeds, the step may be re-executed, but the pipeline never enters a blocking state waiting for human input. Only findings that survive the auto-fix process and still require approval will trigger the parking mechanism.

Observable Parking Without Pipeline Congestion

The architecture separates the concept of "parking" a run from "blocking" the pipeline scheduler. This distinction ensures system resources remain available for concurrent executions.

The Database Schema and await_agent_since

The persistence layer supports this non-blocking guarantee through the schema defined in internal/db/schema.go. The runs table includes the awaiting_agent_since timestamp field, which serves as a visibility aid rather than a lock.

When a gate is entered, the executor sets this flag (lines 76-82), and it is cleared immediately after the user responds (lines 90-96 of executor.go). Because the flag is transient and run-specific, other components never perceive the system as blocked; they simply observe that particular run is in a parked state awaiting input.

Step Ordering and Skip Remaining Logic

The executor also optimizes flow through step ordering. After a step completes without needing approval, the executor may skip remaining steps when the outcome signals SkipRemaining. This is safe because, as noted in the source comments, only non-blocking findings can trigger that path.

The IPC protocol in internal/ipc/protocol.go exposes the AwaitingAgent and AwaitingAgentSince fields, allowing external observers to poll status without interfering with execution. The CLI renders this state in internal/cli/axi_render.go (line 271), presenting the information to users running axi status commands.

Code Examples and CLI Output

When running a pipeline that produces only info-only findings—such as a lint step reporting style warnings—the executor completes without entering the parking state:

$ no-mistakes run ./my-repo

# output (excerpt)

status: running

# No awaiting_agent field appears, confirming automatic continuation

Contrast this with a run that encounters a blocking gate:

$ no-mistakes axi status --run 12345
run:
  id: 12345
  status: running
  awaiting_agent: parked 1m12s

This transient awaiting_agent flag appears only when a gate is hit, as verified by the end-to-end tests in internal/e2e/axi_journey_test.go. Once the user responds with no-mistakes axi respond approve, the flag clears and the pipeline resumes.

Summary

  • Automatic continuation: The executor in internal/pipeline/executor.go (lines 43-48) proceeds past steps that lack NeedsApproval flags or "ask-user" findings, ensuring info-only reports never block execution.
  • Preemptive auto-fix: Auto-fixable findings are resolved before blocking checks occur (lines 13-41), preventing unnecessary human intervention.
  • Observable parking: Runs requiring approval are marked with awaiting_agent_since in the database schema, creating a pollable state that pauses only the specific run without congesting the pipeline scheduler.
  • Transient states: The awaiting_agent flag is set when gates are entered (lines 76-82) and cleared immediately after response (lines 90-96), ensuring other runs continue uninterrupted.

Frequently Asked Questions

What determines whether a finding blocks the pipeline or allows automatic continuation?

A finding blocks the pipeline only if outcome.NeedsApproval is true or if hasAskUserFindingsJSON(outcome.Findings) detects a user decision gate. Info-only and non-blocking findings fail both checks, causing the executor to proceed immediately to the next step without human intervention.

How does the system handle auto-fixable findings without blocking?

Before checking whether to pause execution, the executor evaluates outcome.AutoFixable against the autoFixLimit (lines 13-41 of executor.go). If conditions allow, it automatically applies fixes and may re-execute the step. The pipeline only blocks if findings remain after auto-fix attempts exceed the configured limit.

What is the difference between a "parked" run and a "blocked" pipeline in no-mistakes?

A "parked" run has the awaiting_agent_since flag set in the runs table (defined in internal/db/schema.go), indicating it awaits human response. This is purely an observable state visible via axi status. A "blocked" pipeline would prevent other executions from scheduling, which does not occur—the executor continues processing other runs while only the specific run marked with awaiting_agent_since pauses until the user replies.

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 →