Dev Pipeline panel — for agents (part 3)
Part 3 of the Dev Pipeline panel page: the developer-facing reference — the virtual project and its integration, the two separate gating settings, the mobile and Web Access rules with the desktop-only list, and how the panel layout and its rails are put together.
What it is
This is part 3 of the Dev Pipeline panel page, following part 2. It is the developer-facing reference for the panel: how it is registered and gated, what it can do on a phone or over Web Access, and how it is put together.
Where to find it
Nowhere in the app. Everything here is a file in the repository, an IPC channel, or a setting for whoever is working on the panel.
How it behaves
Nothing on this page changes what you see on the screen — it is reference for the code behind the panel. The project registration, the two gating settings, the mobile rules and the layout all follow.
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 — a shipped entry is filtered out oflistInDevelopmentFeatures(), so it generates no Lab row, no reveal toggle and no derived settings-search entry, 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). Two writers touch it: the Setup tab's own on/off switch (SetupView.tsxboth reads the setting and writes it back through the settings patch route) and the developer-machine profile (developer-setup-settings.ts, applied bynpm run setup). A fresh 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) of THREE destinations — Runs (live), Stages (timing) and Setup — plus a content pane showing the active one. TheDevPipelineCategoryunion keeps all six values (fromDEV_PIPELINE_CATEGORIESinsrc/shared/dev-pipeline-panel.ts) because a persisted tab and every?view=deep link are built on it, and a legacyboard/autolanderNORMALIZES intorunsSubViewwhileqafleetnormalizes intostagesSubView, so an old deep link still lands. Agent Board, the Auto-lander (AutoLanderView) and QA Fleet (QaFleetView) are each a quiet line inside Runs or Stages that opens the full view (the first two rideRunsView's quiet lines, QA Fleet ridesStagesView's);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>locked>in-use>uncommitted>unlanded— seven reasons, not six;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 (lockedis what a ledger PIN actually sets). 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, any reviewer asked for while it is off is refused (the app's own crew mission review has its own separate switch), 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. Its quiet line inStagesViewcarries the open-findings count and shows it ONLY when it is above zero, so a clean fleet reads no count at all. 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). - Add a repo is Setup's repo-list control for a folder the app has never seen. The renderer is
AddRepoDialog.tsx(opened fromSetupView.tsx's repo block, replacing the old instruction line); the read ispreviewRepoFolderinsrc/main/services/dev-pipeline/repo-preview-service.tsover the read-only channeldev-pipeline-panel:preview-repo(DEV_PIPELINE_REPO_PREVIEW), which the WS bridge serves to a phone or web client like any registered channel. It is ASYNC fs only — noexecSync/spawnSync — over a fixed allow-list of manifest paths with a 512 KB per-file ceiling, so a huge or odd repo cannot stall the main process, and every refusal is data (not-a-full-path/cannot-read/not-a-repo), never a throw. It calls the same pure detector a run uses (detectRepoProfile,resolvePipelineChecks,detectBaseBranch,repoProfileHealthinsrc/shared/repo-pipeline-profile.ts), so the panel and a run can never disagree about one repo, and the fourHEALTH_*words are translated in the dialog because the detector's constants have no other user-facing surface. Registration happens only on the confirm click, through the project store'saddProject, and the folder is looked up inprojectsFIRST —addProjectanswersnullfor a refusal and for a duplicate alike, so catching an error could not tell the two apart. Contract:dev-pipeline-add-a-repo-contract.md. - 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 does ONE of two things, exclusively: with no cap, load or in-flight session in the way it spawns ONE read-only investigation session (createSessionWithPrompt,isolationOverride:false→ repo main checkout,source:'worktree-session-cleanup') that fs-scans for husks and reports in its final message, staying on the board when it found anything; otherwise it raises one deduped inbox alert itself. The card is the app's, never the session's — an app-spawned session is machinery and is not told to raise one (inbox-alert-contractengine-owned-machinery-is-never-told-to-raise) — and 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 — what the panel is, where it lives, and its rail.
- Dev Pipeline panel (part 2) — the Auto-lander tab, the QA Fleet tab and the Setup tab.
Last verified 2026-10-06