baldart 4.21.0 → 4.22.0

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,30 @@ 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
+ ## [4.22.0] - 2026-06-09
9
+
10
+ **`/prd` Obsidian back-reference.** When a PRD is kicked off from an Obsidian note (the documental starting point), the same note now receives, at the end of the run, an idempotent snippet indexing how the feature was developed and where it landed — PRD path, epic + card IDs, branch, merge commit/PR, and the PRD's Canonical Sources — so the user can later query the note ("come è stata sviluppata la feature X, dov'è finita"). **MINOR** (additive capability on the `prd` skill; no new `baldart.config.yml` key — the note path is runtime-detected and state-persisted, so the schema-change propagation rule does not apply).
11
+
12
+ ### Added
13
+
14
+ - **`framework/.claude/skills/prd/references/validation-phase.md`** — new **Step 7.6 — Obsidian back-reference** (runs after the merge, when the canonical paths/IDs/SHA are final). Writes a marker-delimited section (`<!-- BALDART:prd:<slug> START/END -->`) holding a fenced `yaml` payload + human-readable links back into the spec note. **Idempotent** (re-runs / `/prd-add` replace the block in place), **non-blocking** (no note, unresolved vault path, or unwritable file → skip with a log line). The note lives in the user's vault, outside the worktree and outside git — a plain filesystem write, never staged.
15
+
16
+ ### Changed
17
+
18
+ - **`framework/.claude/skills/prd/references/discovery-phase.md`** — Step 1 point 2 Obsidian detection broadened beyond `[[wikilink]]` to also accept `obsidian://open?…` URIs and pasted `.md` paths, and now resolves + persists the note's **absolute `path:`** (vault root from `paths.obsidian_vault` / memory / one-time ask) so Step 7.6 can write back without re-deriving.
19
+ - **`framework/.claude/skills/prd/assets/state-template.md`** — new structured `## Obsidian Spec Note` section (`wikilink:` / `path:` / `status:`).
20
+ - **`framework/.claude/skills/prd/SKILL.md`** — new **HARD RULE 19** (Obsidian back-reference) + Step 7.6 row in the flow table.
21
+ - **`framework/.claude/skills/prd/references/prd-writing-phase.md`** — Canonical Sources row now reads the structured `wikilink:` field and cross-links Step 7.6.
22
+
23
+ ## [4.21.1] - 2026-06-09
24
+
25
+ **Nightly reconciliation of the canonical API registries (errors.md / schemas.md).** Makes the nightly `doc-review` run explicitly keep `${paths.api_errors}` and `${paths.api_schemas}` in sync with the day's code changes, instead of relying on the generic doc↔code drift step. **PATCH** (strengthens existing routine/agent behaviour; no new agent/skill/command/config key).
26
+
27
+ ### Changed
28
+
29
+ - **`framework/routines/doc-review.routine.yml`** — new step 3b: when `features.has_api_docs: true`, reconcile the canonical `errors.md` (stable error codes added/renamed/removed → apply or flag `DOC_GAP`) and `schemas.md` (Zod/TS shape changes → update or flag `SCHEMA_DRIFT`) against the last-24h commits. Skips silently when the paths are unset.
30
+ - **`framework/.claude/agents/doc-reviewer.md`** — new "Canonical API registries — reconciliation (nightly-owned)" section: the agent now explicitly OWNS the code→doc direction for the two registries (the `doc-writing-for-rag` skill owns the doc-authoring direction). Ties together the existing `SCHEMA_DRIFT` + error-code checks.
31
+
8
32
  ## [4.21.0] - 2026-06-09
9
33
 
10
34
  **Code knowledge graph layer (Graphify) + Karpathy wiki rebind + nightly doc-alignment command.** Introduce [Graphify](https://github.com/safishamsi/graphify) as the new retrieval engine replacing the removed RAG (v4.20.0): a single language-agnostic tool (tree-sitter, 28 langs, local/offline, native Leiden communities; pip `graphifyy`, CLI `graphify` + `graphify-mcp`). Opt-in, runtime-detected, silent fallback to LSP→Grep→Git. **MINOR** (additive; new agent + 2 skills + 1 routine + 1 protocol module; new config key `features.has_code_graph` + `graph.*` propagated end-to-end per the schema-change rule).
package/VERSION CHANGED
@@ -1 +1 @@
1
- 4.21.0
1
+ 4.22.0
@@ -409,6 +409,21 @@ Beyond route existence, also check schema diffs:
409
409
  - For new fields in a documented payload: NEEDS_UPDATE.
410
410
  - For removed fields still in doc: ORPHAN_FIELD.
411
411
 
412
+ ## Canonical API registries — reconciliation (nightly-owned)
413
+
414
+ When `features.has_api_docs: true`, you OWN keeping the two canonical registries in
415
+ sync with code on the nightly `doc-review` run (and on any API-doc rewrite):
416
+ - **`${paths.api_errors}`** (errors.md) — the single registry of stable error codes.
417
+ A code added / renamed / removed in the code → apply it to the right domain
418
+ section (trivial fix) or flag `DOC_GAP`. Endpoint docs link to the **domain
419
+ anchor**; they must never duplicate the table.
420
+ - **`${paths.api_schemas}`** (schemas.md) — the documented projection of the
421
+ Zod/TS shapes (Zod-in-code stays the SSOT). A shape change → update the table or
422
+ flag `SCHEMA_DRIFT`.
423
+ Skip silently when either path is unset. This is the code→doc direction that keeps
424
+ the registries authoritative; the `doc-writing-for-rag` skill handles the
425
+ doc-authoring (APPEND, no duplication) direction.
426
+
412
427
  ## Endpoint Count Reconciliation
413
428
 
414
429
  Applies **when the project uses file-system route handlers** (e.g. Next.js App Router `route.ts`). Adapt the commands to the project's actual API layout — the paths below are the common Next.js convention, not a hardcoded assumption. The convention: SSOT count in `api/index.md` = sum of HTTP method exports (a handler exporting GET + POST counts as 2 endpoints).
@@ -49,6 +49,7 @@ message. You ask questions, wait for answers, and iterate.
49
49
  | 5 | Backlog Cards | [backlog-phase.md](references/backlog-phase.md) |
50
50
  | 6 | Quality Audit | [validation-phase.md](references/validation-phase.md) |
51
51
  | 7 | Resolution, Commit & Merge | [validation-phase.md](references/validation-phase.md) |
52
+ | 7.6 | Obsidian back-reference (only if a spec note was given) | [validation-phase.md](references/validation-phase.md) |
52
53
 
53
54
  **Before starting each phase, read the corresponding reference file.**
54
55
 
@@ -233,6 +234,21 @@ message. You ask questions, wait for answers, and iterate.
233
234
  transcripts for REAL per-role token + wall-clock cost. The token itself is NOT part
234
235
  of the feature description — strip it before recording the user's verbatim feature
235
236
  text in `## Feature Description`.
237
+ 19. **Obsidian back-reference (MANDATORY when a spec note was given).** If the user
238
+ kicked off the PRD from an Obsidian note (any of: `[[Note]]` wikilink,
239
+ `obsidian://open?…` URI, or a pasted `.md` path), Step 1 detection persists it in
240
+ the state file `## Obsidian Spec Note` (`wikilink:` + absolute `path:` + `status:`).
241
+ At the END of the run — **after** the merge (validation-phase Step 7, item 9) so the
242
+ paths/IDs/SHA are final — Step 7.6 writes an **idempotent** snippet back into that
243
+ note: a marker-delimited section (`<!-- BALDART:prd:<slug> START/END -->`) holding a
244
+ fenced `yaml` block with the feature slug, PRD path, epic + card IDs, branch, merge
245
+ commit/PR, and the PRD's Canonical Sources as `resources:`. This makes the original
246
+ note the durable index the user can later query ("come è stata sviluppata la feature
247
+ X, dov'è finita"). The note lives in the user's **vault, outside the worktree and
248
+ outside git** — it is a plain filesystem write, never staged/committed. The step is
249
+ **NON-BLOCKING**: no spec note, unresolved vault path, or an unwritable note all skip
250
+ it with a log line, never aborting the PRD. See discovery-phase.md Step 1 point 2 and
251
+ validation-phase.md Step 7.6.
236
252
 
237
253
  ---
238
254
 
@@ -12,6 +12,15 @@ stats_enabled: {{true if invoked with -stats/--stats, else false}}
12
12
  - created_at: {{ISO-8601 UTC}}
13
13
  - merge_commit: (pending — populated by validation-phase Step 7 after mw-docs)
14
14
 
15
+ ## Obsidian Spec Note
16
+
17
+ <!-- Populated by discovery-phase.md Step 1 point 2 ONLY when the user passed an
18
+ Obsidian note as the documental starting point. When no note was given, leave
19
+ status: none and the Step 7.6 back-reference is skipped. -->
20
+ wikilink: none # [[Note Name]] form — feeds PRD Canonical Sources row
21
+ path: none # absolute fs path of the note — target of the Step 7.6 writeback
22
+ status: none # none | detected | back-reference-written
23
+
15
24
  ## Feature Description
16
25
  {{user's description verbatim}}
17
26
 
@@ -59,12 +59,31 @@ this is a fresh session (no existing state file).
59
59
 
60
60
  1. Derive `<slug>`: kebab-case, lowercase, max 40 chars, no special chars.
61
61
  Example: "Nutritional info on menu" -> `menu-nutritional-info`
62
- 2. **Obsidian spec detection:** scan the user's message for Obsidian note references:
63
- - Wikilink pattern: `[[Note Name]]` or `[[Note Name|Alias]]`
64
- - If found: extract the note name and save it in the state file under
65
- `## Obsidian Spec Note: [[Note Name]]`. This will be added to Canonical Sources in the PRD.
66
- - Read the note content from the vault path in memory (`reference_obsidian_vault.md`)
67
- to pre-populate discovery dimensions where possible treat it as a user-provided spec.
62
+ 2. **Obsidian spec detection (and back-reference setup):** scan the user's message
63
+ for a reference to an Obsidian note used as the documental starting point. Accept
64
+ any of these forms:
65
+ - Wikilink: `[[Note Name]]` or `[[Note Name|Alias]]`.
66
+ - `obsidian://open?vault=<Vault>&file=<rel/path/Note>` URI (URL-decode `file`).
67
+ - A filesystem path to a `.md` file the user pastes ("la nota è in `…/Vault/…/Note.md`").
68
+
69
+ If found, populate the `## Obsidian Spec Note` section of the state file with:
70
+ - `wikilink:` — the `[[Note Name]]` form (for the PRD Canonical Sources row, see
71
+ prd-writing-phase.md Step 4 point 2).
72
+ - `path:` — the **absolute** filesystem path of the note. Resolve it now so the
73
+ end-of-run back-reference (validation-phase Step 7.6) can write to it without
74
+ re-deriving:
75
+ - URI/full path given → use it directly (URL-decode + join `vault`+`file`).
76
+ - Only a bare wikilink given → you need the vault root to resolve it. Use the
77
+ vault path recorded in memory (`reference_obsidian_vault.md`) if present; else
78
+ **ASK the user once** for the vault root (or the note's full path) and persist
79
+ their answer in this state section. Do NOT assume a default. If the user
80
+ declines, set `path: none` — detection still works for pre-population, but the
81
+ Step 7.6 writeback is skipped (logged, never fatal).
82
+ - `status: detected`.
83
+
84
+ Then read the note content (from `path:`) to pre-populate discovery dimensions
85
+ where possible — treat it as a user-provided spec. This same note becomes the
86
+ target of the back-reference snippet at the end of the run (HARD RULE 19).
68
87
  3. **Create the docs worktree (MANDATORY — HARD RULE 17)** — invoke the
69
88
  `worktree-manager` skill in programmatic docs mode BEFORE any file write:
70
89
 
@@ -7,10 +7,12 @@ Mark task 3 as `in_progress`.
7
7
  ## Write PRD
8
8
 
9
9
  1. Create directory `${paths.prd_dir}/<slug>/` if it doesn't exist.
10
- 2. **Obsidian spec note (if present):** if the state file contains `## Obsidian Spec Note`,
11
- add a row to the Canonical Sources table in the PRD:
10
+ 2. **Obsidian spec note (if present):** if the state file `## Obsidian Spec Note`
11
+ section has `status: detected`, add a row to the Canonical Sources table in the PRD
12
+ using its `wikilink:` value:
12
13
  `| Obsidian spec | [[Note Name]] |`
13
- This preserves traceability from the user's original spec note to the final PRD.
14
+ This preserves traceability from the user's original spec note to the final PRD, and
15
+ the same note receives the end-of-run back-reference snippet (validation-phase Step 7.6).
14
16
  3. **Resolve canonical sources** before writing:
15
17
  - Read `${paths.references_dir}/ssot-registry.md` to identify the macro feature and any
16
18
  existing canonical docs.
@@ -247,6 +247,79 @@ markers it can emit, then act:
247
247
  empty, no `[SYNC-NEEDS-DECISION]` marker is left unhandled, and the merged remote
248
248
  branch is gone (or its deletion is explicitly user-deferred).
249
249
 
250
+ ### Step 7.6 — Obsidian back-reference (NON-BLOCKING — runs only when a spec note was given)
251
+
252
+ **Why this exists.** When the user kicked off the PRD from an Obsidian note (state
253
+ file `## Obsidian Spec Note / status: detected`, see HARD RULE 19), they want that
254
+ same note to become the durable index of *how the feature was developed and where it
255
+ landed* — so they can later ask "come è stata sviluppata la feature X?" and get the
256
+ PRD, cards, and merge from the note itself. This step writes a single, idempotent,
257
+ machine-and-human readable snippet back into the note.
258
+
259
+ **Runs AFTER the merge (Step 7 item 9) succeeds** — only then are the canonical paths,
260
+ card IDs, branch, PR/SHA final. The note lives in the user's **vault, OUTSIDE the
261
+ worktree and outside git** — so this is a plain filesystem write to the absolute
262
+ `path:`, NOT a worktree-relative path and NOT a git-tracked artefact (do not stage it).
263
+
264
+ **Skip conditions (each logged, never fatal):**
265
+ - `## Obsidian Spec Note / status` is `none` (no note was given) → skip silently.
266
+ - `path:` is `none` or empty (vault root never resolved at Step 1) → skip with a note.
267
+ - The file at `path:` does not exist or is not writable → skip with a one-line warning.
268
+
269
+ **Procedure:**
270
+
271
+ 1. Read the current content of the note at `path:`.
272
+ 2. Build the snippet, delimited by HTML-comment markers keyed on the slug so the step
273
+ is **idempotent** — a re-run (or a later `/prd-add`) REPLACES the block between the
274
+ markers in place instead of appending a duplicate. If the markers are absent, append
275
+ the block at the end of the note (preceded by one blank line).
276
+
277
+ ```markdown
278
+ <!-- BALDART:prd:<slug> START -->
279
+ ## 🛠 Sviluppo BALDART — <slug>
280
+
281
+ ```yaml
282
+ feature: <slug>
283
+ prd: ${paths.prd_dir}/<slug>/PRD.md
284
+ epic: FEAT-XXXX-00-<slug>-epic
285
+ cards:
286
+ - FEAT-XXXX-01-<sub-slug>
287
+ - FEAT-XXXX-02-<sub-slug>
288
+ resources: # other Canonical Sources from the PRD (mockups, ADRs, ref docs, research)
289
+ - ${paths.prd_dir}/<slug>/design.html # omit if no design
290
+ - <ssot-registry entry / ADR path / research link>
291
+ branch: prd/<slug>
292
+ merge_commit: <SHA from state ## Validation>
293
+ pr: <PR number, or n/a for local-push>
294
+ trunk_branch: <git.trunk_branch>
295
+ date: <ISO-8601 UTC>
296
+ status: planned # planned | in-progress | done
297
+ ```
298
+
299
+ - **PRD:** [`${paths.prd_dir}/<slug>/PRD.md`](...)
300
+ - **Cards:** FEAT-XXXX-00 (epic) · FEAT-XXXX-01 · FEAT-XXXX-02 …
301
+ - **Merge:** `<SHA>` su `<git.trunk_branch>`<!-- · PR #N -->
302
+
303
+ _Generato da `/prd` il <date>. Aggiorna `status:` a `done` quando la feature è in produzione._
304
+ <!-- BALDART:prd:<slug> END -->
305
+ ```
306
+
307
+ Fill the `yaml` block from the final state: `<slug>`, the real epic + child card
308
+ IDs created in Step 5, the merge SHA written under `## Validation` (Step 7 item 8),
309
+ the PR number from the `mw-docs` return (or `n/a`), and the Canonical Sources list
310
+ the PRD already assembled (prd-writing-phase.md Step 4 point 3) for `resources:`.
311
+ The inner ```` ```yaml ```` block is fenced, NOT real top-of-file frontmatter — it
312
+ is the queryable payload Claude reads back when asked about the feature later.
313
+
314
+ 3. Write the updated note back to `path:`.
315
+ 4. Set `## Obsidian Spec Note / status: back-reference-written` in the state file.
316
+ (The state file is already committed; this is a local marker for a possible resume —
317
+ do NOT re-commit just for this field.)
318
+
319
+ **This step is NON-BLOCKING** — any failure (note moved, vault unmounted, permission
320
+ denied) logs "Obsidian back-reference: SKIPPED (<reason>)" and the run completes. The
321
+ PRD merge has already happened; the back-reference is a convenience index, never a gate.
322
+
250
323
  ### Final output
251
324
 
252
325
  Print final summary:
@@ -257,6 +330,7 @@ Print final summary:
257
330
  - Branch & merge strategy used
258
331
  - PR number (if `strategy = pr`) or merge SHA (if `local-push`)
259
332
  - Confirmation that the worktree was cleaned up AND the remote branch was deleted
333
+ - Obsidian back-reference: the note path the snippet was written to (only when Step 7.6 ran; omit otherwise)
260
334
 
261
335
  **HARD RULE — no passive deferral.** The final summary MUST NOT contain a
262
336
  "your manual actions / non-blocking notes / you can do it yourself" section.
@@ -19,6 +19,14 @@ prompt: |
19
19
  references. Flag drift as `DOC_DRIFT`.
20
20
  3. For each source file change that landed without a corresponding doc
21
21
  update, flag `DOC_GAP`.
22
+ 3b. If `features.has_api_docs: true`, reconcile the CANONICAL registries
23
+ against the day's code changes:
24
+ - `${paths.api_errors}` (errors.md): a stable error code added / renamed /
25
+ removed in the code → apply it to the registry (trivial) or flag
26
+ `DOC_GAP`. Endpoint docs must link to the domain anchor, never duplicate.
27
+ - `${paths.api_schemas}` (schemas.md): a route's Zod/TS request/response
28
+ shape changed → update the matching table or flag `SCHEMA_DRIFT`.
29
+ Skip silently when either path is unset.
22
30
  4. If the project ships a design-system SSOT, run the standard DS drift
23
31
  checks (INDEX coverage, per-component accuracy, animations
24
32
  reconciliation, tokens reconciliation).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "baldart",
3
- "version": "4.21.0",
3
+ "version": "4.22.0",
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"