Rename without breaking links
Rename a heading and every workspace anchor link that points at it is rewritten in one atomic edit. Link-reference labels rename with their uses. A colliding slug fails loudly instead of silently breaking cross-file links.
Renaming a heading normally breaks every
[text](file.md#old-slug) link that pointed at it. The
links still parse, so nothing complains until a reader hits
a dead anchor — or until MDS027 flags it on the next lint
pass, after the damage is committed.
mdsmith renames the whole graph at once. Rename a heading
and the editor rewrites the heading line plus every
workspace anchor link that resolved to its slug, in a
single atomic edit. Same-file (#slug) references are
included. When a duplicate-name disambiguator shifts —
renaming the first “Setup” changes the second’s slug from
setup-1 to setup — the affected links update too.
Link-reference labels rename the same way. The [label]: url definition and every [text][label] and shortcut
[label] use in the file move together.
The rename refuses to corrupt the workspace. If the new heading text slugifies to a slug another heading already owns, the rename fails and names the colliding heading rather than silently shifting numbered suffixes. A label that collides with another definition fails the same way. Text that slugifies to nothing, or that contains a newline or a stray bracket, is rejected before any edit applies.
Any LSP-aware editor, and the Claude Code agent, can drive this over the wire. See the LSP reference for the prepare-range table and the collision-error contract.
# From the command line
The same rename engine has a CLI surface, so a script or an agent with no editor reaches it too:
mdsmith rename docs/guide.md --heading "Old Title" "New Title"
mdsmith rename docs/guide.md --link-ref oldlabel newlabel--heading matches the heading’s current visible text;
--link-ref matches the label. The command rewrites
every dependent edit in place and prints a per-file
summary (--format text|json). A collision, an empty or
bracket-bearing name, or a missing target exits non-zero
and names the conflict, exactly like the editor path. See
the mdsmith rename reference
for flags, output, and exit codes.