Skip to content

cleanup command

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.

Invoke it
Claude Code/ca:cleanup
Codex$ca-cleanup
Pi/ca-cleanup

Availability is read from each shipped host catalog. Preview-only commands are marked on the page.

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:cleanup

The command takes no arguments. Run it from the merged topic branch. Codex uses $ca-cleanup; Pi uses /ca-cleanup.

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.

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.

  • 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.
GateWhenEffect
fetched containment proofbefore any local artifact or branch can be removedfetches 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 classificationthe working tree or stash list contains leftover materialevery item is classified with evidence; uncertainty is treated as unique rather than disposable
per-item consentany file, artifact, or local branch is offered for removaleach target is named and confirmed separately; there is no batch approval

This compatibility route remains available for existing workflows. Use pr --cleanup for new work.

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, worktree
residue, 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 clean
fast-forwarded default checkout, and drop the merged local branch.
It exists because nothing else owned it. `/ca:standup` is daily hygiene and
deliberately never touches the current branch or the default one;
`/ca:chore` takes docs, dependency bumps, and reverts. Issue #308 recorded
what the gap produced: a routine cleanup routed to `/ca:chore`, which
refused it, and then to `/ca:override` — a bypass invented to cover missing
coverage. 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-item
confirmations.
## 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.

View in repo