| name | project-maintenance |
| description | Use when the user asks for a maintenance pass, cleanup, end-of-session tidy-up, or health check on a repo. Triggers: 'clean up this project', 'run maintenance', 'end of session cleanup', fleet sweeps that follow project-tracker.find_stale_maintenance. Researched and interactive; every action is logged. |
Project Maintenance
End-of-session cleanup for a single repo. Works in two modes:
- Interactive - running in a user-facing session. Walk the checklist, research each finding, and prompt the user per item before taking action.
- Fleet subagent - running under
fleet-orchestration. Produce the same researched findings but return them to the parent as structured data. Do not prompt - the parent drives the approval loop with the user.
Relationship to the wrap skill: wrap owns the interactive, autonomous-fix, session-close version of per-session hygiene; this skill re-runs the same items detection-only in step 0, reading wrap's references/hygiene-checklist.md (in the installed wrap skill's directory) as the canonical list. For a full end-of-session pass across everything the session touched, use /wrap directly instead.
Operating principles
- Verify before delete. Never delete untracked files. For tracked files, delete only when (a) the working tree is clean and (b) you can state why the file has served its purpose. This governs every finding this skill produces, step 0's hygiene hits included (wrap's looser untracked-delete rule never applies here).
- Research before asking. Each finding you surface must already include evidence, a recommendation, a confidence level, and the exact action you'd take on approval. The user should be able to y/n without opening any files themselves.
- Log everything. Every automated action, every user-approved action, and every user-rejected proposal must appear in the final action log. Nothing the agent does should be invisible.
- Age is a hint, not a gate. A day-old memory may already be obsolete; a month-old memory may still be load-bearing. Semantic checks (fix-implemented, dangling reference, superseded) decide staleness.
Procedure
0. Hygiene survey (findings-only)
If the wrap skill is installed, run the read-only detection queries from its references/hygiene-checklist.md (the canonical per-session item list; consumed by reference, not duplicated here) against this repo. If wrap is not installed, check at minimum: uncommitted changes, unpushed commits, temp files, project-scoped stale memory, merged local branches, and stale worktrees.
Turn every hit into a normal finding per references/finding-schema.md (evidence, recommendation, confidence, exact action on approval) and feed it into step 2's research pass. Detection only: never execute a fix in this step, and never invoke the wrap skill itself - its interactive, whole-session close-out procedure is not part of a maintenance pass.
1. Bootstrap
If the project-tracker MCP server is available, call project-tracker.get_maintenance_checklist(name=<project>) first. This returns the combined mechanical status in one shot and saves you most of the shell work. Without it, run the mechanical checks from references/checklist.md by hand with git/shell.
get_maintenance_checklist does not yet know about the clean_init_* checks below - it emits no findings for them regardless of MCP availability. Always run the "Safe git clean + post-clean init" row of references/checklist.md by hand, even when the MCP server answered everything else.
If available, also call project-tracker.find_stale_memory(days=30) and scope the result to the current project (without the MCP server, skim the project's memory directory for stale entries yourself).
2. Research each finding
For every item the checklist returned, enrich it into a full finding. The schema is in references/finding-schema.md. Never surface a finding without evidence you have actually inspected:
- Temp files (untracked): read the contents. Is this scratch still in progress? Was it copied somewhere? Recommend
delete only if you can explain why it's spent.
- Temp files (tracked): use
git log -- <path> to see when it last changed and why. If the work has landed elsewhere, recommend delete (it's recoverable).
- Dead code: grep for references to the symbol across the repo and the user's other projects. Don't recommend removal without evidence nothing consumes it.
- TODO comments: check whether the referenced condition still holds in current code. Often the fix is already in place and only the comment remains.
- Stale memory: read the memory, then verify each claim it makes against current code. If the referenced issue is fixed, recommend deletion with the commit/line that fixed it as evidence. If it's still valid, keep it. Keep-or-delete is not the only outcome: a multi-item memory (e.g. a handoff note listing follow-ups) where some items are now verifiably done should be updated in place - mark the closed items done with the verifying evidence, leave the still-open items untouched.
- Branches: before recommending branch deletion, run
git merge-base --is-ancestor <tip> <target> to confirm the branch's tip commit is fully merged into the target branch. If the branch is not merged (the common case - agent work branches that were force-pushed, rebased, or abandoned), diff it against the target: git diff <target>..<branch> --stat at minimum. Generic commit messages ("chore: wrap session hygiene", "chore: cleanup") can mask significant unmerged WIP - the diff is the only way to know. If the diff is non-trivial, surface it to the user. If the branch is fully merged, also check whether it still exists on any remote (git ls-remote --heads <remote> <branch>): deleting only the local copy leaves the remote one lingering, and git fetch --prune never deletes the remote branch itself. Propose git push <remote> --delete <branch> alongside the local delete.
- Empty directory husks: untracked directories containing zero files (
find . -type d -empty -not -path "./.git/*"). Git tracks files, not directories, so these are invisible to git status and survive dirty-tree checks indefinitely - typically leftovers from cleaned-out test workspaces. Principle 1's "never delete untracked files" does not block removal (there are no files to lose), but still surface as a finding: confirm the directory name doesn't signal reserved future use before deleting.
3. Interactive approval loop (interactive mode only)
For each researched finding:
- Show: what / evidence / recommendation / confidence / action on approval.
- Ask:
[y]es / [n]o / [s]kip / [e]dit the action.
- Execute or record accordingly.
- Append the outcome to the in-memory action log under one of:
automated, user_authorized, rejected.
In fleet-subagent mode, skip the loop - return findings to the parent and let it drive approval.
4. Safe auto-fixes (Phase 2 only - see rollout)
When Phase 2 is enabled, the following may run without per-item prompting. Log every one under automated:
- Rename
master to main - only on a clean working tree. Steps:
git branch -m master main
- If a remote exists:
git push -u origin main
- If GitHub remote:
gh api -X PATCH repos/:owner/:repo -f default_branch=main
git push origin --delete master
- Grep the repo for hard-coded
master references (CI, README badges, scripts) first; abort the auto-fix and escalate if any exist.
git fetch --prune
- Delete merged local branches - only delete branches whose tips are confirmed merged into the target branch (
git branch --merged main already guarantees this; each returned branch's tip is an ancestor of main, so its content is safe). Do not use this auto-fix for branches that are not merged - those must be researched per Step 2 (merge-base check + diff) and treated as Phase 1 findings.
- Breadcrumb update - always runs; see step 5.
In Phase 1, treat these as researched findings too: surface them for approval, don't execute unasked.
5. Finalize
Build the summary:
{
"timestamp": "<ISO-8601 UTC>",
"head": "<git HEAD sha>",
"automated": [ ... ],
"user_authorized": [ ... ],
"rejected": [ ... ]
}
Call project-tracker.record_maintenance_run(name=<project>, summary=<summary>) to persist the mechanical log in .maintenance.json (or append the entry to .maintenance.json directly when the MCP server is absent).
Return to the user (interactive) or parent (fleet):
- The same action log, plus a short natural-language report describing anything the agent found judgment-worthy: surprises, patterns across findings, suggested follow-ups.
Rollout phase
Check ~/.agents/project-maintenance/phase (file containing 1 or 2). If absent, assume Phase 1. In Phase 1, skip the Phase-2-only auto-fixes above and treat them as researched findings.
References
references/checklist.md - the full checklist with each check's purpose
references/finding-schema.md - exact shape of a finding dict
references/interactive-loop.md - the prompt wording and decision tree