Skip to content

Close out the worktree when /review-pr lands a merge #196

Description

@jacobdrees

What to build

A worktree close-out step in /review-pr, so a merged branch does not leave a live agent session and a stale board column behind.

The gap

.claude/skills/review-pr/SKILL.md runs to step 9 and its last three steps are Linear-side: tick the checkboxes, set the state to Done, drop the triage label, report. Nothing in it touches the worktree the work was done in. So after a successful squash-merge the worktree is still there, its agent session is still running, and its Orca board status is wherever it was when the work started.

Five worktrees were removed by hand on 16 and 17 August 2026 — can-86, can-102, can-123, can-56, can-54 — each one after checking by hand that the branch was genuinely merged. Two of them sat for over an hour reporting working with their pull request already merged.

Why the skill is the right home rather than a person

The safety condition is already computed inside the skill. Step 6 reads the pull request's state and mergedAt as the evidence the merge landed, and step 9 quotes them in the report. The check needed before removing a worktree is exactly that, plus the branch head matching the merged headRefOid. A human doing it afterwards has to re-derive what the skill already knows.

The commands

Three exist and each does one part:

Command What it does
orca worktree set --worktree <sel> --workspace-status completed Moves the board column. Default ids are todo, in-progress, in-review, completed
orca terminal stop --worktree <sel> Stops the live agent session, which otherwise keeps running
orca worktree rm --worktree <sel> Removes it from Orca and git. Repo orca.yaml archive hooks are skipped unless --run-hooks is passed

The worktree selector can be branch:<branch>, which the skill already knows, so no new lookup is needed.

The decision this ticket has to take

Mark completed, or remove outright? They are different postures and the ticket should choose rather than offer both.

  • Mark and stop keeps the checkout on disk for post-merge inspection, and leaves a board column that shows what landed. It also accumulates: five worktrees in two days, each a full checkout.
  • Remove is what actually happened by hand every time, and the branch is recoverable from the remote regardless.

Recommended: stop the terminals and mark completed automatically, and leave removal to a person. Removing a checkout is the one irreversible half, and a skill that deletes a working directory on its own reading of a merge is a worse failure than one that leaves tidy-up to be asked for.

Acceptance criteria

  • /review-pr gains a worktree close-out step, after the Linear close-out and before the report.
  • It runs only when the merge is proven by step 6's state and mergedAt, and the worktree branch head matches the merged headRefOid. A skill that acts on a failed or unverified merge is worse than one that does nothing.
  • It stops the worktree's terminals, so a merged lane stops reporting itself as working.
  • It sets the board status, and the chosen value is recorded rather than assumed.
  • Whether it removes the worktree is decided, with the rejected option and its reasoning written down.
  • It is a no-op, announced rather than failed, when the command is run outside an Orca worktree. /review-pr has to keep working from a plain clone.
  • The report says what it did to the worktree, so the state is visible to whoever reads the run rather than discovered later.
  • docs/agents/workflow.md records the step, since that document owns what a merge carries and what it does not.

Other Orca surfaces reviewed, and what came of each

Surveyed the whole CLI while writing this. Three are worth a look later and the rest are not.

  • orca worktree ps already gives a one-call summary across every lane, including agent state and whether a lane is blocked on a prompt. It is what a monitoring loop should read, and it is the cheapest thing here that nothing currently uses. Worth a note in docs/agents/workflow.md rather than a ticket.
  • orca automations create schedules an agent on a preset, cron or RRULE, with --workspace-mode new-per-run and its own --base-branch. A nightly sweep for merged-but-still-present worktrees would close the same gap from the other side, and would catch the case where /review-pr never ran. Only worth it if the close-out step above proves insufficient.
  • orca orchestration carries Runs, dispatch, supervised workers and decision gates, with orchestration ask letting a worker block on a coordinator question. It does not capture agent permission prompts, which surface in the worktree UI regardless, so it does not solve the interruption problem it looks like it solves. Worth revisiting only for work that genuinely needs cross-lane coordination.
  • orca file open-changed and orca repo set-base-ref are conveniences with no gap behind them. set-base-ref would remove the need to pass --base-branch origin/main on every worktree create, which has been done by hand on every lane so far; that is a one-line setting rather than a ticket.

Not in scope

Changing what /draft-pr does, and anything about the orchestration Run model. Both are their own decisions.

Amended 17 August 2026

The research this ticket was held for has landed:
CAN-131 Research where this repository and Orca do not meet, and settle the worktree workflow,
document docs/research/orca-gaps-and-the-worktree-workflow.md. Three corrections follow, and the
needs-info label comes off: the gap above is real, the recommendation survives, and this is
workable as amended.

One: the data-loss justification is gone, and it was the strongest claim here. The comment below
rests the merge check on Orca calling git branch -D without an upstream check, per
stablyai/orca#2927, described there as closed but
unfixed. That is wrong, not merely stale. The fix landed with the close on 29 May 2026, in a commit
titled fix: preserve unmerged branch when removing a worktree, which replaced branch -D with
branch -d and whose own tests assert that -D is not called. Verified three ways: the issue reads
closed with state_reason: completed; the fix commit's tests assert the safe flag; and an
experiment on Orca 1.4.184 removed a worktree whose branch held an unmerged, upstreamless commit and
got back preservedBranch with the commit still reachable.

Current Orca goes further in a way that matters for this repository specifically. It carries a
deleteAlreadyMergedBranchAfterSafeDeleteFailure path whose comment reads: squash merges rewrite*
commit IDs, so branch -d rejects already-merged branches; delete only when Git proves no unmerged
*tree changes. That is exactly our case, and it is why removal after a landed squash-merge still
tidies the branch rather than accumulating one per ticket.

So keep the merge check, but re-justify it. The reason is ordinary: removing a checkout whose work
has not landed wastes the work. It is no longer a guard over a live data-loss path in the tool, and
the warning below that a later reader might relax it no longer applies, because it now genuinely is
belt and braces.

Two: the choice is two options and neither is Archive, because the CLI has no such verb. The
comment is right that the body offered a false binary, and right to refuse an undocumented archive.
The reason is stronger than it gave. Sleep with Descendants and Delete with Descendants exist
only in the app UI: orca worktree set has no sleep flag and orca worktree rm has no descendants
flag, so a skill cannot reach either. What a skill can reach is three commands, which is what this
ticket already names.

One hazard worth carrying, since it is adjacent. Every lane is a lineage child of the main worktree,
so a descendants cascade invoked there would reach all of them. Whether the UI offers that on the
main worktree was not established.

Three: the recommendation stands, on different footing. *Stop the terminals and mark completed,**
*leave removal to a person was recommended because removal risked losing commits. Removal is safe, so
that reason is spent. It survives on another: a checkout is cheap to keep, and deciding to discard
work is not a skill's call to make. Keep the recommendation and swap its argument.

And one note above should be declined rather than actioned. The survey suggests
orca repo set-base-ref would remove the need to pass --base-branch origin/main on every lane. It
would, but the setting is per-machine and so cannot be committed, and the research recommends the
base stay visible in the command where a reader can see it. The orca worktree ps note is confirmed
and now recorded in the research document instead, along with the finding that agent status is
poll-only while terminal idleness is blocking-waitable via orca terminal wait --for tui-idle.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions