Shipyard

agent-orchestrator control mechanisms

00 · What is Shipyard

Approved plans become software, one measured loop at a time.

Shipyard is a self-hosted platform where AI owns the software development lifecycle end to end. You design a system interactively with an agent and give one approval, at plan level. The platform then works the plan off as a project cascade: wave by wave, each issue is built by a worker, reviewed by an independent worker, merged through a gate you armed, health-verified, and traced end to end. You watch a live tree in Mission Control, you can pause everything with one label, and the platform escalates to you instead of guessing.

1 · PLANYou + an agent design itarchitecture · waves · acceptance 2 · HANDOVEROne approval, at plan levelepic labeled cascade 3 · THE CASCADE RUNSWave by wave, autonomouslybuild · review · gated merge 4 · SOFTWAREMerged, deployed, verifiedtraced and costed end to end wave N+1 unblocks only on merged wave + green health anything stuck stops itself and escalates to you: needs-human
One approval at plan level; every step after it runs inside a measured loop, and a red path leads to you whenever one stops itself.

The interactive bridge to GitHub is part of the system: Shipyard operates its own GitHub App. Inbound, every webhook (issues, comments, PRs, reviews, labels) flows through it into the event router. Outbound, the platform speaks as its bot identity: it posts PRDs and review findings, sets the labels that are the system state, opens and merges PRs, and links every action to its trace. Install the App on a repo and that repo joins the platform. And because the App is a first-class RBAC role, it can never approve its own gates: loop protection at the permission level. Everything below explains the control mechanisms that make this trustworthy.

01 · Overview

Six loop families, nested by timescale

Fast loops run inside slow ones. The eval loop fires on every single AI output; the build loop wraps it per issue; the cascade beats every ten minutes; the engine climbs every six hours. Self-healing watches all of them continuously, and the author is the outermost ring, not a bystander. Hover a ring to read it, click to jump to its chapter.

AUTHOR LOOP outermost · always ENGINE LOOP 6 h · hill-climbing CASCADE LOOP 10 min · wave orchestration BUILD LOOP per issue · minutes–hours EVAL LOOP per output · seconds SELF-HEALING LOOP continuous · watches every ring
The nest, to scale of responsibility rather than time: each ring can stop everything inside it, and every ring escalates outward. Nothing escapes the author ring.

02 · Interlock

How the loops feed each other

Nesting is only half the story. The loops are wired together by three kinds of signal: work flowing forward, escalation converging on the human, and feedback grounding the numbers. Filter by type to see each layer alone.

AUTHOR LOOP · APPROVALS · CAPS · KILL SWITCHES Cascade10-min heartbeat Buildreview↔fix controller EvalLLM-as-judge gate Self-healingsense · classify · heal Enginetrace analysis, 6 h Outcomespost-merge · calibration needs-human→ meta-observer → author unblocks wave N+1 merges complete the wave every output judged pre-ship diagnosis issues enter the normal pipeline approved proposals → same golden path every merge is re-checked daily judge → C (0.25) calibration re-grounds C (weekly) reverts become benchmark cases 5 stop conditions health red · blocked 2 retries exhausted unclear diagnosis every proposal needs approval
Work flows forward in blue; red always points at the same chip: needs-human is the single escalation currency; green closes the outer circle by feeding reality back into the scoring.

03 · The inner loop

Review ↔ fix, as a closed control circuit

The heart of the system. It doesn't count iterations; it measures error, verifies every claim adversarially, and regulates on the trajectory. Confidence is earned from evidence, never self-reported. Play a story below the schematic to walk one signal through the circuit.

THE MEASURED LOOP Review worker findings P1/P2/P3 + fingerprints Adversarial verification grep · repo grep · run tests Σ weighted error severity × verification → 0 LLM judge rubric score 0–1 CI status green · red · none Verification gate verify.yml + GATE-PROOF Confidence C earned per round, 0–1 Controller: decide() error + confidence trajectory, fixed order of checks Round budget ceil(E₀/2) ∈ [3,8] Fix worker fresh context · own worktree Review-loop watchdog outer guard · nudge ≤ 2 FINDINGS survivors w = 0.40 trajectory per round continue: next round push → re-review 0.25 0.20 FAIL → stop now Converged error = 0 → APPROVE auto-merge, 4 locks error → 0 escalate: gate-fail · oscillation · budget · no progress · plateau HUMAN LANE needs-human named finding + evidence Meta-observer triage first Author retry · revert · stop resolvable → re-dispatch (cap 1) Plateau → auto-ticket branch-scoped, pushes this PR
Pick a story to walk one signal through the circuit, step by step.

How the error is measured

error = Σ severity × verification
severity: P1 = 3 · P2 = 1 · P3 = 0
verification: actionable 1.0 · unverified 0.5 · disproved 0

Every finding is attacked before it counts: structural claims get grepped, world-knowledge claims get checked against the deployed repo, behavioral claims get tests executed. Disproved phantoms cost nothing; unproven claims count half. The fixer can dispute a finding, but only with an executable proof.

How confidence is earned

C = 0.40·(1 − error/E₀) + 0.25·judge + 0.20·CIgreen + 0.15·test-evidence
red CI → cap 0.40 gate FAIL → cap 0.30 gate unproven → cap 0.60 gate PASS → +0.15

Missing evidence counts zero, not neutral: a round without CI can never score like a round with a green pipeline. Hard disproof dominates everything else. Tier high ≥ 0.75 is the only tier that may auto-merge.

A real trajectory: one PR, four rounds

RoundErrorConfidencedecide()
06.00.24continue · first round
13.00.51continue · progress
21.00.68continue · progress
300.82converged → auto-merge

Budget for this PR: ceil(6/2) = 3 fix rounds, earned by the size of the initial problem, not a constant. A one-line fix gets the floor (3); a heavy review gets up to 8. Both bounds are live-tunable Airflow Variables.

The whole state (error per round, finding fingerprints, evidence) is persisted as a hidden comment on the PR itself. The loop survives restarts, and a human can read every decision.

05 · In production

What a loop looks like while it runs

Every review↔fix loop renders as a live card in Mission Control: the verdict with its judge score, the round against its budget, the error and judge trajectories as sparklines, agent count, and the token cost of the whole loop. These are unedited captures from the running system.

Mission Control loop card for mycelium PR 43: verdict APPROVE 0.87, round 2 of 3, 3 agents, 737K tokens for $0.70, error trajectory 2 to 1 to 0 to 0, judge trajectory steady around 0.87, state converged, waiting for merge gates
Convergence, measured round by round The review found two weighted findings; two fix rounds drove the error 2 → 1 → 0 while the judge score held at ~0.87. The card shows the loop stayed inside its budget (round 2/3) and what the whole loop cost: 737K tokens, $0.70. State: converged; the auto-merge gates run next.
Mission Control loop card for shipyard PR 446: fixing the merge_reached_production_flow DAG failure, verdict APPROVE 0.91, round 1 of 3, 4 agents, 2.8M tokens for $13.49, error 2 to 0, judge 0.88 to 0.91
The platform repairing its own watchdog The DAG-failure observer flagged a broken production-reconciliation DAG and filed issue #444; this PR is the resulting fix, built and reviewed by the normal loop: error 2 → 0 in a single round, judge rising to 0.91. The system maintains its own control loops through the same pipeline it uses for feature work.
Mission Control loop card for shipyard PR 460, merged: verdict APPROVE 0.92, error 0 in the first round, judge 0.92, one agent
First-pass clean Not every loop needs rounds: here the independent review found nothing blocking (error 0, judge 0.92), so the PR converged immediately and merged 16 minutes after dispatch. The trajectory that didn't happen is evidence too.
Mission Control loop card for mycelium PR 46, merged: verdict APPROVE 0.86, round 1 of 3, 5 agents, 8.5M tokens for $41.40, error 1 to 0 to 0, judge 0.86 to 0.90 to 0.86
Merged, with the full story attached After the merge the card keeps the evidence: the error trajectory (1 → 0 → 0), the judge series, five agents, and the full loop cost of 8.5M tokens / $41.40, with a Langfuse link to every underlying LLM call. Cost and quality stay auditable per PR, not just per month.
Mission Control issue row for mycelium issue 47, labels auto-ticket and ai-task: lifecycle strip queued, working, review, merged; escalated, waiting for you for 59 minutes; badge waiting for human decision; button clear needs-human; 93K tokens for $0.08
An escalation waiting at the front door This ticket was auto-filed from review findings, worked, reviewed, and then the loop hit a stop condition and escalated. The lifecycle strip shows exactly where it stands: escalated · waiting for you. The human decision is one click (clear needs-human), and until it happens, nothing auto-merges.
Mission Control issue row for mycelium issue 51, label auto-ticket: strict-embeddings silently ignored in session bootstrap path; lifecycle queued, not yet dispatched; buttons dispatch agent and escalate
The system files its own work A review finding that didn't block the PR became a standalone auto-ticket. It sits queued (visible, costed at zero, untouched) until the dispatcher or a human sends an agent. Nothing the system discovers gets lost in a chat log; everything becomes a tracked, addressable unit of work.

06 · Stop conditions

Five named ways to stop, checked in this order

"Loop four times, then give up" is not control engineering. The controller distinguishes why it stops, and every escalation names the specific finding that is stuck.

1

Gate failed

verify.yml check exit ≠ 0

The last fix measurably broke the repo's own reference check. Overrides everything: you don't iterate on top of a regression. The human's job is to revert, not to judge prose.

2

Oscillation

fingerprint returns after "fixed"

A finding disappears and comes back: ping-pong between reviewer and fixer. That's a structural disagreement no further round will resolve.

3

Budget exhausted

rounds > ceil(E₀/2) ∈ [3,8]

The parametric lid. Escalates with the full error trajectory so the human sees whether it was converging slowly or going nowhere.

4

No progress

Δerror ≤ 0 ∧ same finding survived

The error didn't fall and the identical finding is still open; the fix channel is producing motion, not progress.

5

Confidence plateau

ΔC < 0.02 despite a new round

The error may still inch down while the wider evidence (judge, CI, tests) has stopped improving. More rounds now add cost, not confidence. Can also file targeted branch-scoped tickets instead of dead-ending.

✓

Otherwise: continue

error falling, evidence growing

Progress is measured, not assumed. And convergence (error → 0 → APPROVE) exits the loop entirely, through the four auto-merge locks.

07 · The operational inventory

Every loop: signal, actuator, cap, proof

The full fleet of closed loops in production. Each row is a running DAG; each has a scenario test that replays its decision logic; several replay real incidents.

LoopCadenceSignalActuatorCap / escalation
The inner circuit
Review↔fix controllerper pushverified weighted error + confidence trajectoryfix worker re-dispatchbudget 3–8 → named-finding escalation
Review-loop watchdog10 minpush/review timestamps in fix cyclesnudge dead channels, re-trigger lost reviews (SHA-dedup)2 nudges → needs-human
Eval gateper outputjudge rubric scoreregenerate with feedback2 retries → escalate with transcript
Workers & dispatch
Worker-timeout healer10 mintimeouts via Loki, 9 root-cause classesWAL checkpoint · cancel · CPU throttleacts ≥ 2 timeouts, per-cause cooldown
Progress livenessper sweeprising tool calls, not wall clockalive / stalled (5 min) / dead (30 min) verdictsfeeds healer & preemption
Dispatch reconciliation5 minack without PR/branchreconcile or re-dispatchunreconcilable → escalate
Implementation resume15 min'implementing' with no PR, no workerre-dispatch until a PR existsthen human
Stuck-issue observer15 mindispatched ticket silent ≥ 90 minexactly one re-dispatch1 re-dispatch → needs-human + page
Merge & cascade
Project cascade10 minwave completion + system healthunblock next wavehealth red → block + page
Acceptance gateon cascadeexit code of the epic's acceptance commandlabel + gate epic closureinfra failure → blocked, terminal until human
Closure gateon closeacceptance criteria of bot-closed issuesbounded reopen1 reopen → needs-human
Merge-readiness shepherd6 happroved-but-blocked PRsbranch update, re-trigger CItrue conflict → named files + needs-human
Transport & deploy
Webhook reconciler10 minGitHub delivery statusredelivery4 attempts → single page
Infrastructure watchdog5 minHTTP/TCP health, OAuth expiry, inodesalert → triage → self-healunresolved → page
Deploy drift monitorhourlylive DAGs vs deploy manifestdrift alert0 out-of-band edits tolerated
Post-deploy canaryafter deploylive canary checksFAIL verdictpage; a deploy proves itself in prod
Merge-reached-productionhourlymain HEAD vs deployed commit + smoke checksreconciliation alertsilent deploy block → loud failure
Meta & grounding
DAG-failure observer30 minFAILED runs + diagnosis classifierretry infra flakes · ticket code errors · page auth3 tickets, 5 retries per sweep; never itself
Coherence auditor4 hcontradictions across the dashboard's own payloadspropose onlyhuman or meta-observer disposes
Meta-observerevent + 4 hevery needs-human escalationresolve resolvable classes, brief the rest1 re-dispatch → human; modes off/dry_run/active
Post-merge outcomesdailyreverts, CI failures, hotfixes after mergeoutcome log + benchmark proposalrevert → page
Confidence calibrationweeklyBrier score, reliability per decileempirical recalibration mappingoverconfidence gap > 0.25 → page

08 · The observer hierarchy

Loops that watch loops

Three tiers of observation, with the human on top. The design rule at every tier: pure, unit-tested decision cores; reversible actuators; a hard cap; and a kill switch per observer.

Object observersheal primitives

Watch workers, issues, and events directly: the timeout healer (9 root causes), progress liveness, dispatch reconciliation, the stuck-issue observer, the webhook reconciler. They fix things (restart, re-dispatch, redeliver) under strict caps.

Loop observersguard the loops themselves

Watch the control loops from outside: the review-loop watchdog (the inner loop's blind spots), the merge-readiness shepherd (approved-but-blocked), the DAG-failure observer (the whole fleet, including other observers, never itself), the coherence auditor (the reporting layer's own contradictions).

Meta-observerwatches the escalations

needs-human is not a terminal state; it's this observer's front door. It gathers context, resolves resolvable classes itself (exactly one re-dispatch), and hands everything else to the author as a synthesized brief. Three operating modes, switchable live: off · dry_run · active.

Authorthe terminal backstop

Behind every cap: re-dispatch 1 · nudges 2 · tickets 3 · retries 5 · redeliveries 4. No inner loop can run unbounded without the author hearing about it, and autonomy is granted per issue, never globally.

any loop hits its cap → label: needs-human → meta-observer triage → resolvable? re-dispatch (cap 1) → author: brief + options

09 · Grounding

The loop that audits the loops

A confidence score that is never checked against reality is just a number. Shipyard closes the outermost circle: real merge outcomes feed back into the scoring.

daily

Post-merge outcomes

Every merged PR is re-checked: reverted? CI failed on the merge commit? hotfixed? The verdict is logged next to the loop's final confidence. Reverts page the author and auto-generate a benchmark proposal.

weekly

Confidence calibration

Claimed confidence vs. empirical accuracy, in ten deciles, plus a Brier score. An overconfidence gap > 0.25 pages. Corrections apply only once a decile has ≥ 10 resolved cases; until then, the mapping honestly stays identity.

continuous

Loop KPIs & scenario proofs

Zero-touch completion rate, phantom-finding rate, fix-rounds-to-convergence, plus scenario tests that replay whole loop trajectories (convergence, oscillation, plateau, crash-resume) as invariants. Several replay real incidents.

A control loop without proof is a guess with a cron schedule. the design rule every loop in this system is held to