docs(orchestration): clean up created_child worktrees after worker-release - #19404
LesleyMurfin wants to merge 1 commit into
Conversation
…lease Adds a coordinator-contract step to the orchestration skill guide: after an accepted worker-release, if the Dispatch's start effect was created_child, run 'orca worktree rm --force --worktree path:<worktreePath> --json' using terminal.worktreePath from worker-show. Documents the fail-closed conditions (user retention, user-taken-over terminal, reused/current placement, unpushed local commits, worktree rm errors). Regenerates the bundled skill-guide artifact so 'orca skills get orchestration' serves it. Fixes stablyai#18411
📝 WalkthroughWalkthroughThe orchestration guide adds a release-time obligation for Dispatches that recorded a Merge Risk: 🟠 High · up to The new cleanup guidance can remove a child worktree while its terminal remains retained and can discard uncommitted or otherwise unverified local work. The release-state and work-preservation guards should be strengthened before merge. 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Team
Run ID: 0218f15d-d523-43db-b880-63eb7c42820e
📒 Files selected for processing (3)
skill-guides/orchestration.mdskill-guides/orchestration/references/recovery-and-cleanup.mdsrc/cli/bundled-skill-guides.ts
Included review availability: Your plan provides up to 10 included reviews per hour; 9 remain after this review.
| After `worker-release` accepts, check whether that Dispatch's own `effects` | ||
| recorded `{ "kind": "worktree", "action": "created_child" }`: |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
Require a terminal-closed release state before cleanup.
orchestration.workerRelease can return state: "retained" while the terminal remains retained. Command acceptance is not proof that the terminal closed. Require state: "released" or "already_released" before worker-show and worktree rm; route retained, release_pending, and release_unknown through recovery. This guard is necessary because worktree rm --force also sets allowUnverifiedPtyStop.
Also applies to: 177-177
| that same response's `terminal.worktreePath`: | ||
|
|
||
| ```text | ||
| ORCA worktree rm --force --worktree path:<worktreePath> --json |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
Preserve local work before force removal.
--force removes a dirty checkout without confirmation. The current rule protects only unpushed commits after STOP or failure and only says to run git status; it does not require checking the exact terminal.worktreePath, and it does not cover uncommitted or untracked changes or a successful report. The worker contract does not require a commit when --files-modified is applicable. Inspect the exact child worktree before every removal and leave/report whenever it is dirty or commit visibility is unproven.
Also applies to: 187-188
There was a problem hiding this comment.
Important
The cleanup recipe as written won't work for the very case it targets: worker-show's terminal field is null after release, so terminal.worktreePath is unavailable from the response the coordinator is told to read. Details inline.
Reviewed changes
recovery-and-cleanup.md— new "Worktree cleanup after release" section: after an acceptedworker-release, check the Dispatch'seffectsfor acreated_childworktree andworktree rm --forceit viaterminal.worktreePath, with five fail-closed leave-in-place conditions.orchestration.md: "Completion accounting" flags the follow-on cleanup check, and the "Conditional references" table routes to the same reference.src/cli/bundled-skill-guides.ts: regenerated so the bundled guide matches the edited Markdown.
ℹ️ Nitpicks
- "
--forceskips the dirty-tree confirmation prompt" — there is no prompt to skip. Non-forceworktree rmrefuses (errors) a dirty tree viagit worktree remove;--forcemaps togit worktree remove --forceand also waives PTY-stop proof (src/cli/handlers/worktree.ts:311). Worth rewording. Relatedly,worktree rmdoes delete the branch by default (safely,-d, not-D), so the "never force-deletes the underlying Git branch" reassurance is correct but easy to misread as "the branch is never touched".
DeepSeek Pro (free via Pullfrog for OSS) | 𝕏
| ``` | ||
|
|
||
| If it did, remove the checkout Orca created for it, using the exact path from | ||
| that same response's `terminal.worktreePath`: |
There was a problem hiding this comment.
terminal.worktreePath won't be present in the response this step is told to read. worker-show returns terminal: observation.exact ? observation.terminal : null (src/main/runtime/rpc/methods/orchestration/worker/worker-control.ts:78), and exact requires the Dispatch's recorded process incarnation to still match (isDispatchProcessCurrent). Release's job is to close/kill that process, so terminal is null afterwards — and for a structured worker it's null unconditionally (inspectWorkerTerminal returns terminal: null on the structured branch). Use the always-exposed worker.worktreeId from that same response instead and drive removal with id:<worktreeId>; worktree rm accepts id: as a first-class selector.
Technical details
# Worktree cleanup path source
## Affected sites
- skill-guides/orchestration/references/recovery-and-cleanup.md:171 — reads terminal.worktreePath from a post-release worker-show response
## Required outcome
- The recipe must obtain the created_child worktree identity from a field that survives release. Prefer `worker.worktreeId` (and/or the `id` on the `created_child` effect) from the `worker-show --json` response, then `ORCA worktree rm --force --worktree id:<worktreeId> --json`.
- If keeping `terminal.worktreePath`, note it must be read from an inspection run before release (when the terminal is still exact), and is never available for structured workers.
## Suggested approach (optional)
- `exposeWorker` already publishes `worktreeId` (parsed from `worker.worktree_id`) and `effects`; both are durable DB values, independent of process liveness. The `id:` selector resolves via `orca-runtime-resolve-worktree-selector.ts`.|
Heads-up on the path source: after Capture Happy to fold those into this PR instead if that's the preferred landing path. |
|
Overlaps #18412 (opened 2026-09-03). That PR already captures |

ELI5
When a coordinator fans work out to several helper agents, each in its own new Git checkout ("child worktree"), finishing that work only closes the helper's terminal — the checkout itself is left on disk forever. This teaches the orchestration guide the coordinator reads to also delete that checkout once the helper's work is safely wrapped up, unless there's a good reason not to (like the user wanting to keep it).
What Changed
Documentation-only change to the orchestration skill guide (no product code):
skill-guides/orchestration/references/recovery-and-cleanup.md: new "Worktree cleanup after release" section. After an acceptedworker-release, if the Dispatch's owneffectsrecordedcreated_child, the coordinator runsorca worktree rm --force --worktree path:<worktreePath> --json, usingterminal.worktreePathfromworker-show --dispatch <id> --json. Documents five fail-closed conditions where the worktree must be left in place and reported instead: user asked to keep the workspace orworker-retainwas recorded, the terminal was user-taken-over, the start effect wasreused/--worktree current/an exact pre-existing workspace, the worker stopped or failed with unpushed local-only commits, orworktree rmitself errors.skill-guides/orchestration.md: "Completion accounting" now flags this follow-on check after release, and the "Conditional references" table gains a row routing to the same reference.src/cli/bundled-skill-guides.ts: regenerated vianode config/scripts/generate-bundled-skill-guides.mjs --writesoorca skills get orchestrationserves the updated guide immediately.Why
worker-releasearchives output and closes the agent terminal only; aworker-start --worktree new-childcheckout stays on disk indefinitely. A coordinator that fans out many workers can leave dozens of stale checkouts behind after every worker settles cleanly, and Workspace Cleanup is suggestion-only and not orchestration-aware. This is a coordinator-contract fix (a MUST-follow step added to the guide the coordinator already reads) rather than a new product flag, so it lands immediately without a schema or RPC change.Linked Issue
Architectural Context (RFC #21556)
Fixes #18411
Visual Proof
N/A — this is a Markdown documentation change to a skill guide with no rendered UI or runtime behavior change.
Testing
Manual verification: ran
node config/scripts/generate-bundled-skill-guides.mjs --checkbefore and after regenerating the bundled artifact — clean both times, confirmingsrc/cli/bundled-skill-guides.tsstays byte-consistent with the edited source Markdown. Verified balanced code fences and consistent table-column padding in both edited files by direct inspection. No automated test added: this changes only prose guidance consumed by an LLM coordinator, not a parsed data structure or code path that a unit test could exercise; the existinggenerate-bundled-skill-guides.test.mjs/--checkstep already guards the one mechanical invariant (guide ↔ bundled-constant consistency) and passes.AI Disclosure
This change was authored with AI assistance (Anthropic Claude) and reviewed by the human maintainer before submission.
Review
Self-reviewed: the added guidance matches the exact fail-closed conditions and command proposed by the issue author, reuses existing field names (
effects[].action,terminal.worktreePath) verified against the currentsrc/main/runtime/rpc/methods/orchestration/workerimplementation rather than guessed, and follows the surrounding guide's section structure, table formatting, and voice.Agent skill upstream boundary
docs/reference/agent-skill-sharing-upstream-boundary.mdand copies or mechanically translates no upstream skill-installer source, tests, fixtures, registry entries, path tables, comments, or documentation.Notes
Residual risk: this is a MUST-follow addition to the coordinator's documented contract, not product-code enforcement. A coordinator can still skip the step or misjudge a fail-closed condition, and nothing here makes it impossible to leave a worktree behind — it makes the expected, documented behavior clean one up instead of silently leaving it. A structural fix (e.g. a
worker-release --remove-worktreeflag, or auto-cleanup wired into release itself) remains out of scope, as the issue itself notes.Checklist
N/Awith reasonpnpm lint,pnpm typecheck,pnpm test, andpnpm buildpass (or CI will cover; local preferred) — not run locally (fresh clone without full dependency install);generate-bundled-skill-guides.mjs --checkwas run directly and passes, and CI will cover the rest