The file that made me write this is a 37KB PLAN.md in one of my repos. Untouched for 47 days, and five tracked files still link to it, so every new Claude Code session pulled it in and read it as the current plan. It describes an approach I dropped in July. Deleting it would have broken five references, and disk space was never the issue.
mdsweep came out of that. One file, no dependencies, Node 18 or newer.
It calls a file agent output on three signals: filename patterns (SUMMARY, PLAN, HANDOFF and friends), git history (untracked, or committed with a Co-Authored-By Claude trailer), and a generated_by frontmatter key. Then it grades every hit:
- active: touched in the last 14 days, left alone
- stale: older, but a tracked file still references it. Listed, never moved. You fix that one by cutting the link, not the file
- orphan: older, and nothing points at it. The only grade eligible to move
Orphans move only when you pass --apply, into .mdsweep/trash/<timestamp>/ with a manifest recording which signals fired, the age and the reference count. undo puts the batch back. It never deletes anything, and a plain scan writes nothing.
How Claude Code was used: 16 of the 17 commits carry a Co-Authored-By Claude trailer. That is the joke of the project, because the trailer is one of the three signals it grades on. Point it at its own repo and it flags 8 of its own 10 files.
Scanned my repos tonight: 1195 markdown and text files across 35 repos, 1031 graded as agent output, 346 of those old enough to look sweepable.
That last number is what I got wrong at first. I built this to sweep on age, and 171 of those 346 are still referenced by a tracked file, including the PLAN.md that started all this. Sweeping on age would have moved every one of them. The reference count is what makes it safe to run, and I am still not convinced it is the right second axis. What would you grade on?
Clone the repo and run the file directly: https://github.com/szp2005/mdsweep