Skip to content

Land — the Ship Loop

/flow-next:land is the third flow-next loop: where pilot and Ralph deliberately stop at a draft PR, land babysits those PRs the rest of the way — CI green, automated reviews converged, merged, and (if your project defines one) released. Shipped in 1.14.0 — and fittingly, it was the first spec pilot drove end-to-end.

It is /loop-shaped, not /goal-shaped: babysitting waits on external events — CI runs, reviewer bots — over hours, so the loop wakes on a cadence, acts on every PR it owns, and sleeps.

/loop 30m /flow-next:land
Terminal window
/flow-next:land # one tick over all build-loop-authored PRs
/flow-next:land --dry-run # full gate classification, zero mutations

Land is fully autonomous by design — there is no interactive mode. It never asks questions; ambiguity maps to NEEDS_HUMAN. Requires gh and jq on PATH and gh auth status passing (gate surfaces verified against gh 2.93.0 — re-verify gh pr checks --json bucket, --match-head-commit, and mergeStateStatus on major gh bumps).

For each open PR the build loop authored, land takes at most one action class per PR per tick:

  1. Discover — open specs with all tasks done, probed by branch: a PR qualifies only with both authorship signals — its head branch matches a spec’s branch_name AND the make-pr breadcrumb is in the PR body. Branch-only matches are reported NEEDS_HUMAN, never acted on; your hand-opened PRs are never touched. Specs with in-flight tasks stay pilot’s — the pilot-concurrency interlock.
  2. CI — tri-state over all checks (gh pr checks --json bucket): any fail → diagnose from the failing run’s logs, scope a fix, push, report FIXING_CI; any pending (or an empty check list right after a push) → wait, never treated as green. Fix attempts are bounded (land.ciFixBudget, default 3, strikes ledgered under .git/); on exhaustion the PR gets a durable flow-next:needs-human label, is reported NEEDS_HUMAN, and is skipped on later ticks until a human removes the label. Unrelated infra flakes get one gh run rerun instead of an edit.
  3. Reviews — wait for automated reviewers inside a patience window (land.patienceMinutes, default 30), anchored to the last push (a CI-fix push invalidates prior reviews and restarts the wait). Report AWAITING_REVIEW until reviews land or the window elapses.
  4. Resolve — unresolved threads route through /flow-next:resolve-pr dispatched with mode:autonomous — fix, verify, reply, resolve — and land gates on its machine-readable terminal line (RESOLVE_PR_VERDICT=<RESOLVED|PENDING|NEEDS_HUMAN> …), looping tick over tick until convergence.
  5. Merge — CI green + threads addressed + the review signal satisfied → flip the draft to ready (gh pr ready) and merge explicitly: gh pr merge --squash --delete-branch --match-head-commit <head-sha>. Never gh pr merge --auto — land itself is the gate, and --auto insta-merges on unprotected repos. Conflicts get a mechanical rebase only; any conflict hunk aborts to an honest BLOCKED — land never hand-resolves hunks.
  6. Close + release — after the merge: flowctl spec close (so the build loop never re-selects merged work), the opt-in tracker touchpoint (tracker.perEvent.land.merged — issue flipped to its terminal state + a release/verdict comment), then discover and follow your project’s own release instructions (docs/RELEASING.md, RELEASING.md, agent_docs/releasing.md, or docs referenced from CLAUDE.md/AGENTS.md) if present — deterministic, non-interactive commands from those docs only, with an idempotency probe so a re-entry tick never re-tags. No release docs → stop at merge. Land never invents versioning or publish steps.

A merged-but-unclosed spec re-enters idempotently: a later tick resumes close → tracker → release, never a second merge.

Per-PR verdicts are MERGED | RELEASED | FIXING_CI | AWAITING_REVIEW | RESOLVING | BLOCKED | NEEDS_HUMAN, echoed as evidence blocks. Every tick ends with exactly one machine-greppable line — the last line of output, nothing after it (the PILOT_VERDICT precedent):

LAND_VERDICT=<verdict|NO_WORK> prs=<n> pr=<deciding-pr-url|-> reason="<one line>"

The tick-level verdict is the worst severity across PRs (NEEDS_HUMAN > BLOCKED > FIXING_CI > RESOLVING > AWAITING_REVIEW > RELEASED > MERGED); NO_WORK when discovery finds zero authored PRs.

Land is the only place in flow-next licensed to auto-merge — an explicit, confined override of the repo-wide “no gh pr merge from skills” rule. The license is bounded by the gate:

  • CI green — every check’s bucket ∈ pass/skipping, fixed by the loop if needed.
  • Every review thread addressed — resolve-pr convergence, bounded at its existing fix-verify cycles.
  • The configured review signal (land.reviewSignal) satisfied:
SignalSatisfied when
silence (default)≥1 review by an automated reviewer + zero unresolved threads + the patience window elapsed since the last push. Built for bot reviewers (Codex et al.) that comment but never file formal APPROVEs.
approveFormal reviewDecision == APPROVED
<github-login>That reviewer’s latest review is APPROVED, or COMMENTED with zero unresolved threads

An automated reviewer is a review author whose login ends in [bot], plus any login you list in land.automatedReviewers. No automated review ever + no signal configured → land never merges unreviewed — it reports NEEDS_HUMAN instead. A repo that dismisses stale approvals on push is detected (approve → re-push → re-required ping-pong) and reported NEEDS_HUMAN rather than re-looped.

All keys ship with seeded defaults — flowctl config get land.reviewSignal returns "silence" on a fresh repo, not null:

KeyDefaultMeaning
land.releasetrueRun the release-follow step after merge (also no-ops when no release docs are discovered)
land.patienceMinutes30Reviewer patience window, anchored to the last push
land.reviewSignalsilenceMerge signal: silence, approve, or a GitHub login
land.automatedReviewers""CSV allowlist of reviewer logins counted as automated, supplementing the [bot]-suffix rule
land.reviewTrigger""One-shot comment posted to summon a reviewer bot on a draft PR with zero automated reviews (e.g. "@codex review" — bots don’t auto-review drafts, and the build loop’s PRs are born draft). Empty = never post
land.ciFixBudget3CI-fix attempts per PR before the durable needs-human label
Terminal window
flowctl config set land.reviewSignal approve
flowctl config set tracker.perEvent.land.merged push # opt-in tracker touchpoint
  • A separate skill — projects that never run it carry zero risk and zero new surface.
  • Touches only PRs the build loop authored — both authorship signals required before any mutation.
  • The release step has its own off-switch (land.release), independent of the rest of the loop.
  • Refuses to nest under the Ralph harness (FLOW_RALPH / REVIEW_RECEIPT_PATH), same as pilot; refuses a dirty working tree at tick start; restores your branch and asserts a clean tree between PRs and at tick end.

With land in place the three loops close the lifecycle end to end:

board / flowctl pilot land
bless a spec ──▶ plan → review → work ──▶ CI → reviews → merge → release
(your judgment) (draft PR out) (shipped)

Run both loops concurrently for the full assembly line — one instance each, separate clones (both mutate the working tree). See Running the full pipeline.

See Going Autonomous for how the loops fit together, and the changelog for the 1.14.0 release notes.