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:landInvocation
Section titled “Invocation”/flow-next:land # one tick over all build-loop-authored PRs/flow-next:land --dry-run # full gate classification, zero mutationsLand 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).
What a tick does
Section titled “What a tick does”For each open PR the build loop authored, land takes at most one action class per PR per tick:
- 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_nameAND the make-pr breadcrumb is in the PR body. Branch-only matches are reportedNEEDS_HUMAN, never acted on; your hand-opened PRs are never touched. Specs with in-flight tasks stay pilot’s — the pilot-concurrency interlock. - CI — tri-state over all checks (
gh pr checks --json bucket): anyfail→ diagnose from the failing run’s logs, scope a fix, push, reportFIXING_CI; anypending(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 durableflow-next:needs-humanlabel, is reportedNEEDS_HUMAN, and is skipped on later ticks until a human removes the label. Unrelated infra flakes get onegh run reruninstead of an edit. - 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). ReportAWAITING_REVIEWuntil reviews land or the window elapses. - Resolve — unresolved threads route through
/flow-next:resolve-prdispatched withmode: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. - 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>. Nevergh pr merge --auto— land itself is the gate, and--autoinsta-merges on unprotected repos. Conflicts get a mechanical rebase only; any conflict hunk aborts to an honestBLOCKED— land never hand-resolves hunks. - 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.
The verdict grammar
Section titled “The verdict grammar”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.
The merge gate, precisely
Section titled “The merge gate, precisely”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:
| Signal | Satisfied 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. |
approve | Formal 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.
Configuration
Section titled “Configuration”All keys ship with seeded defaults — flowctl config get land.reviewSignal returns "silence" on a fresh repo, not null:
| Key | Default | Meaning |
|---|---|---|
land.release | true | Run the release-follow step after merge (also no-ops when no release docs are discovered) |
land.patienceMinutes | 30 | Reviewer patience window, anchored to the last push |
land.reviewSignal | silence | Merge 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.ciFixBudget | 3 | CI-fix attempts per PR before the durable needs-human label |
flowctl config set land.reviewSignal approveflowctl config set tracker.perEvent.land.merged push # opt-in tracker touchpointOpt-in and isolated
Section titled “Opt-in and isolated”- 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.
The full picture
Section titled “The full picture”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.