Skip to content
Back to skills

Wiki Merge

ASecurity

Merge an overlap cluster of Vault concepts into one canonical concept, rewrite wikilinks, and preserve a dry-run/apply boundary. Use when $wiki-curate has identified a winner and fold-in slugs. Not for general wiki auditing or automatic article promotion.

  • 144 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added September 23, 2026
ai-agentspythongobash

Security analysis

A100/100

Scanned September 23, 2026

npx -y skills add flonat/flonat-research --skill wiki-merge --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Wiki Merge?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Wiki Merge
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/flonat-wiki-merge/badge)](https://www.skillsdirectory.com/skills/flonat-wiki-merge)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: wiki-merge
description: "Merge an overlap cluster of Vault concepts into one canonical concept, rewrite wikilinks, and preserve a dry-run/apply boundary. Use when $wiki-curate has identified a winner and fold-in slugs. Not for general wiki auditing or automatic article promotion."
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`):

1. **Read** winner + every loser concept file under `~/vault/concepts/`.
2. **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.
3. **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.
4. **Write merged content** back to the winner's file.
5. **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.
6. **Delete loser files** from `~/vault/concepts/`.
7. **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. |

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.