Dev Pipeline panel (part 2)
The second half of the Dev Pipeline panel page: the Auto-lander tab, the QA Fleet tab and the Setup tab — the switches, the cleanup jobs and the spend caps — plus how the panel is put together for contributors.
What it is
This is part 2 of the Dev Pipeline panel page. That page covers what the panel is, where it lives, and the first four of its rail entries — Live, Timing, Agent Board and the Worktrees half of the worktree view. This half carries the remaining three rail entries — Auto-lander, QA Fleet and Setup — and, for anyone working on the code, how the panel is put together.
Where to find it
Both halves are the same surface: the built-in Dev Pipeline virtual project, which docks in the main panel beside the projects sidebar and opens from its own row in the Omniscio sidebar. On a phone the rail becomes a row of tabs across the top, so the three entries described here are reached the same way remotely.
How it behaves
Auto-lander. Its own tab on the rail is where you watch it: live daemon status, the queue of branches currently marked ready-to-merge, and the land history — every branch it has landed, handed back on a conflict, or set aside (couldn't land), kept across app restarts, plus two quick actions: pause/resume the whole lander, and pause/resume one repository. Full write-up: auto-lander-dashboard.md. Its switches live in Setup, under All settings: turn it on or off, and choose which repositories it watches (setting a repo to observe-only first). The auto-lander lands branches you've marked ready into your main branch automatically and locally; it only ever moves things forward and never pushes. A branch you mark ready is trusted as finished — the lander merges it even if the dev-pipeline's process record was never marked complete (that check is informational, so a finished branch never sits stuck waiting for a record that was never updated). If a branch you marked ready gets more commits after tagging — or is rebased onto a newer main — the auto-lander now re-checks and re-tags it for you so it still lands, instead of stranding it behind a "moved after tagging" alert; you're only notified if that automatic re-check genuinely can't land it. When a branch lands you also see it in two more places: the session that produced it gets a green "Landed … to master" note (with a check) just below its final message — even after that session has finished (it's never reopened or re-run) — and the run is marked "Landed ✓" in the Timing tab instead of just quietly disappearing when its worktree is cleaned up. If the auto-lander's integration checkout ever drifts out of sync it quietly re-syncs it — this self-heal runs silently (logged for diagnostics, never an inbox notice) and always snapshots a backup first, so nothing is lost.
Expanding a conflict row lists the conflicting files. That list is bounded and says so: the first 20 with a "+N more" tail, and — because only the first 50 conflicting paths are ever recorded per conflict — a plain note when you're at that recording limit, so a 90-file conflict never masquerades as a complete 50-file one.
Automatic master catch-up. The other thing in this panel that can move your local master
on its own, which is exactly why it sits beside the auto-lander: a background check that fetches
the remote and merges it into your local master for you — about five minutes after the app
starts, then every six hours. Off by default, and it only applies when you run Omniscio from
source. Off does not mean silent: you are still told when you have fallen behind, with a
one-click catch-up — nothing moves your branch unless you ask.
Beside it is a paid sibling, also off by default: an hourly job that finishes a catch-up
origin/master conflicts have blocked, by buying a capped AI session for whatever the free path
cannot resolve. It is a separate switch on purpose — one of these moves a branch and the other
spends money, so arming the free one must never quietly arm the paid one. Neither implies the
other. Both are the sort of switch a person has to flip: they are on the CLI's patch denylist, so
no agent token can turn them on for you.
QA Fleet. The QA fleet's results, in the panel — what the background QA runs found, read
from the ledger they write locally (~/.amc/qa-fleet/ledger.db). Its rail entry (a flask
icon, sitting between Auto-lander and Setup) shows an amber badge with the number of open
findings whenever there is at least one, so you can see at a glance whether there is
anything to look at without opening the tab.
Five totals lead the view — Open Findings, High/Critical Open, E2E Passing, E2E Failing and Features Covered — followed by a 14-day open-findings trend, one bar per day showing how many findings were still open at the end of it. Below that sit three lists:
- Findings — each open one with its severity, the file it lives in, and how many times it has been seen, with three inline actions: Resolve, Dismiss and Reopen. A filter tabs between Open (n) and Resolved/Dismissed (n), so a finding you closed is still reachable rather than gone. Closing one fires straight from the row with no confirm step — it is fully reversible, and taxing every correct click to catch the rare wrong one would be the wrong trade — and a banner above the list carries an Undo for the finding you just changed, right where you are already looking.
- E2E Coverage — each feature with a PASS / FAIL mark.
- Least Recently Exercised — what the fleet has not touched in a while, or Never.
Everything refetches on a 30-second timer while the tab is open (the fleet produces results on a minutes-to-hours cadence, so a mount-only read would go stale the moment it landed), and there is a manual Refresh beside an "Updated <ago>" cue. Two different empty states say which problem you have: "QA fleet has not run on this machine yet" versus "QA fleet results could not be read" — a fleet that never ran is not the same as one whose records came back unreadable, and neither is dressed up as a reassuring zero.
Worktree cleanup. A live view of the automatic cleanup that reclaims disk by retiring finished git worktrees. You see a status card (when it last ran, a countdown to the next run — "in 1h 20m" — and a warning if it hasn't run in a while), four headline tiles (removed / stale entries / kept / disk reclaimed), the run history (each cycle's "removed" and "stale entries cleared" counts), a grid of every worktree with a plain reason it was kept or removed and how long ago it was touched, a recover button that restores a mistakenly-removed worktree's branch, and a Run cleanup now button. Your click on that button always runs, even while the computer is busy — it is a person asking — whereas a cleanup an agent requests through the control server is held until the load eases, so the app never slows you down to tidy worktrees. The restore list shows only the reaps that can actually be brought back right now — one you have already restored, or one whose commit git no longer holds, drops off the list instead of offering a button that would do nothing.
All four tiles describe the same run — the one the status card names — including Kept, which is that run's own count of worktrees it left alone because they held unlanded or uncommitted work. (Kept is deliberately not a tally of the verdict grid: the grid is the latest analyze output rather than the latest run, and every amber Review row would have counted as "Kept".) The Keep-vs-Review distinction lives where you can see it, on each row's verdict pill. In that grid, "last touched" is a plain local "14h ago", the same as the Worktrees section — the underlying tool writes a UTC wall clock, which is parsed to a real instant before it reaches the screen. The reaping itself is done by the same battle-tested cleanup scripts, which Omniscio now runs automatically on a schedule from inside the app — plus a catch-up when Omniscio starts, and it waits for a quiet moment if your machine is busy (so it never causes a stutter). There is no Windows scheduled task to install: Omniscio owns the schedule, removes the old task once, and auto-creates the stranded-worktree triage helper. When cleanup is on you also get two customization controls: How often to tidy (a dropdown — every 1, 2, 4, 6, or 12 hours; every hour by default), and an AI triage for stuck worktrees switch (on by default) that occasionally spends a little on a short AI session to judge worktrees that look stuck — turn it off to keep the free cleanup but skip the paid triage. This panel makes it visible and gives you the controls; it never re-implements the cleanup, so every safety protection is preserved. Windows only; off by default (turn it on with the worktree cleanup toggle in Performance, or here).
Bypass the testing gates. One Setup switch that stands down the machine's testing gates
all at once, for when a broken or slow test system is what is blocking you rather than a real
finding. Two things make it safe to have at all. First, the safety rules are not in the
set it can reach: the rules that stop a commit to master, a destructive stash, or a deleted
worktree stay armed and are never affected. Second, nothing it stands down is ever recorded as
passing — every skipped check says out loud that it did not run, and reports BYPASSED, so a
green after a bypass can never be mistaken for a real green.
It is off by default, it affects this machine only, and it has no expiry — nothing
turns it back off for you. While it is on, the card shows a permanent, deliberately
non-dismissible line — "Nothing is being verified right now. This stays on until you switch it
off." — because how long it has been on is the only thing standing between a quick flip and a
repo that quietly stopped being tested. It is stored in its own file (~/.amc/dev-bypass.json)
rather than in your settings, since scripts and git hooks outside the app read it too. Turn it
off and every gate comes back exactly as it was.
Where checks run. The card beside it holds the machine's one testing setting: Cloud first
(heavy checks run in the cloud; while the cloud is down a few at a time run here), Cloud only
(heavy checks never run here) or This computer (everything runs here, no cloud needed). Small
test runs always stay here. Clicking a value saves it at once; under the choices the card says
where the next heavy check will run and why, whether the cloud is answering, who set the value,
any approved window, and which version of the check service is running. It shows exactly what
npm run testing prints at a terminal. Agents cannot change it — they ask, and you approve a
card. Full detail: Where checks run.
Session-based cleanup (beta). A separate, cross-platform option that goes further than the free reaper: on an intelligent cadence it removes safe worktrees for you — including branches merged via a squash PR, which the plain reaper can't recognize — and, for anything it isn't sure about, spawns one short, conservative AI investigation that scans for stray worktrees and flags anything real to your inbox, then tidies itself away if it found nothing. It runs only on your active dev-pipeline repos (plus a slower sweep for stray worktrees anywhere), never deletes uncommitted or in-use work, and is bounded by a hard daily session + spend cap so it can't run up a bill. Off by default; enable it and set the caps in this section. It runs alongside the free reaper, never replacing it.
For agents
- Virtual project
__dev_pipeline_panel__, integration iddev-pipeline-panel(manifest:src/shared/integrations/dev-pipeline-panel.ts). Distinct from thedev-pipelineskill-bundle integration (which installs the CLI skill). - Gating — the reveal and the Dev Pipeline switch are DIFFERENT settings. The panel's
visibility comes from the
dev-pipeline-panelentry insrc/shared/unreleased-features.ts; itsstatus: 'shipped'makescomputeVisibility()return true BEFORE it ever looks at a setting, so itssettingKey(devPipelinePanelEnabled) does not gate the panel — there is no Lab row (a shipped entry is filtered out oflistInDevelopmentFeatures(), so it generates no reveal toggle and no derived settings-search entry), no file undersrc/rendererreferences it at all, andAMC_SHOW_DEV_PIPELINE_PANELis inert. The sidebar row is gated byUNRELEASED_PROJECT_GATESinproject-visibility.ts.filterVisibleProjectsALSO reveals it whensettings.devPipelineSkillEnabled(the dev-pipeline skill-bundle'sfeatureFlag) is on — a cross-feature coupling so enabling the skill surfaces its dashboard.devPipelinePanelEnabledis the Dev Pipeline's own opt-in, and it defaults tofalse(session-behavior-settings.ts). It is read directly — never through the registry gate — by four behaviours: whether the auto-lander is armed at all (auto-lander-repos.ts, andresolveAutoLanderReposreturns[]while it is off), the worktree-mutation lockdown (dev-pipeline-repos.ts), daily maintenance (daily-maintenance-supervisor.ts) and git-store maintenance (git-store-maintenance.ts). The only in-repo writer is the developer-machine profile (developer-setup-settings.ts), so a standard install has it off and none of the four run. Gate any NEW dev-pipeline-panel surface throughisUnreleasedFeatureVisibleas usual — never the raw setting — but do not add gating on the assumption the panel is hidden. It isn't. - Mobile / Web Access: the manifest declares
mobile: { status: 'ready' }, so the panel shows + mounts on mobile via the samefilterSidebarOnlyVirtualProjectsgate +panelOwnsLayoutrouting the desktop uses (its IPC channels proxy over Web Access). The desktop-only set (declaredmobile: { status: 'desktop-only' }) is exactly THIRTEEN ids —browser,native-browser,running-apps,screen-recordings,screenshots(the five with a real<webview>/desktopCapturer/ keyboard constraint), plusjournal,gauntlet-loop,phone-control,hooks,teach-recorder,contextdock-native,composioandmemory, which are desktop-only for PRODUCT reasons rather than a platform one —contextdock-nativeandmemoryshare their cause (both read theCONTEXTDOCK_STORE_*channels, which the mobile/web WS bridge blocks), whilecomposioopens a DESKTOP browser sign-in and wires the resulting tools into locally-spawned Claude sessions. Do NOT reason from an older four-, five- or twelve-member list; the authoritative inventory is theui-registry.test.tsguard, whose test name reads "exactly the THIRTEEN known desktop-only integrations declare mobile: desktop-only", mirrored indev-pipeline-panel-contract.mdavailable-on-mobile-and-web-access. (shared-sessionsmoved OFF this list on 2026-09-10 — mobile reached full parity and its WS channels came off the denylist — so do not re-add it.) - Layout (renderer):
DevPipelinePanelrenders a category rail (CategoryRail— Live / Timing / Agent Board / Auto-lander / QA Fleet / Setup; theDevPipelineCategoryunion is'live' | 'timing' | 'board' | 'autolander' | 'qafleet' | 'setup', fromDEV_PIPELINE_CATEGORIESinsrc/shared/dev-pipeline-panel.ts) + a content pane showing the active category. Auto-lander (AutoLanderView) and QA Fleet (QaFleetView) are BOTH first-class rail entries rendered UNCONDITIONALLY — see auto-lander-dashboard.md for the first;CategoryRailgates onlyboardbehind its optionalshowBoardprop. Agent Board (shown only whenagentStatusBoardEnabled, viaCategoryRail's optionalshowBoardprop) renders the sharedAgentBoardList— the same board body the global Agent Board view uses — and jumps to a session vianavigateToSessionInProject; the panel resetscategoryto Live if the feature is turned off while the tab is open (seeagent-status-board.md+dev-pipeline-panel-contract.mdL1). Live isLiveView, which unions the flat runs list with the already-per-project worktrees via the purebuildProjectGroups(pipeline-live-grouping.ts) into one collapsible group per project, reusingRunRow+RepoGroup(worktree-rows.tsx) verbatim and oneuseWorktreeRemovalhook + dialog. Gate/phase labels are humanized + overflow-hardened inpipeline-labels.ts(gateLabelrecovers the canonicalGATE_nfrom a noisy value and caps an unknown one; the Waiting pill is width-capped + truncates). Timing isTimingView— a five-tile summary grid (Working · Waiting on you · Stuck · Avg wait · Spend) + a biggest-stall line, over a list of expandableRecentRunRows, each a proportional green/amber/red/idleSplitBarthat opens to a per-phase working-time-and-spend + per-gate waitRunBreakdown. Seedev-pipeline-panel-contract.mdL1–L3. - Active runs are derived on demand by
derivePipelineRuns()(src/main/services/dev-pipeline/dev-pipeline-panel-service.ts), which reads each non-terminal session's worktree.claude/pipeline/state.mdwith the same parser the Agent Status Board uses — so it does NOT depend on the (default-off) Agent Status Board feature. It also carries each run'sstatusChangedAt/needsYouAtso the row can render the livewaiting <time>counter. IPC:PIPELINE_RUNS_GET. - Run timing (the Timing tab) is captured by Omniscio itself, NOT by the skill:
registerPipelineRunTimeline(src/main/services/dev-pipeline/pipeline-run-timeline-service.ts) subscribes once (at handler registration → always-on) to the internalsessionEvents'statusChanged' bus thatSessionStatusManager.updateStatusfires on every committed transition (process-manager.tsnotifyStatusChanged), and appends apipeline_run_eventsrow ONLY for dev-pipeline runs (same phase/gate test asderivePipelineRuns) — so the table is naturally scoped and capture works whether or not the panel is open (deliberately NOT the default-off status-board tick, NOT the ~165-call-site DB chokepoint). Capture is best-effort (guarded, can't perturb the status path) + idempotent (an in-memory last-tuple cache, restart-seeded from the DB viagetLatestPipelineRunTuple). The pure reducerderivePipelineRunTimeline(src/shared/pipeline-run-timeline.ts, caller passesnowIso) splits each run into working / gate-wait / stuck (deterministic) + per-phase (best-effort), andsummarizePipelineRunsbuilds the strip. History is a SEPARATE readderivePipelineRunHistory(.../pipeline-run-history-service.ts, IPCPIPELINE_RUN_HISTORY_GET) over the durable events joined to sessions (incl. finished runs), with an inline 90-day prune on write. No AI calls → zero cost. Seedev-pipeline-panel-contract.mdRT1–RT5. - Worktrees are derived on demand by
deriveRepoWorktrees()(src/main/services/worktree/dev-pipeline-worktrees-service.ts): per real-repo project it readsgit worktree list+ branch descriptions + each worktree'sstate.md, cross-referenced with the sessions table — no stored registry, so it never goes stale and surfaces orphans. Removal runs the pureevaluateWorktreeRemovableguard (precedencemain-checkout>not-a-worktree>keep-marker>in-use>uncommitted>unlanded— six reasons, not five;keep-markeris an ABSOLUTE veto for a branch whose DESCRIPTION carries a do-not-delete directive, so a clean/landed/orphaned-but-PINNED worktree is still refused. It reads fail-CLOSED at remove time — an unreadable branch description counts as marked. Kill switchAMC_DISABLE_WT_KEEP_MARKER_VETO), RE-gathered with real git reads in Main before any delete; live ownership includesagentDetectedWorkdir(how a self-created worktree is tracked), and deletion goes through the junction-saferemoveWorktree. IPC:WORKTREES_GET(read),WORKTREE_REMOVE_ONE/WORKTREE_REMOVE_SAFE_BULK(destructive). Both removals are ALSO CLI control-server routes —POST /project/:id/worktrees/remove({ worktreePath }) and/remove-safe— so an agent can clean up worktrees headlessly; they reuse the same service verbatim, so the same guard runs and a kept worktree comes back as a normal200 { removed: false, blockedReason }(cli-server-project-ops-routes.ts; documented in the omniscio-controlprojects.mdspoke). Seedev-pipeline-panel-contract.mdW1–W7. - Run cost is captured by Omniscio, not the skill: each
pipeline_run_eventsrow snapshots the owning session's cumulativecost_usd(nullable, additive migration), and the purederivePipelineRunCost(src/shared/pipeline-run-timeline.ts) turns consecutive snapshots into run + per-phase deltas — run-scoped by construction (a session's total includes pre-pipeline chat), clamped ≥ 0,null= unknown (never a fabricated 0). The Live list closes each open run against the session's current cost via ONE batchedgetFirstPipelineCostSnapshotsread (never N+1). Seedev-pipeline-panel-contract.mdRT6. - Stale runs + Adopt: a worktree is a stale run when it carries a non-complete
pipeline state, no live session owns it, and its recorded
## Ownersession is gone or terminal (isStalePipelineRun).adoptStalePipelineRunre-verifies everything at click time, serializes concurrent adopts (in-flight set), transfers the state file's## Ownerto a RESERVED session id BEFORE spawning (a failed spawn stays stale → retryable), then spawns viacreateSessionWithPromptwithreuseWorktree(runs INSIDE the stranded worktree; fails closed pre-insert if the path vanished) and a/dev-pipelineresume prompt — the skill's own STEP-0 discovery matches the new owner and resumes. IPC:PIPELINE_ADOPT_RUN, also the CLI routePOST /project/:id/worktrees/adopt-run({ worktreePath }). Because adopting spawns a real (paid) session, the CLI kindpipeline.adopt_runis NON_TOGGLEABLE + IRREVERSIBLE: the route only ENQUEUES an inbox approval (no in-app-session bypass — an AI can never self-approve it) and requires a source session; thepipeline-adopt-run-handlerrunsadoptStalePipelineRunonly on approval. Seedev-pipeline-panel-contract.mdA1–A5. - Load-failure behavior: a failed panel read toasts once (while un-hydrated) and shows
the empty state instead of an infinite "Loading…"; the panel's own interval keeps
retrying, and a transient failure after a good load keeps the last-good data. See
dev-pipeline-panel-contract.mdL8. - Gate auto-approval is per-phase: five independent gate toggles (Plan · Red
Team · Build · Elegance · Docs) + a select-all master, backed by
pipelineGateAutoApproveand resolved byresolveGateAutoApprove(fallback to the deprecatedpipelineAutoAdvanceEnabled/pipelineAutoApprovePlanGate; seepipeline-auto-advance-contract.md). This panel and Settings → Features render the SAME controls (GateAutoApprovalControls), so their wording can't drift. - The two always-on standards gates (🚦/🔬) also appear as toggles here (panel-only —
Settings → Features shows the built-in five). They persist in a separate setting
pipelineStandardsGateAutoApprove(NOTpipelineGateAutoApprove), default auto-approve; the panel routes their on/off through the same row list and the setting flows through the manifest so a gate set manual holds the run for you. Seedev-pipeline-panel-contract.mdL9. (The ops-onlyDEV_PIPELINE_DISABLE_BUNDLED_STANDARDSkill switch is honored by the pipeline but not reflected in this panel's display.) - Custom phases show up here too (when Enable custom phases is on). The panel
resolves your phase manifest (
phases.json) and feeds it toGateAutoApprovalControls, so BOTH the flow diagram AND the switch list weave each custom phase in at its insert point (with its emoji) — each custom gate gets its own auto-approve switch at its true pipeline position (e.g. 🚦 Standards Check between Red Team and Build), not appended after the built-in five, so the switch order matches the flow diagram above it. One list controls every stop. Settings → Features (no manifest passed) keeps the plain built-in six. Seedev-pipeline-panel-contract.mdL6/L7. - AI code review — a review step after any phase. The AI code review card offers one
switch per phase (after Plan, Red Team, Build, Elegance, Docs); each one you turn on inserts a
real 🧭 AI Code Review phase right after that phase, where fresh AI reviewers read the work
and report what they find. Off everywhere by default, so an untouched install is unchanged.
Every step that runs gets a row — including one your repo sets for everyone, which the card
labels as such; its switch turns it off for you alone, leaving your team's setup untouched.
These gates get NO auto-approve switch in the list above, because there is no third state for a
switch to select: the review's own verdict decides. A clean review closes green and the run
moves straight on; a review that found something worth your attention parks for you. Each point
you turn on spends
reviewer tokens on every run. Your choice is saved alongside your custom phases and your own
phases are never disturbed by these switches; it applies whether or not Enable custom
phases is on. See
dev-pipeline-panel-contract.mdL11 (ops kill switch:DEV_PIPELINE_DISABLE_BUNDLED_AI_REVIEW). Above those switches, Run AI code review steps (on by default; thedevPipelineAiReviewEnabledsetting) turns every review step off at once, including in runs already under way: agents stop being given review steps, a reviewer asked for from a review step is refused, and a session already waiting at one still moves on. While it is off, the per-step rows hide and the flow diagram shows no review step; the per-step choices stay saved for when it goes back on. It is the one AI-review control stored as a setting, because the app applies it itself — seedev-pipeline-panel-contract.mdai-review-switch-reaches-running-work. Under the switches, How each AI has done is the reviewer scorecard: one row per AI model with how many reviews it ran (and how many got no answer), the serious and minor problems it found that the pipeline checked and confirmed, its false alarms, how often the pipeline approved of its reviews (shown as "75% approved" once any review is rated — never 0% before that), and what it cost in total and per review. Cost is read from each reviewer's own session, so it is exact, and it stays on the scorecard even after you delete that session; a dash means the cost isn't reported (a reviewer that ran inside the pipeline's own session is billed with it, and some AI companies don't report cost to Omniscio yet). Below it, Whose work was reviewed lists each AI whose work the reviews looked at — its reviews, the serious problems found in it, and serious problems per review — so you can see which AIs need more review. Both stay empty until a review step runs. Seeai-review-scorecard-contract.md. - Who writes the code — pick a cheaper model for the build step. The Who writes the code
card sets which model actually writes code during the build phase, and whether it runs as a
helper inside the run (the default, cheapest) or as its own session you can watch in
Mission Control. Picking a cheaper writer is safe because it turns the pipeline's existing
cheap-implementer preference into a rule: the smart model becomes an overseer that writes
the failing test, hands the work over, reviews every change that comes back, sends work back
with specific fixes, and keeps only what it accepts. Nothing a cheaper model writes is kept
unreviewed, and the build gate has to report which model built it and how many changes were
accepted versus sent back — a run that quietly skipped the loop has no counts to show. You
store a speed level (Genius / Smart / Worker / Basic), never a specific model name, so your
choice never goes stale when a new model ships. Default: Worker (Sonnet-level), as a helper
in the session. Own-session mode starts a real session per build and costs money — turning it
on is what allows the pipeline to start them. Saved alongside your custom phases in
phases.json, which is the one file both Omniscio and the Claude skill read — a normal setting would be invisible to the run it configures. Seedev-pipeline-panel-contract.mdbuild-model-lives-in-the-manifest-not-settings. - What you set is what runs — the editor stays in sync with the project copy. The editor
saves to your personal manifest (
~/.claude/dev-pipeline/phases.json), but a run resolves project-over-personal, so an edit to a phase a repo ALSO commits (<repo>/.claude/dev-pipeline/phases.json) would otherwise be silently overridden. The panel bridges both directions (phase-manifest-service.ts): on save it writes the edit THROUGH into every repo that already commits that phase (syncCustomPhasesToProjectManifests— your fresh edit wins; it never adds a personal-only phase to a repo, never deletes a project phase, and never commits/pushes — you commit the file), and on read it shows the effective value (overlayProjectValuesOntoPersonal— a phase a repo commits displays that project value, so a switch can't read "on" while "off" is what actually runs). Both are fail-safe. A personal-only phase (no repo commits it) stays yours; a committed project manifest applies to every dev on that project (see dev-pipeline.md "Project-level phases"). AI Code Review steps are the exception both ways: a repo's review steps are the team default, and once you change any review setting for a step, YOUR settings are what run on your machine — so the editor shows your own values for it, and a save never writes a review step into a repo's shared file. A step you switch on without changing anything keeps (and shows) the shared settings, and a save never quietly turns that copy into your own. - Auto-lander reuses
AutoLanderSettings(per-repo config, force-revealed via itsembeddedprop) +MergeDaemonStatusCard(live status). The land history is a newauto_lander_eventstable written fail-open by the auto-lander supervisor's per-tick sink (the three terminal outcomes only — landed / conflict / unlanded — deduped + retention-pruned); IPC:AUTO_LANDER_EVENTS_GET, refetched on the existingAUTO_LANDER_STATUS_UPDATEDpush. Seeauto-lander-contract.md. - QA Fleet (
QaFleetView) is a read + triage surface over the QA fleet ledger at~/.amc/qa-fleet/ledger.db. Two IPC channels:QA_FLEET_SUMMARY_GET(qa-fleet:summary) for the totals / trend / findings / E2E / coverage read, andQA_FLEET_FINDING_STATUS_SET(qa-fleet:finding-status-set) for the resolve / dismiss / reopen triage write. TheCategoryRailbadge counts open findings and renders ONLY when the count is above zero, so a clean fleet shows no pill. It is an UNCONDITIONAL rail entry — it carries nounreleasedFeatureId, novisibleWhenand no setting, so it ships to every user of this shipped panel; if that is ever meant to change, the missing gate is the fix, not a doc. The richer developer-facing driver for the same fleet isinternal/qa-fleet-desktop-routes.md, which is repo-only (theinternal/tree is excluded from the published mirror, fromextraResourcesand from the packaged app), so this page is deliberately the customer's only route to it. - Landed-session attribution + note. On a
landed, the sink ALSO resolves the dev-pipeline session that authored the branch — via the SAME owner-resolver the conflict hand-back uses (worktree_branch→ the branch's git worktree dir →agent_detected_workdir), so a self-created worktree is found and terminated authors count — and stamps it onto a new nullableauto_lander_events.session_id(migration20260716130010). Two surfaces read it: the supervisor appends a PASSIVE kindednotable-system"landed" note to that session (landed-session-notify.ts→addMessage+SESSION_OUTPUTpush — fail-open, idempotent on a FRESH insert, and it NEVER wakes / reopens / spawns the session, unlike the conflict hand-back'sdeliverPeerMessage; kill switchAMC_DISABLE_LANDED_SESSION_NOTIFY), andderivePipelineRunHistorymarks the Timing run "Landed ✓" via a singlelistLandedSessionIdsjoin. Runs after the status push, before the worktree retire. Seeauto-lander-contract.md(S26) +dev-pipeline-panel-contract.md(RT7). - Worktree cleanup (
WorktreeCleanupSection) is a dashboard over the vendored PowerShell cleanup scripts (scripts/worktree-maintenance/, self-contained via$PSScriptRoot). A Windows-gated Main service (src/main/services/worktree-cleanup/) READS the tool outputs (per-runsummary.json, theworktrees-*.tsvverdict grid, thewt-deleted-recovery.tsvrestore log — read from the out-dir root AND everyrun-<ts>/dir, since every app-driven reap writes it into the run dir; tail-bounded with a row cap like the sibling append-only readers, ref probes pinned with-C <resolveMergeRepoRoot()>to the same reporecoverWorktreerestores into, and therecoverableflag applied at the render site), and a 5-min supervisor BOTH ingests completed runs intoworktree_cleanup_runs(pushing status on-change + raising a deduped stale alert) AND is the in-app scheduler — it fires the reap on a user-configurable cadence + a startup catch-up, load-gated viaisBoxHeavyOrSettling, decided by the puredecideScheduledRun(worktree-cleanup-schedule.ts). The cadence isworktreeCleanupIntervalHours(default 1 —WORKTREE_CLEANUP_INTERVAL_HOURSinsrc/shared/worktree-cleanup.ts, lowered from 2 on 2026-09-02 because idle unlanded worktrees filled a drive overnight; the reap retires a capped batch per run, so cadence is the throughput lever) read throughresolveCleanupIntervalHours(clamp[1, 24], bad value → default), and the stale window scales with it (resolveStaleThresholdHours) so a long interval never false-alarms. There is no OS Scheduled Task:worktree-cleanup-ostask.tsremoves the legacy one — only while the in-app replacement is active (toggle on + available; fail-safe skips), re-checked every boot and cleanup-settings save so a re-created task is re-detected (no permanent marker) — andworktree-triage-cron.tsauto-seeds the stranded-worktree triage-dispatch cron — active iffisWorktreeTriageActive(settings)(=worktreeCleanupEnabled && worktreeTriageEnabled), so the paid AI triage is an independent on/off while the free cleanup keeps running. The status card's "next run" is derived from the in-app cadence (scheduledTaskStateis null; a load-deferred run reads "waiting", not "wedged"; the healthy label is generic, not a fixed interval). The runner is the only mutating spawn surface (a NON-detached argv-array spawn of the wrapper for the reap — a detached spawn silently never runs the script on Windows;git branchfor recover — nevershell:true). The reaping stays entirely in the scripts, so all their safety invariants are preserved. FlagsworktreeCleanupEnabled/worktreeTriageEnabled/worktreeCleanupIntervalHours; IPCWT_CLEANUP_*. Seeworktree-cleanup-contract.md. - Session-based cleanup (
worktreeSessionCleanupEnabled, cross-platform, default off) is a SEPARATEcreatePeriodicTaskscheduler (src/main/services/worktree-cleanup/session-cleanup-*.ts) from the reaper above — it runs alongside it. Each tick, for a qualifying repo (active dev-pipeline OR a broad stray-worktree sweep — puredecideRepoCleanupinsession-cleanup-decide.ts) it removes every orphaned candidate through the guardedremoveOneWorktree— now PR-aware:prMergedConfirmed(gathered authoritatively at remove time viacheckBranchHasPR, fail-safe false) relaxes ONLY theunlandedrefusal so a squash-merged branch cleans up, while every higher veto (main-checkout / in-use / uncommitted) stays absolute. For a REFUSED residual it spawns ONE read-only investigation session (createSessionWithPrompt,isolationOverride:false→ repo main checkout,source:'worktree-session-cleanup') that fs-scans for husks, raises one deduped inbox alert, and self-archives on empty — the session NEVER deletes. Feature daily session + spend caps (resolveDailyCaps, read-time clamped) sit on top of the global daily budget cap; boot start + a teardown task + a settings-apply reactor mirror the reaper. SettingsworktreeSessionCleanupEnabled/...MaxSessionsPerDay/...DailyBudgetUsd; kill switchAMC_DISABLE_DEVPIPE_WT_CLEANUP. Seeworktree-session-cleanup-contract.md(its invariants) +dev-pipeline-panel-contract.mdW4.
Related
Dev Pipeline panel is the first half — the panel's overview and its Live, Timing, Agent Board and Worktrees views. Dev Pipeline documents the workflow these controls drive.
Last verified 2026-10-04