diff --git a/CLAUDE.md b/CLAUDE.md
index e4c809d..7c2417c 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -12,7 +12,7 @@ plugins/
llm-security/ v6.0.0 — Security scanning, auditing, threat modeling
ms-ai-architect/ v1.8.0 — Microsoft AI architecture (Cosmo Skyberg persona)
okr/ v1.0.0 — OKR guidance for Norwegian public sector
- ultraplan-local/ v2.3.1 — Brief, research, architect, plan, execute (five-command pipeline + skill-factory Fase 1)
+ ultraplan-local/ v2.3.2 — Brief, research, architect, plan, execute (five-command pipeline + skill-factory Fase 1)
```
Hvert plugin er selvstendig med egen CLAUDE.md, README, hooks, agents og commands.
diff --git a/README.md b/README.md
index d6572be..8a5bcf6 100644
--- a/README.md
+++ b/README.md
@@ -61,7 +61,7 @@ Key commands: `/config-audit posture`, `/config-audit feature-gap`, `/config-aud
---
-### [Ultra {brief | research | architect | plan | execute} - local](plugins/ultraplan-local/) `v2.3.1`
+### [Ultra {brief | research | architect | plan | execute} - local](plugins/ultraplan-local/) `v2.3.2`
Deep requirements gathering, research, Claude Code feature matching, implementation planning, self-verifying execution, and skill-factory authoring with specialized agent swarms, adversarial review, IP-hygiene scoring, and failure recovery.
@@ -76,7 +76,7 @@ Five core commands plus an authoring command, one pipeline with clear division o
All artifacts land in one project directory: `.claude/projects/{YYYY-MM-DD}-{slug}/` contains `brief.md`, `research/NN-*.md`, `architecture/` *(v2.2)*, `plan.md`, `sessions/`, and `progress.json`. `--project
` works across `/ultraresearch-local`, `/ultra-cc-architect-local`, `/ultraplan-local`, and `/ultraexecute-local`.
-v2.3 (non-breaking) ships the skill-factory Fase 1 MVP: `/ultra-skill-author-local` plus four supporting agents (1 opus orchestrator + 3 sonnet workers) and `scripts/ngram-overlap.mjs` (pure Node stdlib, word-5-gram containment + longest-run secondary signal, calibrated against three source/draft fixture pairs). Catalog growth is now tractable without touching the architect's hallucination gate. Non-goals stay explicit: no automation, no batch, no decision-layer skills, no remote sources — manual `mv` from `.drafts/` to catalog root is the promotion mechanism. v2.3.1 adds a qualified-slug convention (`[-]-.md`) so one feature can host multiple named patterns at different abstraction levels without displacing the baseline — resolved a collision surfaced in v2.3.0 dogfood.
+v2.3 (non-breaking) ships the skill-factory Fase 1 MVP: `/ultra-skill-author-local` plus four supporting agents (1 opus orchestrator + 3 sonnet workers) and `scripts/ngram-overlap.mjs` (pure Node stdlib, word-5-gram containment + longest-run secondary signal, calibrated against three source/draft fixture pairs). Catalog growth is now tractable without touching the architect's hallucination gate. Non-goals stay explicit: no automation, no batch, no decision-layer skills, no remote sources — manual `mv` from `.drafts/` to catalog root is the promotion mechanism. v2.3.1 adds a qualified-slug convention (`[-]-.md`) so one feature can host multiple named patterns at different abstraction levels without displacing the baseline — resolved a collision surfaced in v2.3.0 dogfood. v2.3.2 closes the UX gap: `skill-drafter` now reads `{catalog_root}/.md` before writing and surfaces a collision warning in its confirmation output with a suggested qualified slug, so users see the overwrite risk before running `mv` — not after.
v2.2 (non-breaking) adds the optional `/ultra-cc-architect-local` step between research and planning. The architect phase is backed by a versioned catalog skill (`cc-architect-catalog`) with 10 seed entries across three layers (reference, pattern, decision). Gaps are captured as issue-ready drafts so the catalog grows from real usage rather than speculation. `/ultraplan-local` auto-discovers the architecture note — existing pipelines keep working unchanged.
diff --git a/plugins/ultraplan-local/.claude-plugin/plugin.json b/plugins/ultraplan-local/.claude-plugin/plugin.json
index d22502b..0c35aae 100644
--- a/plugins/ultraplan-local/.claude-plugin/plugin.json
+++ b/plugins/ultraplan-local/.claude-plugin/plugin.json
@@ -1,7 +1,7 @@
{
"name": "ultraplan-local",
"description": "Five-command context-engineering pipeline (brief → research → architect → plan → execute) with project folders, CC-feature matching, specialized agent swarms, external research triangulation, adversarial review, session decomposition, and headless execution.",
- "version": "2.3.1",
+ "version": "2.3.2",
"author": {
"name": "Kjell Tore Guttormsen"
},
diff --git a/plugins/ultraplan-local/CHANGELOG.md b/plugins/ultraplan-local/CHANGELOG.md
index f357a4d..5dfb93e 100644
--- a/plugins/ultraplan-local/CHANGELOG.md
+++ b/plugins/ultraplan-local/CHANGELOG.md
@@ -4,6 +4,50 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
+## [2.3.2] - 2026-04-18
+
+### Fixed — skill-drafter slug-collision hint
+
+`skill-drafter` now checks for an existing file at
+`{catalog_root}/.md` before writing its draft to `.drafts/`.
+When a collision is detected, the agent prepends a warning block to
+its confirmation output showing the overwrite risk and a suggested
+qualified slug derived from the concept handle. The draft is still
+written to `.drafts/.md` — the check is a hint, not a block.
+
+**Why.** v2.3.0 dogfood surfaced the risk (logged as
+`post_dogfood_findings[0]` in that run's `progress.json`): when the
+drafter produced `.drafts/hooks-pattern.md` with an existing approved
+`hooks-pattern.md` seed present at the catalog root, the pipeline
+gave no signal that manual `mv` during promotion would silently
+overwrite the seed. The v2.3.1 qualified-slug convention gave us the
+mechanism to resolve collisions, but `skill-drafter` still didn't
+surface them at the right moment — before promotion, not after.
+
+**Changes.**
+
+- `agents/skill-drafter.md` — new Step 2 "Check for slug collision at
+ the catalog root" between slug computation (Step 1) and reading the
+ source (Step 3). Subsequent workflow steps renumbered 3→7. New
+ "Suggesting a qualifier" guidance derives a kebab-case qualifier
+ from the `concept` field (or source basename as fallback). Output
+ format gains a `Collision:` field (`none | approved | pending |
+ auto-merged | soft`) and an optional warning block when the
+ collision is non-none. New Hard Rule "Slug-collision pre-write
+ check".
+- `tests/fixtures/skill-drafter/slug-collision-expected.md` — new
+ reference fixture documenting the expected confirmation-output
+ shape across four scenarios (no collision, approved collision,
+ soft pending collision, collision with no good qualifier).
+ Skill-drafter is prompt-driven and not auto-tested; the fixture
+ anchors the shape for human verification and downstream parsers.
+
+**Non-breaking.** No changes to `.drafts/` layout, frontmatter
+contract, tool scope, or filename regex. Existing pipelines see an
+extra field (`Collision:`) and an optional warning block — both
+purely additive. No version-gated changes in
+`skill-author-orchestrator` or `ip-hygiene-checker`.
+
## [2.3.1] - 2026-04-18
### Added — Qualified slug convention for cc-architect-catalog
diff --git a/plugins/ultraplan-local/CLAUDE.md b/plugins/ultraplan-local/CLAUDE.md
index 5a829ce..1da02dc 100644
--- a/plugins/ultraplan-local/CLAUDE.md
+++ b/plugins/ultraplan-local/CLAUDE.md
@@ -130,6 +130,7 @@ Architect sits between `/ultraresearch-local` and `/ultraplan-local`. It matches
- **Matcher logic:** `feature-matcher` builds `cc_feature → {layer → [skills]}` and prefers the unqualified baseline when the brief does not specifically justify a variant. Multiple skills can be proposed together when they cover non-overlapping aspects of the same feature.
- **Critic enforcement:** `architecture-critic` verifies every cited `supporting_skill` name exists as a real file in the catalog (blocker severity). The `cc_feature` hallucination gate is unchanged — still validates against the taxonomy, not slugs.
- **Collision handling:** skill-factory drafts that would overwrite an approved slug are a hard error. Resolution is either to qualify the new slug or revise the existing baseline.
+- **Drafter collision hint (v2.3.2):** `skill-drafter` reads `{catalog_root}/.md` before writing, and prepends a warning block to its confirmation output when an existing skill would be overwritten during manual `mv` promotion. The warning cites the existing file's `review_status` and suggests a qualified slug derived from the `concept` handle. The draft is still written to `.drafts/.md` — the check is a hint, not a block.
Seeds v2.3.1: 11 skills across 8 features — one qualified pattern (`hooks-observability-pattern.md`, promoted from `ai-psychosis/README.md`, ngram-overlap 0.01, approved). Decision-layer intentionally empty pending skill-factory Fase 2.
diff --git a/plugins/ultraplan-local/README.md b/plugins/ultraplan-local/README.md
index b7ddea2..fc0f388 100644
--- a/plugins/ultraplan-local/README.md
+++ b/plugins/ultraplan-local/README.md
@@ -1,6 +1,6 @@
# ultraplan-local — Brief, Research, Architect, Plan, Execute
-
+


@@ -226,7 +226,7 @@ Downstream: `/ultraplan-local` auto-discovers `architecture/overview.md` in proj
The architect command reads from `skills/cc-architect-catalog/`, a plugin-internal catalog of hand-written skills covering each CC feature at one or more layers (`reference`, `pattern`, `decision`). v2.2 shipped 10 seeds covering all 8 features at the reference layer (plus pattern layer for hooks and subagents). The catalog is designed for expansion via the skill-factory process (v2.3) — gaps surfaced by the architect command are the backlog for that work.
-**Slug convention (v2.3):** files follow `[-]-.md`. Unqualified slugs (e.g., `hooks-pattern.md`) are the baseline/canonical entry for a `(feature, layer)` pair. Qualified slugs (e.g., `hooks-observability-pattern.md`) cover specific sub-patterns without displacing the baseline. `feature-matcher` prefers the baseline when the brief does not specifically justify a qualified variant; it may propose multiple supporting skills when they cover non-overlapping aspects. Slug collisions with approved skills are a hard error — skill-factory drafts must qualify or revise instead.
+**Slug convention (v2.3):** files follow `[-]-.md`. Unqualified slugs (e.g., `hooks-pattern.md`) are the baseline/canonical entry for a `(feature, layer)` pair. Qualified slugs (e.g., `hooks-observability-pattern.md`) cover specific sub-patterns without displacing the baseline. `feature-matcher` prefers the baseline when the brief does not specifically justify a qualified variant; it may propose multiple supporting skills when they cover non-overlapping aspects. Slug collisions with approved skills are a hard error — skill-factory drafts must qualify or revise instead. **v2.3.2:** `skill-drafter` performs a pre-write check against `{catalog_root}/.md` and prepends a warning block to its confirmation when the proposed slug would collide, suggesting a qualified slug derived from the concept handle. The draft still writes to `.drafts/` — the warning exists so users see the overwrite risk before running `mv`.
### Hallucination gate
diff --git a/plugins/ultraplan-local/agents/skill-drafter.md b/plugins/ultraplan-local/agents/skill-drafter.md
index 799cefd..d500b3e 100644
--- a/plugins/ultraplan-local/agents/skill-drafter.md
+++ b/plugins/ultraplan-local/agents/skill-drafter.md
@@ -54,13 +54,48 @@ message — do not write a file with an invalid name.
The draft file path is `{catalog_root}/.drafts/.md`.
-### 2. Read the source
+### 2. Check for slug collision at the catalog root
+
+Before proceeding, attempt to `Read` `{catalog_root}/.md` (the
+approved location, NOT the draft location).
+
+- If the read fails because the file does not exist → no collision.
+ Proceed to Step 3. Record `collision: false` for the summary.
+- If the read succeeds → inspect the frontmatter for `review_status`.
+ - `review_status: approved` → **collision**. Record it and derive a
+ suggested qualified slug (see "Suggesting a qualifier" below).
+ - `review_status: pending` or `auto-merged` → **soft collision**.
+ Still record and surface it, but the existing file is not a
+ guaranteed baseline; the human reviewer can decide.
+ - Missing or malformed frontmatter → treat as soft collision. Note
+ it in the summary so the reviewer can inspect.
+
+**Do not block** on any of these outcomes. The draft is still
+written to `.drafts/.md` in Step 7. The collision check exists
+to surface the overwrite risk in your confirmation output so the
+user sees it before running `mv` during manual promotion.
+
+**Suggesting a qualifier.** Pick a short, descriptive kebab-case
+word from the `concept` field (3–6 word handle from
+`concept-extractor`). Strip stopwords like "the", "a", "and". Prefer
+the most specific noun or named pattern in the handle. If the
+concept is generic and no good qualifier emerges, fall back to the
+source basename (e.g., `docs/hooks-recipes.md` → `recipes`).
+
+The suggested qualified slug is
+`--.md`. Validate it against the
+filename regex just like Step 1. If the suggestion collides with
+another existing skill (approved or pending), try the next candidate
+qualifier from the concept handle. If no candidate is collision-free,
+report `suggested_slug: none — reviewer must pick`.
+
+### 3. Read the source
Read the source file in full. Extract the load-bearing ideas that map
to the concept handle. You are not summarizing the source verbatim —
you are reframing it as catalog skill content.
-### 3. Compose the frontmatter
+### 4. Compose the frontmatter
The frontmatter MUST have exactly these 9 fields, in this order, with
exactly these values:
@@ -85,7 +120,7 @@ not 0). `review_status` MUST be `pending` (not `approved`, not
populates `ngram_overlap_score`; the human reviewer in promotion
flips `review_status`.
-### 4. Compose the body
+### 5. Compose the body
The body is 150 to 600 words. Use progressive disclosure: short
headings, bullet notes, no long prose paragraphs. Imperative voice,
@@ -115,7 +150,7 @@ For `layer: pattern`, structure as:
Each section gets 2–4 short bullets or one short paragraph. Skip
sections that have no content rather than padding them.
-### 5. Rephrase — do not copy
+### 6. Rephrase — do not copy
You MUST NOT copy verbatim phrases from the source. Rephrase every
sentence in your own words. The downstream `ip-hygiene-checker` runs
@@ -130,7 +165,7 @@ a fixed YAML schema), do not draft it. Stop and emit a short
escalate. Better to skip than to ship a draft that will fail
hygiene.
-### 6. Write the file
+### 7. Write the file
Use the `Write` tool to create the draft at
`{catalog_root}/.drafts/.md`. Overwrite if it exists — the
@@ -147,9 +182,30 @@ After writing the file, return a short confirmation:
Drafted: .md>
Word count:
Frontmatter: 9 fields, review_status=pending, ngram_overlap_score=null
+Collision:
Next: ip-hygiene-checker for IP scoring
```
+If Step 2 detected a collision at `{catalog_root}/.md`, prepend
+a warning block to the confirmation:
+
+```
+⚠️ Slug collision at catalog root
+ Existing: {catalog_root}/.md (review_status=)
+ Draft: {catalog_root}/.drafts/.md (this run)
+ Risk: manual `mv` during promotion will silently overwrite the existing file.
+ Suggested qualified slug: --.md
+ Reason for qualifier:
+ Action: rename the draft before `mv`, or revise the existing baseline.
+```
+
+If no collision-free qualifier could be derived, replace the
+"Suggested qualified slug" line with:
+
+```
+ Suggested qualified slug: none — reviewer must pick one manually.
+```
+
If you stopped because of `too-technical-to-paraphrase`, return:
```
@@ -180,6 +236,11 @@ No file written.
copied draft is wasted work.
- **`.drafts/` only.** Never write to the catalog root. Promotion is
manual `mv` by the user (fase-1 boundary).
+- **Slug-collision pre-write check.** Always `Read`
+ `{catalog_root}/.md` before writing the draft. If the file
+ exists, surface the collision in the confirmation output with a
+ suggested qualified slug. Never block the draft write — the warning
+ exists so the user sees the overwrite risk before running `mv`.
- **Privacy.** Strip any secret-looking strings from the source
before drafting; if the source is meaningfully about credentials,
abort with `too-technical-to-paraphrase`.
diff --git a/plugins/ultraplan-local/tests/fixtures/skill-drafter/slug-collision-expected.md b/plugins/ultraplan-local/tests/fixtures/skill-drafter/slug-collision-expected.md
new file mode 100644
index 0000000..941afe7
--- /dev/null
+++ b/plugins/ultraplan-local/tests/fixtures/skill-drafter/slug-collision-expected.md
@@ -0,0 +1,159 @@
+# Skill-drafter slug-collision — expected output fixture
+
+This fixture documents the expected confirmation-message shape from
+`skill-drafter` when it detects a slug collision at the catalog root.
+It is a reference fixture — not an auto-executed test — used to
+verify the agent by running a synthetic scenario by hand and
+comparing output against the shapes below.
+
+## Scenario A — no collision (baseline)
+
+### Synthetic input
+
+- **Catalog root:** `skills/cc-architect-catalog/`
+- **Concept JSON (from concept-extractor):**
+ ```json
+ {
+ "cc_feature": "worktrees",
+ "layer": "pattern",
+ "concept": "parallel feature isolation",
+ "description": "Isolate concurrent feature work in per-task worktrees to avoid git race conditions.",
+ "source_path": "/tmp/worktrees-notes.md",
+ "out_of_scope": false
+ }
+ ```
+- **Catalog state at time of run:** no `worktrees-pattern.md` present
+ at catalog root (only `worktrees-reference.md`).
+
+### Expected confirmation output
+
+```
+Drafted: /Users/…/skills/cc-architect-catalog/.drafts/worktrees-pattern.md
+Word count: 312
+Frontmatter: 9 fields, review_status=pending, ngram_overlap_score=null
+Collision: none
+Next: ip-hygiene-checker for IP scoring
+```
+
+No warning block. `Collision: none`.
+
+## Scenario B — approved collision (primary case)
+
+### Synthetic input
+
+- **Catalog root:** `skills/cc-architect-catalog/`
+- **Concept JSON:**
+ ```json
+ {
+ "cc_feature": "hooks",
+ "layer": "pattern",
+ "concept": "observability progressive alerts",
+ "description": "Progressive-alert observability pattern for hook-driven telemetry.",
+ "source_path": "/tmp/hooks-telemetry-notes.md",
+ "out_of_scope": false
+ }
+ ```
+- **Catalog state:** `hooks-pattern.md` exists with
+ `review_status: approved` (the v2.3.0 seed).
+
+### Expected confirmation output
+
+```
+⚠️ Slug collision at catalog root
+ Existing: skills/cc-architect-catalog/hooks-pattern.md (review_status=approved)
+ Draft: skills/cc-architect-catalog/.drafts/hooks-pattern.md (this run)
+ Risk: manual `mv` during promotion will silently overwrite the existing file.
+ Suggested qualified slug: hooks-observability-pattern.md
+ Reason for qualifier: concept handle names "observability" as the named sub-pattern.
+ Action: rename the draft before `mv`, or revise the existing baseline.
+
+Drafted: /Users/…/skills/cc-architect-catalog/.drafts/hooks-pattern.md
+Word count: 287
+Frontmatter: 9 fields, review_status=pending, ngram_overlap_score=null
+Collision: approved
+Next: ip-hygiene-checker for IP scoring
+```
+
+The warning is prepended. The draft is still written — the collision
+check is a hint, not a block. `Collision: approved` appears in the
+confirmation for downstream-log parsers.
+
+## Scenario C — soft collision (pending existing)
+
+### Synthetic input
+
+- **Catalog state:** `subagents-pattern.md` exists with
+ `review_status: pending` (a prior draft that was `mv`-ed up without
+ the status being flipped, or a skill-factory auto-merged entry).
+
+### Expected confirmation output
+
+```
+⚠️ Slug collision at catalog root
+ Existing: skills/cc-architect-catalog/subagents-pattern.md (review_status=pending)
+ Draft: skills/cc-architect-catalog/.drafts/subagents-pattern.md (this run)
+ Risk: manual `mv` during promotion will silently overwrite the existing file.
+ Suggested qualified slug: subagents-delegation-pattern.md
+ Reason for qualifier: concept handle centers on "delegation chains".
+ Action: rename the draft before `mv`, or revise the existing baseline.
+
+Drafted: /Users/…/skills/cc-architect-catalog/.drafts/subagents-pattern.md
+Word count: 256
+Frontmatter: 9 fields, review_status=pending, ngram_overlap_score=null
+Collision: pending
+Next: ip-hygiene-checker for IP scoring
+```
+
+`Collision: pending` signals a soft collision — the existing file is
+not necessarily a guaranteed baseline. Reviewer decides.
+
+## Scenario D — collision but no good qualifier
+
+### Synthetic input
+
+- **Concept handle:** `generic feature note` (no specific noun)
+- **Catalog state:** `skills-reference.md` exists (approved).
+
+### Expected confirmation output
+
+```
+⚠️ Slug collision at catalog root
+ Existing: skills/cc-architect-catalog/skills-reference.md (review_status=approved)
+ Draft: skills/cc-architect-catalog/.drafts/skills-reference.md (this run)
+ Risk: manual `mv` during promotion will silently overwrite the existing file.
+ Suggested qualified slug: none — reviewer must pick one manually.
+ Action: rename the draft before `mv`, or revise the existing baseline.
+
+Drafted: /Users/…/skills/cc-architect-catalog/.drafts/skills-reference.md
+Word count: 198
+Frontmatter: 9 fields, review_status=pending, ngram_overlap_score=null
+Collision: approved
+Next: ip-hygiene-checker for IP scoring
+```
+
+The fallback line replaces the "Suggested qualified slug" value.
+`Reason for qualifier` is omitted.
+
+## How to verify against this fixture
+
+This is not an auto-run test. To verify:
+
+1. Stage a synthetic concept JSON matching one of the scenarios above.
+2. Invoke `skill-drafter` via the `Agent` tool with the concept JSON,
+ source path, and catalog root.
+3. Capture the confirmation output.
+4. Compare structurally against the corresponding scenario. The exact
+ word counts and paths will differ; the warning block, collision
+ field, and suggested-slug line are the load-bearing shapes.
+
+If a future change alters the confirmation format, update this file
+alongside the agent prompt so the two remain in lockstep.
+
+## Why a reference fixture and not a unit test
+
+`skill-drafter` is a prompt-driven Sonnet agent. There is no in-repo
+harness that executes prompts deterministically, so a unit test is
+not practical. The reference fixture is the next-best anchor — it
+documents the expected shape for human verification and for
+downstream agents that parse the confirmation (e.g., the
+skill-author-orchestrator's summary phase).