Skip to content

deadrefs: find dead paths in your notes, fix only the certain ones

The problem

Notes, READMEs, runbooks and AI-agent instruction files are full of written-out paths. Reorganise your folders and those notes send every reader, human or agent, to a dead end. An agent told to read a file that is not there will often guess, and a wrong guess is worse than an error.

The method

Check cheaply, fix rarely, never guess.

  • Listing is just existence. Pull every path out of each line, test whether it exists. No search, so it can run at every session start.
  • A line about the past is not an instruction. "was in", "moved from", "old": the line is history and is skipped.
  • Paths with spaces are read whole. Unquoted, the path takes the longest run of following words that exists on disk.
  • Rewrite only on a unique match. --fix indexes every name under the roots once, then tries the dead path's tail, longest first, never shorter than two parts. One hit is rewritten; two hits is a guess and is left.
  • One cautious fallback. No tail match? Look under the nearest folder still there, at most one level deeper than the thing used to be.
  • Some places never count. .git, node_modules, *archive*, vendor: an archived copy is the classic false match.

A one-name path (~/notes) is never rewritten. Tried on a copy of a real notes folder, the first, looser rules made 15 rewrites, several of them into archives or into unrelated folders that happened to share a name. With the rules above: 5, each to the live new home.

Sample

The core of --fix, in Python:

def new_home(written, by):            # by: every name under the roots -> paths
    parts = relative_parts(written)
    if len(parts) < 2:
        return None                   # one name alone: a guess
    for k in range(len(parts), 1, -1):
        tail = "/" + "/".join(parts[-k:])
        hits = [p for p in by.get(parts[-1], []) if p.endswith(tail)]
        if len(hits) == 1:
            return hits[0]
        if hits:
            return None               # two places share the tail
    return nearby_unique(written, by) # nearest live folder, one level deeper at most

Use it:

deadrefs notes/ CLAUDE.md          # file:line  path
deadrefs --fix notes/ CLAUDE.md    # rewrite the certain ones, list the rest

Exit 0 means nothing dead is left, 1 means some is, so it fits a session-start hook or CI.

Limits

  • --fix walks every root once: a minute or two on a large home folder. Narrow DEADREFS_ROOTS.
  • A unique match can still be wrong if a forgotten copy sits outside the skipped folders. Read the fixed lines, and keep notes in git.
  • It knows paths, not meaning: a path that exists but now holds something else is not flagged.

Code

methods/deadrefs/ in the methods repository: the script, a README and a test.