cd /news/ai-agents/twelve-of-thirteen-stale-docs-were-k… · home topics ai-agents article
[ARTICLE · art-126442] src=dev.to ↗ pub= topic=ai-agents verified=true sentiment=· neutral

Twelve of thirteen stale docs were kept alive only by each other

A developer built mdsweep, a dependency-free Node.js tool that scans repositories for stale markdown files left behind by coding agents and sorts them into active, stale, and orphan buckets. Testing across 36 repos with roughly 1,200 markdown files revealed that 12 of 13 old files in one reports folder were kept alive only by circular references among themselves, showing that inbound link counts alone cannot distinguish live documentation from dead citation clusters. The tool moves orphans to a timestamped trash directory with an undo command rather than deleting them.

by read3 min views2 publishedSep 11, 2026

My coding agents are prolific note-takers. Every non-trivial session leaves a PLAN.md, a SUMMARY.md, a HANDOFF.md, sometimes a FINAL_REPORT_V2.md. Across 36 repos on this machine there are about 1,200 markdown files, and I could not tell you which ones anybody still opens.

The obvious cleanup is a glob and a date filter:

find . -name 'PLAN*.md' -o -name 'SUMMARY*.md' -mtime +30 -delete

I did not run that, because I already knew what it would hit. A PLAN.md from May can still be the file a README points at when it explains why the approach changed. Age alone says nothing about whether a file is load-bearing.

So the next rule: keep anything that something else links to. Count inbound references, and if the count is above zero, the file is still wired into the repo. Old and unreferenced means safe to move.

That rule survived about a day. Here is the scan that killed it, from a trading repo with a reports/ folder:

reports/E_F_G_RESULTS.md              116d  stale  refs=1
reports/FINAL_HONEST_PLAN.md          116d  stale  refs=1
reports/FUNDING_HARVEST_REPORT.md     116d  stale  refs=2
reports/HONEST_FINDINGS.md            116d  stale  refs=1
reports/J_SUMMARY.md                  114d  stale  refs=1
reports/FINAL_REPORT.md               114d  stale  refs=6
... 13 files, all 114-116 days old, every one with refs > 0

Every file passed the "someone links to it" test. Then I traced where the links came from:

grep -rl "J_SUMMARY\.md" --exclude-dir=.git .

L1_AUDIT_REPORT.md is in the same folder and is just as dead. I walked all thirteen. Twelve of them had every single inbound link coming from another file inside reports/. The folder was citing itself in a circle. Only FINAL_REPORT.md had a reference from outside: mql5/README.md, and a Python script that actually runs.

A reference count of 1 was not evidence that anyone used the file. It was evidence that the agent wrote two files in the same session and made one mention the other.

I stopped trying to find a rule that decides. The scanner now sorts into three buckets and hands the ambiguous one back to me:

h.grade = h.ageDays <= days   ? 'active'   // touched recently, leave it
        : h.refs > 0          ? 'stale'    // old but linked, I read these by hand
        :                       'orphan';  // old and unlinked, movable

Across those 36 repos: 687 active, 172 stale, 176 orphan. The 172 in the middle are exactly the files the glob would have eaten, and the ones the reference rule would have blessed. They are not a category the tool can resolve, so it doesn't pretend to.

Orphans get moved rather than deleted. fs.renameSync puts them in .mdsweep/trash/<timestamp>/ next to a manifest that records every original path. mdsweep undo renames them back. Nothing in your tree gets unlinked; the only rmSync in the codebase targets the trash directory itself after a full restore.

The same scan flags 1,035 of 1,199 files, which is 86%, and that number is almost meaningless. One of the three detection signals is "untracked by git," so a repo with a messy working tree lights up wholesale. The flag rate measures my hygiene, not the tool's precision. The grading is the part that earns its keep.

The stale bucket is also a genuine dead end, not a staging area. The reports folder above proves the tool cannot distinguish a live citation cluster from a dead one, and I do not think heuristics will get there. Thirteen files is a two-minute read for a human. Thirteen hundred would not be, and I have no answer for that yet.

It is a single .mjs file, no dependencies, Node 18+. It reads your repo and prints a table; you have to pass --apply before it touches anything.

git clone https://github.com/szp2005/mdsweep
node mdsweep/bin/mdsweep.mjs scan ~/code/your-repo

I built it (szp2005/mdsweep) for my own repos, and the reports folder above is why the middle bucket exists at all. If your agents also write more markdown than you read, the scan is read-only, so the worst case is that you find out your repos were fine.

── more in #ai-agents 4 stories · sorted by recency
── more on @mdsweep 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/twelve-of-thirteen-s…] indexed:0 read:3min 2026-09-11 ·