Session cleanup
Audit first, delete second, and only after inspecting the target. The goal is that the owner can walk away from the session knowing nothing is running, nothing is lost, and nothing stale is left behind. A missed leftover is cheap; a deleted unpushed commit is not. When in doubt, a finding goes to ASK, never to AUTO-CLEAN.
Works in any git repo. The lanes harness, beads and Vercel parts switch on only when they are present; skip them silently otherwise.
Phase 1: Audit (read-only)
Run the bundled audit from the repo (any worktree of it). Use the script for your OS; the skill folder may be under ~/.claude/skills/, ~/.codex/skills/ or ~/.agents/skills/:
# Linux and macOS
bash <skill-dir>/scripts/audit.sh # add --no-fetch offline
# Windows (PowerShell 5.1 or 7)
powershell -NoProfile -ExecutionPolicy Bypass -File <skill-dir>\scripts\audit.ps1 # add -NoFetch offline
Both print one section per area (CONTEXT, WORKING_TREE, SYNC, WORKTREES, BRANCHES, STASHES, LANES, PROCESSES, ARTIFACTS, TRACKER, DEPLOY, SESSION_LOG). Its only write is a plain git fetch (never --prune). It never reads .env files or prints process environments.
How it decides "this session" (this matters for every classification):
- Processes:
owner=this_sessionmeans this session (or something it launched) started the process. On Linux that is proven by the inheritedCLAUDE_CODE_SESSION_ID, which survivesnohup. macOS and Windows hide other processes' environments, so there it means "descendant of the Claude process" (CLAUDE_PID); a process that was detached and reparented shows asstarted_during_sessioninstead, which is ASK unless you can trace it in this conversation.owner=harness_do_not_killis Claude Code's own MCP servers and plugins: never touch these.other_session_or_useris someone else's. - Files, branches, stashes:
this_session/pre_sessioncompares the timestamp tosession_start(first timestamp in this session's transcript). Timestamps are a hint, not proof: something created during the session window could come from a parallel session. Treat an item as this session's only when the timestamp says so and you can trace it in this conversation (you ran the command that created it). Otherwise it is ASK.
Outside Claude Code (for example in Codex) there is no CLAUDE_CODE_SESSION_ID or CLAUDE_PID, so session_id is unknown, everything is tagged pre_session, and processes are matched only by in_repo. Pass --since <ISO time> (-Since on Windows) with the session start if you know it, and otherwise treat files and processes as ASK unless you can trace them to a command in this conversation.
Then fill the gaps the script cannot see, in parallel where possible:
- Your own background work. List background Bash tasks, Monitors, subagents and scheduled wakeups you started in this conversation and which are still running. Stop finished or idle ones with the tool that started them (TaskStop, Monitor stop, etc.).
- Request leftovers. Scan the conversation for anything the owner asked to delete later or keep only temporarily (an uploads folder, a debug flag, a test account, a temporary file). Check whether it still exists.
- Deploy state (only if DEPLOY shows a platform). Get the commit SHA of the latest production deployment and compare it with
main_tip. For Vercel:vercel ls --prodto find the latest production deployment, thenvercel inspect <url>(or the Vercel MCP / dashboard) for its git commit. If you cannot obtain the SHA, report "deploy: unverified" with the reason. Never infer a match from timestamps. - Anything outside the repo that the session touched (another repo's worktree, a global install). Report it; do not modify it.
Phase 2: Classify each finding
AUTO-CLEAN (safe and recoverable; do it, then report it):
- Local branches fully merged into main (
git branch -d, never-D), excluding main, the current branch, and any branch checked out in a worktree. - Prunable worktree records whose folder is already gone (
git worktree prune). - Clean linked worktrees inside this repo whose branch is merged into main and has no commits ahead of it (
git worktree remove <path>, no--force; thengit branch -d). If the lanes harness owns it, use the harness script instead (see below). - Temp folders whose lane or branch no longer exists and that no process has open (
open_handles=0; recheck withlsof +D <dir>immediately before deleting). - Processes with
owner=this_sessionthat you can trace to this conversation and that are idle or no longer needed (dev servers, watchers, headless browsers). Kill by PID only (kill <pid>on Linux/macOS,Stop-Process -Id <pid>on Windows). - Stale build type caches (
.next/types,.next/dev/types) that are gitignored. These regenerate on the next build. - This session's own scratch files in its scratchpad folder, and untracked junk in the repo (
*.orig,*.rej, stray logs) that isthis_sessionand traceable to a command you ran.
ASK (could lose work, or not provably this session's):
- Unmerged branches, or any commits not in main. A branch marked
PATCHES_ALREADY_IN_mainwas likely squash- or rebase-merged: say so, but still ask before-D. - Dirty worktrees (
dirty_files > 0), stashes,coverage/andtest-results/that may be wanted as evidence. - Processes
other_session_or_userorstarted_during_session, and any process you cannot trace. - Anything
pre_session, and any untracked file you did not create.
REPORT ONLY (the owner acts, or it is informational):
- Drift between main and origin (unpushed or behind). Recommend the push or pull; do not do it as part of cleanup.
- Deploy mismatches or "unverified" deploy state.
- Open tracker items (beads
in_progress, tasks.md WIP) with no active work, and finished work whose task is still open. Name the item and what you saw. - Worktrees or folders outside this repo, and
upstream_gonebranches that still have unique commits.
Safety rules
These protect work that cannot be recreated. Each one exists because the obvious shortcut has destroyed work before.
- Inspect before deleting. For each folder, list its contents and size first. For each branch, show
git log --oneline main..<branch>first. Put that evidence in the report. - Never delete unmerged commits, dirty worktrees or stashes without the owner's explicit approval in this conversation. Approval for one item does not cover the next.
- Kill processes only by PID, after confirming
owner=this_sessionand that you started it. Neverpkill,killall,kill -9on a first attempt, or kill by port alone. - Never use bare
git stash,git reset --hard,git clean -fdx(or anygit clean -f), orrm -rfwith a glob. These have no undo. Delete named paths one at a time. git branch -D,git stash dropandgit worktree remove --forcerun only on the single item the owner approved, after showing what will be lost (commits, diff stat). Record the branch tip SHA in the report so it can be restored.- Never read, print, move or delete
.envfiles, keys or credentials, even when they look like junk. Report them by path only. - Stay inside this repo. Other apps' worktrees, detached checkouts or shared
/tmpfolders are reported, not touched. Never glob-delete in/tmp. - Never kill
harness_do_not_killprocesses or the Claude process itself.
When the lanes harness is present
Only if the LANES section shows a state dir. Otherwise skip this block.
- Remove lane worktrees, lane temp dirs, relay job dirs and
lanes.tsvrows with the harness's own script, never withrm:bash ~/.claude/skills/lanes/lane/cleanup.sh <lane-dir> <branch>for a merged lane, thenbash ~/.claude/skills/lanes/lane/cleanup.sh --sweep. Run it from the main worktree. WORKTREE_MISSINGandBRANCH_MERGEDrows go through the sweep. Rows for unmerged lanes are ASK.- Relay jobs still running (no
rcfile) are REPORT ONLY; the lanes watchdog owns them. - In a
/lanessession the main lane integrates; do not delete a lane branch whose work is not yet merged to origin/main.
Without the harness, worktrees under .claude/worktrees/ (for example from Claude Code's EnterWorktree) follow the plain git rules above.
Phase 3: Report
Use this structure exactly. Keep it scannable; the owner reads it at the end of a long session.
## Session cleanup
**Already clean:** working tree, sync, worktrees, branches, stashes, processes, artifacts, tracker, deploy
(list only the areas that passed)
**Cleaned**
- `feat/login-form` branch: merged into main at a1b2c3d, 0 commits ahead. Deleted with `git branch -d` (restore: `git branch feat/login-form a1b2c3d`).
- `python3 -m http.server 3000` (PID 170308): started by this session for preview, idle. Stopped.
- `.next/types` (1.2M): gitignored, regenerates on build.
**Needs your call**
- `feat/wip` branch: 1 commit not in main ("wip: draft parser"), last commit 2h ago, linked task bd-42 in_progress.
Resume (keep it) or abandon (`git branch -D feat/wip`)?
- `stash@{0}` "On main: sc test stash", 5d old. Apply or drop?
**Report only**
- main is 2 commits ahead of origin/main (unpushed). Push recommended.
- Production deploy: unverified (vercel CLI not logged in).
**Next Actions**
- Run `git worktree list`, expect only the main worktree.
- Run `git status --short`, expect no output.
Rules for the report:
- Every "Cleaned" line says what it was, its size (for files and folders) and why it was safe. For branches include the tip SHA so it can be restored.
- Every "Needs your call" item gives the facts needed to decide (age, commit count, commit subjects, linked task) and two concrete options.
- Never say an area is clean unless the audit or a command in this session showed it. If a check was skipped (offline, CLI missing, no permission), say so under Report only.
- Next Actions always includes at least one verification command with its expected output.
After the owner answers ASK items, carry out exactly what they approved, rerun the relevant audit section, and report the result.
Logging
If the repo has a session log folder (SESSION_LOG shows _sessions/ or similar), append a short cleanup entry: date, what was cleaned, what is waiting on the owner. Commit it only if the project's rules allow committing session logs; check CLAUDE.md or the folder's ignore status (ignored=yes means do not commit).
Out of scope
Refactoring, lint fixes, dead-code removal and dependency upgrades. If you notice them, record them as backlog items (memory or tracker) and mention them in one line. Pushing, pulling and deploying are also out of scope: recommend them, do not do them.