baldart 3.21.2 → 3.22.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,97 @@ All notable changes to BALDART will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [3.22.1] - 2026-05-27
9
+
10
+ Rimosso il gate `AskUserQuestion` di conferma merge introdotto in v3.22.0 Step 7 — era friction inutile contro il "seamless" che è il punto della release. Quando l'utente lancia `/prd` ha già implicitamente accettato la pipeline completa (discovery → design → cards → commit → merge in develop). Chiedere "Procedo con merge?" a fine sessione equivale a chiedere "sei sicuro di voler completare quello che mi hai chiesto di fare?".
11
+
12
+ ### Changed — `/prd` Step 7 merge è ora full-seamless
13
+
14
+ - **[framework/.claude/skills/prd/references/validation-phase.md](framework/.claude/skills/prd/references/validation-phase.md)**: Step 7 point 9 non è più un `AskUserQuestion` ma una nota che chiarisce il razionale del no-confirmation flow + escape hatch user-initiated ("non mergiare" / "lascia il worktree" honora l'override e ferma dopo il commit).
15
+ - **[framework/.claude/skills/prd/SKILL.md](framework/.claude/skills/prd/SKILL.md)** HARD RULE 17 lifecycle: la descrizione di Step 7 cita "Seamless by default, no confirmation gate" + l'escape hatch.
16
+ - **[framework/.claude/skills/prd/references/discovery-phase.md](framework/.claude/skills/prd/references/discovery-phase.md)**: il messaggio di kickoff visibile all'utente promette esplicitamente "commit + merge automatico in develop + cleanup worktree, seamless" — niente più sorprese a fine sessione.
17
+
18
+ ### Why PATCH and not MINOR
19
+
20
+ Rimozione di un comportamento (gate di conferma) introdotto solo 0 minuti fa nella stessa giornata. Nessuna nuova capability, nessun breaking change per consumer: il gate non era una feature documentata né attesa dagli utenti pre-v3.22.0, era una sovra-cautela introdotta da me contro la richiesta esplicita ("seamless"). La decision tree di MAINTAINING.md classifica "bugfix di behaviour non desiderato senza breaking change" come PATCH.
21
+
22
+ ### Why no schema-change propagation
23
+
24
+ Modifica puramente comportamentale dentro un singolo step di una singola skill. Zero chiavi nuove, zero modifiche CLI, zero hook.
25
+
26
+ ## [3.22.0] - 2026-05-27
27
+
28
+ Le sessioni `/prd` ora vivono in un **docs worktree** dedicato, esattamente come fa `/new` per le card di codice. Il problema risolto: con 5-10 sessioni Claude in parallelo, ogni PRD inquinava il main checkout con `docs/prd/<slug>/PRD.md`, lo state file, le card YAML, l'eventuale `design.html`, e gli update a `ssot-registry.md` / `project-status.md`. `git status` diventava un campo minato, le sessioni `/new` rischiavano di stashare/committare file PRD non loro, e la review manuale era pressoché impossibile. Soluzione: estendere `worktree-manager` con una **modalità docs lean** (no `npm install`, no porta, no `.env` copy, no build verify, no lint/tsc gates) e integrarla nel ciclo di vita del PRD — creazione automatica al kickoff, merge automatico (previa conferma utente) al termine, cleanup seamless.
29
+
30
+ ### Added — `worktree-manager` programmatic docs mode
31
+
32
+ - **[framework/.claude/skills/worktree-manager/SKILL.md](framework/.claude/skills/worktree-manager/SKILL.md)**: nuova sezione "Programmatic API — docs mode" con due funzioni:
33
+ - **`nw-docs`** — input `{ slug, branchPrefix? }`, output `{ path, branch, kind: "docs" }`. Esegue solo `git fetch origin develop` + `git worktree add .worktrees/prd-<slug> -b prd/<slug> origin/develop` + entry nel registry con `kind: "docs"`, `port: null`, `buildVerified: null`. Target di costo: < 5 secondi (vs minuti per `/nw` standard a causa di `npm install`).
34
+ - **`mw-docs`** — input `{ worktreePath, commitMessage? }`, output `{ merged, mergeCommit, prNumber, strategy, worktreeRemoved }`. Esegue safety commit + rebase su `origin/develop` (con il protocollo conflict-resolution doc-friendly esistente in `/mw` step 4b) + merge via `git.merge_strategy` configurato (`pr` o `local-push`) + cleanup worktree/branch. **Salta** i gate inapplicabili a un worktree di docs: `npm run build`, `npx eslint`, `npx tsc`, `npm run test`, post-merge build verify.
35
+ - Forme **FORBIDDEN** documentate esplicitamente: niente `npm install`/port scan/`.env*` copy/build in `nw-docs`; niente lint/tsc/build gates in `mw-docs`. Il senso della modalità lean è proprio non eseguirli.
36
+ - Registry condiviso con i code worktrees (`.worktrees/registry.json`) — `/lw` e `/cw` mostrano docs worktrees accanto ai code worktrees, distinti dal campo `kind`.
37
+
38
+ ### Changed — `worktree-manager`: rebase conflict protocol hardened
39
+
40
+ - **[framework/.claude/skills/worktree-manager/SKILL.md](framework/.claude/skills/worktree-manager/SKILL.md)** — la tabella di conflict-resolution dello step 4b di `/mw` (riusata verbatim da `mw-docs`) è stata estesa con due categorie nuove **prima** della catch-all "Docs/config":
41
+ - **Structured registries** (`project-status.md`, `ssot-registry.md`, `field-registry.*`, `traceability-matrix.md`, `REGISTRY.md`) → **STOP**: abort rebase, report all'utente. Senza questa riga, due PRD paralleli che toccano `project-status.md` farebbero auto-strip dei marker di conflitto producendo file con sezioni duplicate e tabelle malformate. Il fix vale anche per `/mw` su code worktrees — qualsiasi card che modifica una di queste registry ora chiede risoluzione manuale invece di corromperle silenziosamente.
42
+ - **Append-only logs** (`**/*.jsonl` sotto `docs/metrics/`) → auto-resolve "keep both sides", che per JSONL è semanticamente corretto (file line-oriented additivo). Questo permette al Metrics Log del PRD (vedi sotto) di sopravvivere a merge concorrenti senza intervento.
43
+
44
+ ### Changed — `/prd` skill: HARD RULE 17 (worktree isolation)
45
+
46
+ - **[framework/.claude/skills/prd/SKILL.md](framework/.claude/skills/prd/SKILL.md)**: nuova HARD RULE 17 obbligatoria — ogni sessione PRD apre un docs worktree allo Step 1 prima di scrivere qualunque file, e committa/mergia tutto allo Step 7 prima di terminare. La regola include:
47
+ - **Path resolution explicit rule**: tutti i `Write` / `Edit` / `Read` di Claude Code DEVONO prefissare i path con `$WORKTREE_PATH` (Claude Code richiede path assoluti — senza prefisso esplicito i file finirebbero nel main repo, vanificando l'isolamento). Esempio `right vs wrong` nel testo della regola.
48
+ - **Forbidden operations**: nessun `git checkout`/`switch`/`branch` sul main, nessun `git stash` (refs/stash è condiviso fra worktree), nessuna scrittura diretta sul main repo durante la sessione.
49
+ - **Failure handling**: se `nw-docs` fallisce (e.g. `.worktrees/` non in `.gitignore`), la skill DEVE fermarsi e segnalare — niente fallback silenzioso al main repo.
50
+ - **HARD RULE 9 aggiornata**: il session-start update di `project-status.md` viene **skippato** quando la sessione gira in un docs worktree (sarebbe invisibile alle altre sessioni). L'update at-commit resta attivo, eseguito nel worktree come ultima scrittura prima del rebase + merge.
51
+ - **Step 1 (Kickoff)** in [discovery-phase.md](framework/.claude/skills/prd/references/discovery-phase.md): aggiunto step 3 che chiama `worktree-manager nw-docs` subito dopo aver derivato lo `<slug>`, prima di creare lo state file. Output kickoff aggiornato per mostrare path/branch del worktree all'utente.
52
+ - **Step 0 (Context Recovery)** in [discovery-phase.md](framework/.claude/skills/prd/references/discovery-phase.md): scan iniziale di `.worktrees/registry.json` per entries con `kind: "docs"` che matchano lo slug — se trovate, `cd` nel worktree e riprendi. Gestito anche il caso "state file legacy nel main da pre-v3.22.0" (chiede all'utente se migrare o continuare in legacy mode).
53
+ - **Step 7 (Resolution, Commit & Merge)** in [validation-phase.md](framework/.claude/skills/prd/references/validation-phase.md) — rinominato da "Resolution and Commit" e riscritto end-to-end:
54
+ - Update di `ssot-registry.md` / `project-status.md` avviene nel worktree (skip se file inesistente).
55
+ - Commit con `git -C "$WORKTREE_PATH" commit` (file espliciti, mai `git add .`).
56
+ - **Gate di conferma esplicito** (`AskUserQuestion`) prima del merge: "Procedo con merge automatico in `develop` e cleanup del worktree?". Opzione "lascia il worktree" per review manuale o test.
57
+ - Sulla conferma: invocazione `worktree-manager mw-docs` che rebase + merge + cleanup. Failure handling: il worktree resta su disco, niente retry automatico.
58
+ - **[framework/.claude/skills/prd/assets/state-template.md](framework/.claude/skills/prd/assets/state-template.md)**: nuova sezione `## Worktree` (path, branch, kind, created_at, merge_commit).
59
+ - **Metrics Log riposizionato dentro il worktree.** La sezione "Metrics Log" di SKILL.md scriveva precedentemente in `docs/metrics/skill-runs.jsonl` con risoluzione del path rispetto al main repo root — incompatibile con HARD RULE 17 e con isolamento parallelo. Ora scrive in `$WORKTREE_PATH/docs/metrics/skill-runs.jsonl` come ultimo append PRIMA del commit di Step 7; il file è incluso nella lista di stage esplicita e il conflict protocol di `mw-docs` lo riconosce come append-only (vedi categoria "Append-only logs" sopra). Risultato: due PRD paralleli che terminano insieme producono un append di entrambe le righe nel file su `develop`, senza intervento manuale.
60
+
61
+ ### Why MINOR and not PATCH
62
+
63
+ Nuova capability portata da una skill esistente (`worktree-manager` guadagna l'API docs mode) + cambio di workflow per `/prd` (gira sempre in worktree). Nessun breaking change per i consumer: le sessioni PRD esistenti pre-3.22.0 sono detettate in Step 0 e gestite con prompt di migrazione (legacy mode resta supportato). La decision tree di `MAINTAINING.md` classifica "added capability" come MINOR.
64
+
65
+ ### Why no schema-change propagation
66
+
67
+ Zero nuove chiavi in `baldart.config.yml`. La modalità docs riusa:
68
+ - `git.merge_strategy` (già esistente da v3.9.0) per il merge — `pr` o `local-push`, rispetta la scelta del progetto.
69
+ - `paths.prd_dir`, `paths.backlog_dir`, `paths.references_dir` (esistenti) — risolti relativamente al worktree (HARD RULE 17).
70
+ - `features.has_prd_workflow` (esistente) — gating della skill.
71
+
72
+ Nota CHANGELOG-only (non normativa): per i PRD molti consumer preferiscono `merge_strategy: local-push` (no PR per documentazione). Chi vuole differenziare la strategia per skill può farlo via overlay `.baldart/overlays/prd.md` — la skill non impone scelte.
73
+
74
+ ### Pre-release code review fixes (within v3.22.0)
75
+
76
+ Un `/code-review` high-effort eseguito prima del tag ha individuato 10 bug — tutti corretti in questa stessa release prima del rilascio. I più gravi:
77
+
78
+ - **`prd-card-writer` agent + `backlog-phase.md` invocation**: il subagent scriveva le card a `backlog/` consumer-root-relative senza alcuna `$WORKTREE_PATH` awareness — Step 5 del PRD spruzzava le card nel main repo, vanificando l'isolamento. Fix: nuova sezione "Working Directory (MANDATORY)" nel file dell'agent + il prompt da `backlog-phase.md` ora passa `WORKING_DIRECTORY` esplicito (regola di substitution documentata).
79
+ - **`ui-design/SKILL.md` Step G**: copia `design.html` a `${paths.prd_dir}/<slug>/design.html` consumer-root-relative. Fix identico: sezione "Working Directory" + `ui-design-phase.md` ora passa `WORKING_DIRECTORY=$WORKTREE_PATH` come arg.
80
+ - **`/prd-add` Step 0**: listava `${paths.prd_dir}/sessions/` sul main repo, zero scan del registry. Fix: Step 0 riscritto — scansiona `.worktrees/registry.json` per `kind: "docs"` prima di guardare il main; gestisce sia worktree-mode che legacy; documenta gli effetti collaterali downstream (delta commit nel worktree, sub-agents ri-invocati con `WORKING_DIRECTORY`, no auto-merge per CR).
81
+ - **Regressione `/new` introdotta dal conflict protocol hardening**: la prima versione della tabella step 4b in `worktree-manager` abortiva blanket il rebase su `ssot-registry.md` / `project-status.md`, ma `/new` AGGIORNA `ssot-registry.md` per ogni card (line 1131 di `framework/.claude/skills/new/SKILL.md`, hook pre-commit che blocca commit a `backlog/` senza ssot). Risultato: ogni batch multi-card di `/new` sarebbe fallito al rebase. Fix: sostituito il blanket abort con **structural validation** (`validate_structured_md` helper) — strip markers + check struttura (no marker residui, no header table duplicati, no frontmatter doppio). Se valido → accept (caso routine: append additivo); se invalido → abort (caso raro: due card hanno modificato la stessa riga). Restituisce a `/new` il comportamento additivo originale, mantiene la protezione contro corruzione reale.
82
+ - **`git stash` in `mw-docs`**: la prima versione riusava verbatim `/mw` step 4b che fa `git stash push --include-untracked` prima del rebase. Violazione diretta della Safety Rule "NEVER use git stash in worktrees" (refs/stash condiviso fra worktree — incidente FEAT-0522). Fix: la sezione `mw-docs` ora esplicita "NO stash" — il safety commit dello step 1 garantisce working tree clean, qualunque dirty post-safety è un errore che richiede STOP, mai uno stash di recovery.
83
+ - **`nw-docs` mancante `.gitignore` check**: la Safety Rule generale dice "Always verify `.worktrees/` is in `.gitignore` before creating", ma `nw-docs` la omette. Fix: step 0 di `nw-docs` è ora un pre-flight `.gitignore` check che fallisce con errore esplicito se mancante.
84
+ - **`nw-docs` pseudo-bash relativo invece che assoluto**: il path ritornato come `path` doveva essere assoluto (per HARD RULE 17), ma lo pseudo-code lo settava relativo. Fix: ancorato a `$MAIN_ROOT` esplicito via `git rev-parse --show-toplevel` + `WORKTREE_PATH="$MAIN_ROOT/$WORKTREE_REL"`.
85
+ - **Esempio HARD RULE 17 fuorviante**: l'esempio "RIGHT" mostrava `Write file_path = "$WORKTREE_PATH/..."` come stringa literal. Claude Code NON espande shell variables → o errore "path must be absolute" o creazione di una dir letterale `$WORKTREE_PATH/`. Fix: esempio riscritto con 3 forme "wrong" (main repo, literal var, relative) + 1 "right" (substitution textuale dell'absolute path).
86
+ - **Off-by-one cross-ref Metrics Log**: "Add the file to Step 7 point 5" ma il staging è point 6 (point 5 è il Metrics Log step stesso, self-referential). Fix: cross-ref corretto a point 6 con nota di disambiguazione.
87
+ - **Case pattern `*.jsonl` non raggiungibile per il secondo arm + auto-strip non desiderato per fixture**: `*.jsonl|docs/metrics/*.jsonl` matchava ogni `.jsonl` ovunque (anche fixture/seed). Fix: tabella sostituita con pattern espliciti — `docs/metrics/*.jsonl` auto-resolve, altri `*.jsonl` abort + manuale.
88
+ - **Numerazione stale "Step 1, point 7"** in `discovery-phase.md` § 1.6: dopo la renumerazione, point 7 è "Context Loading", non l'output kickoff. Fix: aggiornato a "point 9 (Business Rationale Extraction is the final point)".
89
+
90
+ ### Verification
91
+
92
+ Modifiche applicate ma non testabili automaticamente (nessuna test suite in questo repo, come da `CLAUDE.md`). Validazione richiesta in un consumer reale:
93
+ 1. Lanciare `/prd` su una feature qualunque → verificare la creazione `.worktrees/prd-<slug>/` + entry `kind: "docs"` nel registry.
94
+ 2. Aprire una seconda sessione Claude in parallelo e fare `git status` sul main → deve essere pulito.
95
+ 3. Procedere fino allo Step 7 → verificare il prompt di conferma merge, completare → worktree rimosso, branch eliminato, PRD su `develop`.
96
+ 4. Resume test: chiudere/riaprire la sessione a metà PRD → Step 0 deve trovare il worktree dal registry e `cd` lì.
97
+ 5. `/prd-add` su PRD attivo → deve riusare il worktree esistente, non crearne uno nuovo.
98
+
8
99
  ## [3.21.2] - 2026-05-26
9
100
 
10
101
  Aggiunto un livello di automazione che intercetta il drift fra la skill `/baldart-update` (v3.21.0+) e le sorgenti CLI che essa replica in chat. La skill replica **5 decision point fissi** del comando `npx baldart update`; quando una release tocca `src/commands/update.js` (nuovi prompt), `src/utils/hooks.js` (nuove entry in `HOOK_REGISTRY`), o `framework/templates/baldart.config.template.yml` (nuove top-level key), la skill può silenziosamente disallinearsi. Il bug v3.21.0 → v3.21.1 (`git -C .framework fetch` errato) è già stato un esempio del problema: la skill prometteva un pattern che il test live ha smentito. Senza un meccanismo di alert, futuri drift sarebbero individuabili solo per accidente.
package/VERSION CHANGED
@@ -1 +1 @@
1
- 3.21.2
1
+ 3.22.1
@@ -8,6 +8,42 @@ color: amber
8
8
 
9
9
  You are **PRD Card Writer** — a specialist agent that converts an approved PRD into a set of atomic, well-structured backlog cards with full traceability.
10
10
 
11
+ ## Working Directory (MANDATORY — read FIRST, since v3.22.0)
12
+
13
+ When invoked by `/prd` Step 5 the caller passes a **`WORKING_DIRECTORY`** field
14
+ in the prompt — its value is the absolute path of the docs worktree where the
15
+ PRD lives (e.g. `/Users/alice/proj/.worktrees/prd-menu-info`). All your file
16
+ writes MUST land **inside** this directory, otherwise the cards spray into the
17
+ consumer's main repo and HARD RULE 17 of `/prd` SKILL.md is broken (cards
18
+ become invisible to the worktree's commit, isolation collapses, parallel
19
+ sessions get polluted `git status`).
20
+
21
+ **Rule of thumb:** every path in this document — `backlog/`,
22
+ `${paths.backlog_dir}/`, `docs/references/ssot-registry.md`,
23
+ `${paths.references_dir}/...`, the card template — is **relative to
24
+ WORKING_DIRECTORY**. Before any `Write`, `Read`, `Glob`, or `Grep` call,
25
+ construct the absolute path as `<WORKING_DIRECTORY>/<relative-path>`.
26
+
27
+ **Examples:**
28
+ - ❌ `Write(file_path="backlog/FEAT-0500-00-...yml")` — relative path: Claude
29
+ Code rejects, or resolves against the wrong cwd.
30
+ - ❌ `Write(file_path="/Users/alice/proj/backlog/FEAT-0500-00-...yml")` —
31
+ absolute, but main-repo: defeats the worktree.
32
+ - ✅ `Write(file_path="/Users/alice/proj/.worktrees/prd-menu-info/backlog/FEAT-0500-00-...yml")`
33
+ — absolute, inside `WORKING_DIRECTORY`.
34
+
35
+ **Sanity check before writing.** Always begin your work by running
36
+ `Bash("cd <WORKING_DIRECTORY> && pwd && ls -la backlog/ | head -5")` and
37
+ confirming the output matches `WORKING_DIRECTORY`. If it doesn't, halt and
38
+ report — do NOT proceed to write cards on whatever cwd you ended up in.
39
+
40
+ **When the caller does NOT pass `WORKING_DIRECTORY`** (legacy call sites
41
+ predating v3.22.0): fall back to the consumer root (whatever Bash `pwd`
42
+ returns). Log a `[WORKING-DIR-FALLBACK]` warning in your response so the
43
+ caller can detect it and migrate.
44
+
45
+ ---
46
+
11
47
  ## Field Grounding Rule (HARD RULE — zero tolerance)
12
48
 
13
49
  **BEFORE writing any field name in any card**, execute this protocol:
@@ -38,7 +38,7 @@ message. You ask questions, wait for answers, and iterate.
38
38
  | 4b | Confirm Specs | [prd-writing-phase.md](references/prd-writing-phase.md) |
39
39
  | 5 | Backlog Cards | [backlog-phase.md](references/backlog-phase.md) |
40
40
  | 6 | Quality Audit | [validation-phase.md](references/validation-phase.md) |
41
- | 7 | Resolution & Commit | [validation-phase.md](references/validation-phase.md) |
41
+ | 7 | Resolution, Commit & Merge | [validation-phase.md](references/validation-phase.md) |
42
42
 
43
43
  **Before starting each phase, read the corresponding reference file.**
44
44
 
@@ -55,6 +55,7 @@ message. You ask questions, wait for answers, and iterate.
55
55
  7. No code generation. This skill produces planning artifacts only.
56
56
  8. Use exact terminology from `agents/coding-standards.md` and the project's terminology section in `.baldart/overlays/prd.md` (audience segments come from `identity.audience_segments`; domain entities are listed in the overlay).
57
57
  9. Update `${paths.references_dir}/project-status.md` Active Code Context at session start and at commit (AGENTS.md MUST). Skip when the file does not exist in the project.
58
+ **Worktree-mode exception (HARD RULE 17):** when the PRD runs inside a docs worktree (default since v3.22.0), the session-start update is **SKIPPED** — writing `project-status.md` in the worktree wouldn't be visible to other terminals working on the main repo, and writing it on the main repo would pollute `git status` for parallel sessions (exactly what worktree isolation is meant to prevent). The at-commit update still applies and runs inside the worktree as the last write before rebase + merge — see [validation-phase.md](references/validation-phase.md) § Step 7.
58
59
  10. **STOP means STOP.** When you see `STOP`, end your message. Do not make more tool
59
60
  calls. Do not continue to the next step. Wait for the user.
60
61
  11. **Every message MUST end with the Progress Bar.** No exceptions.
@@ -108,6 +109,88 @@ message. You ask questions, wait for answers, and iterate.
108
109
  riusa esattamente questa stessa procedura di Step 1.6 → Step 3 entra in Hybrid mode.
109
110
  Vedi [ui-design-phase.md](references/ui-design-phase.md) § "Step 3.0 — Mockup Source Decision".
110
111
 
112
+ 17. **Worktree isolation (MANDATORY since v3.22.0).** Every PRD session runs inside
113
+ a dedicated **docs worktree** created by the `worktree-manager` skill in
114
+ programmatic docs mode — never on the consumer's main checkout. The worktree
115
+ isolates PRD artefacts from other parallel Claude sessions: `git status` on
116
+ the main repo stays clean, accidental stashes / commits / push from sibling
117
+ `/new` runs cannot pick up PRD files, and the merge back into `develop`
118
+ becomes a single atomic operation.
119
+
120
+ **Why this exists.** Without the worktree, every PRD pollutes the main
121
+ checkout with `${paths.prd_dir}/<slug>/PRD.md`, `${paths.prd_dir}/sessions/...`,
122
+ `${paths.backlog_dir}/FEAT-XXXX-*.yml`, plus design assets and updated
123
+ SSOT/project-status files. With 5-10 parallel sessions, this is unworkable.
124
+
125
+ **Lifecycle (deterministic, no opt-in):**
126
+ - **Step 1 (Kickoff)** — after computing `<slug>`, before writing ANY file,
127
+ call `worktree-manager` programmatic `nw-docs` with `{ slug: <slug> }`.
128
+ Save the returned `path` as `$WORKTREE_PATH` in the state file under
129
+ `## Worktree` (path, branch, kind: "docs"). Then `cd "$WORKTREE_PATH"`
130
+ and run `pwd` to verify. From this moment, EVERY file write happens inside
131
+ the worktree. See [discovery-phase.md](references/discovery-phase.md) § Step 1.
132
+ - **Step 0 (Context Recovery)** — when resuming a `/prd` or running
133
+ `/prd-add`, scan `.worktrees/registry.json` for entries with
134
+ `kind: "docs"` matching the slug; if found, `cd` into that worktree
135
+ before scanning for state files. See [discovery-phase.md](references/discovery-phase.md) § Step 0.
136
+ - **Step 7 (Commit & Merge)** — commit happens inside the worktree, then
137
+ `worktree-manager` programmatic `mw-docs` is invoked immediately to
138
+ rebase onto `origin/develop` and land the PRD via the configured
139
+ `git.merge_strategy`. Seamless by default, no confirmation gate (the
140
+ user opted into the full pipeline when they ran `/prd`). If the user
141
+ explicitly says "non mergiare" / "lascia il worktree", honor the
142
+ override and stop after the commit. See [validation-phase.md](references/validation-phase.md) § Step 7.
143
+
144
+ **Path resolution rule (CRITICAL — read carefully).** Claude Code's
145
+ `Write` / `Edit` / `Read` tools require ABSOLUTE paths and **do NOT
146
+ expand shell variables**. All `${paths.X}` references in this skill and
147
+ its phase references are relative to the worktree for the entire
148
+ session — but you must construct the final absolute path **textually
149
+ by concatenation**, never by passing the literal string `$WORKTREE_PATH`
150
+ to a tool call.
151
+
152
+ The variable name `$WORKTREE_PATH` used throughout this document is a
153
+ **placeholder for the absolute path returned by `nw-docs` at Step 1**
154
+ (e.g. `/Users/alice/my-project/.worktrees/prd-menu-info`). Substitute
155
+ that absolute path before every Write/Edit. Worked example:
156
+
157
+ ```
158
+ # State: nw-docs returned path="/Users/alice/my-project/.worktrees/prd-menu-info"
159
+ # Goal: write PRD.md for slug=menu-info
160
+
161
+ # ❌ WRONG #1 — writes to main repo, defeats isolation:
162
+ Write(file_path="/Users/alice/my-project/docs/prd/menu-info/PRD.md")
163
+
164
+ # ❌ WRONG #2 — literal $WORKTREE_PATH string:
165
+ Write(file_path="$WORKTREE_PATH/docs/prd/menu-info/PRD.md")
166
+ # Claude Code rejects ("path must be absolute") or creates a literal
167
+ # directory named "$WORKTREE_PATH" in the current cwd.
168
+
169
+ # ❌ WRONG #3 — relative path (also rejected by Write/Edit):
170
+ Write(file_path="docs/prd/menu-info/PRD.md")
171
+
172
+ # ✅ RIGHT — substitute the absolute path you got from nw-docs:
173
+ Write(file_path="/Users/alice/my-project/.worktrees/prd-menu-info/docs/prd/menu-info/PRD.md")
174
+ ```
175
+
176
+ Before every Write/Edit, mentally check: "does this path string start
177
+ with the absolute `nw-docs` path I saved at Step 1?" If not, you've
178
+ broken isolation. The exception is `/tmp/...` paths used for transient
179
+ reports (e.g., audit phase Step 2 step f) — those are intentionally
180
+ outside any worktree.
181
+
182
+ **Forbidden operations during the session:**
183
+ - `git checkout` / `git switch` / `git branch` on the main repo (worktree-manager Safety Rules).
184
+ - `git stash` anywhere (shared `refs/stash` across worktrees — see Safety Rules in worktree-manager).
185
+ - Writing to the main repo's `${paths.prd_dir}`, `${paths.backlog_dir}`,
186
+ or `${paths.references_dir}` directly. Only the merge in Step 7 touches `develop`.
187
+
188
+ **Exception — when the worktree cannot be created.** If `git worktree add`
189
+ fails (e.g., `.worktrees/` not in `.gitignore`, disk full, repo not a git
190
+ repository, or the consumer has explicitly disabled docs worktrees via
191
+ overlay), STOP and report the error to the user. Do NOT silently fall back
192
+ to writing on the main repo — that defeats the entire purpose of this rule.
193
+
111
194
  ---
112
195
 
113
196
  ## TEMPLATES
@@ -121,12 +204,16 @@ Use these templates when creating artifacts:
121
204
  | Backlog epic (always 1) | [assets/epic-template.yml](assets/epic-template.yml) |
122
205
  | Backlog child card (N≥1) | [assets/card-template.yml](assets/card-template.yml) |
123
206
 
124
- **State file location:** `${paths.prd_dir}/sessions/YYYY-MM-DD-<slug>-state.md`
125
- **PRD location:** `${paths.prd_dir}/<slug>/PRD.md`
126
- **Design location:** `${paths.prd_dir}/<slug>/design.html`
207
+ **State file location:** `$WORKTREE_PATH/${paths.prd_dir}/sessions/YYYY-MM-DD-<slug>-state.md`
208
+ **PRD location:** `$WORKTREE_PATH/${paths.prd_dir}/<slug>/PRD.md`
209
+ **Design location:** `$WORKTREE_PATH/${paths.prd_dir}/<slug>/design.html`
127
210
  **Cards location:**
128
- - Epic: `${paths.backlog_dir}/FEAT-XXXX-00-<slug>-epic.yml` (mandatory when `features.has_backlog: true`)
129
- - Children: `${paths.backlog_dir}/FEAT-XXXX-NN-<sub-slug>.yml` for N=1..M (at least 1)
211
+ - Epic: `$WORKTREE_PATH/${paths.backlog_dir}/FEAT-XXXX-00-<slug>-epic.yml` (mandatory when `features.has_backlog: true`)
212
+ - Children: `$WORKTREE_PATH/${paths.backlog_dir}/FEAT-XXXX-NN-<sub-slug>.yml` for N=1..M (at least 1)
213
+
214
+ **`$WORKTREE_PATH`** is set in Step 1 (Kickoff) by `worktree-manager nw-docs` —
215
+ see HARD RULE 17. Until Step 1 has run, no file writes are allowed; until then
216
+ the value lives only in the state file `## Worktree` section.
130
217
 
131
218
  ---
132
219
 
@@ -146,7 +233,7 @@ At the END of every message (after all text, before stopping), display:
146
233
  | 2 | Design UI & approvazione | ⬜/🔄/✅/⏭️ |
147
234
  | 3 | Conferma specifiche | ⬜/🔄/✅ |
148
235
  | 4 | Creazione backlog cards | ⬜/🔄/✅ |
149
- | 5 | Validazione e commit | ⬜/🔄/✅ |
236
+ | 5 | Validazione, commit & merge | ⬜/🔄/✅ |
150
237
 
151
238
  Comprensione: X% (N/M dimensioni coperte) — ISA: N punti identificati
152
239
  Mockup: ⬜ non chiesto / 🔄 in attesa / ✅ N mockup / ⏭️ nessuno
@@ -231,7 +318,7 @@ Dimension 10 uses a built-in evaluation tree (see discovery-phase.md).
231
318
  | 2 | Design UI & approvazione | ✅/⏭️ |
232
319
  | 3 | Conferma specifiche | ✅ |
233
320
  | 4 | Creazione backlog cards | ✅ |
234
- | 5 | Validazione e commit | ✅ |
321
+ | 5 | Validazione, commit & merge | ✅ |
235
322
 
236
323
  Comprensione: 100%
237
324
  Mockup: ✅ N mockup analizzati / ⏭️ nessuno fornito
@@ -242,9 +329,22 @@ Step 3 mode: full / hybrid / skipped
242
329
 
243
330
  ---
244
331
 
245
- ## Metrics Log (MANDATORY — after Phase 5 Validazione)
332
+ ## Metrics Log (MANDATORY — runs inside Step 7, BEFORE the commit)
333
+
334
+ After cards are created and audited (Steps 5-6) and BEFORE the explicit stage in
335
+ validation-phase.md Step 7 point 5, log this PRD run to the skill-runs file.
246
336
 
247
- After cards are created and committed, log this PRD run to `docs/metrics/skill-runs.jsonl`.
337
+ **Location (HARD RULE 17 applies):**
338
+ `$WORKTREE_PATH/docs/metrics/skill-runs.jsonl`
339
+
340
+ The file is committed together with the rest of the PRD artefacts in Step 7,
341
+ so it flows into `develop` via `mw-docs` atomically with the PRD.
342
+
343
+ **Conflict resilience.** JSONL is line-oriented and additive: when two parallel
344
+ PRDs both append a line and one rebases onto the other, the doc-friendly conflict
345
+ protocol in `worktree-manager` step 4b auto-resolves the `.jsonl` conflict by
346
+ keeping both lines (this is the one canonical case where "keep both sides" is
347
+ exactly the correct semantics). No special handling needed.
248
348
 
249
349
  **Steps:**
250
350
 
@@ -256,10 +356,13 @@ After cards are created and committed, log this PRD run to `docs/metrics/skill-r
256
356
  - `has_db_indexes_pct`: % of cards that have a `db_indexes` field (covers any persistence layer; legacy `firestore_indexes` cards count too)
257
357
  - `discovery_iterations`: approximate number of Q&A rounds with the user (count AskUserQuestion calls in this session, default 1 if unknown)
258
358
 
259
- 2. Write ONE JSON line (append) to `docs/metrics/skill-runs.jsonl`:
359
+ 2. Append ONE JSON line to `$WORKTREE_PATH/docs/metrics/skill-runs.jsonl`
360
+ (create the file + parent directory if absent):
260
361
 
261
362
  ```json
262
363
  {"ts":"<ISO-8601-UTC>","skill":"prd","run_id":"prd-<slug>","prd_slug":"<slug>","cards_created":0,"ac_coverage_ratio":0.0,"isa_count":0,"has_test_plan_pct":0.0,"has_db_indexes_pct":0.0,"discovery_iterations":1,"prd_path":"${paths.prd_dir}/<slug>/PRD.md"}
263
364
  ```
264
365
 
265
- **This step is NON-BLOCKING** if it fails, do not abort. Log "Metrics Log: SKIPPED" in the progress bar.
366
+ 3. Add the file to the explicit stage list in validation-phase.md Step 7 point 6 (the stage list is at point 6; point 5 is the invocation of this very Metrics Log step).
367
+
368
+ **This step is NON-BLOCKING** — if it fails, do not abort. Log "Metrics Log: SKIPPED" in the progress bar. The PRD merge proceeds regardless.
@@ -2,6 +2,13 @@
2
2
  Created: {{YYYY-MM-DD HH:MM}}
3
3
  Status: discovery
4
4
 
5
+ ## Worktree
6
+ - path: {{absolute worktree path returned by worktree-manager nw-docs}}
7
+ - branch: prd/{{slug}}
8
+ - kind: docs
9
+ - created_at: {{ISO-8601 UTC}}
10
+ - merge_commit: (pending — populated by validation-phase Step 7 after mw-docs)
11
+
5
12
  ## Feature Description
6
13
  {{user's description verbatim}}
7
14
 
@@ -162,9 +162,16 @@ Agent(
162
162
  prompt: """
163
163
  Generate backlog cards from the approved PRD.
164
164
 
165
- PRD path: <prd_path>
166
- State file path: <state_file_path>
167
- Card template: .claude/skills/prd/assets/card-template.yml
165
+ WORKING_DIRECTORY: <$WORKTREE_PATH absolute path>
166
+ (Per HARD RULE 17 of /prd SKILL.md — all file writes must go inside this
167
+ directory, NOT into the consumer's main repo. See your "Working Directory"
168
+ section for the rule and sanity check.)
169
+
170
+ PRD path: <$WORKTREE_PATH>/<prd_path>
171
+ State file path: <$WORKTREE_PATH>/<state_file_path>
172
+ Card template: <$WORKTREE_PATH>/.claude/skills/prd/assets/card-template.yml
173
+ (the template is symlinked from .framework/ into the worktree just like
174
+ in the main repo — the symlink works inside the worktree)
168
175
  Feature slug: <slug>
169
176
 
170
177
  The PRD has been approved by the user. Read it in full, read the state file
@@ -175,7 +182,7 @@ Agent(
175
182
  error_handling, reuse_analysis). Populate them per your field-mapping instructions.
176
183
  Use Grep/Glob to verify file paths and line numbers for existing_patterns and reuse_analysis.
177
184
 
178
- Write all card YAML files to backlog/.
185
+ Write all card YAML files to <$WORKTREE_PATH>/backlog/ (absolute path).
179
186
  Update the state file ## Backlog Cards section with card list and traceability matrices.
180
187
  Return the Parallel Execution Map summary.
181
188
  """,
@@ -183,6 +190,12 @@ Agent(
183
190
  )
184
191
  ```
185
192
 
193
+ **Substitution rule.** In the prompt above, `<$WORKTREE_PATH>` is a textual
194
+ placeholder — the `/prd` skill MUST replace it with the absolute path stored
195
+ in the state file's `## Worktree` section BEFORE invoking the agent. Do NOT
196
+ pass the literal string `$WORKTREE_PATH` — the subagent has no shell context
197
+ to expand it.
198
+
186
199
  ### What the agent handles
187
200
 
188
201
  The `prd-card-writer` agent owns the entire card writing pipeline:
@@ -4,15 +4,36 @@
4
4
 
5
5
  Run BEFORE any other step.
6
6
 
7
- 1. Check if `${paths.prd_dir}/sessions/` contains a state file for the current feature.
8
- 2. If found: read it, identify last completed step, resume from next pending step.
9
- 3. If not found: fresh session, proceed to Step 1.
10
-
11
- Triggers: session start, context compression, re-invocation of `/prd`.
7
+ 1. **Worktree lookup (since v3.22.0)** read `.worktrees/registry.json` from
8
+ the main repo and scan for an entry with `kind: "docs"` whose `slug` matches
9
+ the feature the user just mentioned (or that you can infer from their
10
+ message — e.g., `/prd-add` for an active PRD).
11
+ - **Found**: `cd` into the worktree's `path` (save as `$WORKTREE_PATH`),
12
+ log "Resuming PRD session in worktree `<path>`", then continue to step 2.
13
+ All subsequent file paths in this skill resolve under `$WORKTREE_PATH`
14
+ (HARD RULE 17).
15
+ - **Not found, but main repo has a stale state file** at
16
+ `${paths.prd_dir}/sessions/*-<slug>-state.md`: this is a pre-v3.22.0 PRD
17
+ session created before the worktree mandate. ASK the user: "Found a
18
+ legacy PRD state file outside any worktree. Migrate it to a fresh docs
19
+ worktree before resuming, or continue on the main repo (legacy mode)?"
20
+ If migrate: create the worktree via `nw-docs`, `git mv` the relevant
21
+ files into it. If legacy mode: STOP and warn that parallel sessions
22
+ will pollute `git status`.
23
+ - **Not found and no state file**: fresh session, proceed to Step 1.
24
+ 2. With `$WORKTREE_PATH` resolved (or null for fresh sessions), check if
25
+ `$WORKTREE_PATH/${paths.prd_dir}/sessions/` contains a state file for the
26
+ current feature.
27
+ 3. If found: read it, identify last completed step, resume from next pending step.
28
+ 4. If not found: proceed to Step 1.
29
+
30
+ Triggers: session start, context compression, re-invocation of `/prd`, every
31
+ `/prd-add` invocation.
12
32
 
13
33
  ## Step 1 — Kickoff
14
34
 
15
- **Precondition:** user has described the feature.
35
+ **Precondition:** user has described the feature; Step 0 ran and confirmed
36
+ this is a fresh session (no existing state file).
16
37
 
17
38
  1. Derive `<slug>`: kebab-case, lowercase, max 40 chars, no special chars.
18
39
  Example: "Nutritional info on menu" -> `menu-nutritional-info`
@@ -22,16 +43,44 @@ Triggers: session start, context compression, re-invocation of `/prd`.
22
43
  `## Obsidian Spec Note: [[Note Name]]`. This will be added to Canonical Sources in the PRD.
23
44
  - Read the note content from the vault path in memory (`reference_obsidian_vault.md`)
24
45
  to pre-populate discovery dimensions where possible — treat it as a user-provided spec.
25
- 3. Create state file: `${paths.prd_dir}/sessions/YYYY-MM-DD-<slug>-state.md`
26
- using template from `assets/state-template.md`.
27
- 3. Create 5 macro-tasks via TaskCreate:
46
+ 3. **Create the docs worktree (MANDATORY — HARD RULE 17)** — invoke the
47
+ `worktree-manager` skill in programmatic docs mode BEFORE any file write:
48
+
49
+ ```
50
+ Skill: worktree-manager
51
+ Mode: programmatic, nw-docs
52
+ Input: { "slug": "<slug>" }
53
+ ```
54
+
55
+ On success the skill returns `{ path, branch, kind: "docs" }`. Save
56
+ `path` as `$WORKTREE_PATH` for the entire session.
57
+
58
+ Verify the working directory is the worktree:
59
+
60
+ ```bash
61
+ cd "$WORKTREE_PATH"
62
+ pwd
63
+ # MUST print the absolute worktree path. If pwd shows the main repo root,
64
+ # STOP — every Write/Edit you make next will pollute the main checkout.
65
+ ```
66
+
67
+ **Failure handling.** If `nw-docs` fails (e.g., `.worktrees/` not in
68
+ `.gitignore`, slug already in registry as a non-docs entry, repo not
69
+ initialized), STOP and surface the error verbatim. Do NOT fall back to
70
+ writing on the main repo — that breaks HARD RULE 17.
71
+
72
+ 4. **Create state file** inside the worktree:
73
+ `$WORKTREE_PATH/${paths.prd_dir}/sessions/YYYY-MM-DD-<slug>-state.md`
74
+ using template from `assets/state-template.md`. Populate the `## Worktree`
75
+ section with `path`, `branch`, `kind: docs`, `created_at` (ISO-8601 UTC).
76
+ 5. Create 5 macro-tasks via TaskCreate:
28
77
  - `[PRD] Discovery & comprensione feature`
29
78
  - `[PRD] Design UI & approvazione`
30
79
  - `[PRD] Conferma specifiche complete`
31
80
  - `[PRD] Creazione backlog cards`
32
- - `[PRD] Validazione e commit`
33
- 4. Mark task 1 as `in_progress`.
34
- 5. **Context Loading (MANDATORY):** invoke the context-primer skill (`/cont`) with
81
+ - `[PRD] Validazione, commit & merge`
82
+ 6. Mark task 1 as `in_progress`.
83
+ 7. **Context Loading (MANDATORY):** invoke the context-primer skill (`/cont`) with
35
84
  2-4 keywords extracted from the user's feature description. This launches
36
85
  `codebase-architect` which searches the Obsidian-first LightRAG MCP index,
37
86
  docs, backlog, source code, and git history. The returned context informs all
@@ -39,10 +88,10 @@ Triggers: session start, context compression, re-invocation of `/prd`.
39
88
  feature domain. Use Obsidian hits for concept context, then verify
40
89
  implementation and stateful claims against repo docs/code before carrying
41
90
  them into the PRD.
42
- 6. Mark clearly irrelevant dimensions as "N/A" with reason
91
+ 8. Mark clearly irrelevant dimensions as "N/A" with reason
43
92
  (e.g., backend-only -> UI impact = N/A).
44
93
  If UI impact is N/A, immediately mark task 2 as `completed` ("Skipped — no UI").
45
- 7. **Business Rationale Extraction (MANDATORY):** Before entering the discovery loop,
94
+ 9. **Business Rationale Extraction (MANDATORY):** Before entering the discovery loop,
46
95
  evaluate the user's initial feature description for business rationale signals:
47
96
  - WHY is this feature needed? (business motivation)
48
97
  - What customer/market signal triggered it?
@@ -59,10 +108,16 @@ Triggers: session start, context compression, re-invocation of `/prd`.
59
108
  **Output:**
60
109
 
61
110
  ```
62
- Ho creato la sessione PRD per **<slug>**.
111
+ Ho creato la sessione PRD per **<slug>** in un worktree dedicato.
63
112
 
113
+ Worktree: <relative-worktree-path>
114
+ Branch: prd/<slug>
64
115
  Descrizione: <user's description>
65
- Contesto caricato: <one-line summary from context-primer>
116
+ Contesto: <one-line summary from context-primer>
117
+
118
+ Tutti i file del PRD vivono nel worktree — il main repo resta pulito.
119
+ Al termine commit + merge automatico in develop + cleanup worktree, seamless.
120
+ (Se in qualunque momento mi dici "non mergiare", mi fermo dopo il commit.)
66
121
 
67
122
  Ora comincio la fase di **Discovery** — ti faro delle domande per capire bene
68
123
  la feature prima di scrivere qualsiasi documento.
@@ -70,7 +125,9 @@ la feature prima di scrivere qualsiasi documento.
70
125
  <Progress Bar>
71
126
  ```
72
127
 
73
- **Gate:** state file exists on disk AND all tasks created AND context loaded.
128
+ **Gate:** docs worktree created (registry entry with `kind: "docs"` present)
129
+ AND state file exists on disk inside the worktree AND all tasks created AND
130
+ context loaded.
74
131
 
75
132
  **Immediately proceed to Step 1.6** — do NOT stop here. Show the kickoff message
76
133
  and ask the mockup intake question in the same turn.
@@ -86,7 +143,7 @@ result.
86
143
 
87
144
  ### 1.6.1 — Ask
88
145
 
89
- After the kickoff output (Step 1, point 7), append this question to the SAME message:
146
+ After the kickoff output (Step 1, point 9 — Business Rationale Extraction is the final point of the Kickoff step since the v3.22.0 renumbering), append this question to the SAME message:
90
147
 
91
148
  ```
92
149
  ### Domanda — Mockup
@@ -118,6 +118,13 @@ The skill handles the full pipeline:
118
118
 
119
119
  When invoking `ui-design`, ensure it has access to:
120
120
 
121
+ - **`WORKING_DIRECTORY`** — the absolute path of the PRD's docs worktree,
122
+ read from the state file `## Worktree` section. Pass it explicitly in the
123
+ args (e.g. `WORKING_DIRECTORY=<absolute-path-of-$WORKTREE_PATH>`) so the
124
+ skill's Step G saves `design.html` inside the worktree, not into the
125
+ consumer's main repo. Without this, the design lands on main, the `/prd`
126
+ Step 7 stage list can't find it, and the merged PRD ships without its
127
+ design asset. See `ui-design/SKILL.md` § "Working Directory" (added v3.22.0).
121
128
  - Feature description (from state file `## Feature Description`)
122
129
  - All discovery answers relevant to UI (from state file `## Discovery Log`)
123
130
  - The `<slug>` for file naming
@@ -49,34 +49,115 @@ Mark task 5 as `in_progress`.
49
49
 
50
50
  **Gate:** all HIGH/MEDIUM findings resolved, no open `[MANUAL]` items.
51
51
 
52
- ## Step 7 — Resolution and Commit
52
+ ## Step 7 — Resolution, Commit & Merge
53
53
 
54
- **Precondition:** Step 6 complete.
54
+ **Precondition:** Step 6 complete; the session is running inside a docs worktree
55
+ created by Step 1 (HARD RULE 17). `$WORKTREE_PATH` is set in the state file.
55
56
 
56
57
  ### Resolve remaining items
57
58
 
58
59
  1. If `[MANUAL]` items remain: resolve each one.
59
60
  2. If resolution required card re-edits: re-run the audit protocol (audit-phase.md) on affected cards.
60
61
 
61
- ### Update knowledge base
62
-
63
- 3. Add/update entry in `${paths.references_dir}/ssot-registry.md` pointing to the new PRD
64
- as canonical source for this macro feature.
65
- 4. Update `${paths.references_dir}/project-status.md` Active Code Context with PRD completion.
66
-
67
- ### Commit
68
-
69
- 5. Stage ONLY PRD session artifacts (explicit file names, never `git add .`):
70
- - `${paths.prd_dir}/sessions/YYYY-MM-DD-<slug>-state.md`
71
- - `docs/prd/<slug>/PRD.md`
72
- - `docs/prd/<slug>/design.html` (if exists)
73
- - `backlog/FEAT-XXXX-*.yml` (all cards created in Step 5)
74
- - `${paths.references_dir}/ssot-registry.md` (if updated)
75
- - `${paths.references_dir}/project-status.md` (if updated)
76
- 6. Update state file: status -> `completed`, add commit hash to `## Validation`.
77
- 7. Commit with format: `[PRD] <slug>: <brief description>`
78
-
79
- **Gate:** commit successful, state file shows `completed`.
62
+ ### Update knowledge base (inside the worktree)
63
+
64
+ 3. Add/update entry in `$WORKTREE_PATH/${paths.references_dir}/ssot-registry.md`
65
+ pointing to the new PRD as canonical source for this macro feature. **Skip
66
+ when the file does not exist in the project** (some consumers don't maintain
67
+ one — check the path before writing).
68
+ 4. Update `$WORKTREE_PATH/${paths.references_dir}/project-status.md` Active Code
69
+ Context with PRD completion. **Skip when the file does not exist.**
70
+
71
+ **Note on cross-PRD collisions.** Both files (`ssot-registry.md` and
72
+ `project-status.md`) live on `develop` and are touched by other PRD sessions
73
+ in parallel. The rebase in step 8 below brings the worktree up to the latest
74
+ `origin/develop` BEFORE the merge, so two parallel PRDs ending at the same
75
+ time produce a clean append-only diff in most cases. If the rebase reports
76
+ conflicts on these two files specifically, the `worktree-manager mw-docs`
77
+ protocol stops and asks for manual resolution do NOT auto-strip merge
78
+ markers on structured files like these.
79
+
80
+ ### Commit (inside the worktree)
81
+
82
+ 5. **Run the Metrics Log step from SKILL.md** ("Metrics Log — MANDATORY") FIRST
83
+ — it appends the run summary to `$WORKTREE_PATH/docs/metrics/skill-runs.jsonl`,
84
+ which must be part of the same commit. Non-blocking: if it fails, log
85
+ "Metrics Log: SKIPPED" in the progress bar and continue.
86
+
87
+ 6. Stage ONLY PRD session artefacts by explicit file name (NEVER `git add .`
88
+ or `git add -A`):
89
+ - `$WORKTREE_PATH/${paths.prd_dir}/sessions/YYYY-MM-DD-<slug>-state.md`
90
+ - `$WORKTREE_PATH/${paths.prd_dir}/<slug>/PRD.md`
91
+ - `$WORKTREE_PATH/${paths.prd_dir}/<slug>/design.html` (if exists)
92
+ - `$WORKTREE_PATH/${paths.prd_dir}/<slug>/mockups/**` (if any)
93
+ - `$WORKTREE_PATH/${paths.backlog_dir}/FEAT-XXXX-*.yml` (all cards from Step 5)
94
+ - `$WORKTREE_PATH/${paths.references_dir}/ssot-registry.md` (if updated)
95
+ - `$WORKTREE_PATH/${paths.references_dir}/project-status.md` (if updated)
96
+ - `$WORKTREE_PATH/docs/metrics/skill-runs.jsonl` (if the Metrics Log step in 5 wrote a line)
97
+
98
+ Verify staged set with `git -C "$WORKTREE_PATH" diff --staged --name-only`.
99
+
100
+ 7. Update state file: status -> `completed`, add `worktree.branch`, will fill
101
+ commit hash after the commit lands.
102
+
103
+ 8. Commit with format: `[PRD] <slug>: <brief description>`
104
+ ```bash
105
+ git -C "$WORKTREE_PATH" commit -m "[PRD] <slug>: <brief description>"
106
+ ```
107
+ Capture the SHA via `git -C "$WORKTREE_PATH" rev-parse HEAD` and write it
108
+ back into the state file under `## Validation`.
109
+
110
+ ### Merge into develop (worktree-manager mw-docs)
111
+
112
+ 9. **Invoke `worktree-manager` programmatic mw-docs immediately** — no
113
+ confirmation prompt. The user opted into the full PRD pipeline when they
114
+ ran `/prd`; chiedere conferma a fine sessione è friction inutile e rompe
115
+ il "seamless" che è il punto della v3.22.0.
116
+
117
+ The merge is recoverable: if something goes wrong post-merge the user can
118
+ `git revert` on develop just like any other commit. The hard-to-reverse
119
+ operations (`git push`, branch deletion) happen inside `mw-docs` which
120
+ has its own failure handling (rebase abort, push rejection, gh CLI error)
121
+ — none of which silently corrupts state.
122
+
123
+ **Escape hatch.** If the user explicitly says "non mergiare" or "lascia il
124
+ worktree" at any point during Step 7 (e.g. they want to review the PRD
125
+ manually before it lands on develop), respect that and STOP after the
126
+ commit — the worktree stays on disk, ready for a future manual `/mw` or
127
+ `worktree-manager mw-docs`. This is a user-initiated override, not a
128
+ default gate.
129
+
130
+ 10. **Invoke `worktree-manager` programmatic mw-docs**:
131
+
132
+ ```
133
+ Skill: worktree-manager
134
+ Mode: programmatic, mw-docs
135
+ Input: { "worktreePath": "$WORKTREE_PATH" }
136
+ ```
137
+
138
+ The skill executes:
139
+ - Safety commit (idempotent — likely no-op after step 8).
140
+ - `git fetch origin develop` + `git rebase origin/develop` inside the worktree.
141
+ - Conflict auto-resolution table (see `/mw` step 4b): additive docs/yaml and
142
+ append-only `.jsonl` files auto-resolve; **structured registries**
143
+ (`project-status.md`, `ssot-registry.md`, `field-registry.*`,
144
+ `traceability-matrix.md`, `REGISTRY.md`) abort the rebase and report —
145
+ these must be resolved manually because blindly stripping markers would
146
+ corrupt their internal structure.
147
+ - Merge via the configured `git.merge_strategy` (`pr` or `local-push`).
148
+ - Cleanup: `git worktree remove` + `git branch -d` + registry entry removal.
149
+ - Local develop ref sync (only if main repo HEAD is already `develop`).
150
+
151
+ On success it returns `{ merged: true, mergeCommit, prNumber, strategy,
152
+ worktreeRemoved: true }`.
153
+
154
+ **Failure handling.** If `mw-docs` reports failure (rebase conflicts, push
155
+ rejected, gh CLI error, post-cleanup error): STOP and surface the error
156
+ verbatim. The worktree stays on disk so the user can investigate. Do NOT
157
+ retry automatically — the next attempt should be user-driven.
158
+
159
+ **Gate:** `mw-docs` returned `merged: true` AND `worktreeRemoved: true` AND
160
+ the state file (now on `develop` via the merge) shows `completed`.
80
161
 
81
162
  Mark task 5 as `completed`.
82
163
 
@@ -84,9 +165,11 @@ Mark task 5 as `completed`.
84
165
 
85
166
  Print final summary:
86
167
 
87
- - PRD path
168
+ - PRD path (relative to repo root, e.g. `docs/prd/<slug>/PRD.md`)
88
169
  - Design path (if applicable)
89
170
  - Card IDs created
90
- - Commit hash
171
+ - Branch & merge strategy used
172
+ - PR number (if `strategy = pr`) or merge SHA (if `local-push`)
173
+ - Confirmation that the worktree was cleaned up
91
174
 
92
175
  Display completed Progress Bar.
@@ -64,11 +64,54 @@ Sequential, single-turn analysis + selective multi-turn re-execution.
64
64
 
65
65
  ## Step 0 — Session Locate
66
66
 
67
- 1. List `${paths.prd_dir}/sessions/` for state files.
68
- 2. If exactly ONE active session (status != `completed`): use it.
69
- 3. If multiple active sessions: ask user which one.
70
- 4. If zero sessions: inform user, suggest `/prd` instead.
71
- 5. Read the state file AND the PRD document (if exists).
67
+ **Since v3.22.0, active PRD sessions live inside docs worktrees** created by
68
+ `/prd` Step 1 (HARD RULE 17 of `/prd` SKILL.md). The main repo's
69
+ `${paths.prd_dir}/sessions/` may be EMPTY even when there are active sessions
70
+ each one lives at `<docs-worktree>/${paths.prd_dir}/sessions/`. This step
71
+ must scan the worktree registry FIRST, then fall back to the main repo for
72
+ legacy sessions.
73
+
74
+ 1. **Read `.worktrees/registry.json` from the main repo root.** Filter entries
75
+ with `kind: "docs"`. For each, list state files at
76
+ `<entry.path>/${paths.prd_dir}/sessions/*.md` and read the first line of
77
+ each to extract `status:` (or scan for `Status:` line — depends on
78
+ state-template.md format). Collect every state with `status != "completed"`
79
+ together with its `WORKING_DIRECTORY` = `<entry.path>` and `branch` =
80
+ `<entry.branch>`.
81
+
82
+ 2. **Also list `${paths.prd_dir}/sessions/` on the main repo** (legacy
83
+ pre-v3.22.0 sessions). Collect any state files there as candidates with
84
+ `WORKING_DIRECTORY` = main repo root.
85
+
86
+ 3. Merge the two lists. Behavior:
87
+ - **Exactly ONE active session**: use it. Save its `WORKING_DIRECTORY` and
88
+ `branch` for every subsequent step.
89
+ - **Multiple active sessions**: ask the user which one, surfacing
90
+ `WORKING_DIRECTORY` (worktree path or "main repo") in the choice list so
91
+ they know where the CR will be written.
92
+ - **Zero sessions**: inform user, suggest `/prd` instead.
93
+
94
+ 4. **`cd "$WORKING_DIRECTORY"`** before any read or write — every subsequent
95
+ step in this skill (intake → impact analysis → selective execution → delta
96
+ commit) MUST happen inside the selected session's directory.
97
+
98
+ 5. Read the state file AND the PRD document (if exists), both resolved under
99
+ `$WORKING_DIRECTORY`.
100
+
101
+ 6. **Worktree-mode side effects for the rest of the skill:**
102
+ - Step 5 "Delta Commit" stages files inside the worktree and commits with
103
+ `git -C "$WORKING_DIRECTORY" commit`. NEVER `git add` on the main repo.
104
+ - If `prd-card-writer` is re-invoked in Step 4 (Backlog Cards REDO), pass
105
+ `WORKING_DIRECTORY: $WORKING_DIRECTORY` in the prompt — same convention
106
+ as backlog-phase.md (see `framework/.claude/agents/prd-card-writer.md` §
107
+ "Working Directory").
108
+ - If `ui-design` is re-invoked in Step 4 (UI Design REDO), pass
109
+ `WORKING_DIRECTORY=$WORKING_DIRECTORY` as args — same convention as
110
+ ui-design-phase.md.
111
+ - The delta commit is NOT auto-merged. Document the new branch tip in the
112
+ `## Change Requests` section. The user merges with the rest of the PRD
113
+ when they run validation-phase.md Step 7 (`mw-docs` is invoked once per
114
+ PRD, not per CR).
72
115
 
73
116
  ---
74
117
 
@@ -28,6 +28,26 @@ Evaluation is always performed by a separate agent with fresh context.
28
28
 
29
29
  **On missing/empty keys:** ask the user; do not assume defaults. See `framework/agents/project-context.md` § 3.
30
30
 
31
+ ## Working Directory (MANDATORY when invoked from `/prd`, since v3.22.0)
32
+
33
+ When `/prd` Step 3 invokes this skill, the caller passes (or sets as cwd) an
34
+ absolute **`WORKING_DIRECTORY`** that points to the PRD's docs worktree
35
+ (e.g. `/Users/alice/proj/.worktrees/prd-menu-info`). All persistent design
36
+ artefacts produced by this skill — most notably the `design.html` saved in
37
+ Step G — MUST be written inside that directory, NOT into the consumer's main
38
+ checkout. Without this, the design lands on the main repo, the `/prd` Step 7
39
+ stage list at `$WORKTREE_PATH/${paths.prd_dir}/<slug>/design.html` finds
40
+ nothing, and the PRD merged into `develop` ships without its design asset.
41
+
42
+ **Rule:** every `${paths.prd_dir}/...` reference in this document — including
43
+ Step G's "Copy approved HTML to `${paths.prd_dir}/<slug>/design.html`" — is
44
+ relative to `WORKING_DIRECTORY` when invoked from `/prd`. Construct the
45
+ absolute target path as `<WORKING_DIRECTORY>/<paths.prd_dir>/<slug>/design.html`
46
+ before any `Write`.
47
+
48
+ **Standalone invocations** (when the user runs `/ui-design` directly, no PRD
49
+ worktree): fall back to the consumer root. No prefix needed.
50
+
31
51
  ---
32
52
 
33
53
  ## Prerequisites — BLOCKING reads before ANY design work
@@ -141,7 +161,7 @@ Invoke a **separate** `code-reviewer` agent (NOT the same agent that generated):
141
161
 
142
162
  Read [references/inventory.md](references/inventory.md).
143
163
 
144
- 1. Copy approved HTML to `${paths.prd_dir}/<slug>/design.html` (if `features.has_prd_workflow: true`; otherwise ask the user where to persist the design).
164
+ 1. Copy approved HTML to `${paths.prd_dir}/<slug>/design.html` (if `features.has_prd_workflow: true`; otherwise ask the user where to persist the design). **When invoked from `/prd` (since v3.22.0), prefix this with `WORKING_DIRECTORY` — see the "Working Directory" section near the top of this file.** Concrete absolute target: `<WORKING_DIRECTORY>/<paths.prd_dir>/<slug>/design.html`.
145
165
  2. Extract UI Element Inventory (sprint contract).
146
166
  3. Update state file with chosen option, design decisions, component lists.
147
167
  4. Clean up `/tmp/prd-design-<slug>/`.
@@ -45,6 +45,207 @@ Output: `{ path: string, branch: string, port: number }`
45
45
  Input: `{ worktreePath: string, checksAlreadyPassed?: boolean }`
46
46
  Output: `{ merged: boolean, developVerified: boolean, prNumber: number|null, mergeCommit: string, strategy: "pr"|"local-push" }`
47
47
 
48
+ ## Programmatic API — docs mode (for /prd orchestrator)
49
+
50
+ The docs mode is the **lean** counterpart to `/nw` and `/mw`. It is intentionally
51
+ stripped down for skills that produce **documentation artefacts only** — PRDs,
52
+ backlog cards, design references — and never touch source code.
53
+
54
+ What docs mode SKIPS vs the standard flow:
55
+ - No `npm install` (no `node_modules/` inside the worktree)
56
+ - No port allocation (no dev server)
57
+ - No `.env`/`.env.local` copy
58
+ - No `npm run build` baseline verification
59
+ - No lint / tsc baseline checks
60
+ - No `--dev` server bootstrap
61
+ - No build / lint / tsc gates at merge time
62
+
63
+ What docs mode KEEPS:
64
+ - Pre-flight `git fetch origin develop` (read-only on the main repo).
65
+ - `git worktree add` branched from `origin/develop`.
66
+ - Registry entry with `kind: "docs"` so `/lw` and `/cw` can list and clean docs worktrees alongside code worktrees.
67
+ - Safety commit at merge time (uncommitted files are never lost).
68
+ - Rebase onto `origin/develop` before merging (prevents PR/FF conflicts).
69
+ - The configured `git.merge_strategy` (`pr` or `local-push`).
70
+ - Cleanup of worktree + local branch + remote branch after merge.
71
+
72
+ Cost target: **< 5 seconds** to create a docs worktree on a typical machine (no
73
+ network beyond the `fetch`, no install, no build). Compare to `/nw` which can
74
+ run for minutes due to `npm install` + build.
75
+
76
+ ### nw-docs programmatic
77
+
78
+ Input:
79
+ ```json
80
+ {
81
+ "slug": "string", // REQUIRED — kebab-case feature slug
82
+ "branchPrefix": "string" // OPTIONAL — defaults to "prd/"
83
+ }
84
+ ```
85
+
86
+ Output:
87
+ ```json
88
+ {
89
+ "path": "string", // absolute worktree path
90
+ "branch": "string", // e.g. "prd/menu-nutritional-info"
91
+ "kind": "docs"
92
+ }
93
+ ```
94
+
95
+ **Steps (run exactly these, nothing else):**
96
+
97
+ ```bash
98
+ # 0. Pre-flight: .gitignore safety check (MANDATORY — Safety Rules
99
+ # "Always verify .worktrees/ is in .gitignore before creating").
100
+ # Without this, the worktree IS git-tracked: `git status` on the main
101
+ # repo explodes with every file inside the worktree, exactly defeating
102
+ # the parallel-isolation purpose of the docs-mode.
103
+ MAIN_ROOT="$(git rev-parse --show-toplevel)"
104
+ if [ ! -f "$MAIN_ROOT/.gitignore" ] || ! grep -qE '^\.worktrees/?$' "$MAIN_ROOT/.gitignore"; then
105
+ echo "ERROR: .worktrees/ is not in $MAIN_ROOT/.gitignore" >&2
106
+ echo "Add it before running nw-docs: echo '.worktrees/' >> .gitignore" >&2
107
+ echo "(or invoke this skill with --auto-ignore to append it for you — not yet implemented)" >&2
108
+ exit 1
109
+ fi
110
+
111
+ # 1. Pre-flight — read-only fetch, NEVER touches main repo HEAD
112
+ git fetch origin develop
113
+
114
+ # 2. Duplicate check — read registry; if an entry with the same slug AND kind=docs
115
+ # exists, return the existing { path, branch, kind } instead of creating a new
116
+ # one (resume semantics — Step 0 of /prd needs this).
117
+ # If an entry with same slug AND kind != "docs" exists (code worktree
118
+ # collision), fail loudly — never silently coexist.
119
+
120
+ # 3. Create the worktree. The path returned MUST be ABSOLUTE — Claude Code's
121
+ # Write/Edit require absolute paths, and downstream skills (/prd, ui-design,
122
+ # prd-card-writer) interpolate this path verbatim.
123
+ SLUG="<slug>"
124
+ BRANCH_PREFIX="${branchPrefix:-prd/}"
125
+ BRANCH="${BRANCH_PREFIX}${SLUG}"
126
+ WORKTREE_REL=".worktrees/prd-${SLUG}"
127
+ WORKTREE_PATH="$MAIN_ROOT/$WORKTREE_REL" # absolute, anchored to main repo root
128
+ git -C "$MAIN_ROOT" worktree add "$WORKTREE_REL" -b "$BRANCH" origin/develop
129
+
130
+ # 4. Registry entry — kind: "docs", port: null, buildVerified: null
131
+ # Same registry file (.worktrees/registry.json) as code worktrees.
132
+ # The `path` field MUST hold $WORKTREE_PATH (absolute), not $WORKTREE_REL.
133
+ ```
134
+
135
+ **Registry entry shape for docs worktrees:**
136
+
137
+ ```json
138
+ {
139
+ "card": null,
140
+ "cards": [],
141
+ "groupParent": null,
142
+ "slug": "menu-nutritional-info",
143
+ "branch": "prd/menu-nutritional-info",
144
+ "path": "/abs/.worktrees/prd-menu-nutritional-info",
145
+ "port": null,
146
+ "kind": "docs",
147
+ "createdAt": "2026-05-27T10:00:00Z",
148
+ "envSyncedAt": null,
149
+ "buildVerified": null
150
+ }
151
+ ```
152
+
153
+ **Forbidden in docs mode**: `npm install`, port scan, `.env*` copy, `npm run build`,
154
+ `npx tsc`, `npx eslint`, dev server start, `git checkout`/`switch`/`branch` on main.
155
+
156
+ ### mw-docs programmatic
157
+
158
+ Input:
159
+ ```json
160
+ {
161
+ "worktreePath": "string", // REQUIRED — absolute path of the docs worktree
162
+ "commitMessage": "string" // OPTIONAL — defaults to "[PRD] <slug>: <generated summary>"
163
+ }
164
+ ```
165
+
166
+ Output:
167
+ ```json
168
+ {
169
+ "merged": true,
170
+ "mergeCommit": "string", // SHA of the merge commit (or branch tip in local-push)
171
+ "prNumber": null, // populated only when strategy = "pr"
172
+ "strategy": "pr" | "local-push",
173
+ "worktreeRemoved": true
174
+ }
175
+ ```
176
+
177
+ **Steps (run exactly these, nothing else):**
178
+
179
+ ```bash
180
+ cd "$WORKTREE_PATH"
181
+
182
+ # 1. Safety commit (MANDATORY — same as /mw step 3, never skippable).
183
+ # Stage every changed and untracked file by explicit name, then commit.
184
+ # For docs worktrees the staged set is typically:
185
+ # - ${paths.prd_dir}/<slug>/PRD.md
186
+ # - ${paths.prd_dir}/<slug>/design.html (if exists)
187
+ # - ${paths.prd_dir}/<slug>/mockups/** (if any)
188
+ # - ${paths.prd_dir}/sessions/YYYY-MM-DD-<slug>-state.md
189
+ # - ${paths.backlog_dir}/FEAT-XXXX-*.yml (all cards)
190
+ # - ${paths.references_dir}/ssot-registry.md (if updated by Step 7)
191
+ # - ${paths.references_dir}/project-status.md (if updated by Step 7)
192
+ # NEVER `git add .` or `git add -A`. NEVER `git stash` (see Safety Rules).
193
+
194
+ # 2. Rebase onto latest develop. Reuses the /mw step 4b conflict-resolution
195
+ # table (additive auto-strip for docs/yaml/jsonl-in-docs-metrics; abort on
196
+ # structured registries when validation fails; abort on code/tests/fixtures).
197
+ #
198
+ # IMPORTANT — NO `git stash` in mw-docs. The safety commit in step 1
199
+ # above guarantees a clean working tree, so the stash logic at the top of
200
+ # /mw step 4b ("stash dirty files before rebase, pop after") is a no-op
201
+ # for mw-docs and must be SKIPPED. Running `git stash push` from a
202
+ # worktree violates the Safety Rule "NEVER use git stash in worktrees"
203
+ # (refs/stash is shared across all worktrees via git.commondir — see the
204
+ # FEAT-0522 incident note). Two parallel mw-docs runs that both stash
205
+ # would race on the shared stash list and could pop into the wrong tree.
206
+ #
207
+ # Direct rebase, no stash. If the working tree is unexpectedly dirty here
208
+ # (someone wrote between step 1 and step 2), STOP and report — a second
209
+ # safety commit would be the right answer, never a stash.
210
+ DIRTY=$(git -C "$WORKTREE_PATH" status --porcelain 2>/dev/null)
211
+ if [ -n "$DIRTY" ]; then
212
+ echo "ERROR: working tree dirty in $WORKTREE_PATH after safety commit." >&2
213
+ echo "Files: $DIRTY" >&2
214
+ echo "Investigate — never stash to recover (refs/stash shared across worktrees)." >&2
215
+ exit 1
216
+ fi
217
+ git -C "$WORKTREE_PATH" fetch origin develop
218
+ git -C "$WORKTREE_PATH" rebase origin/develop
219
+ # (apply /mw 4b conflict-resolution table if rebase reports conflicts)
220
+
221
+ # 3. Land on develop — reuse /mw step 4c verbatim. Read git.merge_strategy from
222
+ # baldart.config.yml. NEVER `git checkout develop` on the main repo.
223
+ # - pr → gh pr create + gh pr merge --merge --delete-branch
224
+ # - local-push → git push origin <branch>:develop (fast-forward only)
225
+ #
226
+ # Note: many consumers prefer `local-push` for docs worktrees specifically,
227
+ # because a PRD is rarely worth a GitHub PR roundtrip. The CLI does not
228
+ # differentiate — it respects the project's configured strategy. If the user
229
+ # wants per-skill strategy, they should override via overlay (.baldart/overlays/prd.md).
230
+
231
+ # 4. Cleanup — reuse /mw step 6 verbatim (worktree remove + branch -d + prune).
232
+ # Skip /mw step 5 (post-merge `npm run build`) — docs worktrees have nothing
233
+ # to build.
234
+
235
+ # 5. Sync local develop ref — reuse /mw "Common" block: ff-only pull when main
236
+ # repo HEAD is already develop; otherwise just fetch.
237
+
238
+ # 6. Remove the registry entry for this worktree.
239
+ ```
240
+
241
+ **Forbidden in docs merge**: pre-merge `npm run build`, `npx eslint`, `npx tsc`, `npm run test`, post-merge `npm run build`. The whole point of docs mode is that these gates are inapplicable.
242
+
243
+ **Failure handling**: if the safety commit, rebase, or merge fails, STOP and
244
+ report — do NOT proceed to cleanup. The worktree must stay on disk so the user
245
+ can investigate. Cleanup runs only after a successful merge.
246
+
247
+ ---
248
+
48
249
  The merge path depends on `git.merge_strategy` in `baldart.config.yml`:
49
250
  - `pr` (default, since v3.4.0): merge via `gh pr create` + `gh pr merge`. `prNumber` is the PR number, `mergeCommit` is the SHA returned by the GitHub merge API.
50
251
  - `local-push` (since v3.9.0): direct fast-forward push of the rebased feature branch to `origin/develop` — no PR, no `gh`. `prNumber` is `null`, `mergeCommit` is the local SHA of the feature branch tip.
@@ -412,25 +613,97 @@ fi
412
613
  CONFLICTED=$(git diff --name-only --diff-filter=U)
413
614
  ```
414
615
 
415
- Categorize each conflicted file and resolve:
416
-
417
- | Category | Patterns | Action |
418
- |----------|----------|--------|
419
- | **Docs/config** | `docs/**/*.md`, `backlog/*.yml`, `*.md` outside `src/`, `*.json`/`*.yml` outside `src/` | Auto-resolve: strip markers, keep both sides |
420
- | **Code** | `src/**/*.ts`, `*.tsx`, `*.js`, `*.jsx` | STOP — abort rebase, report to user |
421
- | **Tests** | `*.test.*`, `*.spec.*` | Manual only — report to user |
616
+ Categorize each conflicted file and resolve. **Per-file rule of thumb**:
617
+ auto-resolve only when "keep both sides" is semantically additive (markdown
618
+ bullet lists, YAML lists, JSONL append-only logs); abort on anything with
619
+ internal structure (tables, key/value blocks, code).
620
+
621
+ | Category | Patterns | Action | Note |
622
+ |----------|----------|--------|------|
623
+ | **Structured registries** | `project-status.md`, `ssot-registry.md`, `field-registry.*`, `traceability-matrix.md`, `REGISTRY.md` | Strip markers, then **structural validation** — if valid, accept; if invalid, abort | The auto-strip "keep both sides" usually produces an additive result (new bullet rows appended to a table or section). The validation step catches the rare case where the two sides modified the same row. See `validate_structured_md` below. |
624
+ | **JSONL logs under `docs/metrics/`** | `docs/metrics/*.jsonl`, `docs/metrics/**/*.jsonl` | Auto-resolve: strip markers, keep both sides | JSONL is line-oriented and additive — duplicating both branches' lines yields a valid file. |
625
+ | **Other `.jsonl`** | `*.jsonl` outside `docs/metrics/` | STOP — abort and report | Fixtures, seeds, training data: auto-strip can corrupt them. The user must inspect. |
626
+ | **Docs/config** | `docs/**/*.md`, `backlog/*.yml`, `*.md` outside `src/`, `*.json`/`*.yml` outside `src/` (excluding rows above) | Auto-resolve: strip markers, keep both sides | The canonical additive case. |
627
+ | **Code** | `src/**/*.ts`, `*.tsx`, `*.js`, `*.jsx` | STOP — abort rebase, report to user | |
628
+ | **Tests** | `*.test.*`, `*.spec.*` | Manual only — report to user | |
629
+
630
+ The "Structured registries" row replaces the v3.22.0-initial blanket-abort
631
+ behaviour. The blanket abort regressed the `/new` flow (every multi-card batch
632
+ that updates `ssot-registry.md` would fail rebase); the validation-based
633
+ approach restores the additive merge for the routine case while still
634
+ catching genuine corruption.
422
635
 
423
636
  ```bash
637
+ # Helper: validate that a structured markdown file is still parseable after
638
+ # auto-strip. Cheap heuristics; returns 0 if file looks structurally intact.
639
+ validate_structured_md() {
640
+ local f="$1"
641
+ # Reject if any residual conflict markers (shouldn't happen after sed)
642
+ if grep -qE '^(<{7}|={7}|>{7})' "$f"; then return 1; fi
643
+ # Reject if a top-level markdown table got duplicated header rows back-to-back
644
+ # (two `|---|---|` separator lines in a row = malformed table).
645
+ if awk 'prev~/^\|[ -:|]+\|$/ && $0~/^\|[ -:|]+\|$/{found=1; exit} {prev=$0} END{exit !found}' "$f"; then
646
+ return 1
647
+ fi
648
+ # Reject if a YAML frontmatter block (--- ... ---) got duplicated.
649
+ if [ "$(grep -cE '^---[[:space:]]*$' "$f")" -gt 2 ]; then return 1; fi
650
+ return 0
651
+ }
652
+
424
653
  for FILE in $CONFLICTED; do
654
+ BASENAME=$(basename "$FILE")
655
+
656
+ # 1. Code / tests — always abort
425
657
  case "$FILE" in
426
658
  src/*.ts|src/*.tsx|src/*.js|src/*.jsx|*.test.*|*.spec.*)
427
- # Code or test conflict — abort and report
428
659
  git rebase --abort
660
+ # When invoked from /mw (code worktree) a stash may have been created
661
+ # at the start of step 4b. Pop it back. mw-docs never stashes
662
+ # (safety commit step 1 leaves the tree clean) so the pop is a no-op.
429
663
  git stash pop 2>/dev/null || true
430
664
  echo "CONFLICT in $FILE — cannot auto-resolve" >&2
431
665
  exit 1 ;;
666
+ esac
667
+
668
+ # 2. Structured registries — strip + structural validation
669
+ case "$BASENAME" in
670
+ project-status.md|ssot-registry.md|traceability-matrix.md|REGISTRY.md)
671
+ sed -i '' '/^<<<<<<< /d; /^=======/d; /^>>>>>>> /d' "$FILE"
672
+ if ! validate_structured_md "$FILE"; then
673
+ git checkout --conflict=merge "$FILE" 2>/dev/null || true
674
+ git rebase --abort
675
+ git stash pop 2>/dev/null || true
676
+ echo "CONFLICT in structured registry $FILE produced invalid structure after auto-strip — manual resolution required." >&2
677
+ exit 1
678
+ fi
679
+ git add "$FILE"
680
+ continue ;;
681
+ esac
682
+ case "$BASENAME" in
683
+ field-registry.*)
684
+ # field-registry.json typically — strict JSON, can't auto-strip safely
685
+ git rebase --abort
686
+ git stash pop 2>/dev/null || true
687
+ echo "CONFLICT in structured registry $FILE — JSON cannot be auto-stripped." >&2
688
+ exit 1 ;;
689
+ esac
690
+
691
+ # 3. JSONL — only auto-resolve under docs/metrics/
692
+ case "$FILE" in
693
+ docs/metrics/*.jsonl|docs/metrics/**/*.jsonl)
694
+ sed -i '' '/^<<<<<<< /d; /^=======/d; /^>>>>>>> /d' "$FILE"
695
+ git add "$FILE"
696
+ continue ;;
697
+ *.jsonl)
698
+ git rebase --abort
699
+ git stash pop 2>/dev/null || true
700
+ echo "CONFLICT in $FILE (.jsonl outside docs/metrics/ — may be fixture/seed) — manual resolution required." >&2
701
+ exit 1 ;;
702
+ esac
703
+
704
+ # 4. Generic docs/config — additive merge
705
+ case "$FILE" in
432
706
  docs/*|backlog/*|*.md|*.json|*.yml)
433
- # Doc/config conflict — auto-resolve keeping both sides
434
707
  sed -i '' '/^<<<<<<< /d; /^=======/d; /^>>>>>>> /d' "$FILE"
435
708
  git add "$FILE" ;;
436
709
  esac
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "baldart",
3
- "version": "3.21.2",
3
+ "version": "3.22.1",
4
4
  "description": "Claude Agent Framework - Reusable framework for coordinating AI agents and humans in software projects",
5
5
  "bin": {
6
6
  "baldart": "./bin/baldart.js"