baldart 4.18.0 → 4.21.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.
Files changed (45) hide show
  1. package/CHANGELOG.md +47 -0
  2. package/README.md +15 -9
  3. package/VERSION +1 -1
  4. package/framework/.claude/agents/REGISTRY.md +3 -2
  5. package/framework/.claude/agents/api-perf-cost-auditor.md +2 -3
  6. package/framework/.claude/agents/code-reviewer.md +2 -2
  7. package/framework/.claude/agents/codebase-architect.md +31 -52
  8. package/framework/.claude/agents/coder.md +1 -2
  9. package/framework/.claude/agents/doc-graph-aligner.md +72 -0
  10. package/framework/.claude/agents/doc-reviewer.md +3 -39
  11. package/framework/.claude/agents/plan-auditor.md +2 -3
  12. package/framework/.claude/agents/prd-card-writer.md +1 -1
  13. package/framework/.claude/agents/qa-sentinel.md +1 -2
  14. package/framework/.claude/agents/security-reviewer.md +2 -3
  15. package/framework/.claude/agents/senior-researcher.md +2 -3
  16. package/framework/.claude/agents/wiki-curator.md +19 -74
  17. package/framework/.claude/commands/codexreview.md +5 -6
  18. package/framework/.claude/skills/bug/SKILL.md +9 -8
  19. package/framework/.claude/skills/capture/SKILL.md +12 -14
  20. package/framework/.claude/skills/context-primer/SKILL.md +21 -69
  21. package/framework/.claude/skills/graph-align/SKILL.md +80 -0
  22. package/framework/.claude/skills/graphify-bootstrap/SKILL.md +125 -0
  23. package/framework/.claude/skills/issue-review/SKILL.md +1 -1
  24. package/framework/.claude/skills/new/SKILL.md +1 -1
  25. package/framework/.claude/skills/new/references/implement.md +1 -1
  26. package/framework/.claude/skills/prd/SKILL.md +12 -11
  27. package/framework/.claude/skills/prd/references/discovery-phase.md +79 -5
  28. package/framework/.claude/skills/simplify/SKILL.md +3 -0
  29. package/framework/agents/code-graph-protocol.md +108 -0
  30. package/framework/agents/code-search-protocol.md +27 -21
  31. package/framework/agents/index.md +4 -2
  32. package/framework/agents/llm-wiki-methodology.md +42 -78
  33. package/framework/docs/CODE-GRAPH-LAYER.md +104 -0
  34. package/framework/docs/LSP-LAYER.md +6 -6
  35. package/framework/docs/MCP-INTEGRATION.md +4 -4
  36. package/framework/docs/PROJECT-CONFIGURATION.md +11 -0
  37. package/framework/routines/doc-graph-align.routine.yml +53 -0
  38. package/framework/routines/index.yml +14 -4
  39. package/framework/routines/wiki-review.routine.yml +8 -5
  40. package/framework/templates/baldart.config.template.yml +32 -5
  41. package/package.json +1 -1
  42. package/src/commands/configure.js +67 -1
  43. package/src/commands/doctor.js +91 -0
  44. package/src/commands/update.js +6 -0
  45. package/src/utils/graphify-installer.js +239 -0
@@ -0,0 +1,104 @@
1
+ # Code Graph Layer (Graphify) — Operator Guide
2
+
3
+ > Since v4.21.0. Opt-in, gated on `features.has_code_graph`. The **runtime**
4
+ > protocol (when to use the graph vs LSP vs Grep) lives in
5
+ > [`framework/agents/code-graph-protocol.md`](../agents/code-graph-protocol.md);
6
+ > this document covers the *plumbing* — install, config, lifecycle, fallback.
7
+
8
+ ## 1. Why this exists
9
+
10
+ After removing the (unused, costly) RAG engine in v4.20.0, BALDART needed a
11
+ retrieval tier for **structural / relational** code questions — "what connects X
12
+ to Y", blast-radius of a change, which modules cluster — that Grep and even LSP
13
+ answer poorly. [Graphify](https://github.com/safishamsi/graphify) builds a code
14
+ knowledge graph (tree-sitter, 28 languages, **local/offline**) with native Leiden
15
+ community detection. The same graph also **re-activates the Karpathy LLM-wiki
16
+ auto-learning loop**: its native `GRAPH_REPORT.md` (god nodes, communities,
17
+ suggested questions) is the gap signal that feeds synthesis candidates.
18
+
19
+ ## 2. What BALDART adds vs what Graphify already ships
20
+
21
+ Graphify is a complete tool on its own — it installs its **own** skill, an
22
+ always-on pre-tool hook, a post-commit git hook, and an MCP server. BALDART does
23
+ **not** reimplement any of that. It adds only:
24
+
25
+ - **Gating + config** (`features.has_code_graph` + `graph:` block).
26
+ - **Opt-in install** (`configure` interactive branch, `/graphify-bootstrap`, `doctor` backfill).
27
+ - **A retrieval protocol** telling BALDART's own agents *when* the graph is the right tier.
28
+ - **The wiki rebind** (wiki-curator / capture / `doc-graph-align` consume `GRAPH_REPORT.md`).
29
+ - **Fallback discipline** (silent degrade to LSP→Grep→Git).
30
+
31
+ Everything mutating is a thin wrapper over Graphify's native commands in
32
+ [`src/utils/graphify-installer.js`](../../src/utils/graphify-installer.js).
33
+ There is **no per-language adapter registry** (unlike LSP) — Graphify is one
34
+ language-agnostic tool.
35
+
36
+ ## 3. The moving parts
37
+
38
+ | Part | Where | Role |
39
+ |------|-------|------|
40
+ | Config flag + block | `framework/templates/baldart.config.template.yml` | `features.has_code_graph` + `graph.{output_dir,auto_rebuild_hook,register_mcp}` |
41
+ | Installer wrapper | `src/utils/graphify-installer.js` | `detect/install/verify/buildGraph/installGitHook/installAlwaysOn/registerMcp/isStale` |
42
+ | Configure | `src/commands/configure.js` | autodetect (binary on PATH) + prompt + interactive install/build/wire |
43
+ | Update detector | `src/commands/update.js` | diffs the `graph:` block → offers `configure` (extended to diff nested top-level blocks) |
44
+ | Doctor | `src/commands/doctor.js` | `Code graph` line + `graph-install` / `graph-rebuild` / `graph-hook` actions |
45
+ | Retrieval protocol | `framework/agents/code-graph-protocol.md` | when to use the graph; budget; fallback |
46
+ | Wiki rebind | `llm-wiki-methodology.md`, `wiki-curator.md`, `wiki-review.routine.yml`, `capture` | GRAPH_REPORT.md → synthesis candidates |
47
+ | Nightly command | agent `doc-graph-aligner` + routine `doc-graph-align` + skill `/graph-align` | doc↔graph alignment |
48
+ | Bootstrap skill | `/graphify-bootstrap` | explicit install path (CI-safe backfill) |
49
+
50
+ ## 4. Install lifecycle
51
+
52
+ ```
53
+ features.has_code_graph: true
54
+
55
+ ├─ baldart configure (INTERACTIVE) ─→ pipx install graphifyy
56
+ │ → graphify update . (build, offline)
57
+ │ → graphify <tool> install (always-on per tools.enabled)
58
+ │ → graphify hook install (auto-rebuild, if auto_rebuild_hook)
59
+ │ → claude mcp add … graphify-mcp (if register_mcp)
60
+
61
+ ├─ baldart configure --yes / CI ──→ writes the flag ONLY (no silent
62
+ │ Python install) → doctor backfills
63
+
64
+ ├─ /graphify-bootstrap ───────────→ the explicit, full install path
65
+
66
+ └─ baldart doctor ────────────────→ graph-install (binary missing)
67
+ graph-rebuild (stale: built_at_commit ≠ HEAD) · graph-hook (hook missing)
68
+ ```
69
+
70
+ **CI behavior is deliberate**: a Python tool is never installed silently in
71
+ `--yes`/non-interactive runs. The flag is written from autodetect; `doctor` and
72
+ `/graphify-bootstrap` own the actual install.
73
+
74
+ ## 5. Native commands BALDART relies on (all offline, 0 API cost)
75
+
76
+ | Purpose | Command |
77
+ |---------|---------|
78
+ | Build / refresh graph | `graphify update <root>` → `<root>/graphify-out/{graph.json, GRAPH_REPORT.md, graph.html}` |
79
+ | Auto-rebuild on commit | `graphify hook install` (post-commit + graph.json union merge-driver) |
80
+ | Always-on per tool | `graphify claude install` / `graphify codex install` / … |
81
+ | Query (relational) | `graphify query "…"`, `graphify path "A" "B"`, `graphify explain "X"`, `graphify affected "X"` |
82
+ | MCP server | `graphify-mcp [graph.json]` (stdio default; `--transport http` available) |
83
+ | Staleness (cron-safe) | `graphify check-update <root>`, or compare `graph.json.built_at_commit` to `git rev-parse HEAD` |
84
+
85
+ LLM API keys are needed **only** for `--wiki` / community naming (`graphify label`)
86
+ / URL & vision ingestion — all optional. The structural graph + report are free.
87
+
88
+ ## 6. Invariants
89
+
90
+ - **The graph is never canonical.** Synthesis candidates it produces cite repo
91
+ SSOT and carry `canonicality: derived`.
92
+ - **Silent fallback.** No task aborts because the graph is missing — degrade to
93
+ LSP→Grep→Git; surface setup gaps via `baldart doctor`, never mid-task.
94
+ - **`graphify-out/` is generated** — must be in `.gitignore`, never versioned.
95
+ - **No per-language registry.** Add nothing per language; Graphify handles 28 via
96
+ tree-sitter. The wrapper composes native commands, never reimplements them.
97
+ - **Schema-change propagation** applies to `features.has_code_graph` + `graph.*`.
98
+
99
+ ## 7. Adding capability later
100
+
101
+ The retrieval tier ships CLI-first; the MCP path is opt-in. To deepen the
102
+ integration (e.g. wire `graphify-mcp` as a first-class MCP tool, or use `--wiki`
103
+ community pages directly as wiki concept pages), extend `graphify-installer.js`
104
+ and the protocol module — do not fork Graphify's native behavior.
@@ -13,7 +13,7 @@ A complete operator + agent reference for the LSP retrieval tier introduced in
13
13
  - a contributor wants to add a new language adapter or change the fallback
14
14
  rules.
15
15
 
16
- For the *runtime* protocol (RAG → LSP → Grep → Git, query-type
16
+ For the *runtime* protocol (LSP → Grep → Git, query-type
17
17
  discrimination, budget) read [`framework/agents/code-search-protocol.md`](../agents/code-search-protocol.md).
18
18
  This document covers the *plumbing*: how the layer is installed, configured,
19
19
  verified, and wired into agents/skills.
@@ -24,7 +24,7 @@ verified, and wired into agents/skills.
24
24
 
25
25
  Pre-v3.10, every BALDART code-exploration flow ran:
26
26
 
27
- > RAG hybrid → `git log` → **Grep** → read files.
27
+ > canonical-doc routing → `git log` → **Grep** → read files.
28
28
 
29
29
  Grep collapses semantically distinct symbols that share a name. A search for
30
30
  `handleSubmit` in a medium repo dumps every form handler, every CLI utility,
@@ -41,7 +41,7 @@ unrelated `handleSubmit` is filtered out before any file is read.
41
41
  The layer is **opt-in** (some consumers don't want a global npm install for a
42
42
  language server, some target languages we don't have an adapter for yet) and
43
43
  **degrades gracefully** (when
44
- LSP is unavailable, agents silently fall back to the legacy RAG → Grep flow,
44
+ LSP is unavailable, agents silently fall back to the Grep flow,
45
45
  so existing behavior is preserved).
46
46
 
47
47
  ---
@@ -217,14 +217,14 @@ When `codebase-architect` or one of the code-exploration skills (`bug`,
217
217
  `prd`, `new`, `simplify`, `context-primer`) is invoked:
218
218
 
219
219
  1. Read `baldart.config.yml`. If `features.has_lsp_layer !== true`, behave
220
- exactly as v3.9.x (RAG → Grep → Git).
220
+ as the Grep → Git flow.
221
221
  2. Otherwise: classify the query.
222
222
  - Identifier-shaped (function name, type name, class, exported symbol) →
223
223
  **LSP first** (`ToolSearch("LSP")` → `find-references` / `definition`).
224
224
  - Free text / phrase / comment / path / regex → **Grep first**, LSP is
225
225
  useless here.
226
- - Mixed (e.g. "refactor function X used in 5 places") → RAG hybrid for
227
- conceptual context, then LSP for the structural part.
226
+ - Mixed (e.g. "refactor function X used in 5 places") → Grep to disambiguate
227
+ the conceptual context, then LSP for the structural part.
228
228
  3. Budget: max **3 LSP calls per task**. After 3 calls without convergence,
229
229
  escalate to direct file reads — don't ping-pong references.
230
230
  4. If LSP tool isn't loaded / plugin missing / timeout > 8s / zero
@@ -27,8 +27,8 @@ Non è un'imposizione: BALDART non installa MCP, non li valida, non li richiede.
27
27
  ### Browser automation
28
28
  - **Playwright MCP** (`@modelcontextprotocol/server-playwright`) — usato da [bug](../.claude/skills/bug/SKILL.md) e [webapp-testing](../.claude/skills/webapp-testing/SKILL.md) per cattura visiva, network, console.
29
29
 
30
- ### Documentation retrieval (RAG)
31
- - **doc-rag MCP** (interno o `@modelcontextprotocol/server-everything-search` come stand-in) usato da [codebase-architect](../.claude/agents/codebase-architect.md) e [code-search-protocol.md](../agents/code-search-protocol.md) per ricerca semantica nei doc + knowledge graph.
30
+ ### Code knowledge graph (Graphify)
31
+ - **Graphify** (`pipx install graphifyy` → CLI `graphify` + MCP server `graphify-mcp`) code knowledge graph (tree-sitter, locale/offline, Leiden nativo). Gatato da `features.has_code_graph`. Usato da [codebase-architect](../.claude/agents/codebase-architect.md) e dalle skill di esplorazione per query **strutturali/relazionali** (`graphify query`/`path`/`explain`/`affected`), e dal layer wiki (`wiki-curator`, `/capture`, routine `doc-graph-align`) che si alimenta del `GRAPH_REPORT.md` nativo. **CLI-first** (sempre disponibile post-install); l'MCP `graphify-mcp` è opt-in (`graph.register_mcp`, best-effort `claude mcp add`). Fallback: degrada a LSP→Grep→Git. Vedi [code-graph-protocol.md](../agents/code-graph-protocol.md) e [CODE-GRAPH-LAYER.md](CODE-GRAPH-LAYER.md).
32
32
 
33
33
  ### Database
34
34
  - **Firebase MCP** (`@modelcontextprotocol/server-firebase` — già integrato come plugin BALDART quando `stack.database.primary` è Firestore) — ispezione documenti, query collection, transazioni.
@@ -86,8 +86,8 @@ Subito dopo la sezione `## Project Context` (o, in mancanza, subito dopo il fron
86
86
  ### Esempi nel framework corrente
87
87
 
88
88
  Vedi le seguenti dichiarazioni per pattern di riferimento:
89
- - [framework/.claude/agents/codebase-architect.md](../.claude/agents/codebase-architect.md) — `## MCP dependencies` con doc-rag required + LSP-related optional.
90
- - [framework/.claude/skills/bug/SKILL.md](../.claude/skills/bug/SKILL.md) — Playwright required per UI bug, doc-rag + Firestore optional.
89
+ - [framework/.claude/agents/codebase-architect.md](../.claude/agents/codebase-architect.md) — `## MCP dependencies` con Graphify (code graph) + LSP-related optional.
90
+ - [framework/.claude/skills/bug/SKILL.md](../.claude/skills/bug/SKILL.md) — Playwright required per UI bug, Firestore optional.
91
91
  - [framework/.claude/skills/playwright-skill/SKILL.md](../.claude/skills/playwright-skill/SKILL.md) — esempio di sezione "None" (la skill usa Playwright Test CLI, non MCP).
92
92
 
93
93
  ---
@@ -209,6 +209,7 @@ Every flag MUST be present as `true` or `false` once `baldart configure` has run
209
209
  | `has_prd_workflow` | PRD workflow (`paths.prd_dir`). `/prd` and `/prd-add` skills refuse to run without it. |
210
210
  | `has_wiki_overlay` | LLM-wiki overlay (`paths.wiki_dir`). `/capture` skill refuses to run without it. |
211
211
  | `has_lsp_layer` | LSP symbol-search layer (since v3.10.0). When `true`, `codebase-architect`, `context-primer`, `bug`, `prd`, `new`, and `simplify` prefer LSP `find-references` / `go-to-definition` over Grep for identifier queries. Wired by `framework/agents/code-search-protocol.md`. The flag also triggers `baldart configure` (and the `/lsp-bootstrap` skill) to install the matching language servers. |
212
+ | `has_code_graph` | Code knowledge graph layer (Graphify, since v4.21.0). When `true`, agents prefer the graph for **structural/relational** queries (`graphify query`/`path`/`affected`) via `framework/agents/code-graph-protocol.md`, and the LLM-wiki overlay is fed by Graphify's native `GRAPH_REPORT.md`. Triggers `baldart configure` / `/graphify-bootstrap` to install Graphify (`pipx install graphifyy`). Install is never silent in CI — `baldart doctor` backfills. Falls back silently to LSP→Grep→Git. |
212
213
 
213
214
  ### 4.6 `lsp` — installed language servers (since v3.10.0)
214
215
 
@@ -219,6 +220,16 @@ Populated by `baldart configure` and the `/lsp-bootstrap` skill when `features.h
219
220
  | `lsp.installed_servers` | List of language IDs (`typescript`, `python`, `go`, `rust`, `ruby`, …) whose server BALDART has recorded for this project. Identifiers map 1:1 to adapter files under `src/utils/lsp-adapters/`. |
220
221
  | `lsp.auto_verify` | When `true` (default), `baldart doctor` re-verifies the binaries are reachable **on `$PATH`** (via `command -v`, mirroring how the Claude Code LSP tool spawns them) on every run. Disable on CI if the verify step is too noisy. |
221
222
 
223
+ ### 4.7 `graph` — code knowledge graph state (since v4.21.0)
224
+
225
+ Populated by `baldart configure` / the `/graphify-bootstrap` skill when `features.has_code_graph: true`. Scalars only (no arrays) by design. See `framework/docs/CODE-GRAPH-LAYER.md`.
226
+
227
+ | Key | Meaning |
228
+ |---|---|
229
+ | `graph.output_dir` | Directory Graphify writes the graph + report to (relative to the graphed root). Graphify's native default is `graphify-out`. Add it to `.gitignore` — generated artifact, never versioned. |
230
+ | `graph.auto_rebuild_hook` | When `true` (default), `configure` / `/graphify-bootstrap` run Graphify's native `graphify hook install` (post-commit hook that rebuilds the graph, no API cost). `baldart doctor` restores it if missing. |
231
+ | `graph.register_mcp` | When `true`, register Graphify's MCP server (`graphify-mcp`) with the AI tool (best-effort `claude mcp add`). Opt-in: the CLI path (`graphify query`) works without it. |
232
+
222
233
  **Install modes per adapter:**
223
234
 
224
235
  - `typescript`, `python` — installed globally via npm (`npm install -g typescript-language-server typescript` / `pyright`). Global on purpose: the consumer spawns the server by name from `$PATH`, so a project-local devDep under `node_modules/.bin/` would never be reachable. A binary present only in `node_modules` is reported `installed-but-unreachable`, not `verified`.
@@ -0,0 +1,53 @@
1
+ name: doc-graph-align
2
+ description: Nightly documentation alignment via the Graphify code knowledge graph — rebuilds the graph offline and surfaces uncovered core code, stale docs, and registry drift.
3
+ since_version: 4.21.0
4
+
5
+ schedule:
6
+ cron: "0 4 * * *" # 04:00 UTC daily (after wiki-review at 02:00)
7
+ timezone: UTC
8
+ jitter_minutes: 0
9
+ cadence_label: nightly
10
+
11
+ agent: doc-graph-aligner
12
+
13
+ prompt: |
14
+ Run the nightly doc–graph alignment pass (only if `features.has_code_graph: true`
15
+ AND the `graphify` CLI is installed — otherwise emit
16
+ `doc-graph-align skipped: graphify not installed` and exit cleanly):
17
+
18
+ 1. Refresh the graph offline: `graphify update .` (rebuilds
19
+ `${graph.output_dir}/graph.json` + `GRAPH_REPORT.md`, no API cost).
20
+ 2. Read `${graph.output_dir}/GRAPH_REPORT.md` (god nodes, Leiden communities,
21
+ surprising connections, suggested questions, freshness).
22
+ 3. Cross-check graph → docs and flag:
23
+ - Uncovered core code: god nodes / communities with no page under
24
+ `${paths.wiki_dir}/syntheses/` and no canonical reference doc → append a
25
+ synthesis candidate to `${paths.wiki_dir}/log.md`
26
+ (`entry_type: synthesis_candidate`, cite the graph node/community id).
27
+ - Stale docs: doc files referencing symbols/files absent from the graph
28
+ (deleted/renamed code) → drift finding for doc-reviewer follow-up.
29
+ - Registry drift: large graph communities with no
30
+ `${paths.references_dir}/ssot-registry.md` entry, or registry features whose
31
+ code cluster is unrecognizable in the graph.
32
+ 4. Emit a consolidated report under
33
+ `docs/reports/{{YYYYMMDD}}-doc-graph-align.md`.
34
+
35
+ Propose, don't author: do NOT rewrite canonical SSOT or wiki pages. The graph
36
+ is never canonical — synthesis candidates must cite repo SSOT.
37
+
38
+ output:
39
+ path: docs/reports/{{YYYYMMDD}}-doc-graph-align.md
40
+ commit:
41
+ enabled: true
42
+ prefix: "[DOC-GRAPH-ALIGN]"
43
+ branch: main
44
+
45
+ required_artifacts:
46
+ - .claude/agents/doc-graph-aligner.md
47
+
48
+ optional: true # routine is silently skipped when the agent / graph layer is absent
49
+
50
+ backend_hints:
51
+ - claude-code-cloud
52
+ - github-actions
53
+ - cron
@@ -5,7 +5,7 @@
5
5
  # RemoteTrigger, GitHub Actions, cron, …) is chosen at install time via
6
6
  # `npx baldart routines install <name>`.
7
7
  #
8
- # Routines are designed to make the framework's auto-learning and drift-
8
+ # Routines are designed to make the framework's maintenance and drift-
9
9
  # detection loops actually run. Without these schedules, agents like
10
10
  # wiki-curator or skill-improver are dormant.
11
11
  #
@@ -37,9 +37,19 @@ routines:
37
37
  cadence: nightly
38
38
  since_version: 2.1.0
39
39
  summary: |
40
- Nightly wiki review — drives the LLM-wiki auto-learning loop.
41
- Surfaces synthesis candidates and validates anchors. Required for
42
- the LLM Wiki Overlay methodology to actually run.
40
+ Nightly wiki review — maintains the derived LLM-wiki overlay.
41
+ Surfaces synthesis candidates (from recent ADRs/PRDs), validates
42
+ anchors, and checks frontmatter discipline.
43
+
44
+ - name: doc-graph-align
45
+ file: doc-graph-align.routine.yml
46
+ cadence: nightly
47
+ since_version: 4.21.0
48
+ summary: |
49
+ Nightly documentation alignment via the Graphify code knowledge graph —
50
+ rebuilds the graph offline and surfaces uncovered core code, stale docs,
51
+ and registry drift. Optional (only runs when features.has_code_graph is
52
+ true and Graphify is installed).
43
53
 
44
54
  # Weekly cadence ----------------------------------------------------------
45
55
  - name: skill-improve
@@ -17,13 +17,16 @@ prompt: |
17
17
  (provider swap, schema change, auth change, API contract, multi-card
18
18
  epic) propose a synthesis page candidate and append it to
19
19
  `${paths.wiki_dir}/log.md` with `entry_type: synthesis_candidate`.
20
- 2. Read `${paths.wiki_dir}/log.md` for RAG queries with verdict=weak|empty
21
- repeated ≥3 times. These are documentation gaps propose a synthesis.
22
- 3. Validate anchor slugs across all wiki pages (internal and cross-file).
20
+ 1b. (only if `features.has_code_graph: true` AND `${graph.output_dir}/GRAPH_REPORT.md`
21
+ exists) Cross-check the code graph: god nodes / Leiden communities / suggested
22
+ questions in GRAPH_REPORT.md with no corresponding page under
23
+ `${paths.wiki_dir}/syntheses/` → propose a synthesis candidate (cite the graph
24
+ node/community id as provenance). Skip silently if Graphify is absent.
25
+ 2. Validate anchor slugs across all wiki pages (internal and cross-file).
23
26
  Flag `WIKI_ANCHOR_BROKEN` and fix in-place when possible.
24
- 4. Verify frontmatter discipline on every wiki page. Run the project's
27
+ 3. Verify frontmatter discipline on every wiki page. Run the project's
25
28
  frontmatter validator if it exists.
26
- 5. Emit a consolidated report under `docs/reports/{{YYYYMMDD}}-wiki-review.md`.
29
+ 4. Emit a consolidated report under `docs/reports/{{YYYYMMDD}}-wiki-review.md`.
27
30
 
28
31
  Do NOT create canonical truth in the wiki layer. SSOT always wins.
29
32
 
@@ -50,11 +50,6 @@ paths:
50
50
  # Default convention is "docs/metrics" — set explicitly to override.
51
51
  metrics: "" # e.g. docs/metrics
52
52
 
53
- # Optional telemetry tap for the wiki auto-learning loop. When set, skills
54
- # append retrieval signal here; when empty, the tap is skipped with a
55
- # WARNING (never a silent no-op). Only meaningful with has_wiki_overlay.
56
- wiki_log: "" # e.g. tools/doc-rag/wiki_log.py
57
-
58
53
  # High-risk module paths used by RISK DETECTORS (review-profile escalation,
59
54
  # security/perf signal detection). A portable list of repo-relative globs
60
55
  # the project considers sensitive (auth, payments, billing, core engines).
@@ -162,6 +157,18 @@ features:
162
157
  # `baldart configure` installs the relevant language servers when enabled.
163
158
  has_lsp_layer: false
164
159
 
160
+ # Code knowledge graph layer (Graphify) — since v4.21.0. When true, agents and
161
+ # skills that explore code prefer Graphify for STRUCTURAL / RELATIONAL queries
162
+ # ("what connects X to Y", neighbours, communities, impact) over LSP/Grep, and
163
+ # the LLM-wiki overlay (capture/wiki-curator) is fed by Graphify's native
164
+ # GRAPH_REPORT.md (god nodes, communities, suggested questions). Falls back
165
+ # silently to LSP -> Grep -> Git when the graph is unavailable. Graphify is a
166
+ # single language-agnostic tool (tree-sitter, local/offline; pip pkg
167
+ # `graphifyy`, CLI `graphify`). `baldart configure` / `/graphify-bootstrap`
168
+ # install it. See framework/agents/code-graph-protocol.md and
169
+ # framework/docs/CODE-GRAPH-LAYER.md.
170
+ has_code_graph: false
171
+
165
172
  # End-to-end review BLOCKING gate (since v3.18.0). When true, /new Phase 2.6
166
173
  # invokes the /e2e-review skill, which combines functional E2E (Playwright
167
174
  # spec written by `coder`, executed via playwright-skill) with visual
@@ -214,6 +221,26 @@ lsp:
214
221
  # every run. Disable on CI if the verify step is too noisy.
215
222
  auto_verify: true
216
223
 
224
+ # ─── CODE GRAPH ────────────────────────────────────────────────────────────
225
+ # State of the Graphify code-knowledge-graph layer. Populated by
226
+ # `baldart configure` / the `/graphify-bootstrap` skill. Only meaningful when
227
+ # `features.has_code_graph: true`. Scalars only (no arrays) by design.
228
+ graph:
229
+ # Directory Graphify writes the graph + report to (relative to the graphed
230
+ # root). Graphify's own default is `graphify-out`. Add it to `.gitignore` —
231
+ # it is a generated artifact, never versioned.
232
+ output_dir: graphify-out
233
+
234
+ # When true, `baldart configure` / `/graphify-bootstrap` run Graphify's
235
+ # NATIVE `graphify hook install` (post-commit git hook that rebuilds the
236
+ # graph after each commit, no API cost) so the graph never goes stale.
237
+ auto_rebuild_hook: true
238
+
239
+ # When true, register Graphify's MCP server (`graphify-mcp`) with the AI tool
240
+ # (best-effort `claude mcp add`). Opt-in: the CLI path (`graphify query`) works
241
+ # without it, so this is an enhancement, not a requirement.
242
+ register_mcp: false
243
+
217
244
  # ─── GIT ─────────────────────────────────────────────────────────────────
218
245
  # Controls how worktree-manager (`/mw`) integrates a worktree's feature
219
246
  # branch back into the integration trunk.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "baldart",
3
- "version": "4.18.0",
3
+ "version": "4.21.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"
@@ -5,6 +5,7 @@ const UI = require('../utils/ui');
5
5
  const toolAdapters = require('../utils/tool-adapters');
6
6
  const LspInstaller = require('../utils/lsp-installer');
7
7
  const lspAdapters = require('../utils/lsp-adapters');
8
+ const GraphifyInstaller = require('../utils/graphify-installer');
8
9
 
9
10
  const CONFIG_FILE = 'baldart.config.yml';
10
11
  // The subtree pull copies the entire BALDART repo (which itself has a
@@ -375,7 +376,6 @@ function detect(cwd = process.cwd()) {
375
376
  wiki_dir: exists('docs/wiki') ? 'docs/wiki' : '',
376
377
  e2e_tests_dir: e2eTestsDir,
377
378
  metrics: exists('docs/metrics') ? 'docs/metrics' : '',
378
- wiki_log: exists('tools/doc-rag/wiki_log.py') ? 'tools/doc-rag/wiki_log.py' : '',
379
379
  high_risk_modules: [],
380
380
  },
381
381
  identity: {
@@ -428,6 +428,10 @@ function detect(cwd = process.cwd()) {
428
428
  // LSP recommended when any supported language server adapter would
429
429
  // detect this project. Drives the default for the configure prompt.
430
430
  has_lsp_layer: lspAdapters.detectAll(cwd).length > 0,
431
+ // Code graph recommended when the Graphify CLI is already on PATH.
432
+ // Drives the default for the configure prompt; the install/build side
433
+ // effects only run in the interactive branch (see below).
434
+ has_code_graph: new GraphifyInstaller(cwd).detect(),
431
435
  },
432
436
  tools: {
433
437
  enabled: toolAdapters.defaultEnabled(cwd)
@@ -595,6 +599,7 @@ async function interactivePrompts(merged, detected) {
595
599
  ['has_prd_workflow', 'Project uses PRD workflow (docs/prd/)?'],
596
600
  ['has_wiki_overlay', 'Project has LLM-wiki overlay (docs/wiki/)?'],
597
601
  ['has_lsp_layer', 'Enable LSP symbol-search layer? (recommended for large codebases)'],
602
+ ['has_code_graph', 'Enable Graphify code-knowledge-graph layer? (structural queries + wiki feed; recommended for large codebases)'],
598
603
  ['has_e2e_review', 'Enable BLOCKING end-to-end review (Phase 2.6 of /new invokes /e2e-review — functional + visual fidelity gate)?'],
599
604
  ]) {
600
605
  const [key, question] = flag;
@@ -817,6 +822,67 @@ async function interactivePrompts(merged, detected) {
817
822
  merged.lsp.installed_servers = [];
818
823
  }
819
824
 
825
+ // ---- Code graph layer (Graphify, since v4.21.0) -----------------------
826
+ // Single language-agnostic tool — no per-language adapters. This block lives
827
+ // inside interactivePrompts (so it only runs in the interactive path; CI /
828
+ // `--yes` writes the flag from autodetect and `baldart doctor` backfills the
829
+ // install). Everything is a thin wrapper over Graphify's native commands.
830
+ merged.graph = merged.graph || { output_dir: 'graphify-out', auto_rebuild_hook: true, register_mcp: false };
831
+ if (merged.features.has_code_graph === true) {
832
+ UI.section('Code graph layer (Graphify — structural retrieval + wiki feed)');
833
+ const gi = new GraphifyInstaller(process.cwd());
834
+ let present = gi.detect();
835
+
836
+ if (!present) {
837
+ const want = await UI.confirm('Graphify CLI not found. Install it now (`pipx install graphifyy`)?', true);
838
+ if (want) {
839
+ const res = gi.install();
840
+ if (res.ok) { UI.success(`Graphify installed (${res.method}).`); present = true; }
841
+ else { UI.warning(`Graphify install failed: ${res.error}`); UI.info('Run `/graphify-bootstrap` or `pipx install graphifyy` later, then `baldart doctor`.'); }
842
+ } else {
843
+ UI.info('Skipping install. Run `/graphify-bootstrap` later — `baldart doctor` will flag the missing binary.');
844
+ }
845
+ } else {
846
+ const v = gi.verify();
847
+ UI.info(`Graphify present (${v.version || 'version unknown'}).`);
848
+ }
849
+
850
+ if (present) {
851
+ // Initial offline graph build (no API cost).
852
+ if (await UI.confirm('Build the code graph now (`graphify update .`, offline)?', true)) {
853
+ const b = gi.buildGraph(process.cwd());
854
+ if (!b.ok) UI.warning(`Graph build failed: ${b.error}`);
855
+ }
856
+ // Always-on wiring for each enabled AI tool (graph-first instructions + pre-tool hook).
857
+ const aw = gi.installAlwaysOn(merged.tools.enabled || ['claude']);
858
+ if (aw.wired.length) UI.success(`Graphify always-on wired for: ${aw.wired.join(', ')}`);
859
+ for (const s of aw.skipped) UI.info(`Always-on skipped for ${s.tool}: ${s.reason}`);
860
+ // Native post-commit git hook (auto-rebuild) when opted in.
861
+ if (merged.graph.auto_rebuild_hook !== false) {
862
+ const h = gi.installGitHook();
863
+ if (h.ok) UI.success('Graphify git hook installed (auto-rebuild on commit).');
864
+ else UI.info(`Git hook not installed: ${h.error}`);
865
+ }
866
+ // Optional MCP registration (CLI path works without it).
867
+ if (merged.graph.register_mcp === true) {
868
+ const m = gi.registerMcp(process.cwd(), merged.graph.output_dir || 'graphify-out');
869
+ if (m.ok) UI.success('Graphify MCP server registered (`graphify-mcp`).');
870
+ else UI.info(`MCP registration skipped: ${m.reason}`);
871
+ }
872
+
873
+ // Certification — attest binary + first run + freshness + hook in one shot.
874
+ const cert = gi.certify(process.cwd(), {
875
+ outputDir: merged.graph.output_dir || 'graphify-out',
876
+ expectHook: merged.graph.auto_rebuild_hook !== false,
877
+ });
878
+ if (cert.ok && cert.fresh && cert.hook) {
879
+ UI.success(`Code graph CERTIFIED: graphify ${cert.version || ''} present, first graph built (${cert.builtAtCommit || 'commit n/a'}), auto-rebuild hook active.`);
880
+ } else {
881
+ UI.warning(`Code graph NOT fully certified — ${cert.details}${cert.hook ? '' : ' · auto-rebuild hook missing'}. Run \`baldart doctor\` or \`/graphify-bootstrap\` to finish.`);
882
+ }
883
+ }
884
+ }
885
+
820
886
  UI.section('Stack (autodetected from package.json — confirm or override)');
821
887
  const charting = merged.stack.charting;
822
888
  const chartingCanonical = await promptForKey(
@@ -32,6 +32,7 @@ const State = require('../utils/state');
32
32
  const Hooks = require('../utils/hooks');
33
33
  const GitHooks = require('../utils/githooks');
34
34
  const LspInstaller = require('../utils/lsp-installer');
35
+ const GraphifyInstaller = require('../utils/graphify-installer');
35
36
  const UpdateNotifier = require('../utils/update-notifier');
36
37
  const cliPackageJson = require('../../package.json');
37
38
 
@@ -363,6 +364,30 @@ async function detectState(cwd, opts = {}) {
363
364
  }
364
365
  }
365
366
  } catch (_) { /* never block doctor on LSP probe */ }
367
+
368
+ // ---- Code graph layer (Graphify, since v4.21.0) --------------------
369
+ state.graphEnabled = false;
370
+ state.graphBinaryMissing = false;
371
+ state.graphStale = false;
372
+ state.graphNotBuilt = false;
373
+ state.graphHookMissing = false;
374
+ try {
375
+ if (config && !config.__malformed && config.features && config.features.has_code_graph === true) {
376
+ state.graphEnabled = true;
377
+ const gi = new GraphifyInstaller(cwd);
378
+ if (!gi.detect()) {
379
+ state.graphBinaryMissing = true;
380
+ } else {
381
+ const outDir = (config.graph && config.graph.output_dir) || 'graphify-out';
382
+ const st = gi.isStale(cwd, outDir);
383
+ state.graphNotBuilt = !st.built;
384
+ state.graphStale = st.stale === true;
385
+ if (config.graph && config.graph.auto_rebuild_hook !== false) {
386
+ state.graphHookMissing = gi.hookStatus(cwd).installed === false;
387
+ }
388
+ }
389
+ }
390
+ } catch (_) { /* never block doctor on graph probe */ }
366
391
  }
367
392
 
368
393
  return state;
@@ -702,6 +727,60 @@ function planActions(state) {
702
727
  });
703
728
  }
704
729
 
730
+ // ---- Code graph layer (Graphify, since v4.21.0) ----------------------
731
+ // The install side effects of `configure` only run interactively (a Python
732
+ // tool is never installed silently in CI). So doctor is the backfill: it
733
+ // installs the binary, (re)builds a stale/missing graph, and restores the
734
+ // native auto-rebuild git hook.
735
+ if (state.graphEnabled && state.graphBinaryMissing) {
736
+ actions.push({
737
+ key: 'graph-install',
738
+ label: 'Install Graphify code-graph tool',
739
+ why: 'features.has_code_graph is true but the `graphify` CLI is not on $PATH. Agents fall back to LSP/Grep and the wiki feed is dormant until it is installed (`pipx install graphifyy`).',
740
+ autoOk: false, // installs a Python package; let the user confirm
741
+ run: async () => {
742
+ const gi = new GraphifyInstaller(state.cwd);
743
+ const res = gi.install();
744
+ if (res.ok) {
745
+ UI.success(`Graphify installed (${res.method}).`);
746
+ const b = gi.buildGraph(state.cwd);
747
+ if (!b.ok) UI.warning(`Initial graph build failed: ${b.error}`);
748
+ } else {
749
+ UI.warning(`Install failed: ${res.error}`);
750
+ }
751
+ },
752
+ });
753
+ }
754
+ if (state.graphEnabled && !state.graphBinaryMissing && (state.graphStale || state.graphNotBuilt)) {
755
+ actions.push({
756
+ key: 'graph-rebuild',
757
+ label: state.graphNotBuilt ? 'Build the code graph (not built yet)' : 'Rebuild the stale code graph',
758
+ why: state.graphNotBuilt
759
+ ? 'features.has_code_graph is true but no graph.json exists yet. Build it (`graphify update .`, offline, no API cost).'
760
+ : 'The code graph was built from an older commit than HEAD (built_at_commit ≠ HEAD). Rebuild so structural queries and the wiki feed reflect current code.',
761
+ autoOk: true, // offline, idempotent, no API cost
762
+ run: async () => {
763
+ const gi = new GraphifyInstaller(state.cwd);
764
+ const b = gi.buildGraph(state.cwd);
765
+ if (!b.ok) UI.warning(`Graph build failed: ${b.error}`);
766
+ },
767
+ });
768
+ }
769
+ if (state.graphEnabled && !state.graphBinaryMissing && state.graphHookMissing) {
770
+ actions.push({
771
+ key: 'graph-hook',
772
+ label: 'Install Graphify auto-rebuild git hook',
773
+ why: 'graph.auto_rebuild_hook is true but Graphify\'s native post-commit hook is not installed, so the graph will drift after commits. `graphify hook install` restores it.',
774
+ autoOk: true,
775
+ run: async () => {
776
+ const gi = new GraphifyInstaller(state.cwd);
777
+ const h = gi.installGitHook(state.cwd);
778
+ if (h.ok) UI.success('Graphify git hook installed.');
779
+ else UI.warning(`Hook install failed: ${h.error}`);
780
+ },
781
+ });
782
+ }
783
+
705
784
  // v3.25.0+: drift detection is authoritative via VERSION compare (isAligned).
706
785
  // The HEAD...FETCH_HEAD commit count is subtree-merge noise and never reaches
707
786
  // 0, so we MUST NOT use it as the "needs update" signal.
@@ -946,6 +1025,18 @@ function renderDiagnostic(state) {
946
1025
  console.log(statusLine('LSP layer', 'disabled', 'ok'));
947
1026
  }
948
1027
 
1028
+ if (state.graphEnabled) {
1029
+ let value, severity;
1030
+ if (state.graphBinaryMissing) { value = 'enabled but graphify CLI missing'; severity = 'warn'; }
1031
+ else if (state.graphNotBuilt) { value = 'enabled, graph not built yet'; severity = 'warn'; }
1032
+ else if (state.graphStale) { value = 'enabled, graph stale (behind HEAD)'; severity = 'warn'; }
1033
+ else if (state.graphHookMissing) { value = 'enabled, verified (auto-rebuild hook missing)'; severity = 'warn'; }
1034
+ else { value = 'enabled, graph fresh'; severity = 'ok'; }
1035
+ console.log(statusLine('Code graph', value, severity));
1036
+ } else {
1037
+ console.log(statusLine('Code graph', 'disabled', 'ok'));
1038
+ }
1039
+
949
1040
  console.log();
950
1041
  }
951
1042
 
@@ -1291,11 +1291,17 @@ async function update(options = {}, unknownArgs = []) {
1291
1291
  const missingStack = Object.keys(tpl.stack || {})
1292
1292
  .filter((k) => typeof tpl.stack[k] === 'string')
1293
1293
  .filter((k) => !(k in (cur2.stack || {})));
1294
+ // Top-level nested config namespaces (e.g. `graph:` since v4.21.0).
1295
+ // Unlike `lsp:` (which propagates only via its `has_lsp_layer` flag),
1296
+ // diff the block's own scalar keys so a new sub-key surfaces too.
1297
+ const missingGraph = Object.keys(tpl.graph || {})
1298
+ .filter((k) => !(k in (cur2.graph || {})));
1294
1299
  const allMissing = [
1295
1300
  ...missingPaths,
1296
1301
  ...missingFeatures,
1297
1302
  ...missingGit.map((k) => `git.${k}`),
1298
1303
  ...missingStack.map((k) => `stack.${k}`),
1304
+ ...missingGraph.map((k) => `graph.${k}`),
1299
1305
  ];
1300
1306
  if (allMissing.length) {
1301
1307
  UI.newline();