cleanup command
Finish an already-merged branch — classify the leftover artifacts, return to a fast-forwarded default checkout, and delete the merged local branch. Every discard confirmed per item; containment proven, never assumed.
/ca:cleanup$ca-cleanup/ca-cleanupAvailability is read from each shipped host catalog. Preview-only commands are marked on the page.
What it does
Section titled “What it does”Use this after a pull request has merged but your local checkout is still on the topic branch.
cleanup proves that the branch’s work reached the fetched default branch, inventories everything
left locally, and walks back to a clean default checkout without treating an upstream marked
gone as proof. This repo squash-merges by default, so a plain SHA-ancestry check fails for most
landings; when it does, cleanup falls back to the merged PR record (the PR’s headRefOid
matching local HEAD) as an equally valid containment proof, and reports whichever proof held.
/ca:cleanupThe command takes no arguments. Run it from the merged topic branch. Codex uses $ca-cleanup; Pi
uses /ca-cleanup.
What you decide
Section titled “What you decide”codeArbiter explains whether each leftover file is reproducible, replaced by landed work, or the
only remaining copy. You approve or decline each removal by name. A stash is reported but never
dropped. Before the checkout, a stale local default ref is fast-forwarded from the fetched one so
it can’t be mistaken for a conflicting kept artifact; then the default branch is checked out and
fast-forwarded, and the merged local branch is offered for deletion with git branch -d. If -d
refuses because the remote branch is already gone, -D is offered instead, but only when the
squash-merge PR-record proof held — restated in the confirmation alongside the branch name.
Successful exit
Section titled “Successful exit”The receipt names the fetched default ref used for proof, what was removed, what was kept, the current checkout, and whether the local topic branch remains. Declining any deletion is a valid result.
When to use another command
Section titled “When to use another command”- The PR has not merged: use
/ca:pr. - The current work needs committing: use
/ca:commit. - You want a read-only repository summary: use
/ca:status. - You want broad daily hygiene across other branches and worktrees: use
/ca:standup.
| Gate | When | Effect |
|---|---|---|
| fetched containment proof | before any local artifact or branch can be removed | fetches the default branch and stops unless the current HEAD is proven contained in that fetched ref — by SHA-ancestry, or, for a squash merge, by the merged PR record matching HEAD |
| residue classification | the working tree or stash list contains leftover material | every item is classified with evidence; uncertainty is treated as unique rather than disposable |
| per-item consent | any file, artifact, or local branch is offered for removal | each target is named and confirmed separately; there is no batch approval |
Related
Section titled “Related”Compatibility
Section titled “Compatibility”This compatibility route remains available for existing workflows. Use pr --cleanup for new work.
Source
Section titled “Source”Source — plugins/ca/commands/cleanup.md (v2.18.2)
---description: Finish an already-merged branch — classify the leftover artifacts, return to a fast-forwarded default checkout, and delete the merged local branch. Every discard confirmed per item; containment proven, never assumed.argument-hint: (none)---
# /ca:cleanup — post-merge branch transition
<!-- catalog-compatibility-notice:start -->> Compatibility route. Prefer `/ca:pr --cleanup` for new usage. This installed route remains> functional under the command-route compatibility policy at ${CLAUDE_PLUGIN_ROOT}/includes/command-compatibility.md;> continue with the unchanged cleanup workflow below.<!-- catalog-compatibility-notice:end -->
Your PR merged. You are still standing on the branch, with build output, worktreeresidue, and scratch files around you. This command owns the ordinary walk back:prove the branch actually landed, decide what the leftovers are, get to a cleanfast-forwarded default checkout, and drop the merged local branch.
It exists because nothing else owned it. `/ca:standup` is daily hygiene anddeliberately never touches the current branch or the default one;`/ca:chore` takes docs, dependency bumps, and reverts. Issue #308 recordedwhat the gap produced: a routine cleanup routed to `/ca:chore`, whichrefused it, and then to `/ca:override` — a bypass invented to cover missingcoverage. This is that coverage.
## Routes to
The `post-merge-cleanup` skill (`${CLAUDE_PLUGIN_ROOT}/skills/post-merge-cleanup/SKILL.md`),which owns the containment proof, the artifact classification, and the per-itemconfirmations.
## When NOT to use
- The branch has NOT merged yet → `/ca:pr` (`finishing-a-development-branch`) owns the terminal decision; come back here after it lands.- Daily start-of-day hygiene across *other* branches and worktrees → `/ca:standup`.- A read-only look at what is dirty → `/ca:status`.- Uncommitted work you want to keep → `/ca:commit`. This command never commits for you.
## Hard gate
- MUST prove the current branch is contained in the **fetched** default branch — SHA-ancestry, or a squash-merge proven by the merged PR record (`headRefOid` == HEAD) — before anything is deleted. An unproven or unfetched comparison STOPs — a branch that only *looks* merged is not merged.- MUST classify every dirty or untracked artifact as **unique**, **redundant**, or **superseded**, and MUST NOT discard a unique or unclassifiable one without explicit per-item confirmation naming it.- MUST confirm each removal individually — no batched yes, no implied yes.- MUST reach the default branch with a clean working tree, and MUST fast-forward with `--ff-only` only — never a merge commit, never a rebase, never a reset that discards work.- MUST use `git branch -d`, and MAY use `-D` only when the squash-merge PR-record proof held this run and `-d` refused, with that proof restated and the branch named in the confirmation. MUST NOT otherwise force-delete a branch, force-push, delete a remote branch, or write to the default branch.- MUST NOT require `/ca:override`. This is ordinary lifecycle work; if it cannot proceed, the reason is a stated gate, not a bypass.