Playbook 09 and the hq-cleanup skill: a cleanup that deletes only what is proven done #388

Merged
mesh-tools merged 2 commits from process/09-cleanup into main 2026-10-16 19:08:33 +00:00
4 changed files with 95 additions and 1 deletions
+44
View File
@@ -0,0 +1,44 @@
---
name: hq-cleanup
description: Use when the operator asks to clean up the forge and the working copies — stale or merged branches, old pull requests, finished worktrees, leftover folders, stashes. Triggers on "cleanup", "clean up our repos", "stale branches", "old worktrees", "tidy the forge". Reads first, deletes only what the operator approves, and reports what it cleaned, kept and left.
---
# hq-cleanup
Runs playbook [09 — Cleanup](../../../00-META/process/09-cleanup.md); the playbook is authoritative. This skill
adds the mechanics.
## 1. Take stock (one read-only agent, smaller model)
Brief it to change nothing and to write one report to the session's scratchpad:
- **Forge.** `gitea.gitea_list_repos`; per repository its default branch and **every branch from the git refs**
(`gitea.gitea_api` GET `/repos/{owner}/{repo}/git/refs/heads`; the list tool misses branches, issue 949);
`gitea.gitea_branch_protection_get`; open pull requests (`gitea.gitea_open_pulls`, titles and update times
from `gitea.gitea_api` `/repos/{owner}/{repo}/pulls?state=open`). Per branch: contained in the default branch
(`gitea.gitea_contains`, with the default branch's sha), patch-equal (`git cherry` in a local clone), tip date.
- **Local.** Under the projects folder: each clone's `git worktree list --porcelain`, `git branch -vv`,
`git branch --merged origin/<default>`, `git stash list`, `git status --porcelain` per worktree; folders and
loose files beside the clones with `du -sh` and newest file. A worktree under another session's scratchpad is
Kept.
- A **Missing tools** section: each read it did without a mesh tool.
## 2. Classify and ask
Classes as playbook 09 step 2: Safe, Likely safe, Kept, Unknown. Tell the operator the counts and the report's
place, and ask one question: delete the Safe list? Likely-safe and Unknown items are asked separately.
## 3. Delete the approved list only
- Forge branch: `gitea.gitea_delete_branch`.
- Worktree: `git worktree remove <path>` (never `--force`), then `git worktree prune`.
- Local branch: `git branch -d <name>` (never `-D`).
Once design 58 milestone 7 is built (issue 884), each deletion is a call held as an ask: the operator approves
the exact list on Telegram and the mesh carries it out on the warrant. Until then a session's permission check
refuses these; hand the operator the approved list as a file, with the commands, and do not work around the
refusal.
## 4. Report
Four lists: **cleaned** (with its evidence), **kept** (why), **unknown** (what it looks like), **the operator
kept** (their word). Open each missing tool with `issue-tracker.open`, or note it on an existing issue.
+1
View File
@@ -58,6 +58,7 @@ the expensive half.
| [06](06-writing-a-module.md) | Writing a module | Something that runs today must run on the mesh |
| [07](07-feature-branches.md) | Features | Work that changes code across issues or repositories: prepared context, local development, one review, one check, one delivery |
| [08](08-small-fixes.md) | Small fixes | One issue in one repository, about an hour of work: one review, one push, one delivery |
| [09](09-cleanup.md) | Cleanup | Merged branches, stale pull requests, finished worktrees and folders: read first, delete only what the operator approves, report the rest |
## The cycle is checked
+49
View File
@@ -0,0 +1,49 @@
# Playbook 09 — Cleanup
**Trigger.** The operator asks for a cleanup, or the forge and the working copies have gathered what nobody
uses: merged branches, stale pull requests, worktrees and folders of finished work.
**Who runs it.** A session on the operator's word, with the operator deciding every deletion. Agents read and
propose; a deletion is the operator's act or is done on the operator's word for the list it was shown.
## The aim
Remove what is provably done, and nothing else. A cleanup that deletes one piece of unfinished work costs more
than every stale branch it removed. So every item is shown with its evidence, and anything not provably safe is
reported and left.
## Steps
1. **Take stock, reading only.** One agent on the smaller model reads, changing nothing:
- the forge: every repository, every branch **as git refs** (the branch list tool misses some, issue 949),
every open pull request with its head, title and last update;
- each working copy on the machine: its worktrees, local branches, stashes, and the folders beside the
clones, with size and newest file.
It writes one report with each item, its class and its evidence, and a list of the tools it lacked.
2. **Classify each item**, by evidence, never by name or age alone:
- **Safe** — a forge branch whose tip is contained in its repository's default branch, with no open pull
request, not protected and not a long-lived branch the mesh treats as a trunk; a worktree that is clean,
whose branch is contained in the remote default branch, untouched for two hours and not in another
session's working folder; a local branch contained in the remote default branch.
- **Likely safe, not proven** — a branch whose every commit is patch-equal to one on the default branch
(the forge lands some commits under new hashes): listed, deleted only on the operator's word for it.
- **Kept** — unmerged commits, a dirty worktree, a stash, an open pull request, a protected or trunk-like
branch, a repository of another owner, another session's worktree.
- **Unknown** — a folder or file outside git: described, never opened where a secret may be, left.
Stale open pull requests (no update for three days) are reported with their author's issue, never closed.
3. **Ask the operator** with the counts per class and the report's place. One question: delete the safe
items as listed? The likely-safe and unknown items are separate questions, item by item when few.
4. **Delete only the approved list**, each with the command that refuses an unsafe case (a worktree removal
that refuses a dirty one, a branch deletion that refuses an unmerged one). A refusal is reported, never
forced. The operator approves a deletion on a channel that proves who answered, as an ask bound to that
exact list and carried out on the warrant (ADR 0387, design 58 milestone 7, issue 884). Until that is built,
an agent session's permission check refuses these deletions, and the approved list is handed to the
operator to run.
5. **Report**: what was cleaned, what was kept and why, what was unknown, what the operator kept, and the
missing tools, each opened as an issue (`issue-tracker.open`) or added to an existing one.
## How it is checked
- The report names, for every deleted item, the evidence it was safe (contained, clean, no pull request).
- Nothing classed Kept or Unknown is deleted without the operator's word for that item.
- A cleanup's missing tools are issues, not notes in a session.
+1 -1
View File
@@ -10,7 +10,7 @@ Before changing anything here, read the playbooks in
amendment, issues, build handoff, constitution sync) is documented there, and agents operate
through them. Thin skills in `.claude/skills/` wrap these playbooks for invocation
(`hq-new-research`, `hq-graduate`, `hq-new-issue`, `hq-diagnose`, `hq-amend-design`,
`hq-handoff`, `hq-sync-constitution`, `hq-status`); each defers to its playbook as
`hq-handoff`, `hq-sync-constitution`, `hq-status`, `hq-cleanup`); each defers to its playbook as
authoritative and adds only the mechanical scaffolding.
## The development cycle