@hegemonart/get-design-done 1.30.5 → 1.31.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 (43) hide show
  1. package/.claude-plugin/marketplace.json +6 -3
  2. package/.claude-plugin/plugin.json +5 -2
  3. package/CHANGELOG.md +129 -0
  4. package/README.md +22 -1
  5. package/SKILL.md +1 -0
  6. package/agents/design-integration-checker.md +1 -1
  7. package/agents/design-planner.md +1 -1
  8. package/agents/gdd-graph-refresh.md +90 -0
  9. package/bin/gdd-graph +261 -0
  10. package/connections/connections.md +10 -9
  11. package/connections/graphify.md +65 -54
  12. package/package.json +8 -3
  13. package/reference/capability-gap-stage-gate.md +7 -4
  14. package/reference/model-tiers.md +2 -2
  15. package/reference/start-interview.md +1 -1
  16. package/scripts/detect-stale-refs.cjs +6 -0
  17. package/scripts/lib/figma-extract/digest.cjs +430 -0
  18. package/scripts/lib/figma-extract/parse-url.cjs +87 -0
  19. package/scripts/lib/figma-extract/payload-schema.json +108 -0
  20. package/scripts/lib/figma-extract/pull.cjs +394 -0
  21. package/scripts/lib/figma-extract/receiver.cjs +273 -0
  22. package/scripts/lib/figma-extract/render-md.cjs +143 -0
  23. package/scripts/lib/figma-extract/styles-resolver.cjs +147 -0
  24. package/scripts/lib/figma-extract/walk.cjs +100 -0
  25. package/scripts/lib/graph/atomic-write.mjs +68 -0
  26. package/scripts/lib/graph/build.mjs +124 -0
  27. package/scripts/lib/graph/diff.mjs +90 -0
  28. package/scripts/lib/graph/index.mjs +14 -0
  29. package/scripts/lib/graph/query.mjs +155 -0
  30. package/scripts/lib/graph/schema.json +69 -0
  31. package/scripts/lib/graph/schema.mjs +47 -0
  32. package/scripts/lib/graph/status.mjs +88 -0
  33. package/scripts/lib/graph/token-estimate.mjs +27 -0
  34. package/scripts/lib/graph/upsert.mjs +210 -0
  35. package/scripts/lib/{gsd-health-mirror → health-mirror}/index.cjs +89 -2
  36. package/scripts/mcp-servers/gdd-mcp/tools/gdd_health.ts +3 -3
  37. package/skills/connections/connections-onboarding.md +6 -6
  38. package/skills/figma-extract/SKILL.md +64 -0
  39. package/skills/graphify/SKILL.md +11 -10
  40. package/skills/health/SKILL.md +10 -0
  41. package/skills/scan/scan-procedure.md +9 -8
  42. package/agents/gdd-graphify-sync.md +0 -110
  43. /package/scripts/lib/{gsd-health-mirror → health-mirror}/index.d.cts +0 -0
@@ -5,14 +5,14 @@
5
5
  },
6
6
  "metadata": {
7
7
  "description": "Get Design Done — 5-stage agent-orchestrated design pipeline with 9 connections, handoff-first workflow, bidirectional Figma write-back, 22+ specialized agents, queryable knowledge layer (intel store, dependency analysis, learnings extraction), and a self-improvement loop (reflector, frontmatter + budget feedback, global-skills layer). v1.20.0 ships the SDK foundation: gdd-state MCP server (11 typed tools), lockfile-safe STATE.md mutations, event stream, and resilience primitives (jittered-backoff, rate-guard, error-classifier, iteration-budget) for rate-limit + 429 + context-overflow recovery. Full CI/CD pipeline (Node 22/24 × Linux/macOS/Windows) and release automation (auto-tag + GitHub Release + release-time smoke test).",
8
- "version": "1.30.5"
8
+ "version": "1.31.0"
9
9
  },
10
10
  "plugins": [
11
11
  {
12
12
  "name": "get-design-done",
13
13
  "source": "./",
14
14
  "description": "Agent-orchestrated 5-stage design pipeline: Brief → Explore → Plan → Design → Verify. 22+ specialized agents, 9 connections (Figma, Refero, Preview, Storybook, Chromatic, Figma Writer, Graphify, Pinterest, Claude Design), Claude Design handoff, bidirectional Figma write-back, and a queryable intel store (.design/intel/) for dependency and learnings queries. Standalone commands: style, darkmode, compare, figma-write, graphify, handoff, analyze-dependencies, skill-manifest, extract-learnings. Embeds NNG heuristics, WCAG thresholds, typographic systems, motion framework, and anti-pattern catalog. Ships with a full CI/CD pipeline (Node 22/24 × Linux/macOS/Windows) and release automation. Optimization layer (v1.0.4.1, retroactive): gdd-router + gdd-cache-manager skills, PreToolUse budget-enforcer hook, tier-aware agent frontmatter, lazy checker gates, streaming synthesizer, /gdd:warm-cache + /gdd:optimize commands, and cost telemetry at .design/telemetry/costs.jsonl — targeting 50-70% per-task token-cost reduction with no quality-floor regression. v1.20.0 SDK foundation: gdd-state MCP server (11 typed tools), lockfile-safe STATE.md mutations, event stream at .design/telemetry/events.jsonl, resilience primitives (jittered-backoff, rate-guard, error-classifier, iteration-budget) with rate-limit + 429 + context-overflow recovery, and TypeScript toolchain.",
15
- "version": "1.30.5",
15
+ "version": "1.31.0",
16
16
  "author": {
17
17
  "name": "hegemonart"
18
18
  },
@@ -68,7 +68,10 @@
68
68
  "gemini",
69
69
  "mcp",
70
70
  "parallel-agents",
71
- "agent-sdk"
71
+ "agent-sdk",
72
+ "figma",
73
+ "extractor",
74
+ "design-system-sync"
72
75
  ]
73
76
  }
74
77
  ]
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "get-design-done",
3
3
  "short_name": "gdd",
4
- "version": "1.30.5",
4
+ "version": "1.31.0",
5
5
  "description": "Agent-orchestrated 5-stage design pipeline: Brief → Explore → Plan → Design → Verify. 22+ specialized agents, 9 connections (Figma, Refero, Preview, Storybook, Chromatic, Figma Writer, Graphify, Pinterest, Claude Design), handoff-first workflow via Claude Design bundles, bidirectional Figma write-back (annotations, Code Connect), queryable intel store (`.design/intel/`) for O(1) design surface lookups, and self-improvement loop (reflector agent, frontmatter + budget feedback, global-skills layer at `~/.claude/gdd/global-skills/`). Standalone commands: style, darkmode, compare, figma-write, graphify, handoff, analyze-dependencies, skill-manifest, extract-learnings, reflect, apply-reflections. Embeds NNG heuristics, WCAG thresholds, typographic systems, motion framework, and anti-pattern catalog. Ships with a full CI/CD pipeline (Node 22/24 × Linux/macOS/Windows, lint + schema + frontmatter + stale-ref + shellcheck + gitleaks + injection-scan + blocking size-budget) and release automation (auto-tag + GitHub Release + release-time smoke test). Optimization layer (v1.0.4.1, retroactive): gdd-router + gdd-cache-manager skills, PreToolUse budget-enforcer hook, tier-aware agent frontmatter, lazy checker gates, streaming synthesizer, /gdd:warm-cache + /gdd:optimize commands, and cost telemetry at .design/telemetry/costs.jsonl — targeting 50-70% per-task token-cost reduction with no quality-floor regression. v1.20.0 SDK foundation: gdd-state MCP server (11 typed tools), lockfile-safe STATE.md mutations, event stream at .design/telemetry/events.jsonl, resilience primitives (jittered-backoff, rate-guard, error-classifier, iteration-budget) with rate-limit + 429 + context-overflow recovery, and TypeScript toolchain. v1.27.7 ships gdd-mcp (Phase 27.7): 12 read-only MCP tools for sub-3s priming. v1.28.0 (Phase 28): Foundational References Tier 2 — 5 new reference files (color-theory, composition, proportion-systems, i18n, contrast-advanced), 2 verifier i18n probes + 1 explore i18n-readiness probe, 12 additive cross-link insertions across 10 existing references, 2 orthogonal audit-scoring lens-tags (composition_alignment + i18n_readiness).",
6
6
  "author": {
7
7
  "name": "hegemonart",
@@ -62,7 +62,10 @@
62
62
  "agent-sdk",
63
63
  "mcp-server",
64
64
  "context-loading",
65
- "cross-session"
65
+ "cross-session",
66
+ "figma",
67
+ "extractor",
68
+ "design-system-sync"
66
69
  ],
67
70
  "skills": [
68
71
  "./skills/"
package/CHANGELOG.md CHANGED
@@ -4,6 +4,135 @@ All notable changes to get-design-done are documented here. Versions follow [sem
4
4
 
5
5
  ---
6
6
 
7
+ ## [1.31.0] - 2026-05-29
8
+
9
+ ### Phase 31 — Figma Off-Context Extractor + Variables Sync Plugin
10
+
11
+ Ships `gdd-figma-extract` — pull a whole Figma design system into a compact, queryable local digest (`DESIGN.md` + `tokens.json` + `components.json`) **without the raw JSON ever entering Claude's context**. One command extracts the file via the Figma REST API to a local raw cache; a separate digest stage reduces it to an LLM-readable spec. Plus a thin **"GDD Sync"** Figma plugin that fills the Variables-API-Enterprise gap by reading `figma.variables` from inside Figma (works on any plan — including Free) and POSTing them to an ephemeral localhost receiver. 10 plans across 4 waves: Wave A (raw puller + digest + styles resolver + SKILL), Wave B (plugin scaffold + export + receiver), Wave C (`--component` slice + `figma_extract` health check), Wave D (closeout).
12
+
13
+ ### Motivation — the spike trail
14
+
15
+ Spike 001 (commit `c3a9cf6`, `.planning/spikes/001-figma-offcontext-extractor/`) validated the economics: **898× compression** (223 MB raw → 254 KB digest), a 15.7K-token DESIGN.md (under the 20K target), 127 component sets + 40 singletons captured with variants/props/defaults, ~33s wall time, and crucially **0 Claude tokens + 0 Figma MCP calls during extraction**. This is the economic alternative to Figma MCP for whole-design-system workflows (Figma MCP remains correct for spot questions on individual components). The spike surfaced two gaps, both closed by this phase:
16
+
17
+ 1. **Variables API → 403 (Enterprise-only)** — closed by **Path C** (the GDD Sync plugin reads variables locally and POSTs to the receiver).
18
+ 2. **Legacy styles → 0 tokens** — closed by **Path B** (two-step `/styles` + `/nodes?ids=` lookup; published-style source nodes live in canvas frames, not the main document tree).
19
+
20
+ ### Added
21
+
22
+ - **`gdd-figma-extract` off-context extractor** — the two-stage pipeline (D-01: extract → digest stay separated, re-digest without re-pulling):
23
+ - `scripts/lib/figma-extract/pull.cjs` — productionized Figma REST puller (retry/backoff, version-based cache invalidation with 1h TTL fallback per D-11, drops `geometry=paths` per D-03). Writes raw JSON to disk only; raw bodies never returned to a logging caller.
24
+ - `scripts/lib/figma-extract/digest.cjs` — reads the raw cache, walks the node tree with **variant rollup** (D-02 — naive walk inflates ~16×), assembles tokens via the 3-path chain, renders `DESIGN.md` + `tokens.json` + `components.json`.
25
+ - `scripts/lib/figma-extract/styles-resolver.cjs` — **Path B** two-step `/styles` + `/nodes?ids=` resolver (fixes the spike's 0-tokens bug).
26
+ - `scripts/lib/figma-extract/render-md.cjs` + `walk.cjs` — deterministic, byte-stable DESIGN.md renderer + the variant-rollup walker.
27
+ - **Three-path token extraction (D-04)** with a fallback chain — Path A (Variables API, Enterprise; 403 skipped silently), Path B (`/styles` + `/nodes`), Path C (plugin sync). Resolution priority on collision: Variables > plugin sync > styles, with a `--prefer-styles` escape hatch.
28
+ - **"GDD Sync" Figma plugin** (`figma-plugin/`, D-05) — TypeScript, single "Export to GDD" button. Reads ALL local variables (D-13 — digest filters later), resolves aliases + modes, and POSTs to the localhost receiver.
29
+ - **Localhost receiver** (`scripts/lib/figma-extract/receiver.cjs`, D-06) — ephemeral, **127.0.0.1-only**, port hardcoded to 5179, schema-validated, refuses non-loopback remotes, exits on first valid receipt or timeout.
30
+ - **`--component <name|glob>` digest slice** (D-08) — a ~500-token per-component slice instead of the full ~16K digest; strictly additive (omitting it reproduces the full digest unchanged).
31
+ - **`figma_extract` health check** (Plan 31-09) — `/gdd:health` now reports one of three exact states: `figma extract: ready (token set)`, `figma extract: token missing`, or `figma extract: plugin sync needed for variables (Free tier detected)`. Presence-only token check (D-10); the Free-tier signal is read from the local raw-pull cache only (no network call).
32
+ - **`skills/figma-extract/SKILL.md`** (`name: gdd-figma-extract`) — off-context orchestration that never instructs reading `raw/*.json` (D-12).
33
+ - **`tests/phase-31-baseline.test.cjs`** + 6 baseline files at `test-fixture/baselines/phase-31/` (design-md, components-json, tokens-json, health-line, manifest-network-scope, token-isolation-static), **`tests/phase-31-end-to-end.test.cjs`** (offline pull+digest against fixtures), and **`tests/figma-extract-token-isolation.test.cjs`** (the D-10 static scanner + meta-tests).
34
+
35
+ ### Security & guarantees
36
+
37
+ - **Off-context guarantee (D-12) — statically enforced.** The SKILL never instructs reading `raw/*.json`; the digest is a pure function of the raw cache. The raw pull consumes 0 Claude tokens.
38
+ - **Token isolation (D-10) — statically enforced.** `FIGMA_TOKEN` (fallback `FIGMA_PERSONAL_ACCESS_TOKEN`) is read from the environment only and is sent ONLY as the `X-Figma-Token` request header — never logged, never written to disk. `tests/figma-extract-token-isolation.test.cjs` scans every file under `scripts/lib/figma-extract/` for any `writeFile`/`appendFile`/`console.*`/`logger.*`/`process.std*.write` call referencing the token and fails on a non-zero count (meta-tested to prove the scanner is not vacuous).
39
+ - **Receiver network scope (D-06).** The plugin manifest's `allowedDomains` is exactly the localhost pair (`http://localhost:5179`, `http://127.0.0.1:5179`) — any widening trips the baseline test. No external host, no wildcard.
40
+
41
+ ### Deferred
42
+
43
+ - **Live Figma validation (D-07).** The phase ships with hermetic offline tests (stubbed fetch against committed fixtures); a one-time end-to-end run against a real Figma file with a live token is a maintainer follow-up, not a v1.31.0 blocker. Plugin Community-directory submission is likewise deferred (dev-install path ships now).
44
+
45
+ ### Decisions (D-01 through D-13)
46
+
47
+ - **D-01**: Two-stage pipeline (extract → digest) stays separated. Re-run digest without re-pulling.
48
+ - **D-02**: Variant rollup default-on — skip COMPONENT children of a COMPONENT_SET; record variants as a field on the parent (naive walk inflates ~16×).
49
+ - **D-03**: Drop the `geometry=paths` query param (~30% smaller raw; geometry is discarded in the digest).
50
+ - **D-04**: Three-path token extraction with a fallback chain (Variables > plugin sync > styles; `--prefer-styles` escape).
51
+ - **D-05**: "GDD Sync" plugin as a separate `figma-plugin/` package (TypeScript, single button).
52
+ - **D-06**: Receiver is ephemeral + 127.0.0.1-only + hardcoded port 5179; refuses non-loopback; closes on receipt or timeout.
53
+ - **D-07**: Plugin distribution is dev-build now, Community submission as a follow-up; live-Figma validation is a maintainer follow-up — neither blocks v1.31.0.
54
+ - **D-08**: `--component <name|glob>` filter on digest for per-component slicing (~500 tokens vs ~16K).
55
+ - **D-09**: Raw cache gitignored (`.figma-extract-cache/`), reproducible from `pull.cjs`; `digest/` artifacts may be committed.
56
+ - **D-10**: Token never logged or persisted — `FIGMA_TOKEN` from env only; CI static-analysis test enforces it library-wide.
57
+ - **D-11**: Cache invalidation is content-based via Figma's `version` field, with a 1h wall-clock TTL fallback.
58
+ - **D-12**: Off-context guarantee enforced statically — the skill never instructs reading `raw/*.json`.
59
+ - **D-13**: Plugin emits ALL local variables (not just published-collection ones); filtering happens at the digest stage.
60
+
61
+ ### Backward compatibility
62
+
63
+ - 4-manifest + 2 Tier-2 manifest lockstep at v1.31.0 (`package.json` + `.claude-plugin/plugin.json` + `.claude-plugin/marketplace.json` (metadata.version + plugins[0].version) + `.cursor-plugin/plugin.json` + `.codex-plugin/plugin.json`). Keywords `figma`, `extractor`, `design-system-sync` added across the manifest keyword arrays.
64
+ - `NOTICE` preserved verbatim — Phase 31 productionizes our own spike (`c3a9cf6`) and uses Figma's official REST + plugin APIs plus `@figma/plugin-typings` (a normal npm devDependency, not a vendored code transplant). No third-party CODE was vendored, so no new attribution is owed.
65
+
66
+ ---
67
+
68
+ ## [1.30.6] - 2026-05-28
69
+
70
+ ### Phase 30.6 — Graphify Self-Ownership
71
+
72
+ Removes the **last runtime touchpoint** between get-design-done and the user's `~/.claude/get-shit-done/` install. 8 callsites in `agents/`, `skills/`, and `connections/` previously dispatched the upstream `gsd-tools` graphify subcommands at runtime; they now dispatch native `bin/gdd-graph`. After v1.30.6, a user who has never installed GSD (or who only installs the failed upstream and not the redux fork) can still run the full GDD pipeline including everything that touches the knowledge graph. 9 plans across 3 waves: Wave A (research + spec), Wave B (`bin/gdd-graph` core + extensions + decoupling acceptance test, 56 tests), Wave C (migration + rename + cleanup + closeout).
73
+
74
+ ### Motivation — rug-pull resilience
75
+
76
+ The `gsd-build/get-shit-done` rug-pull in May 2026 (TÂCHES drained $GSD Solana token + deleted accounts) was downstream-survivable for us — we have zero npm dependency on GSD packages, the community fork `open-gsd/get-shit-done-redux` is MIT-bit-perfect, and Phase 28.7's install-pipeline port is standalone in our tree. The remaining touchpoint was graphify runtime dispatch. Phase 30.6 closes it. After v1.30.6, our runtime is independent of upstream's release cadence and any future subcommand / schema drift.
77
+
78
+ ### Added
79
+
80
+ - **`bin/gdd-graph`** native Node CLI with 6 subcommands: `build`, `query`, `status`, `diff`, `upsert-node`, `upsert-edge`. Output at `.design/graph/graph.json` (D-02), Ajv-validated against `scripts/lib/graph/schema.json` schema 1.0 (D-03), atomic-write seam per D-05 (tmp + rename in same dir; no `proper-lockfile`).
81
+ - **Token-budget heuristic** for `gdd-graph query --budget N` per D-04: `Math.ceil(JSON.stringify(payload).length / 4)`; override via `GDD_GRAPH_TOKEN_FACTOR` env for tests.
82
+ - **5-scenario decoupling test** at `tests/graph-decoupled.test.cjs` (19 tests) — renames `~/.claude/get-shit-done/` to `.bak` for test duration, exercises all 6 subcommands across 5 fixture scenarios (empty / single-node / dense / with-cycles / malformed-intel). Single most important acceptance gate of the phase.
83
+ - **`tests/phase-30.6-baseline.test.cjs`** + 5 baseline files at `test-fixture/baselines/phase-30.6/` (manifests-version, decoupling-callsite-count, gdd-graph-subcommand-inventory, graph-schema-shape, no-gsd-runtime-touch).
84
+ - **D-01 through D-10** locked decisions + 5 sub-decisions (D-03.a/b/c, D-04.a, D-09.a) documented in `.planning/phases/30.6-graphify-self-ownership/`.
85
+
86
+ ### Changed
87
+
88
+ - **8 callsite files** migrated from `gsd-tools.cjs graphify *` dispatch to native `bin/gdd-graph`:
89
+ - `agents/gdd-graphify-sync.md` (renamed to `gdd-graph-refresh.md`)
90
+ - `agents/design-integration-checker.md`
91
+ - `agents/design-planner.md`
92
+ - `skills/graphify/SKILL.md`
93
+ - `skills/scan/scan-procedure.md`
94
+ - `skills/connections/connections-onboarding.md`
95
+ - `connections/connections.md`
96
+ - `connections/graphify.md` (rewritten for native CLI, no external graphifyy)
97
+ - **`agents/gdd-graphify-sync.md`** renamed to **`agents/gdd-graph-refresh.md`** (D-08 one-way rename, no alias) — protocol simplified now that we own both ends of the intel→graph translation (single schema; no translation step).
98
+ - **`scripts/lib/gsd-health-mirror/`** renamed to **`scripts/lib/health-mirror/`** (D-10 cosmetic, atomic with single import-site update at `scripts/mcp-servers/gdd-mcp/tools/gdd_health.ts`). The module is pure local-file inspection; the "mirror" refers to our own `skills/health/SKILL.md` surface, never upstream.
99
+ - **`.design/graph/`** replaces upstream's `.planning/graphs/` location (per D-02 — aligns with the rest of GDD's `.design/` artifact convention).
100
+ - **`connections/graphify.md`** rewritten for native CLI (no external `graphifyy` dependency).
101
+ - **`reference/start-interview.md`** updated to reference `/gdd:discuss` (our equivalent) instead of `/gsd-discuss-phase`.
102
+ - **`README.md`** at the `gsd-build/get-shit-done (MIT — see NOTICE)` citation gains the redux-pointer parenthetical "(now archived; community continuation at `open-gsd/get-shit-done-redux`)". Citation preserved verbatim — only annotated for reader clarity.
103
+ - **Graphify enable/disable state** (D-09) lives in `.design/config.json` at `{ "graphify": { "enabled": bool } }`. Read directly by `gdd-graph` via fs; no `config-set` / `config-get` CLI subcommand.
104
+
105
+ ### Removed
106
+
107
+ - **Runtime dispatch into `~/.claude/get-shit-done/`** — 8 callsites no longer invoke `gsd-tools.cjs graphify *`.
108
+ - **`.planning/get-shit-done-main/`** (10MB pre-rug-pull vendored snapshot) — used during Phase 28.7's architectural port; port shipped, snapshot dead weight.
109
+ - Intel→graphify translation layer (dead code post-migration; intel slices are now the canonical input to `bin/gdd-graph build` with no intermediate translation step).
110
+
111
+ ### Backward compatibility
112
+
113
+ - Phase 27 / Phase 28.5 / Phase 28.7 `NOTICE` attribution subsections **preserved verbatim** per D-06. Those describe historical MIT/Apache ports (peer-CLI delegation protocol shapes from cc-multi-cli; skill-authoring contract from mattpocock/skills; install-pipeline architecture from gsd-build/get-shit-done) — they remain in our tree under the original MIT/Apache terms. Phase 30.6 removes a **runtime touchpoint**, not a **historical port**.
114
+ - `.design/intel/` schema unchanged — Phase 10's knowledge layer keeps its current ownership; we only consume from it differently.
115
+ - 4-manifest + 2 Tier-2 manifest lockstep at v1.30.6 (`package.json` + `.claude-plugin/plugin.json` + `.claude-plugin/marketplace.json` (metadata.version + plugins[0].version) + `.cursor-plugin/plugin.json` + `.codex-plugin/plugin.json`).
116
+
117
+ ### Decisions (D-01 through D-10)
118
+
119
+ - **D-01**: Native CLI binary name = `gdd-graph` (not `gdd-graphify`). Shorter; doesn't semantically shadow the user's `/gsd:graphify-*` redux commands.
120
+ - **D-02**: Canonical graph file at `.design/graph/graph.json` (not upstream's `.planning/graphs/graph.json`). Aligns with the rest of GDD's `.design/` artifact convention.
121
+ - **D-03**: Schema validated by Ajv against `scripts/lib/graph/schema.json` on every write; schema version pinned to `1.0` at ship; future migrations bump explicitly.
122
+ - **D-04**: Token-budget heuristic = `Math.ceil(JSON.stringify(payload).length / 4)`; `GDD_GRAPH_TOKEN_FACTOR` env override for tests.
123
+ - **D-05**: Atomic-write seam = `fs.writeFile(tmpPath); fs.rename(tmpPath, finalPath)` in same directory. No `proper-lockfile`. Single-writer assumption (revisit if Phase 41 Team Collaboration forces multi-writer).
124
+ - **D-06**: `NOTICE` retains Phase 27 / Phase 28.5 / Phase 28.7 architectural attributions verbatim. We're removing a runtime touchpoint, not voiding a historical port.
125
+ - **D-07**: Phase 30.6 ships off-cadence as a decimal from v1.30.5 parent (same shape v1.30.5 used coming off v1.30.0). NO 1.31.x bump.
126
+ - **D-08**: Agent rename `gdd-graphify-sync` → `gdd-graph-refresh` is one-way (no alias). Internal name; no external callers from outside the plugin.
127
+ - **D-09**: Graphify enable/disable state lives in `.design/config.json` at `{ "graphify": { "enabled": bool } }`. Read directly by `gdd-graph` via `JSON.parse(fs.readFileSync(...))` with sensible default (`enabled: false`). No `config-set` / `config-get` CLI subcommand — simpler than the upstream config-tool pattern.
128
+ - **D-10**: `scripts/lib/gsd-health-mirror/` rename is one-way (no alias). Only one import site (`scripts/mcp-servers/gdd-mcp/tools/gdd_health.ts`) which is updated atomically with the rename.
129
+
130
+ ### Attribution preservation
131
+
132
+ Phase 27 / Phase 28.5 / Phase 28.7 attribution subsections in `NOTICE` are preserved verbatim per D-06. The architectural ports they describe are historical MIT-licensed code transplants; this release removes a runtime touchpoint, **NOT** a historical port. The `gsd-build/get-shit-done (MIT — see NOTICE)` citation in `README.md` is preserved verbatim; only the redux-pointer parenthetical was added.
133
+
134
+ ---
135
+
7
136
  ## [1.30.5] - 2026-05-21
8
137
 
9
138
  ### Phase 30.5 — Failure-Mode Catalogue
package/README.md CHANGED
@@ -139,7 +139,7 @@ The installer prompts you to choose:
139
139
  1. **Runtime** — Claude Code, OpenCode, Gemini, Kilo, Codex, Copilot, Cursor, Windsurf, Antigravity, Augment, Trae, Qwen Code, CodeBuddy, Cline, or all (interactive multi-select — pick multiple runtimes in a single session)
140
140
  2. **Location** — Global (all projects) or local (current project only)
141
141
 
142
- All 14 runtimes receive their native artifact layout (`skills/`, `command/`, `agents/`, or `.clinerules`) via per-runtime content converters — Claude SKILL.md sources are translated to each runtime's expected shape at install time (frontmatter pass-through, path rewrite, tool-name rewrite via the Phase 21 cross-harness maps). Architecture ported from `gsd-build/get-shit-done` (MIT — see `NOTICE`).
142
+ All 14 runtimes receive their native artifact layout (`skills/`, `command/`, `agents/`, or `.clinerules`) via per-runtime content converters — Claude SKILL.md sources are translated to each runtime's expected shape at install time (frontmatter pass-through, path rewrite, tool-name rewrite via the Phase 21 cross-harness maps). Architecture ported from `gsd-build/get-shit-done` (MIT — see `NOTICE`; upstream is now archived following the May 2026 $GSD token rug-pull, community continuation lives at [`open-gsd/get-shit-done-redux`](https://github.com/open-gsd/get-shit-done-redux)).
143
143
 
144
144
  Verify with:
145
145
 
@@ -256,6 +256,27 @@ When K=3 stable clusters surface across M=10 reflection cycles (defaults in `ref
256
256
  **Discipline preserved.** Reflector authors nothing that auto-ships. `/gdd:apply-reflections` remains the single human gate (Phase 11 SC-8). Stage 1 never auto-flips — user opts in.
257
257
 
258
258
 
259
+ ### Figma off-context extraction (v1.31.0+)
260
+
261
+ Pull an entire Figma design system into a compact, LLM-readable local digest — **without the raw JSON ever entering Claude's context**. One command extracts the file via the Figma REST API into a local raw cache; a separate digest stage reduces it to `DESIGN.md` + `tokens.json` + `components.json`.
262
+
263
+ ```bash
264
+ # Stage 1 — raw pull (0 Claude tokens; writes a gitignored cache)
265
+ node scripts/lib/figma-extract/pull.cjs <figma-file-url-or-key>
266
+ # Stage 2 — digest (reads the cache, writes the compact spec)
267
+ node scripts/lib/figma-extract/digest.cjs --raw <cache>/raw/<key> --out .design/figma
268
+ ```
269
+
270
+ **The economics.** A spike measured **898× compression** (223 MB raw → 254 KB digest) with a ~15.7K-token `DESIGN.md`, capturing 127 component sets + 40 singletons (variants, props, defaults) in ~33s — at **0 Claude tokens and 0 Figma MCP calls during extraction**. This is the cost-sane alternative to the Figma MCP for whole-design-system work, which can run tens of minutes and 50–500K+ tokens for the same data. (The Figma MCP remains the right tool for spot questions on a single component.)
271
+
272
+ - **Token-safe by construction.** `FIGMA_TOKEN` is read from the environment only and sent solely as a request header — never logged, never written to disk (a CI static-analysis test enforces this across the whole extract library). The digest never reads raw JSON into context.
273
+ - **Works on any Figma plan.** The optional **"GDD Sync"** Figma plugin (`figma-plugin/`) fills the Variables-API-Enterprise gap: it reads `figma.variables` from inside Figma and POSTs them to an ephemeral, 127.0.0.1-only receiver — so Free-tier users get full token coverage too.
274
+ - **Per-component slices.** `digest --component <name|glob>` renders a ~500-token slice of just the components you ask for, instead of the full digest.
275
+ - **Health-aware.** `/gdd:health` reports a `figma_extract` readiness line (token set / token missing / Free-tier plugin-sync needed).
276
+
277
+ See [`skills/figma-extract/SKILL.md`](skills/figma-extract/SKILL.md) and [`figma-plugin/README.md`](figma-plugin/README.md) for the full flow.
278
+
279
+
259
280
  ## How It Works
260
281
 
261
282
  > **New to an existing codebase?** Run `/gdd:map` first. It dispatches 5 specialist mappers in parallel (tokens, components, visual hierarchy, a11y, motion) and writes structured JSON to `.design/map/` — much higher signal than the grep-based fallback in Explore.
package/SKILL.md CHANGED
@@ -35,6 +35,7 @@ Each stage produces artifacts in `.design/` inside the current project.
35
35
  | `darkmode` | `get-design-done:gdd-darkmode` | Audit dark mode architecture + contrast + anti-patterns → .design/DARKMODE-AUDIT.md |
36
36
  | `compare` | `get-design-done:gdd-compare` | Delta between DESIGN.md baseline and DESIGN-VERIFICATION.md → .design/COMPARE-REPORT.md |
37
37
  | `figma-write <mode>` | `get-design-done:gdd-figma-write` | Write design decisions to Figma (annotate/tokenize/mappings) |
38
+ | `figma-extract <file-url-or-key>` | `get-design-done:gdd-figma-extract` | Off-context Figma design-system extraction → compact local digest (DESIGN.md + tokens.json + components.json), zero raw JSON in context |
38
39
  | `graphify <subcommand>` | `get-design-done:gdd-graphify` | Manage Graphify knowledge graph (build/query/status/diff) |
39
40
  | `discuss [topic] [--all] [--spec] [--cycle <name>]` | `get-design-done:gdd-discuss` | Adaptive design interview — spawns design-discussant; appends D-XX decisions to STATE.md |
40
41
  | `list-assumptions [--area]` | `get-design-done:gdd-list-assumptions` | Surface implicit design assumptions baked into the codebase |
@@ -57,7 +57,7 @@ Minimum expected files:
57
57
  For each D-XX decision in DESIGN-CONTEXT.md, query the graph before grepping:
58
58
 
59
59
  ```
60
- node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" graphify query "decision:D-<nn>" --budget 1500
60
+ node bin/gdd-graph query "decision:D-<nn>" --budget 1500
61
61
  ```
62
62
 
63
63
  The query returns a subgraph of components and tokens connected to this decision. Use the returned node IDs (`component:<name>` and `token:<name>`) as the seed list for your grep searches. This reduces false-negatives where a decision is implemented but grep pattern misses it.
@@ -71,7 +71,7 @@ Each task maps to a domain with specific reference files. These types are the on
71
71
  Before scoping any task that involves a design token change (color, spacing, typography, motion):
72
72
 
73
73
  ```
74
- node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" graphify query "<token-name>" --budget 1500
74
+ node bin/gdd-graph query "<token-name>" --budget 1500
75
75
  ```
76
76
 
77
77
  The query returns all components that reference this token. Annotate the planned task with:
@@ -0,0 +1,90 @@
1
+ ---
2
+ name: gdd-graph-refresh
3
+ description: "Refreshes the knowledge graph at .design/graph/graph.json from .design/intel/ slices using the native bin/gdd-graph CLI. Run after gdd-intel-updater to keep the semantic graph current. Phase 30.6 simplified this agent: intel and graph now share a single {from,to,kind,weight?} schema, so no translation step is needed."
4
+ tools: Bash, Read, Write
5
+ color: green
6
+ default-tier: haiku
7
+ tier-rationale: "Refresh is a deterministic file-walk + atomic write — cheap Haiku is enough"
8
+ parallel-safe: false
9
+ typical-duration-seconds: 20
10
+ reads-only: false
11
+ writes:
12
+ - .design/graph/graph.json
13
+ ---
14
+
15
+ @reference/shared-preamble.md
16
+
17
+ # gdd-graph-refresh
18
+
19
+ **Role:** Refresh the project knowledge graph at `.design/graph/graph.json` from the intel store at `.design/intel/`. Reads intel slices and (re)builds the graph via the native `bin/gdd-graph build` command. Phase 30.6 simplification: intel and graph share a single `{from,to,kind,weight?}` edge schema (D-03.b), so there is no longer a translation step — `gdd-graph build` ingests intel slices directly.
20
+
21
+ ## When to invoke
22
+
23
+ - After `gdd-intel-updater` completes (intel store updated)
24
+ - After a phase plan that adds new skill/agent/reference files
25
+ - When semantic graph queries return stale results
26
+
27
+ ## Protocol
28
+
29
+ ### Step 1 — Check intel store
30
+
31
+ ```bash
32
+ test -d .design/intel/ && echo "ready" || echo "missing"
33
+ ```
34
+
35
+ If missing: print "Intel store not found — run node scripts/build-intel.cjs --force first." and stop.
36
+
37
+ ### Step 2 — Check graphify enabled
38
+
39
+ ```bash
40
+ node -e "try{const c=JSON.parse(require('fs').readFileSync('.design/config.json','utf8'));process.stdout.write(String(c.graphify?.enabled===true))}catch{process.stdout.write('false')}"
41
+ ```
42
+
43
+ If `false`: print "Graphify not enabled in .design/config.json — skipping refresh. To enable, set `graphify.enabled: true` in .design/config.json." and stop gracefully (exit 0, do not fail).
44
+
45
+ ### Step 3 — Rebuild graph from intel slices
46
+
47
+ Phase 30.6 simplification: with shared `{from,to,kind,weight?}` schema between intel and graph (D-03.b), the canonical refresh is a single `build` invocation. No per-node iteration, no translation step.
48
+
49
+ ```bash
50
+ node bin/gdd-graph build
51
+ ```
52
+
53
+ Exit code 0 indicates success; non-zero with stderr indicates a schema violation in an intel slice — report and stop.
54
+
55
+ ### Step 4 — Verify the rebuilt graph
56
+
57
+ ```bash
58
+ node bin/gdd-graph status --format json
59
+ ```
60
+
61
+ Capture `{ node_count, edge_count, built_at, schema_version }` from the JSON output.
62
+
63
+ ### Step 5 — Summary
64
+
65
+ ```
66
+ ━━━ Graph refresh complete ━━━
67
+ Graph path: .design/graph/graph.json
68
+ Nodes: <node_count>
69
+ Edges: <edge_count>
70
+ Schema version: <schema_version>
71
+ Built at: <built_at>
72
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
73
+ ```
74
+
75
+ ## Required reading (conditional)
76
+
77
+ @.design/intel/graph.json (if present)
78
+ @.design/intel/files.json (if present)
79
+
80
+ ## GRAPH-REFRESH COMPLETE
81
+
82
+ ## Record
83
+
84
+ At run-end, append one JSONL line to `.design/intel/insights.jsonl`:
85
+
86
+ ```json
87
+ {"ts":"<ISO-8601>","agent":"<name>","cycle":"<cycle from STATE.md>","stage":"<stage from STATE.md>","one_line_insight":"<what was produced or learned>","artifacts_written":["<files written>"]}
88
+ ```
89
+
90
+ Schema: `reference/schemas/insight-line.schema.json`. Use an empty `artifacts_written` array for read-only agents.
package/bin/gdd-graph ADDED
@@ -0,0 +1,261 @@
1
+ #!/usr/bin/env node
2
+ // bin/gdd-graph — Plan 30.6-02 Task 3
3
+ //
4
+ // Native CLI replacing every `gsd-tools.cjs graphify *` dispatch in our
5
+ // tree. This bin is a thin CJS dispatcher that dynamic-imports the ESM
6
+ // handler modules (package.json has no "type":"module", so the no-ext
7
+ // bin file is resolved as CJS by Node — we bridge with `await import()`).
8
+ //
9
+ // Subcommands shipped in 30.6-02:
10
+ // build — read .design/intel/graph.json, write .design/graph/graph.json
11
+ // status — report graph file state (configured/exists/counts/stale)
12
+ // diff <a> <b> — emit added/removed/changed nodes + edges
13
+ //
14
+ // Subcommands shipped in 30.6-03 (this plan):
15
+ // query <term> [--budget N] — search graph, return ranked matches +
16
+ // 1-hop neighbors, budget-truncated per D-04
17
+ // upsert-node --json '<json>' — create/update a node by id (idempotent)
18
+ // upsert-edge --json '<json>' — create/update an edge by (from,to,kind);
19
+ // fails if either endpoint node is absent
20
+
21
+ 'use strict';
22
+
23
+ const path = require('node:path');
24
+
25
+ const SUBCOMMANDS = new Set([
26
+ 'build', 'status', 'diff', 'query', 'upsert-node', 'upsert-edge',
27
+ ]);
28
+
29
+ function printUsage(stream) {
30
+ stream.write([
31
+ 'Usage: gdd-graph <subcommand> [options]',
32
+ '',
33
+ 'Subcommands:',
34
+ ' build [--intel <path>] [--out <path>] [--now <iso>]',
35
+ ' Build .design/graph/graph.json from .design/intel/graph.json.',
36
+ ' status [--graph <path>] [--intel <path>] [--format json|text]',
37
+ ' Report graph store state (configured/exists/counts/stale).',
38
+ ' diff <from> <to> [--format json|text]',
39
+ ' Diff two graph.json files; emit added/removed/changed nodes+edges.',
40
+ ' query <term> [--budget N] [--graph <path>]',
41
+ ' Search graph; return ranked matches + 1-hop neighbors,',
42
+ ' budget-truncated per D-04 (chars/4 heuristic, default 8000).',
43
+ ' upsert-node {--json \'<obj>\' | --id <id> --type <type> [--label <l>] [--source <s>] [--attrs <json>]}',
44
+ ' Idempotent node upsert by id; bootstraps graph file if absent.',
45
+ ' upsert-edge {--json \'<obj>\' | --from <id> --to <id> --kind <kind> [--weight N] [--source <s>] [--attrs <json>]}',
46
+ ' Idempotent edge upsert by (from,to,kind); requires both endpoint',
47
+ ' nodes to exist — emits GDD_GRAPH_MISSING_ENDPOINT otherwise.',
48
+ '',
49
+ 'Env:',
50
+ ' GDD_GRAPH_DEBUG=1 include stack traces in error JSON',
51
+ ' GDD_GRAPH_TOKEN_FACTOR <int> override chars-per-token divisor (D-04)',
52
+ '',
53
+ 'Exit codes:',
54
+ ' 0 success / 1 failure (structured-error JSON on stderr)',
55
+ '',
56
+ ].join('\n'));
57
+ }
58
+
59
+ function parseArgs(rest) {
60
+ // Minimal hand-rolled parser. Positional args land in `_`; flags with
61
+ // `--name value` (and `--name=value`) land in `opts`.
62
+ const opts = {};
63
+ const positional = [];
64
+ for (let i = 0; i < rest.length; i++) {
65
+ const arg = rest[i];
66
+ if (arg === '--' ) { positional.push(...rest.slice(i + 1)); break; }
67
+ if (arg.startsWith('--')) {
68
+ const eq = arg.indexOf('=');
69
+ if (eq !== -1) {
70
+ opts[arg.slice(2, eq)] = arg.slice(eq + 1);
71
+ } else {
72
+ const next = rest[i + 1];
73
+ if (next === undefined || next.startsWith('--')) {
74
+ opts[arg.slice(2)] = true;
75
+ } else {
76
+ opts[arg.slice(2)] = next;
77
+ i++;
78
+ }
79
+ }
80
+ } else {
81
+ positional.push(arg);
82
+ }
83
+ }
84
+ return { _: positional, opts };
85
+ }
86
+
87
+ function emitError(subcommand, err, exitCode = 1) {
88
+ const payload = {
89
+ ok: false,
90
+ subcommand,
91
+ message: err && err.message ? err.message : String(err),
92
+ };
93
+ if (err && err.code) payload.code = err.code;
94
+ if (err && err.schemaErrors) payload.schemaErrors = err.schemaErrors;
95
+ if (err && err.missingEndpoints) payload.missingEndpoints = err.missingEndpoints;
96
+ if (process.env.GDD_GRAPH_DEBUG && err && err.stack) payload.stack = err.stack;
97
+ process.stderr.write(JSON.stringify(payload) + '\n');
98
+ process.exit(exitCode);
99
+ }
100
+
101
+ async function dispatch(subcommand, parsed) {
102
+ const lib = await import(
103
+ // Resolve via relative require root — bin/ is sibling of scripts/.
104
+ 'file://' + path.resolve(__dirname, '..', 'scripts', 'lib', 'graph', 'index.mjs').replace(/\\/g, '/')
105
+ );
106
+
107
+ if (subcommand === 'build') {
108
+ const r = lib.buildGraph({
109
+ intelPath: parsed.opts.intel,
110
+ outPath: parsed.opts.out,
111
+ now: parsed.opts.now,
112
+ });
113
+ process.stdout.write(JSON.stringify(r) + '\n');
114
+ return;
115
+ }
116
+
117
+ if (subcommand === 'status') {
118
+ const r = lib.statusGraph({
119
+ graphPath: parsed.opts.graph,
120
+ intelPath: parsed.opts.intel,
121
+ });
122
+ process.stdout.write(JSON.stringify(r) + '\n');
123
+ return;
124
+ }
125
+
126
+ if (subcommand === 'diff') {
127
+ const [fromPath, toPath] = parsed._;
128
+ if (!fromPath || !toPath) {
129
+ const err = new Error('diff requires two positional args: <from> <to>');
130
+ err.code = 'DIFF_ARGS_MISSING';
131
+ throw err;
132
+ }
133
+ const r = lib.diffGraph({ fromPath, toPath });
134
+ process.stdout.write(JSON.stringify(r) + '\n');
135
+ return;
136
+ }
137
+
138
+ if (subcommand === 'query') {
139
+ const [term] = parsed._;
140
+ if (!term) {
141
+ const err = new Error('query requires a positional argument: <term>');
142
+ err.code = 'QUERY_TERM_MISSING';
143
+ throw err;
144
+ }
145
+ const budget = parsed.opts.budget !== undefined
146
+ ? Number.parseInt(parsed.opts.budget, 10)
147
+ : undefined;
148
+ if (parsed.opts.budget !== undefined && !Number.isFinite(budget)) {
149
+ const err = new Error(`query --budget must be an integer (got: ${parsed.opts.budget})`);
150
+ err.code = 'QUERY_BUDGET_INVALID';
151
+ throw err;
152
+ }
153
+ const r = lib.queryGraph({
154
+ graphPath: parsed.opts.graph,
155
+ query: term,
156
+ budget,
157
+ });
158
+ process.stdout.write(JSON.stringify(r) + '\n');
159
+ return;
160
+ }
161
+
162
+ if (subcommand === 'upsert-node') {
163
+ const node = parseUpsertInput(parsed, 'upsert-node');
164
+ const r = lib.upsertNode({
165
+ graphPath: parsed.opts.graph,
166
+ node,
167
+ });
168
+ process.stdout.write(JSON.stringify(r) + '\n');
169
+ return;
170
+ }
171
+
172
+ if (subcommand === 'upsert-edge') {
173
+ const edge = parseUpsertInput(parsed, 'upsert-edge');
174
+ const r = lib.upsertEdge({
175
+ graphPath: parsed.opts.graph,
176
+ edge,
177
+ });
178
+ process.stdout.write(JSON.stringify(r) + '\n');
179
+ return;
180
+ }
181
+ }
182
+
183
+ /**
184
+ * Parse the upsert payload from argv. Supports two shapes:
185
+ * - `--json '<json-string>'` (preferred — single source of truth for batch
186
+ * callers in agents/gdd-graph-refresh.md and skills/graphify)
187
+ * - flat flags `--id ... --type ... --label ... --from ... --to ... --kind ...
188
+ * --weight N --source ... --attrs '<json>'` (convenience for shell users
189
+ * + matches the upstream gsd-tools.cjs graphify flag surface verbatim
190
+ * per RESEARCH.md §8-callsite inventory)
191
+ *
192
+ * Conflict: `--json` wins when both are provided.
193
+ */
194
+ function parseUpsertInput(parsed, subcommand) {
195
+ if (parsed.opts.json !== undefined) {
196
+ try {
197
+ const obj = JSON.parse(parsed.opts.json);
198
+ if (!obj || typeof obj !== 'object') {
199
+ throw new Error(`${subcommand} --json must decode to an object`);
200
+ }
201
+ return obj;
202
+ } catch (e) {
203
+ const err = new Error(`${subcommand} --json parse failed: ${e.message}`);
204
+ err.code = 'UPSERT_JSON_PARSE_FAILED';
205
+ throw err;
206
+ }
207
+ }
208
+ // Flat-flag mode — assemble from individual --field flags.
209
+ const obj = {};
210
+ for (const key of ['id', 'type', 'label', 'from', 'to', 'kind', 'source']) {
211
+ if (parsed.opts[key] !== undefined && parsed.opts[key] !== true) {
212
+ obj[key] = parsed.opts[key];
213
+ }
214
+ }
215
+ if (parsed.opts.weight !== undefined) {
216
+ const w = Number.parseFloat(parsed.opts.weight);
217
+ if (!Number.isFinite(w)) {
218
+ const err = new Error(`${subcommand} --weight must be a number (got: ${parsed.opts.weight})`);
219
+ err.code = 'UPSERT_WEIGHT_INVALID';
220
+ throw err;
221
+ }
222
+ obj.weight = w;
223
+ }
224
+ if (parsed.opts.attrs !== undefined) {
225
+ try {
226
+ obj.attrs = JSON.parse(parsed.opts.attrs);
227
+ } catch (e) {
228
+ const err = new Error(`${subcommand} --attrs parse failed: ${e.message}`);
229
+ err.code = 'UPSERT_ATTRS_PARSE_FAILED';
230
+ throw err;
231
+ }
232
+ }
233
+ return obj;
234
+ }
235
+
236
+ (async () => {
237
+ const argv = process.argv.slice(2);
238
+ if (argv.length === 0 || argv[0] === '-h' || argv[0] === '--help') {
239
+ printUsage(process.stderr);
240
+ process.exit(argv.length === 0 ? 1 : 0);
241
+ }
242
+ const subcommand = argv[0];
243
+ if (!SUBCOMMANDS.has(subcommand)) {
244
+ process.stderr.write(JSON.stringify({
245
+ ok: false,
246
+ message: `unknown subcommand: ${subcommand}`,
247
+ }) + '\n');
248
+ process.exit(1);
249
+ }
250
+ const parsed = parseArgs(argv.slice(1));
251
+ try {
252
+ await dispatch(subcommand, parsed);
253
+ process.exit(0);
254
+ } catch (err) {
255
+ emitError(subcommand, err, 1);
256
+ }
257
+ })().catch((err) => {
258
+ // Last-resort guard. dispatch() already routes via emitError; this only
259
+ // fires for bugs in argv parsing or the dispatch glue itself.
260
+ emitError('<bootstrap>', err, 1);
261
+ });
@@ -185,15 +185,16 @@ Note: First Chromatic run has no baseline — all stories become new snapshots.
185
185
  **Graphify probe (execute at agent entry, before using graph):**
186
186
 
187
187
  ```
188
- Step G1 — Config check:
189
- node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" graphify status
190
- Error or { enabled: false } → graphify: not_configured
191
- { enabled: true } → proceed to Step G2
192
-
193
- Step G2 — Graph file check:
194
- Check if graphify-out/graph.json exists in project root
195
- Absent → graphify: unavailable (graph not built yet)
196
- Present → graphify: available
188
+ Step G1 — Config check (per D-09 direct read, no CLI subcommand):
189
+ Bash: node -e "try{const c=JSON.parse(require('fs').readFileSync('.design/config.json','utf8'));process.stdout.write(String(c.graphify?.enabled===true))}catch{process.stdout.write('false')}"
190
+ → false → graphify: not_configured
191
+ → true → proceed to Step G2
192
+
193
+ Step G2 — Graph file check (native CLI):
194
+ Bash: node bin/gdd-graph status --format json
195
+ { configured: true, exists: true } graphify: available
196
+ { configured: true, exists: false } → graphify: unavailable (graph not built yet)
197
+ → { configured: false, exists: ... } → graphify: not_configured (mirrors G1)
197
198
 
198
199
  Write graphify status to STATE.md <connections>.
199
200
  ```