Skip to content

Driving a loop

Pilot and land are ticks, not runners. One invocation advances one thing and prints one terminal verdict line. Repetition, cadence, budgets, and stop conditions all belong to the driver you wrap around them: your host’s /goal or /loop primitive, a cron entry, or a scheduler that starts one headless session per wake.

Two shapes cover almost everything:

Driver shapeStops whenFits
/goala stop condition matches the printed verdictpilot, draining a backlog until it reports NO_WORK
/loopyou cancel it (or it expires)land, which waits on CI and reviewer bots over hours

/goal validators are transcript-blind: they read conversation output and never run tools. That single constraint shapes the whole design. Each tick echoes its verification evidence (flowctl fields, task counts, the gh-confirmed PR URL) into the transcript and ends with exactly one machine-greppable line, nothing after it:

PILOT_VERDICT=<ADVANCED|NO_WORK|DEFERRED_TO_LAND|BLOCKED|NEEDS_HUMAN|ASKED> spec=<id> stage=<stage> reason="…"
LAND_VERDICT=<MERGED|RELEASED|FIXING_CI|AWAITING_REVIEW|RESOLVING|BLOCKED|NEEDS_HUMAN|NO_WORK> prs=<n> pr=<url|-> reason="…"

So you phrase stop conditions against the grammar rather than against prose. The full verdict tables are on the pilot reference and the land page. Terminal names are never renamed, because drivers grep them.

/goal (v2.1.139+) drains and stops:

/goal keep running /flow-next:pilot until it prints PILOT_VERDICT=NO_WORK, or stop after 20 turns

Variants worth knowing:

/goal keep running /flow-next:pilot --review=codex until PILOT_VERDICT=NO_WORK or PILOT_VERDICT=NEEDS_HUMAN
/goal run /flow-next:pilot --spec fn-12 until it prints PILOT_VERDICT, then stop # one spec, one tick
/goal keep running /flow-next:land until it prints LAND_VERDICT=NO_WORK or LAND_VERDICT=NEEDS_HUMAN

/loop (v2.1.72+; loops expire after 7 days) runs on a cadence and keeps watch:

/loop 10m /flow-next:pilot
/loop 30m /flow-next:land

Every 10 minutes pilot takes one tick: if a spec is ready it advances one stage; if nothing qualifies it reports NO_WORK and the loop idles until you bless more work. That makes /loop plus the tracker board a standing pipeline: drag an issue to Todo in Linear, and the next tick picks it up. For land, a 30-minute cadence comfortably brackets the default 30-minute patience window.

/goal is opt-in: add [features] goals = true to your Codex config (CLI ≥ 0.128.0). Codex has no $skill-in-goal syntax, so write a plain-text objective that names the behavior and the grammar:

/goal Run the flow-next pilot skill repeatedly: each run advances one ready spec by one
pipeline stage and ends with a PILOT_VERDICT line. Stop when it prints
PILOT_VERDICT=NO_WORK or PILOT_VERDICT=NEEDS_HUMAN.
/goal Run the flow-next land skill repeatedly: each run takes one tick over the build
loop's open PRs - CI, reviews, merge, release - and ends with a LAND_VERDICT line. Stop
when it prints LAND_VERDICT=NO_WORK or LAND_VERDICT=NEEDS_HUMAN.

Codex has no cadence primitive, so the /goal form re-ticks back-to-back rather than sleeping. That is functionally safe, because a tick never blocks: it reports AWAITING_REVIEW and exits. Expect rapid re-checks while waiting on reviewers, and prefer a /loop cadence where your host has one.

Both verdict lines are machine-readable, so a driver can compose them into a spec-to-merged-PR pipeline in one prompt:

/loop 30m - one tick: run /flow-next:pilot --review=codex --depth=deep.
If PILOT_VERDICT=DEFERRED_TO_LAND, run /flow-next:land in the same tick.
Send implementation tasks to the implementer tier,
keep UI tasks on the session model, reviews come from codex.
Stop when pilot prints NO_WORK and land prints LAND_VERDICT=NO_WORK,
or on any NEEDS_HUMAN.

DEFERRED_TO_LAND exists exactly for this hand-off. Running the two loops as separate instances instead is the assembly-line topology, and it needs a clone or worktree each.

Iteration caps, budgets, and wall-clock limits belong to the driver (/goal stop clauses, --tokens, /loop cadence). A tick has no timeout machinery of its own.

One review backend has a machine dependency worth knowing before you walk away: the rp backend uses the CE-first CLI ladder and needs RepoPrompt CE running on the same Mac (cold start with open -ga "RepoPrompt CE"; a stopped app fails fast). Discontinued Classic is the final compatibility fallback only. On remote or CI machines use --review=codex, --review=copilot, --review=cursor, or --review=none.

A prompt steers only the session it is typed in. Your routing block and per-run flags are read every turn while you are there, and an unattended tick at 3am has no prompt to read. If you want the 3am pilot tick to review with a different backend, that is a config change (flowctl config set review.backend …), not a sentence. The two steering layers are laid out in Orchestration & model routing.

If a tick sends implementation out to a second CLI, one failure class matters more unattended than it ever does in a session. Raw bridge calls fail quietly: outside a trusted git directory, codex exec refuses in about a second with the error only in its log, and cursor-agent blocks on an interactive workspace-trust prompt, then exits “successfully” with empty output. An interactive host sees the stderr and fixes it. An autonomous loop dies silently.

Wrap the bridge in a thin fast-scout-tier subagent instead of calling it raw. The wrapper composes the self-contained prompt, runs the bridge, verifies the output is non-empty and parseable, repairs the environment if not, and retries once.

Two rules are load-bearing:

  • The wrapper runs the bridge in the foreground, as one blocking call. A backgrounded bridge loses the completion signal, and the wrapper idles forever on a finished or silently dead process.
  • The self-heal license covers environment and flags only, never judgment. In scope: git trust, sandbox flags, stale model ids, empty-output retry. Out of scope: rewriting the task prompt, interpreting review verdicts, or switching models on quality grounds.

This is a documented pattern rather than a shipped agent type; quick interactive calls may stay raw. The bridge recipes themselves ship into the repo you work in and are read on demand with flowctl usage (## Orchestration & model steering).

/goal and /loop need an interactive host. A scheduler can run the same policy with one fresh headless session per wake (claude -p, codex exec, or an equivalent), which is the shape Unattended operation documents, along with the reasons a fresh wake beats an immortal shell.