Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
8.5 KiB
name, description
| name | description |
|---|---|
| cleanup | Free the disk space agents filled: ask every other agent session on this machine which data it still needs, inventory /tmp, Docker and the other directories agents write to, then propose a cleanup with its risks and let the operator choose through single-select (radio button) and multi-select (checklist) questions before anything is deleted. Trigger on /cleanup, "aufräumen", "bereinigen", "platte voll", "no space left on device", or when the operator asks to clean up after agents. Portable across projects. |
Nothing is deleted before the operator has picked it. Every candidate carries its owner, its size, and its risk.
Step 0: the resource chair
Shared resources belong to the resource chair of the democracy skill. If
another session holds the chair, send it the cleanup request and stop, unless
the operator ordered the cleanup in this session; then tell the chair before
step 1, so its grants and queue stay consistent.
Step 1: ask the peers
List every agent the host can message (in Claude Code: ListAgents). Only
peers sharing this machine's filesystem and Docker daemon count: local
sessions and your own subagents. Cloud sessions and remote sessions on other
machines hold nothing here; skip them.
Send each local peer one message (SendMessage) and go on with step 2 while
they answer:
Cleanup planned by <own session name>. Reply to me with everything you still
need, one item per line:
- paths under /tmp, caches, worktrees
- containers, compose or stack projects, volumes, images, networks
- running jobs (deploys, tests, builds) and when they finish
Reply "nothing" if you need none of it. Items you do not answer for stay.
Step 2: inventory
Read-only, in parallel, sizes included:
- Scope: the directories agents may write to, taken from the host's
sandbox or permission config (in Claude Code:
sandbox.filesystem.allowWritein.claude/settings.json) plus the session scratch dirs. Anything outside is out of scope, even when readable. - /tmp:
du -shper top-level entry the current user owns. System entries (.X11-unix,.ICE-unix,systemd-private-*,ssh-*,tmux-*, sockets) are never candidates. - Docker:
docker system df -v; containers with state and compose project label, volumes with the containers using them (docker ps -a --filter volume=<name>), dangling and unused images, build cache, unused networks. For every stopped container (exited,created) record its volumes ({{.Mounts}}); for every volume no running container uses, record size,CreatedAt(docker volume inspect) and compose project label, anonymous ones included. - Other agent dirs: package and tool caches (pip, npm, pre-commit, act,
gh, buildx), worktrees with
git status --shortand whether their branch is merged or pushed, Ansible and build temp dirs. - Live use: open handles (
fuser,lsof) and running processes by name only (ps -o pid,etime,comm). Never print full command lines or environments: process arguments carry credentials. A sandboxed agent often sees only its own processes, so an empty handle list proves nothing there; then only entries untouched for more than 24 hours (find -mtime +0) are candidates, and newer ones stay askeep (recent, possibly in use). - Archive duties: memory and project instructions that require copying
something out before deletion (logs, reports, generated maps). Such an item
is
archive first, never a plain delete.
Prefer the project's own cleanup and teardown targets (Makefile, scripts) over raw commands where they exist, and obey project rules that forbid raw commands.
Step 3: attribute
Give every candidate an owner: a peer's reply, a session id in the path, a
worktree or compose project name, a container label, an open handle, or
unknown. Then apply, first match wins:
- Claimed by a peer:
keep. - Attributable to a peer that has not answered:
keep (no answer from <peer>). Silence is not consent. - Archive duty:
archive first. - Everything else is a candidate with a risk class:
| Risk | Meaning | Typical items |
|---|---|---|
| low | regenerated automatically, cheap | stopped containers without volumes, dangling images, unused networks, scratch dirs and logs of finished sessions |
| medium | regenerated, but slow, rate-limited or network-bound | unused tagged images (re-pull, registry limits), build cache (cold rebuilds), package caches |
| high | data loss or a broken run possible | volumes, stopped containers with volumes, running unclaimed containers or stacks, worktrees with uncommitted or unpushed work, unread reports, anything unknown |
Step 4: propose
One table, biggest first:
| Area | Item | Size | Owner | Risk | Proposal | What breaks if wrong |
Below it: reclaimable size per risk class, and every keep row grouped by
reason, so the operator sees what was protected and why.
Then ask with AskUserQuestion in two calls.
Call 1, the selection (multiSelect: true, checklists, at most four
questions): /tmp, Docker, Other dirs, and a separate High risk
question that holds every high-risk candidate. Size, risk and worst case go
into each option's description. An area with more than four options is
grouped by owner or risk, or split into a further call. Only ticked items are
selected; nothing is preselected.
Stopped containers and volumes always get their own checklist
(multiSelect: true, header ⚠ Volumes, in a further call when call 1 is
full). Every stopped container and every volume without a running container
appears there unless a peer claimed it; none is dropped as "not proposed",
unknown and anonymous ones included. The question text carries the warning:
Deleting a volume is irreversible; its data does not come back unless the description says how. One option per stopped container together with its
volumes (removing the container alone frees nothing of them), one per
unattached volume, anonymous ones grouped. Each description gives size,
CreatedAt, owner or compose project, and what is lost.
Call 2, the confirmation (multiSelect: false, radio buttons), computed
from the ticks: Execute: <n> items, <size> (Recommended), Revise the selection, Abort. The execute description names the worst case of the
ticked items. Revise repeats call 1; nothing is deleted before Execute.
Step 5: execute
- Re-check claims, open handles and running state right before each delete: a peer may have started something since the inventory.
- Delete exactly the selected items, by name or path. No blanket prune
(
docker system prune -a --volumes,rm -rf /tmp/*) that sweeps beyond the selection. For more than a handful of paths, write the list to a file under/tmp, grep it against every claim once more, then delete withxargs -d '\n' rm -rf -- < <list>. - Locally built images free little on their own: their layers stay behind as
build cache. After removing images, re-measure
docker system df; the layers show up as reclaimable build cache. Offerdocker builder prune --filter until=24has a follow-up candidate, ask the peers that claimed build cache first, and run it outside their running builds. - A host permission layer (an auto-mode classifier, a deny rule) may refuse a delete. Never route around it with another command or a peer. Finish the rest, then put the refused item to the operator again as its own option: an explicit renewed selection may pass; if it is refused again, hand over the exact command with its list file for the operator to run.
- Running stacks go down through the project's teardown target, never by removing their containers or volumes underneath them.
- Archive-first items: copy out, verify the copy, then delete.
- A delete failing on permissions (files owned by a container UID): use the project's container helper. Never sudo, never bypass the sandbox; without a helper, report the path.
- Stop on the first unexpected error and report it.
Step 6: report
df -h and docker system df before and after, freed size per area, every
skipped or failed item with its reason. Tell each peer that answered which of
the removed items lay near its own.
Rules
- Questions, inventory and proposal change nothing. Deletion needs the operator's selection in this run; a selection from an earlier run does not carry over.
- Never delete outside the agent write scope, another user's files, or system
entries in
/tmp. - Never invent a peer's answer or a size. Unmeasured is
unknown, andunknownis high risk.