| name | wiki-merge |
| description | Use when /wiki-curate has identified an overlap cluster and you want to collapse it. Takes a canonical winner slug + one or more fold-in slugs; merges bodies, rewrites all [[wikilink]] references in the corpus, deletes losers, denylists them. Dry-run by default; --apply writes. |
| allowed-tools | Bash, Read |
| argument-hint | [--apply] <winner-slug> <loser-slug-1> [<loser-slug-2> ...] |
Wiki Merge — Collapse an Overlap Cluster
Folds one or more concept slugs into a single canonical entry.
Preserves provenance, rewrites incoming wikilinks across atlas /
books / concepts / project knowledge folders, deletes the losers,
and denylists them so the Saturday /wiki-grow cron doesn't
re-promote.
When to Use
- Right after
/wiki-curate flags an overlap cluster in Section A
and you've decided which slug should be canonical.
- Manual cleanup when you notice two concepts that should be one.
When NOT to Use
- For trivial renames — keep both files and add an alias.
- For tag normalisation — that's edit-in-place, not a merge.
- When the "overlap" turns out to be a genuine sub-concept relation
— keep both, add a
[[wikilink]] reference between them instead.
What it does
uv run python scripts/wiki-merge.py <winner> <loser1> [<loser2> ...]
uv run python scripts/wiki-merge.py --apply <winner> <loser1> [<loser2> ...]
Steps performed (in order, only on --apply):
- Read winner + every loser concept file under
~/vault/concepts/.
- Build merged body — winner's body verbatim, then each loser's
body under a
## From <loser-slug> section. Each section includes
a small admonition naming the source project + promotion date for
traceability. Sub-headings in loser bodies are demoted by one
level (## → ###) so they don't compete with the new section
delimiter.
- Build merged frontmatter — winner's fields preserved; tags
becomes the union of winner ∪ loser tags; a new
fold_in_sources:
block records each loser's slug + source_project + promoted_on
date; last_merged: is set to today.
- Write merged content back to the winner's file.
- Rewrite wikilinks — every
[[<loser-slug>]] (with or without
alias suffix) across atlas topics, book chapters, other concepts,
and project knowledge folders gets rewritten to
[[<winner-slug>|<original-display-text>]]. The alias keeps the
original display label visible so the change isn't jarring on
pages that referenced the loser by name.
- Delete loser files from
~/vault/concepts/.
- Append to denylist — each loser slug is added to
~/vault/concepts/.denylist with a comment noting the
merge date. This stops the Saturday wiki-grow cron from
re-promoting the loser slug if a project knowledge article with
that slug still exists.
Dry-run output
Default invocation (no --apply) prints a plan:
Merge plan (dry-run):
Winner: goodharts-law (concepts/goodharts-law.md)
Fold in: goodhart-taxonomy, goodhart-resistance
Merged file size: 11666 chars (winner was 3516)
Wikilink rewrites: 12 file(s)
concepts/strategic-classification.md: 1 occurrence(s)
.../knowledge/goodhart-resistance.md: 1 occurrence(s)
...
Denylist additions: goodhart-taxonomy, goodhart-resistance
Files to delete: concepts/goodhart-taxonomy.md, concepts/goodhart-resistance.md
(dry-run — pass --apply to perform the merge)
Inspect the file count and the rewrite targets. If anything looks
wrong (e.g. a loser slug is wildly overrepresented across the corpus
suggesting it's actually a distinct concept), abort and reconsider.
Apply
uv run python scripts/wiki-merge.py --apply goodharts-law goodhart-taxonomy goodhart-resistance
Performs all six steps. After the run:
~/vault/concepts/goodharts-law.md contains the merged
content with fold-in provenance in frontmatter.
goodhart-taxonomy.md and goodhart-resistance.md are deleted.
- All atlas/books/concepts/project-knowledge files that wikilinked to
the loser slugs now wikilink to the winner with the original
display label preserved as the alias.
~/vault/concepts/.denylist has two new lines.
Verify with /wiki-curate — the goodhart cluster should be gone
on the next run.
Safety properties
- Dry-run is default. Forgetting
--apply previews only.
- Loser frontmatter preserved in
fold_in_sources: — even though
the loser file is deleted, the merged file records source_project +
promoted_on for each fold-in, so the provenance is recoverable.
- Wikilinks preserve display labels — rewrite produces
[[winner|Original Display]] form, so a topic page that wrote
[[Goodhart Taxonomy]] will still render "Goodhart Taxonomy" after
the merge, just pointing at goodharts-law now.
- Denylist prevents re-promotion — if a project still has
<loser-slug>.md in its knowledge folder, the next Saturday cron
won't re-promote it.
Anti-patterns
- Don't merge a curated concept INTO an auto-generated one. If
you must, swap winner/loser. Curated content should be the
canonical surface.
- Don't merge concepts from different domains just because slugs
share a token (e.g.
model token in language-model and
linear-model). Use judgement.
- Don't merge without dry-running first. The dry-run output is
the only confirmation step.
Cross-References
| Skill | Relationship |
|---|
/wiki-curate | Identifies the clusters this skill collapses. |
/wiki-grow | Writer of auto-promoted concepts; denylist entries from /wiki-merge prevent it from re-promoting losers. |
/compile-knowledge | Source of project knowledge articles that get promoted to concepts. |