wicked-garden 12.27.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 (640) hide show
  1. package/.claude-plugin/archetypes.json +166 -0
  2. package/.claude-plugin/components.json +75 -0
  3. package/.claude-plugin/marketplace.json +15 -0
  4. package/.claude-plugin/plugin.json +174 -0
  5. package/.claude-plugin/specialist.json +48 -0
  6. package/.claude-plugin/stack-registry.json +96 -0
  7. package/AGENTS.md +13 -0
  8. package/CHANGELOG.md +712 -0
  9. package/CONTRIBUTING.md +99 -0
  10. package/ETHOS.md +83 -0
  11. package/LICENSE +21 -0
  12. package/README.md +115 -0
  13. package/WICKED_GARDEN_BUS_EVENTS.md +149 -0
  14. package/agents/agentic/architect.md +449 -0
  15. package/agents/agentic/performance-analyst.md +702 -0
  16. package/agents/agentic/safety-reviewer.md +662 -0
  17. package/agents/crew/implementer.md +163 -0
  18. package/agents/crew/researcher.md +94 -0
  19. package/agents/crew/reviewer.md +184 -0
  20. package/agents/data/data-engineer.md +227 -0
  21. package/agents/engineering/api-documentarian.md +440 -0
  22. package/agents/engineering/migration-engineer.md +301 -0
  23. package/agents/engineering/solution-architect.md +208 -0
  24. package/agents/jam/brainstorm-facilitator.md +297 -0
  25. package/agents/jam/council.md +322 -0
  26. package/agents/jam/quick-facilitator.md +85 -0
  27. package/agents/persona/persona-agent.md +121 -0
  28. package/agents/platform/compliance-officer.md +266 -0
  29. package/agents/platform/privacy-expert.md +496 -0
  30. package/agents/platform/security-engineer.md +287 -0
  31. package/agents/product/a11y-expert.md +323 -0
  32. package/agents/product/requirements-analyst.md +238 -0
  33. package/agents/product/ui-reviewer.md +180 -0
  34. package/agents/product/ux-designer.md +199 -0
  35. package/agents/product/value-strategist.md +269 -0
  36. package/agents/qe/semantic-reviewer.md +78 -0
  37. package/commands/agentic/audit.md +24 -0
  38. package/commands/agentic/design.md +24 -0
  39. package/commands/agentic/frameworks.md +25 -0
  40. package/commands/agentic/review.md +27 -0
  41. package/commands/archetype/build.md +12 -0
  42. package/commands/archetype/decide.md +12 -0
  43. package/commands/archetype/explore.md +12 -0
  44. package/commands/archetype/incident.md +12 -0
  45. package/commands/archetype/migrate.md +12 -0
  46. package/commands/archetype/modernize.md +12 -0
  47. package/commands/archetype/review.md +14 -0
  48. package/commands/archetype/ship.md +12 -0
  49. package/commands/archetype/specify.md +12 -0
  50. package/commands/archetype/triage.md +12 -0
  51. package/commands/compile.md +37 -0
  52. package/commands/data/analyze.md +18 -0
  53. package/commands/data/data.md +21 -0
  54. package/commands/data/ml.md +18 -0
  55. package/commands/data/ontology.md +22 -0
  56. package/commands/data/pipeline.md +17 -0
  57. package/commands/deliberate.md +181 -0
  58. package/commands/engineering/add-field.md +77 -0
  59. package/commands/engineering/apply.md +58 -0
  60. package/commands/engineering/arch.md +26 -0
  61. package/commands/engineering/debug.md +27 -0
  62. package/commands/engineering/docs.md +27 -0
  63. package/commands/engineering/new-generator.md +257 -0
  64. package/commands/engineering/patch-plan.md +59 -0
  65. package/commands/engineering/plan.md +29 -0
  66. package/commands/engineering/remove.md +48 -0
  67. package/commands/engineering/rename.md +44 -0
  68. package/commands/engineering/review.md +32 -0
  69. package/commands/help.md +128 -0
  70. package/commands/install.md +118 -0
  71. package/commands/intent.md +54 -0
  72. package/commands/jam/brainstorm.md +37 -0
  73. package/commands/jam/council.md +49 -0
  74. package/commands/jam/quick.md +21 -0
  75. package/commands/jam/revisit.md +79 -0
  76. package/commands/persona/as.md +136 -0
  77. package/commands/persona/define.md +24 -0
  78. package/commands/persona/list.md +118 -0
  79. package/commands/platform/actions.md +20 -0
  80. package/commands/platform/assert.md +18 -0
  81. package/commands/platform/audit.md +23 -0
  82. package/commands/platform/compliance.md +20 -0
  83. package/commands/platform/gh.md +22 -0
  84. package/commands/platform/health.md +22 -0
  85. package/commands/platform/incident.md +23 -0
  86. package/commands/platform/infra.md +24 -0
  87. package/commands/platform/peer-health.md +103 -0
  88. package/commands/platform/plugin-health.md +58 -0
  89. package/commands/platform/security.md +38 -0
  90. package/commands/platform/toolchain.md +96 -0
  91. package/commands/platform/traces.md +20 -0
  92. package/commands/product/a11y.md +19 -0
  93. package/commands/product/acceptance.md +19 -0
  94. package/commands/product/align.md +20 -0
  95. package/commands/product/analyze.md +23 -0
  96. package/commands/product/elicit.md +19 -0
  97. package/commands/product/listen.md +24 -0
  98. package/commands/product/mockup.md +20 -0
  99. package/commands/product/screenshot.md +19 -0
  100. package/commands/product/strategy.md +40 -0
  101. package/commands/product/synthesize.md +23 -0
  102. package/commands/product/ux-review.md +42 -0
  103. package/commands/product/ux.md +20 -0
  104. package/commands/product/visual-direction.md +34 -0
  105. package/commands/prove.md +47 -0
  106. package/commands/report-issue.md +243 -0
  107. package/commands/reset.md +144 -0
  108. package/commands/search/blast-radius.md +58 -0
  109. package/commands/search/hotspots.md +55 -0
  110. package/commands/search/index.md +38 -0
  111. package/commands/search/lineage.md +47 -0
  112. package/commands/search/service-map.md +79 -0
  113. package/commands/setup.md +363 -0
  114. package/commands/smaht/briefing.md +200 -0
  115. package/commands/smaht/events-import.md +95 -0
  116. package/commands/smaht/state.md +19 -0
  117. package/commands/where-am-i.md +58 -0
  118. package/docs/README.md +32 -0
  119. package/docs/adr/0001-code-relationship-graph-engine.md +116 -0
  120. package/docs/adr/0002-major-cleanup-keep-cut.md +91 -0
  121. package/docs/adr/0003-peers-gate-required-layers-optin.md +41 -0
  122. package/docs/adr/0004-code-graph-moves-to-wicked-brain.md +47 -0
  123. package/docs/brain-chunk-format.md +135 -0
  124. package/docs/compiler.md +95 -0
  125. package/docs/daemon-api.md +70 -0
  126. package/docs/domains.md +197 -0
  127. package/docs/getting-started.md +208 -0
  128. package/docs/plans/2026-06-08-wicked-loom-conduct.md +1337 -0
  129. package/docs/plans/2026-06-08-wicked-loom-contract.md +638 -0
  130. package/docs/plans/2026-06-08-wicked-loom-cutover.md +1300 -0
  131. package/docs/plans/2026-06-08-wicked-loom-expand-compose.md +843 -0
  132. package/docs/plans/2026-06-08-wicked-loom-flow-cutover.md +403 -0
  133. package/docs/plans/2026-06-10-codegraph-to-brain-phase1a-graph-core.md +838 -0
  134. package/docs/plans/2026-06-10-codegraph-to-brain-phase1b-injected-edges.md +44 -0
  135. package/docs/required-peers.md +60 -0
  136. package/docs/specs/2026-06-08-wicked-loom-extraction.md +225 -0
  137. package/docs/specs/2026-06-10-codegraph-to-brain-migration.md +168 -0
  138. package/docs/v11/archetypes.md +231 -0
  139. package/hooks/hooks.json +275 -0
  140. package/hooks/scripts/bootstrap.py +1797 -0
  141. package/hooks/scripts/invoke.py +62 -0
  142. package/hooks/scripts/notification.py +166 -0
  143. package/hooks/scripts/permission_request.py +223 -0
  144. package/hooks/scripts/post_tool.py +1374 -0
  145. package/hooks/scripts/pre_compact.py +272 -0
  146. package/hooks/scripts/pre_tool.py +1278 -0
  147. package/hooks/scripts/prompt_submit.py +1109 -0
  148. package/hooks/scripts/session_end.py +95 -0
  149. package/hooks/scripts/stop.py +624 -0
  150. package/hooks/scripts/subagent_lifecycle.py +464 -0
  151. package/hooks/scripts/subscribers/on_gate_decided.py +84 -0
  152. package/hooks/scripts/task_completed.py +322 -0
  153. package/hooks/scripts/worktree_guard.py +148 -0
  154. package/hooks/subscriptions/on_gate_decided.json +9 -0
  155. package/install.mjs +128 -0
  156. package/package.json +41 -0
  157. package/pyproject.toml +59 -0
  158. package/schemas/README.md +32 -0
  159. package/schemas/assert_contracts.json +37 -0
  160. package/schemas/health_probe.json +46 -0
  161. package/schemas/plugin_status.json +37 -0
  162. package/scripts/_adapters/__init__.py +166 -0
  163. package/scripts/_adapters/jira_adapter.py +18 -0
  164. package/scripts/_adapters/linear_adapter.py +18 -0
  165. package/scripts/_adapters/miro_adapter.py +18 -0
  166. package/scripts/_adapters/notion_adapter.py +18 -0
  167. package/scripts/_agents.py +357 -0
  168. package/scripts/_brain_ingest/__init__.py +2 -0
  169. package/scripts/_brain_ingest/session_fact_extractor.py +341 -0
  170. package/scripts/_brain_port.py +163 -0
  171. package/scripts/_bus.py +1081 -0
  172. package/scripts/_bus_catalog_gen.py +93 -0
  173. package/scripts/_bus_consumers.json +46 -0
  174. package/scripts/_bus_emit.py +43 -0
  175. package/scripts/_capability_registry.py +334 -0
  176. package/scripts/_capability_resolver.py +322 -0
  177. package/scripts/_domain_store.py +559 -0
  178. package/scripts/_event_log_reader.py +154 -0
  179. package/scripts/_event_schema.py +305 -0
  180. package/scripts/_event_store.py +397 -0
  181. package/scripts/_heavy_cadence.py +324 -0
  182. package/scripts/_integration_resolver.py +321 -0
  183. package/scripts/_logger.py +151 -0
  184. package/scripts/_loom.py +482 -0
  185. package/scripts/_paths.py +133 -0
  186. package/scripts/_python.sh +22 -0
  187. package/scripts/_run.py +137 -0
  188. package/scripts/_session.py +502 -0
  189. package/scripts/_validate_registry.py +1042 -0
  190. package/scripts/_wicked_testing_probe.py +277 -0
  191. package/scripts/agentic/analyze_agents.py +391 -0
  192. package/scripts/agentic/detect_framework.py +420 -0
  193. package/scripts/agentic/issue_taxonomy.py +357 -0
  194. package/scripts/agentic/pattern_scorer.py +434 -0
  195. package/scripts/classify/persist.py +169 -0
  196. package/scripts/compiler/compile.py +552 -0
  197. package/scripts/compiler/phase0/VERDICT.md +60 -0
  198. package/scripts/compiler/phase0/detect.py +292 -0
  199. package/scripts/compiler/phase0/emit.py +228 -0
  200. package/scripts/compiler/phase0/evidence/Enterprise-AISDLC.bindings.json +30 -0
  201. package/scripts/compiler/phase0/evidence/Enterprise-AISDLC.lint-output.txt +17 -0
  202. package/scripts/compiler/phase0/evidence/Enterprise-AISDLC.stage/.wg/evidence/failing-tests.txt +4 -0
  203. package/scripts/compiler/phase0/evidence/Enterprise-AISDLC.stage/.wg/evidence/honest-tests.txt +2 -0
  204. package/scripts/compiler/phase0/evidence/Enterprise-AISDLC.stage/fab-fail.build.md +8 -0
  205. package/scripts/compiler/phase0/evidence/Enterprise-AISDLC.stage/fab-missing.build.md +8 -0
  206. package/scripts/compiler/phase0/evidence/Enterprise-AISDLC.stage/honest.build.md +8 -0
  207. package/scripts/compiler/phase0/evidence/Enterprise-AISDLC.stage/wg_check_claims.py +174 -0
  208. package/scripts/compiler/phase0/evidence/command_iq.bindings.json +45 -0
  209. package/scripts/compiler/phase0/evidence/command_iq.lint-output.txt +17 -0
  210. package/scripts/compiler/phase0/evidence/command_iq.stage/.projects/evidence-domain/phase-1-clarify/evidence/failing-tests.txt +4 -0
  211. package/scripts/compiler/phase0/evidence/command_iq.stage/.projects/evidence-domain/phase-1-clarify/evidence/honest-tests.txt +3 -0
  212. package/scripts/compiler/phase0/evidence/command_iq.stage/fab-fail.build.md +8 -0
  213. package/scripts/compiler/phase0/evidence/command_iq.stage/fab-missing.build.md +8 -0
  214. package/scripts/compiler/phase0/evidence/command_iq.stage/honest.build.md +8 -0
  215. package/scripts/compiler/phase0/evidence/command_iq.stage/wg_check_claims.py +174 -0
  216. package/scripts/compiler/phase0/evidence/memos.bindings.json +28 -0
  217. package/scripts/compiler/phase0/evidence/memos.lint-output.txt +17 -0
  218. package/scripts/compiler/phase0/evidence/memos.stage/.wg/evidence/failing-tests.txt +4 -0
  219. package/scripts/compiler/phase0/evidence/memos.stage/.wg/evidence/honest-tests.txt +2 -0
  220. package/scripts/compiler/phase0/evidence/memos.stage/fab-fail.build.md +8 -0
  221. package/scripts/compiler/phase0/evidence/memos.stage/fab-missing.build.md +8 -0
  222. package/scripts/compiler/phase0/evidence/memos.stage/honest.build.md +8 -0
  223. package/scripts/compiler/phase0/evidence/memos.stage/wg_check_claims.py +174 -0
  224. package/scripts/compiler/phase0/evidence/verdict.json +104 -0
  225. package/scripts/compiler/phase0/evidence/wicked-bus.bindings.json +29 -0
  226. package/scripts/compiler/phase0/evidence/wicked-bus.lint-output.txt +17 -0
  227. package/scripts/compiler/phase0/evidence/wicked-bus.stage/coverage/failing-tests.txt +4 -0
  228. package/scripts/compiler/phase0/evidence/wicked-bus.stage/coverage/honest-tests.txt +3 -0
  229. package/scripts/compiler/phase0/evidence/wicked-bus.stage/fab-fail.build.md +8 -0
  230. package/scripts/compiler/phase0/evidence/wicked-bus.stage/fab-missing.build.md +8 -0
  231. package/scripts/compiler/phase0/evidence/wicked-bus.stage/honest.build.md +8 -0
  232. package/scripts/compiler/phase0/evidence/wicked-bus.stage/wg_check_claims.py +174 -0
  233. package/scripts/compiler/phase0/evidence/wire-vault-transcript.txt +60 -0
  234. package/scripts/compiler/phase0/run_probe.py +234 -0
  235. package/scripts/compiler/phase0/wire_vault.py +310 -0
  236. package/scripts/crew/__init__.py +0 -0
  237. package/scripts/crew/_task_audit_writer.py +243 -0
  238. package/scripts/crew/_task_reader.py +389 -0
  239. package/scripts/crew/archetypes_v11.py +348 -0
  240. package/scripts/crew/detectors/__init__.py +12 -0
  241. package/scripts/crew/flow_compiler.py +121 -0
  242. package/scripts/crew/phase_manager.py +703 -0
  243. package/scripts/crew/scope_delta.py +264 -0
  244. package/scripts/crew/specialist_resolver.py +218 -0
  245. package/scripts/crew/stack_registry.py +189 -0
  246. package/scripts/data/data_profiler.py +271 -0
  247. package/scripts/data/ontology_recommender.py +231 -0
  248. package/scripts/data/schema_validator.py +267 -0
  249. package/scripts/delivery/drift.py +739 -0
  250. package/scripts/delivery/telemetry.py +614 -0
  251. package/scripts/engineering/patch/codegraph_db.py +125 -0
  252. package/scripts/engineering/patch/generators/__init__.py +56 -0
  253. package/scripts/engineering/patch/generators/base.py +373 -0
  254. package/scripts/engineering/patch/generators/csharp_generator.py +494 -0
  255. package/scripts/engineering/patch/generators/go_generator.py +430 -0
  256. package/scripts/engineering/patch/generators/java_generator.py +928 -0
  257. package/scripts/engineering/patch/generators/jsp_generator.py +454 -0
  258. package/scripts/engineering/patch/generators/kotlin_generator.py +561 -0
  259. package/scripts/engineering/patch/generators/perl_generator.py +510 -0
  260. package/scripts/engineering/patch/generators/php_generator.py +644 -0
  261. package/scripts/engineering/patch/generators/propagation_engine.py +929 -0
  262. package/scripts/engineering/patch/generators/python_generator.py +487 -0
  263. package/scripts/engineering/patch/generators/ruby_generator.py +463 -0
  264. package/scripts/engineering/patch/generators/rust_generator.py +400 -0
  265. package/scripts/engineering/patch/generators/sql_generator.py +594 -0
  266. package/scripts/engineering/patch/generators/typescript_generator.py +439 -0
  267. package/scripts/engineering/patch/patch.py +800 -0
  268. package/scripts/engineering/patch/safety.py +429 -0
  269. package/scripts/jam/__init__.py +0 -0
  270. package/scripts/jam/_bus_consumers.py +271 -0
  271. package/scripts/jam/agentic_cli_registry.py +703 -0
  272. package/scripts/jam/consensus.py +737 -0
  273. package/scripts/jam/detect_clis.py +409 -0
  274. package/scripts/jam/jam.py +283 -0
  275. package/scripts/jam/save_transcript.py +171 -0
  276. package/scripts/loom/__init__.py +22 -0
  277. package/scripts/loom/cli.py +170 -0
  278. package/scripts/loom/compose.py +180 -0
  279. package/scripts/loom/gate.py +120 -0
  280. package/scripts/loom/manifest.py +140 -0
  281. package/scripts/loom/resolve.py +59 -0
  282. package/scripts/persona/__init__.py +0 -0
  283. package/scripts/persona/registry.py +688 -0
  284. package/scripts/platform/guard_pipeline.py +1214 -0
  285. package/scripts/platform/guard_profiles.py +216 -0
  286. package/scripts/platform/observability/assert_contracts.py +434 -0
  287. package/scripts/platform/observability/health_probe.py +915 -0
  288. package/scripts/platform/observability/ops_log_viewer.py +209 -0
  289. package/scripts/platform/prereq_doctor.py +567 -0
  290. package/scripts/qe/conditions_manifest.py +260 -0
  291. package/scripts/qe/content_sanitizer.py +160 -0
  292. package/scripts/qe/coverage_tracker.py +535 -0
  293. package/scripts/qe/discover_scenarios.py +243 -0
  294. package/scripts/qe/evidence_tracker.py +232 -0
  295. package/scripts/qe/prove.py +196 -0
  296. package/scripts/qe/registry_lookup.py +80 -0
  297. package/scripts/qe/registry_store.py +176 -0
  298. package/scripts/qe/semantic_review.py +1005 -0
  299. package/scripts/qe/vault_gate.py +382 -0
  300. package/scripts/qe/verdict_audit.py +175 -0
  301. package/scripts/qe/verdict_schema.py +335 -0
  302. package/scripts/reset.py +220 -0
  303. package/scripts/resolve_path.py +22 -0
  304. package/scripts/sentinel/invariants.py +402 -0
  305. package/scripts/sentinel/pre_push.py +73 -0
  306. package/scripts/setup/__init__.py +1 -0
  307. package/scripts/setup/detect_state.py +114 -0
  308. package/scripts/setup/migrate_legacy.py +67 -0
  309. package/scripts/setup/migrate_v6_projects.py +232 -0
  310. package/scripts/setup/onboarding.py +114 -0
  311. package/scripts/smaht/_bus_consumers.py +98 -0
  312. package/scripts/smaht/adapters/__init__.py +83 -0
  313. package/scripts/smaht/adapters/brain_adapter.py +254 -0
  314. package/scripts/smaht/adapters/context7_adapter.py +438 -0
  315. package/scripts/smaht/adapters/delegation_adapter.py +104 -0
  316. package/scripts/smaht/adapters/domain_adapter.py +206 -0
  317. package/scripts/smaht/adapters/events_adapter.py +231 -0
  318. package/scripts/smaht/adapters/tools_adapter.py +49 -0
  319. package/scripts/smaht/cheatsheet_store.py +236 -0
  320. package/scripts/smaht/context_package.py +386 -0
  321. package/scripts/smaht/knowledge_graph.py +395 -0
  322. package/scripts/smaht/propose_skills.py +856 -0
  323. package/scripts/smaht/test_cheatsheet_store.py +428 -0
  324. package/scripts/statusline.py +151 -0
  325. package/scripts/where_am_i.py +236 -0
  326. package/skills/agentic/agentic-patterns/SKILL.md +91 -0
  327. package/skills/agentic/agentic-patterns/refs/anti-patterns-design.md +283 -0
  328. package/skills/agentic/agentic-patterns/refs/anti-patterns-operational.md +216 -0
  329. package/skills/agentic/agentic-patterns/refs/pattern-catalog.md +329 -0
  330. package/skills/agentic/context-engineering/SKILL.md +142 -0
  331. package/skills/agentic/context-engineering/refs/caching-and-optimization.md +251 -0
  332. package/skills/agentic/context-engineering/refs/compression-techniques.md +171 -0
  333. package/skills/agentic/context-engineering/refs/cost-calculation-budget.md +250 -0
  334. package/skills/agentic/context-engineering/refs/cost-optimization-reporting.md +300 -0
  335. package/skills/agentic/context-engineering/refs/selective-loading.md +179 -0
  336. package/skills/agentic/frameworks/SKILL.md +191 -0
  337. package/skills/agentic/frameworks/refs/framework-profiles-1.md +209 -0
  338. package/skills/agentic/frameworks/refs/framework-profiles-2.md +214 -0
  339. package/skills/agentic/frameworks/refs/migration-patterns-paths.md +267 -0
  340. package/skills/agentic/frameworks/refs/migration-patterns-testing.md +208 -0
  341. package/skills/agentic/refs/audit.md +134 -0
  342. package/skills/agentic/refs/design.md +137 -0
  343. package/skills/agentic/refs/frameworks.md +102 -0
  344. package/skills/agentic/refs/review.md +160 -0
  345. package/skills/agentic/review-methodology/SKILL.md +186 -0
  346. package/skills/agentic/review-methodology/refs/deliverable-templates.md +246 -0
  347. package/skills/agentic/review-methodology/refs/issue-taxonomy-quality-testing.md +277 -0
  348. package/skills/agentic/review-methodology/refs/issue-taxonomy-reliability-safety.md +253 -0
  349. package/skills/agentic/trust-and-safety/SKILL.md +177 -0
  350. package/skills/agentic/trust-and-safety/refs/guardrails-actions.md +246 -0
  351. package/skills/agentic/trust-and-safety/refs/guardrails-input-output.md +238 -0
  352. package/skills/agentic/trust-and-safety/refs/guardrails-resources.md +209 -0
  353. package/skills/agentic/trust-and-safety/refs/safety-checklist-advanced.md +209 -0
  354. package/skills/agentic/trust-and-safety/refs/safety-checklist-core.md +215 -0
  355. package/skills/archetype/SKILL.md +104 -0
  356. package/skills/archetype/refs/build.md +142 -0
  357. package/skills/archetype/refs/decide.md +117 -0
  358. package/skills/archetype/refs/explore.md +66 -0
  359. package/skills/archetype/refs/incident.md +149 -0
  360. package/skills/archetype/refs/migrate.md +170 -0
  361. package/skills/archetype/refs/modernize.md +187 -0
  362. package/skills/archetype/refs/review.md +145 -0
  363. package/skills/archetype/refs/ship.md +117 -0
  364. package/skills/archetype/refs/specify.md +108 -0
  365. package/skills/archetype/refs/triage.md +62 -0
  366. package/skills/classify/SKILL.md +157 -0
  367. package/skills/data/analysis/SKILL.md +125 -0
  368. package/skills/data/analysis/refs/templates.md +170 -0
  369. package/skills/data/data/SKILL.md +118 -0
  370. package/skills/data/data/refs/examples.md +235 -0
  371. package/skills/data/ml/SKILL.md +125 -0
  372. package/skills/data/ml/refs/templates.md +172 -0
  373. package/skills/data/pipeline/SKILL.md +136 -0
  374. package/skills/data/pipeline/refs/templates.md +175 -0
  375. package/skills/data/refs/analyze.md +123 -0
  376. package/skills/data/refs/data.md +95 -0
  377. package/skills/data/refs/ml.md +118 -0
  378. package/skills/data/refs/pipeline.md +92 -0
  379. package/skills/deliberate/SKILL.md +125 -0
  380. package/skills/deliberate/refs/architecture-lens.md +37 -0
  381. package/skills/deliberate/refs/assumptions-lens.md +43 -0
  382. package/skills/deliberate/refs/code-lens.md +38 -0
  383. package/skills/deliberate/refs/content-lens.md +37 -0
  384. package/skills/deliberate/refs/data-lens.md +43 -0
  385. package/skills/deliberate/refs/design-lens.md +37 -0
  386. package/skills/deliberate/refs/opportunity-patterns.md +107 -0
  387. package/skills/deliberate/refs/ops-lens.md +43 -0
  388. package/skills/deliberate/refs/product-lens.md +46 -0
  389. package/skills/deliberate/refs/rethink-framework.md +77 -0
  390. package/skills/deliberate/refs/security-lens.md +47 -0
  391. package/skills/deliberate/refs/testing-lens.md +45 -0
  392. package/skills/deliberate/refs/timing-lens.md +42 -0
  393. package/skills/engineering/architecture/SKILL.md +177 -0
  394. package/skills/engineering/architecture/refs/adr-template.md +268 -0
  395. package/skills/engineering/architecture/refs/architecture-template-deployment.md +176 -0
  396. package/skills/engineering/architecture/refs/architecture-template-design.md +300 -0
  397. package/skills/engineering/architecture/refs/examples-ecommerce-analytics.md +299 -0
  398. package/skills/engineering/architecture/refs/examples-saas-trading.md +291 -0
  399. package/skills/engineering/architecture/refs/patterns-advanced.md +238 -0
  400. package/skills/engineering/architecture/refs/patterns-structural.md +303 -0
  401. package/skills/engineering/backend/SKILL.md +102 -0
  402. package/skills/engineering/backend/refs/checklists.md +146 -0
  403. package/skills/engineering/backend/refs/patterns.md +181 -0
  404. package/skills/engineering/debugging/SKILL.md +99 -0
  405. package/skills/engineering/debugging/refs/patterns.md +248 -0
  406. package/skills/engineering/debugging/refs/process.md +203 -0
  407. package/skills/engineering/docs/SKILL.md +97 -0
  408. package/skills/engineering/engineering/SKILL.md +88 -0
  409. package/skills/engineering/engineering/refs/checklists.md +91 -0
  410. package/skills/engineering/engineering/refs/templates.md +71 -0
  411. package/skills/engineering/frontend/SKILL.md +92 -0
  412. package/skills/engineering/frontend/refs/checklists.md +96 -0
  413. package/skills/engineering/frontend/refs/patterns.md +167 -0
  414. package/skills/engineering/integration/SKILL.md +183 -0
  415. package/skills/engineering/integration/refs/error-handling-best-practices.md +139 -0
  416. package/skills/engineering/integration/refs/error-handling-error-classes-typescript.md +212 -0
  417. package/skills/engineering/integration/refs/error-handling-error-response-format.md +301 -0
  418. package/skills/engineering/integration/refs/error-handling-retry-strategies.md +190 -0
  419. package/skills/engineering/integration/refs/event-schemas-best-practices.md +225 -0
  420. package/skills/engineering/integration/refs/event-schemas-event-naming-conventions.md +303 -0
  421. package/skills/engineering/integration/refs/event-schemas-event-structure.md +288 -0
  422. package/skills/engineering/integration/refs/graphql-best-practices.md +138 -0
  423. package/skills/engineering/integration/refs/graphql-error-handling.md +198 -0
  424. package/skills/engineering/integration/refs/graphql-graphql-basics.md +197 -0
  425. package/skills/engineering/integration/refs/graphql-query-examples.md +226 -0
  426. package/skills/engineering/integration/refs/graphql-schema-design-patterns.md +280 -0
  427. package/skills/engineering/integration/refs/grpc-grpc-overview.md +246 -0
  428. package/skills/engineering/integration/refs/grpc-implementation-examples.md +269 -0
  429. package/skills/engineering/integration/refs/grpc-metadata-headers.md +304 -0
  430. package/skills/engineering/integration/refs/grpc-testing.md +49 -0
  431. package/skills/engineering/integration/refs/openapi-template.yaml +682 -0
  432. package/skills/engineering/integration/refs/resilience-best-practices.md +109 -0
  433. package/skills/engineering/integration/refs/resilience-circuit-breaker-pattern.md +302 -0
  434. package/skills/engineering/integration/refs/resilience-rate-limiting.md +245 -0
  435. package/skills/engineering/integration/refs/resilience-timeout-pattern.md +212 -0
  436. package/skills/engineering/integration/refs/rest-api-fundamentals.md +299 -0
  437. package/skills/engineering/integration/refs/rest-api-responses-security.md +302 -0
  438. package/skills/engineering/integration/refs/versioning-breaking-changes.md +237 -0
  439. package/skills/engineering/integration/refs/versioning-migration-strategies.md +257 -0
  440. package/skills/engineering/integration/refs/versioning-versioning-strategies.md +296 -0
  441. package/skills/engineering/large-scale-migration/SKILL.md +65 -0
  442. package/skills/engineering/patch/SKILL.md +184 -0
  443. package/skills/engineering/refs/arch.md +126 -0
  444. package/skills/engineering/refs/debug.md +142 -0
  445. package/skills/engineering/refs/docs.md +190 -0
  446. package/skills/engineering/refs/plan.md +109 -0
  447. package/skills/engineering/refs/review.md +138 -0
  448. package/skills/engineering/system-design/SKILL.md +154 -0
  449. package/skills/engineering/system-design/refs/anti-patterns-big-ball-of-mud.md +254 -0
  450. package/skills/engineering/system-design/refs/anti-patterns-circular-dependencies.md +241 -0
  451. package/skills/engineering/system-design/refs/anti-patterns-feature-envy.md +168 -0
  452. package/skills/engineering/system-design/refs/anti-patterns-god-object.md +247 -0
  453. package/skills/engineering/system-design/refs/component-template-lifecycle.md +210 -0
  454. package/skills/engineering/system-design/refs/component-template-maintenance.md +219 -0
  455. package/skills/engineering/system-design/refs/component-template-structure.md +276 -0
  456. package/skills/engineering/system-design/refs/dependencies-best-practices.md +260 -0
  457. package/skills/engineering/system-design/refs/dependencies-dependency-principles.md +295 -0
  458. package/skills/engineering/system-design/refs/dependencies-dependency-tracking.md +261 -0
  459. package/skills/engineering/system-design/refs/interface-template-lifecycle.md +211 -0
  460. package/skills/engineering/system-design/refs/interface-template-maintenance.md +212 -0
  461. package/skills/engineering/system-design/refs/interface-template-structure.md +269 -0
  462. package/skills/engineering/system-design/refs/patterns-dependency-injection.md +151 -0
  463. package/skills/engineering/system-design/refs/patterns-facade-pattern.md +257 -0
  464. package/skills/engineering/system-design/refs/patterns-layered-pattern.md +204 -0
  465. package/skills/engineering/system-design/refs/patterns-plugin-architecture.md +229 -0
  466. package/skills/engineering/unit-test-quality/SKILL.md +194 -0
  467. package/skills/ground/SKILL.md +130 -0
  468. package/skills/integration-discovery/SKILL.md +168 -0
  469. package/skills/integration-discovery/refs/capabilities.md +282 -0
  470. package/skills/integration-discovery/refs/cli-detection.md +295 -0
  471. package/skills/integration-discovery/refs/discovery-sources.md +233 -0
  472. package/skills/integration-discovery/refs/task-patterns.md +206 -0
  473. package/skills/jam/SKILL.md +45 -0
  474. package/skills/jam/refs/facilitation-patterns.md +125 -0
  475. package/skills/jam/refs/quick.md +64 -0
  476. package/skills/jam/refs/synthesis-patterns.md +114 -0
  477. package/skills/multi-model/SKILL.md +168 -0
  478. package/skills/multi-model/refs/aichat.md +119 -0
  479. package/skills/multi-model/refs/aider.md +100 -0
  480. package/skills/multi-model/refs/auditability.md +238 -0
  481. package/skills/multi-model/refs/codex.md +169 -0
  482. package/skills/multi-model/refs/context.md +306 -0
  483. package/skills/multi-model/refs/copilot.md +161 -0
  484. package/skills/multi-model/refs/examples.md +224 -0
  485. package/skills/multi-model/refs/gemini.md +185 -0
  486. package/skills/multi-model/refs/goose.md +112 -0
  487. package/skills/multi-model/refs/llm.md +124 -0
  488. package/skills/multi-model/refs/opencode.md +196 -0
  489. package/skills/multi-model/refs/orchestration.md +188 -0
  490. package/skills/multi-model/refs/pi.md +208 -0
  491. package/skills/persona/SKILL.md +144 -0
  492. package/skills/persona/refs/define.md +133 -0
  493. package/skills/platform/actions/refs/actions.md +114 -0
  494. package/skills/platform/audit/SKILL.md +174 -0
  495. package/skills/platform/audit/refs/audit.md +145 -0
  496. package/skills/platform/audit/refs/checklists-evidence-operations.md +144 -0
  497. package/skills/platform/audit/refs/checklists-gdpr-pci-evidence.md +213 -0
  498. package/skills/platform/audit/refs/checklists-soc2-hipaa.md +120 -0
  499. package/skills/platform/audit/refs/frameworks-gdpr-pci.md +225 -0
  500. package/skills/platform/audit/refs/frameworks-soc2-hipaa.md +228 -0
  501. package/skills/platform/compliance/SKILL.md +169 -0
  502. package/skills/platform/compliance/refs/checklists.md +303 -0
  503. package/skills/platform/compliance/refs/compliance.md +117 -0
  504. package/skills/platform/compliance/refs/frameworks.md +282 -0
  505. package/skills/platform/errors/SKILL.md +183 -0
  506. package/skills/platform/errors/refs/patterns.md +271 -0
  507. package/skills/platform/errors/refs/severity.md +264 -0
  508. package/skills/platform/gate-benchmark-rebaseline/SKILL.md +108 -0
  509. package/skills/platform/gh/refs/gh.md +105 -0
  510. package/skills/platform/gh-cli/SKILL.md +120 -0
  511. package/skills/platform/gh-cli/refs/automation.md +63 -0
  512. package/skills/platform/gh-cli/refs/gh-ops.md +103 -0
  513. package/skills/platform/gh-cli/refs/patterns.md +132 -0
  514. package/skills/platform/gh-cli/scripts/gh_ops.py +454 -0
  515. package/skills/platform/github-actions/SKILL.md +159 -0
  516. package/skills/platform/github-actions/refs/security.md +150 -0
  517. package/skills/platform/github-actions/refs/templates.md +230 -0
  518. package/skills/platform/github-actions/refs/troubleshooting.md +174 -0
  519. package/skills/platform/github-actions/scripts/workflow_gen.py +215 -0
  520. package/skills/platform/gitlab-ci/SKILL.md +140 -0
  521. package/skills/platform/gitlab-ci/refs/templates.md +223 -0
  522. package/skills/platform/gitlab-ci/refs/troubleshooting.md +213 -0
  523. package/skills/platform/glab-cli/SKILL.md +133 -0
  524. package/skills/platform/glab-cli/refs/ci-debugging.md +95 -0
  525. package/skills/platform/glab-cli/refs/glab-ops.md +78 -0
  526. package/skills/platform/glab-cli/refs/patterns.md +131 -0
  527. package/skills/platform/glab-cli/scripts/glab_ops.py +313 -0
  528. package/skills/platform/health/SKILL.md +177 -0
  529. package/skills/platform/health/refs/health.md +72 -0
  530. package/skills/platform/health/refs/sources.md +302 -0
  531. package/skills/platform/incident/refs/incident.md +136 -0
  532. package/skills/platform/infra/refs/infra.md +104 -0
  533. package/skills/platform/observability/SKILL.md +128 -0
  534. package/skills/platform/observability/refs/toolchain-discovery.md +243 -0
  535. package/skills/platform/prereq-doctor/SKILL.md +57 -0
  536. package/skills/platform/prereq-doctor/refs/tool-registry.md +58 -0
  537. package/skills/platform/traces/refs/traces.md +101 -0
  538. package/skills/product/acceptance-criteria/SKILL.md +193 -0
  539. package/skills/product/acceptance-criteria/refs/ac-anti-patterns.md +291 -0
  540. package/skills/product/acceptance-criteria/refs/ac-examples.md +277 -0
  541. package/skills/product/accessibility/SKILL.md +197 -0
  542. package/skills/product/accessibility/refs/aria-patterns-basics.md +250 -0
  543. package/skills/product/accessibility/refs/aria-patterns-dynamic.md +187 -0
  544. package/skills/product/accessibility/refs/aria-patterns-interactive.md +246 -0
  545. package/skills/product/accessibility/refs/audit-report-findings.md +248 -0
  546. package/skills/product/accessibility/refs/audit-report-results.md +276 -0
  547. package/skills/product/accessibility/refs/common-violations-html-css.md +270 -0
  548. package/skills/product/accessibility/refs/common-violations-interactive.md +303 -0
  549. package/skills/product/accessibility/refs/keyboard-testing-basics.md +222 -0
  550. package/skills/product/accessibility/refs/keyboard-testing-patterns.md +173 -0
  551. package/skills/product/accessibility/refs/screen-reader-testing-advanced.md +294 -0
  552. package/skills/product/accessibility/refs/screen-reader-testing-commands.md +255 -0
  553. package/skills/product/accessibility/refs/wcag-checklist.md +262 -0
  554. package/skills/product/analyze/SKILL.md +164 -0
  555. package/skills/product/analyze/refs/algorithms.md +238 -0
  556. package/skills/product/analyze/refs/sentiment-patterns.md +180 -0
  557. package/skills/product/imagery/SKILL.md +97 -0
  558. package/skills/product/imagery/alter/SKILL.md +105 -0
  559. package/skills/product/imagery/alter/refs/editing-reference.md +146 -0
  560. package/skills/product/imagery/create/SKILL.md +109 -0
  561. package/skills/product/imagery/create/refs/prompt-engineering.md +112 -0
  562. package/skills/product/imagery/create/refs/provider-reference.md +219 -0
  563. package/skills/product/imagery/review/SKILL.md +101 -0
  564. package/skills/product/imagery/review/refs/analysis-lenses.md +136 -0
  565. package/skills/product/imagery/review/refs/quality-gates.md +153 -0
  566. package/skills/product/imagery/scripts/analyze.sh +23 -0
  567. package/skills/product/imagery/scripts/edit.sh +14 -0
  568. package/skills/product/imagery/scripts/generate.sh +13 -0
  569. package/skills/product/imagery/scripts/provider.py +787 -0
  570. package/skills/product/listen/SKILL.md +175 -0
  571. package/skills/product/listen/refs/channels.md +220 -0
  572. package/skills/product/mockup/SKILL.md +106 -0
  573. package/skills/product/mockup/refs/templates.md +95 -0
  574. package/skills/product/refs/a11y.md +109 -0
  575. package/skills/product/refs/acceptance.md +79 -0
  576. package/skills/product/refs/align.md +67 -0
  577. package/skills/product/refs/analyze.md +77 -0
  578. package/skills/product/refs/elicit.md +67 -0
  579. package/skills/product/refs/listen.md +58 -0
  580. package/skills/product/refs/mockup.md +77 -0
  581. package/skills/product/refs/screenshot.md +59 -0
  582. package/skills/product/refs/strategy.md +77 -0
  583. package/skills/product/refs/synthesize.md +54 -0
  584. package/skills/product/refs/ux-review.md +68 -0
  585. package/skills/product/refs/ux.md +101 -0
  586. package/skills/product/requirements-analysis/SKILL.md +136 -0
  587. package/skills/product/requirements-analysis/refs/requirements-example-auth.md +264 -0
  588. package/skills/product/requirements-analysis/refs/requirements-example-export-integration.md +88 -0
  589. package/skills/product/requirements-analysis/refs/requirements-output-format-template.md +247 -0
  590. package/skills/product/requirements-analysis/refs/user-story-guide.md +296 -0
  591. package/skills/product/requirements-graph/SKILL.md +155 -0
  592. package/skills/product/requirements-graph/refs/examples.md +223 -0
  593. package/skills/product/requirements-graph/refs/schema.md +162 -0
  594. package/skills/product/requirements-migrate/SKILL.md +90 -0
  595. package/skills/product/requirements-navigate/SKILL.md +141 -0
  596. package/skills/product/requirements-navigate/refs/meta-templates.md +141 -0
  597. package/skills/product/screenshot/SKILL.md +147 -0
  598. package/skills/product/strategy/SKILL.md +198 -0
  599. package/skills/product/strategy/refs/frameworks.md +295 -0
  600. package/skills/product/strategy/refs/templates-competitive-market.md +299 -0
  601. package/skills/product/strategy/refs/templates-roi-value.md +207 -0
  602. package/skills/product/synthesize/SKILL.md +116 -0
  603. package/skills/product/synthesize/refs/journey-mapping.md +212 -0
  604. package/skills/product/synthesize/refs/prioritization.md +193 -0
  605. package/skills/product/ux-review/SKILL.md +164 -0
  606. package/skills/product/visual-direction/SKILL.md +137 -0
  607. package/skills/product/visual-review/SKILL.md +131 -0
  608. package/skills/runtime-exec/SKILL.md +138 -0
  609. package/skills/search/codebase-narrator/SKILL.md +131 -0
  610. package/skills/search/codebase-narrator/refs/output-template.md +100 -0
  611. package/skills/smaht/SKILL.md +72 -0
  612. package/skills/smaht/discovery/SKILL.md +65 -0
  613. package/skills/smaht/intent/SKILL.md +89 -0
  614. package/skills/smaht/propose-skills/SKILL.md +142 -0
  615. package/skills/smaht/refs/state.md +76 -0
  616. package/skills/swarm/SKILL.md +132 -0
  617. package/skills/swarm/refs/fan-out.md +104 -0
  618. package/skills/swarm/refs/independent-verification.md +86 -0
  619. package/skills/swarm/refs/receipts-and-evidence.md +69 -0
  620. package/skills/swarm/refs/recon-synthesis.md +87 -0
  621. package/skills/swarm/refs/ship-discipline.md +90 -0
  622. package/skills/wickedizer/SKILL.md +147 -0
  623. package/skills/wickedizer/refs/artifact-types.md +238 -0
  624. package/skills/wickedizer/refs/complexity.md +278 -0
  625. package/skills/wickedizer/refs/de-ai-pass.md +140 -0
  626. package/skills/wickedizer/refs/failure-modes.md +249 -0
  627. package/skills/wickedizer/refs/patterns.md +282 -0
  628. package/skills/wickedizer/refs/review.md +221 -0
  629. package/skills/wickedizer/refs/structure.md +282 -0
  630. package/skills/wickedizer/refs/voice-profile.md +125 -0
  631. package/skills/workflow/SKILL.md +132 -0
  632. package/skills/workflow/refs/archetype-adjustments.md +205 -0
  633. package/skills/workflow/refs/evidence.md +58 -0
  634. package/skills/workflow/refs/integration.md +130 -0
  635. package/skills/workflow/refs/risk-dimension-signals.md +260 -0
  636. package/skills/workflow/refs/scoring-rubric.md +49 -0
  637. package/skills/workflow/refs/signal-keywords.md +176 -0
  638. package/skills/workflow/refs/specialist-routing-rules.md +159 -0
  639. package/skills/worktrees/SKILL.md +87 -0
  640. package/skills/worktrees/refs/recipes.md +96 -0
@@ -0,0 +1,838 @@
1
+ # Codegraph → Brain, Phase 1a: Graph Core — Implementation Plan
2
+
3
+ > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
4
+
5
+ **Goal:** Make `wicked-brain` answer code-relationship queries (blast-radius, callers, lineage) from a codegraph-built static graph it owns — with zero `wicked-garden` dependency.
6
+
7
+ **Architecture:** Brain shells the external `@colbymchenry/codegraph` CLI to *build* a per-repo SQLite graph at `<source>/.codegraph/codegraph.db`, then reads that DB **directly** via `better-sqlite3` (no query-time subprocess) to serve new `graph-*` API actions, exposed through a new `wicked-brain:graph` skill. Freshness is lazy: every query carries a "N commits behind HEAD" staleness stamp and rebuilds on demand — never coupled to the file watcher (Decision D5).
8
+
9
+ **Tech Stack:** Node ≥18 ESM (`.mjs`), `better-sqlite3` v12 (read codegraph DB), `node:child_process` (shell codegraph CLI), `node:test` + `node:assert/strict`. The codegraph CLI itself requires **Node ≥22.5** (`node:sqlite`); brain runs on Node 26.
10
+
11
+ **Repo:** `/Users/michael.parcewski/Projects/wicked-brain` (server source under `server/`). This plan does NOT touch wicked-garden.
12
+
13
+ ---
14
+
15
+ ## Subsequent plans (sequenced after this one)
16
+
17
+ - **Phase 1b — injected edges + extractor framework** (brain): built-in extractors (bus producer→consumer, command→agent, hooks, agent→tool) + the drop-in extractor registry (Decision D3). Enriches this plan's graph; independently testable.
18
+ - **Phase 2 — garden-side** (wicked-garden): repoint wicked-patch to brain's DB, ship the archetype extractor as a drop-in, alias/remove `search:*` commands, amend ADR 0001, update CLAUDE.md.
19
+
20
+ Reference spec: `wicked-garden/docs/specs/2026-06-10-codegraph-to-brain-migration.md` (Decisions D1–D6).
21
+
22
+ ---
23
+
24
+ ## File structure
25
+
26
+ | File | New/Mod | Responsibility |
27
+ |---|---|---|
28
+ | `server/lib/codegraph-resolver.mjs` | Create | Resolve the codegraph CLI argv (env → brain config → PATH → node_modules → npx); kill-switch. Port of garden's `_codegraph.py::resolve_codegraph`. |
29
+ | `server/lib/codegraph-index.mjs` | Create | `dbPath(source)`, `staleness(source)` (commits-behind HEAD), `runIndex(source)` (spawn `codegraph index`). |
30
+ | `server/lib/codegraph-client.mjs` | Create | Open `.codegraph/codegraph.db` readonly; `blastRadius`, `callers`, `lineage` via BFS over the `edges` table; attaches staleness to every result. |
31
+ | `server/bin/wicked-brain-server.mjs` | Modify (actions object ~L135–306) | Register `graph-index`, `graph-blast-radius`, `graph-callers`, `graph-lineage`; add the write one to `WRITE_ACTIONS`. |
32
+ | `skills/wicked-brain-graph/SKILL.md` | Create | New `wicked-brain:graph` skill documenting the graph queries. |
33
+ | `skills/wicked-brain-lsp/SKILL.md` | Modify (frontmatter) | Remove "blast radius" / "architecture map" trigger phrases (they were never implemented in LSP; they move here). |
34
+ | `server/test/codegraph-resolver.test.mjs` | Create | Resolver ladder + kill-switch. |
35
+ | `server/test/codegraph-index.test.mjs` | Create | dbPath + staleness (present/absent/behind). |
36
+ | `server/test/codegraph-client.test.mjs` | Create | blastRadius/callers/lineage over a hand-built fixture DB. |
37
+ | `docs/codegraph-contract.md` | Create (Task 1) | Pinned codegraph schema + edge-direction findings the client relies on. |
38
+
39
+ **Edge-direction constant:** the client centralizes the dependents-traversal direction in ONE constant (`DEPENDENTS_BY`), set from Task 1's empirical finding, so a wrong guess is a one-line flip, not a rewrite.
40
+
41
+ ---
42
+
43
+ ## Task 1: Characterization spike — pin codegraph's schema + edge direction
44
+
45
+ **Why:** Garden's `_codegraph.py` says the `nodes`/`edges` schema is `nodes(id,kind,name,qualified_name,file_path,language,start_line,end_line,start_column,end_column,updated_at,signature)` and `edges(source,target,kind,metadata,provenance)`, but its `inject_edges.py` comment is self-contradictory about blast-radius edge direction ("walk incoming edges" vs. an inserted producer→consumer edge that only resolves walking *outgoing*). We must observe the real behavior before writing traversal SQL.
46
+
47
+ **Files:**
48
+ - Create: `docs/codegraph-contract.md`
49
+
50
+ - [ ] **Step 1: Build a graph on a tiny fixture**
51
+
52
+ ```bash
53
+ cd /tmp && rm -rf cg-spike && mkdir cg-spike && cd cg-spike
54
+ git init -q && printf '%s\n' "def base(): pass" > a.py
55
+ printf '%s\n' "from a import base" "def caller(): return base()" > b.py
56
+ git add -A && git commit -qm init
57
+ npx -y @colbymchenry/codegraph index .
58
+ ```
59
+ Expected: `.codegraph/codegraph.db` created; output reports nodes/edges counts.
60
+
61
+ - [ ] **Step 2: Dump the real schema**
62
+
63
+ ```bash
64
+ cd /tmp/cg-spike
65
+ sqlite3 .codegraph/codegraph.db ".schema nodes" ".schema edges"
66
+ sqlite3 .codegraph/codegraph.db "SELECT id,kind,name,file_path FROM nodes;"
67
+ sqlite3 .codegraph/codegraph.db "SELECT source,target,kind FROM edges;"
68
+ ```
69
+ Record the exact column lists for `nodes` and `edges`.
70
+
71
+ - [ ] **Step 3: Determine blast-radius edge direction empirically**
72
+
73
+ `b.py::caller` calls/imports `a.py::base`. So `base`'s dependents (blast radius) must include `caller`. Inspect the edge row for that relationship:
74
+ - If the edge is `(source=<caller/b.py>, target=<base/a.py>)` → **dependents-of-X = rows WHERE target=X, collect `source`** → set `DEPENDENTS_BY = "target"`.
75
+ - If reversed → `DEPENDENTS_BY = "source"`.
76
+
77
+ ```bash
78
+ sqlite3 .codegraph/codegraph.db \
79
+ "SELECT source,target,kind FROM edges WHERE kind IN ('calls','imports','references');"
80
+ ```
81
+
82
+ - [ ] **Step 4: Capture the index CLI contract**
83
+
84
+ ```bash
85
+ npx -y @colbymchenry/codegraph index --help 2>&1 | head -40
86
+ ```
87
+ Record: exact subcommand + flags for indexing a directory, and whether it accepts a path arg or uses cwd. (Used by `runIndex` in Task 3.)
88
+
89
+ - [ ] **Step 5: Write the contract doc**
90
+
91
+ Create `docs/codegraph-contract.md` with: the `nodes` columns, the `edges` columns, the resolved `DEPENDENTS_BY` value (with the evidence row), the index command form, and the codegraph version (`npx -y @colbymchenry/codegraph --version`). This is the single reference Tasks 3–4 cite.
92
+
93
+ - [ ] **Step 6: Commit**
94
+
95
+ ```bash
96
+ cd /Users/michael.parcewski/Projects/wicked-brain
97
+ git add docs/codegraph-contract.md
98
+ git commit -m "docs(codegraph): pin schema + blast-radius edge direction from spike"
99
+ ```
100
+
101
+ ---
102
+
103
+ ## Task 2: `codegraph-resolver.mjs` — resolve the CLI
104
+
105
+ **Files:**
106
+ - Create: `server/lib/codegraph-resolver.mjs`
107
+ - Test: `server/test/codegraph-resolver.test.mjs`
108
+
109
+ - [ ] **Step 1: Write the failing test**
110
+
111
+ ```javascript
112
+ // server/test/codegraph-resolver.test.mjs
113
+ import { test } from "node:test";
114
+ import assert from "node:assert/strict";
115
+ import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from "node:fs";
116
+ import { tmpdir } from "node:os";
117
+ import { join } from "node:path";
118
+ import { resolveCodegraph } from "../lib/codegraph-resolver.mjs";
119
+
120
+ test("env override wins and is split into argv", () => {
121
+ const argv = resolveCodegraph({ env: { WICKED_CODEGRAPH_BIN: "/opt/cg" } });
122
+ assert.deepEqual(argv, ["/opt/cg"]);
123
+ });
124
+
125
+ test("a .mjs/.js env target is invoked via node", () => {
126
+ const argv = resolveCodegraph({ env: { WICKED_CODEGRAPH_BIN: "/x/cg.mjs" } });
127
+ assert.deepEqual(argv, ["node", "/x/cg.mjs"]);
128
+ });
129
+
130
+ test("set-but-empty env is the kill switch -> null", () => {
131
+ assert.equal(resolveCodegraph({ env: { WICKED_CODEGRAPH_BIN: "" } }), null);
132
+ });
133
+
134
+ test("brain config _meta/codegraph.json bin is honored", () => {
135
+ const brain = mkdtempSync(join(tmpdir(), "cg-cfg-"));
136
+ mkdirSync(join(brain, "_meta"), { recursive: true });
137
+ writeFileSync(join(brain, "_meta", "codegraph.json"), JSON.stringify({ bin: "/cfg/cg" }));
138
+ try {
139
+ const argv = resolveCodegraph({ env: {}, brainPath: brain, which: () => null });
140
+ assert.deepEqual(argv, ["/cfg/cg"]);
141
+ } finally {
142
+ rmSync(brain, { recursive: true, force: true });
143
+ }
144
+ });
145
+
146
+ test("falls back to npx when nothing else resolves", () => {
147
+ const argv = resolveCodegraph({ env: {}, which: (c) => (c === "npx" ? "/usr/bin/npx" : null) });
148
+ assert.deepEqual(argv, ["npx", "-y", "@colbymchenry/codegraph"]);
149
+ });
150
+
151
+ test("no npx and nothing resolves -> null", () => {
152
+ assert.equal(resolveCodegraph({ env: {}, which: () => null }), null);
153
+ });
154
+ ```
155
+
156
+ - [ ] **Step 2: Run it, verify failure**
157
+
158
+ Run: `cd /Users/michael.parcewski/Projects/wicked-brain/server && node --test test/codegraph-resolver.test.mjs`
159
+ Expected: FAIL — `Cannot find module '../lib/codegraph-resolver.mjs'`.
160
+
161
+ - [ ] **Step 3: Implement**
162
+
163
+ ```javascript
164
+ // server/lib/codegraph-resolver.mjs
165
+ import { execFileSync } from "node:child_process";
166
+ import { existsSync, readFileSync } from "node:fs";
167
+ import { join } from "node:path";
168
+ import { platform } from "node:os";
169
+
170
+ const PACKAGE = "@colbymchenry/codegraph";
171
+
172
+ function argvFor(target) {
173
+ // A .mjs/.js path is a script -> invoke via node; else run directly.
174
+ return /\.(mjs|js)$/.test(target) ? ["node", target] : [target];
175
+ }
176
+
177
+ function whichDefault(command) {
178
+ try {
179
+ const cmd = platform() === "win32" ? "where" : "which";
180
+ const out = execFileSync(cmd, [command], { encoding: "utf-8", timeout: 5000,
181
+ stdio: ["pipe", "pipe", "pipe"] });
182
+ return out.trim().split("\n")[0] || null;
183
+ } catch {
184
+ return null;
185
+ }
186
+ }
187
+
188
+ function configBin(brainPath) {
189
+ if (!brainPath) return null;
190
+ try {
191
+ const cfg = JSON.parse(readFileSync(join(brainPath, "_meta", "codegraph.json"), "utf-8"));
192
+ return typeof cfg.bin === "string" && cfg.bin.trim() ? cfg.bin.trim() : null;
193
+ } catch {
194
+ return null;
195
+ }
196
+ }
197
+
198
+ /**
199
+ * Resolve the argv prefix that invokes codegraph, or null.
200
+ * Ladder: WICKED_CODEGRAPH_BIN (set-but-empty = kill switch) -> brain
201
+ * _meta/codegraph.json {bin} -> PATH -> source node_modules/.bin -> `npx`.
202
+ * @param {{env?:object, brainPath?:string, sourcePath?:string, which?:Function, allowNpx?:boolean}} opts
203
+ */
204
+ export function resolveCodegraph(opts = {}) {
205
+ const { env = process.env, brainPath, sourcePath, which = whichDefault,
206
+ allowNpx = true } = opts;
207
+
208
+ if (Object.prototype.hasOwnProperty.call(env, "WICKED_CODEGRAPH_BIN")) {
209
+ const v = (env.WICKED_CODEGRAPH_BIN || "").trim();
210
+ return v ? argvFor(v) : null; // empty == kill switch
211
+ }
212
+ const cfg = configBin(brainPath);
213
+ if (cfg) return argvFor(cfg);
214
+
215
+ const onPath = which("codegraph");
216
+ if (onPath) return [onPath];
217
+
218
+ if (sourcePath) {
219
+ const local = join(sourcePath, "node_modules", ".bin", "codegraph");
220
+ if (existsSync(local)) return [local];
221
+ }
222
+ if (allowNpx && which("npx")) return ["npx", "-y", PACKAGE];
223
+ return null;
224
+ }
225
+
226
+ /** True iff a CONCRETE install resolves (not the npx last resort). */
227
+ export function codegraphAvailable(opts = {}) {
228
+ return resolveCodegraph({ ...opts, allowNpx: false }) !== null;
229
+ }
230
+ ```
231
+
232
+ - [ ] **Step 4: Run, verify pass**
233
+
234
+ Run: `node --test test/codegraph-resolver.test.mjs`
235
+ Expected: PASS (6 tests).
236
+
237
+ - [ ] **Step 5: Commit**
238
+
239
+ ```bash
240
+ git add server/lib/codegraph-resolver.mjs server/test/codegraph-resolver.test.mjs
241
+ git commit -m "feat(codegraph): CLI resolution ladder + kill switch"
242
+ ```
243
+
244
+ ---
245
+
246
+ ## Task 3: `codegraph-index.mjs` — dbPath, staleness, runIndex
247
+
248
+ **Files:**
249
+ - Create: `server/lib/codegraph-index.mjs`
250
+ - Test: `server/test/codegraph-index.test.mjs`
251
+
252
+ - [ ] **Step 1: Write the failing test**
253
+
254
+ ```javascript
255
+ // server/test/codegraph-index.test.mjs
256
+ import { test } from "node:test";
257
+ import assert from "node:assert/strict";
258
+ import { mkdtempSync, mkdirSync, writeFileSync, rmSync, utimesSync } from "node:fs";
259
+ import { tmpdir } from "node:os";
260
+ import { join } from "node:path";
261
+ import { execFileSync } from "node:child_process";
262
+ import { dbPath, staleness } from "../lib/codegraph-index.mjs";
263
+
264
+ test("dbPath points at <source>/.codegraph/codegraph.db", () => {
265
+ assert.equal(dbPath("/repo"), join("/repo", ".codegraph", "codegraph.db"));
266
+ });
267
+
268
+ test("staleness reports not-present when db is missing", () => {
269
+ const s = staleness("/no/such/repo");
270
+ assert.equal(s.present, false);
271
+ assert.equal(s.stale, null);
272
+ });
273
+
274
+ test("staleness reports commits behind HEAD", () => {
275
+ const repo = mkdtempSync(join(tmpdir(), "cg-stale-"));
276
+ try {
277
+ const git = (...a) => execFileSync("git", ["-C", repo, ...a], { stdio: "pipe" });
278
+ git("init"); git("config", "user.email", "t@t"); git("config", "user.name", "t");
279
+ writeFileSync(join(repo, "f.txt"), "1"); git("add", "-A"); git("commit", "-m", "c1");
280
+ // build the db, then backdate it before a second commit
281
+ mkdirSync(join(repo, ".codegraph"), { recursive: true });
282
+ const db = join(repo, ".codegraph", "codegraph.db");
283
+ writeFileSync(db, "x");
284
+ const past = new Date(Date.now() - 60_000);
285
+ utimesSync(db, past, past);
286
+ writeFileSync(join(repo, "g.txt"), "2"); git("add", "-A"); git("commit", "-m", "c2");
287
+
288
+ const s = staleness(repo);
289
+ assert.equal(s.present, true);
290
+ assert.equal(s.stale, true);
291
+ assert.ok(s.commits_behind >= 1);
292
+ } finally {
293
+ rmSync(repo, { recursive: true, force: true });
294
+ }
295
+ });
296
+ ```
297
+
298
+ - [ ] **Step 2: Run, verify failure**
299
+
300
+ Run: `node --test test/codegraph-index.test.mjs`
301
+ Expected: FAIL — module not found.
302
+
303
+ - [ ] **Step 3: Implement**
304
+
305
+ ```javascript
306
+ // server/lib/codegraph-index.mjs
307
+ import { execFileSync, spawn } from "node:child_process";
308
+ import { existsSync, statSync } from "node:fs";
309
+ import { join } from "node:path";
310
+ import { resolveCodegraph } from "./codegraph-resolver.mjs";
311
+
312
+ export function dbPath(sourcePath) {
313
+ return join(sourcePath, ".codegraph", "codegraph.db");
314
+ }
315
+
316
+ /**
317
+ * How far the graph has drifted from HEAD. Fail-open: errors report
318
+ * present-but-unknown, never throw. Port of garden _codegraph.py::staleness.
319
+ * @returns {{present:boolean, stale:boolean|null, commits_behind:number|null, indexed_at:string|null}}
320
+ */
321
+ export function staleness(sourcePath) {
322
+ const db = dbPath(sourcePath);
323
+ if (!existsSync(db)) {
324
+ return { present: false, stale: null, commits_behind: null, indexed_at: null };
325
+ }
326
+ try {
327
+ const mtimeMs = statSync(db).mtimeMs;
328
+ const iso = new Date(mtimeMs).toISOString();
329
+ const out = execFileSync("git",
330
+ ["-C", sourcePath, "rev-list", "--count", `--since=${iso}`, "HEAD"],
331
+ { encoding: "utf-8", timeout: 10_000, stdio: ["pipe", "pipe", "pipe"] }).trim();
332
+ const behind = out ? parseInt(out, 10) : 0;
333
+ return { present: true, stale: behind > 0, commits_behind: behind, indexed_at: iso };
334
+ } catch {
335
+ return { present: true, stale: null, commits_behind: null, indexed_at: null };
336
+ }
337
+ }
338
+
339
+ /**
340
+ * Build/refresh the graph by shelling `codegraph index`. Resolves nothing ->
341
+ * returns {ok:false, error}. Never throws.
342
+ * NOTE: the index subcommand/flags are pinned in docs/codegraph-contract.md (Task 1).
343
+ */
344
+ export function runIndex(sourcePath, opts = {}) {
345
+ return new Promise((resolve) => {
346
+ const argv = resolveCodegraph({ ...opts, sourcePath });
347
+ if (!argv) { resolve({ ok: false, error: "codegraph not resolvable" }); return; }
348
+ const [cmd, ...prefix] = argv;
349
+ const proc = spawn(cmd, [...prefix, "index", "."], {
350
+ cwd: sourcePath, stdio: ["ignore", "pipe", "pipe"],
351
+ });
352
+ let stderr = "";
353
+ proc.stderr.on("data", (d) => { stderr += d.toString(); });
354
+ proc.on("error", (e) => resolve({ ok: false, error: e.message }));
355
+ proc.on("close", (code) =>
356
+ resolve(code === 0 ? { ok: true } : { ok: false, error: stderr.trim() || `exit ${code}` }));
357
+ });
358
+ }
359
+ ```
360
+
361
+ - [ ] **Step 4: Run, verify pass**
362
+
363
+ Run: `node --test test/codegraph-index.test.mjs`
364
+ Expected: PASS (3 tests).
365
+
366
+ - [ ] **Step 5: Commit**
367
+
368
+ ```bash
369
+ git add server/lib/codegraph-index.mjs server/test/codegraph-index.test.mjs
370
+ git commit -m "feat(codegraph): dbPath + staleness stamp + index runner"
371
+ ```
372
+
373
+ ---
374
+
375
+ ## Task 4: `codegraph-client.mjs` — blast-radius / callers / lineage
376
+
377
+ **Files:**
378
+ - Create: `server/lib/codegraph-client.mjs`
379
+ - Test: `server/test/codegraph-client.test.mjs`
380
+
381
+ > The client reads codegraph's DB directly (no query-time subprocess). Schema from Task 1: `nodes(id,kind,name,qualified_name,file_path,language,start_line,end_line,start_column,end_column,updated_at,signature)`, `edges(source,target,kind,metadata,provenance)`. `DEPENDENTS_BY` is set from Task 1, Step 3 (default `"target"` — dependents of X are edge rows WHERE target=X, collecting `source`).
382
+
383
+ - [ ] **Step 1: Write the failing test (hand-built fixture DB)**
384
+
385
+ ```javascript
386
+ // server/test/codegraph-client.test.mjs
387
+ import { test } from "node:test";
388
+ import assert from "node:assert/strict";
389
+ import { mkdtempSync, mkdirSync, rmSync } from "node:fs";
390
+ import { tmpdir } from "node:os";
391
+ import { join } from "node:path";
392
+ import Database from "better-sqlite3";
393
+ import { CodegraphClient } from "../lib/codegraph-client.mjs";
394
+
395
+ function makeRepo() {
396
+ const repo = mkdtempSync(join(tmpdir(), "cg-client-"));
397
+ mkdirSync(join(repo, ".codegraph"), { recursive: true });
398
+ const db = new Database(join(repo, ".codegraph", "codegraph.db"));
399
+ db.exec(`
400
+ CREATE TABLE nodes (id TEXT PRIMARY KEY, kind TEXT, name TEXT, qualified_name TEXT,
401
+ file_path TEXT, language TEXT, start_line INT, end_line INT,
402
+ start_column INT, end_column INT, updated_at INT, signature TEXT);
403
+ CREATE TABLE edges (source TEXT, target TEXT, kind TEXT, metadata TEXT, provenance TEXT);
404
+ `);
405
+ const n = db.prepare(`INSERT INTO nodes
406
+ (id,kind,name,qualified_name,file_path,language,start_line,end_line,start_column,end_column,updated_at,signature)
407
+ VALUES (?,?,?,?,?,?,?,?,0,0,0,?)`);
408
+ n.run("file:a.py", "file", "a.py", "a.py", "a.py", "python", 1, 1, null);
409
+ n.run("file:b.py", "file", "b.py", "b.py", "b.py", "python", 1, 2, null);
410
+ n.run("file:c.py", "file", "c.py", "c.py", "c.py", "python", 1, 2, null);
411
+ // b and c depend on a (edge source=dependent, target=dependency)
412
+ const e = db.prepare("INSERT INTO edges (source,target,kind,metadata,provenance) VALUES (?,?,?,?,?)");
413
+ e.run("file:b.py", "file:a.py", "imports", null, "static");
414
+ e.run("file:c.py", "file:b.py", "calls", null, "static");
415
+ db.close();
416
+ return repo;
417
+ }
418
+
419
+ test("blastRadius returns transitive dependents of a node", () => {
420
+ const repo = makeRepo();
421
+ try {
422
+ const c = new CodegraphClient(repo);
423
+ const r = c.blastRadius({ node: "file:a.py" });
424
+ const ids = r.dependents.map((d) => d.id).sort();
425
+ assert.deepEqual(ids, ["file:b.py", "file:c.py"]); // c depends on b depends on a
426
+ assert.equal(r.staleness.present, true);
427
+ c.close();
428
+ } finally {
429
+ rmSync(repo, { recursive: true, force: true });
430
+ }
431
+ });
432
+
433
+ test("callers returns direct dependents only", () => {
434
+ const repo = makeRepo();
435
+ try {
436
+ const c = new CodegraphClient(repo);
437
+ const r = c.callers({ node: "file:a.py" });
438
+ assert.deepEqual(r.callers.map((d) => d.id), ["file:b.py"]);
439
+ c.close();
440
+ } finally {
441
+ rmSync(repo, { recursive: true, force: true });
442
+ }
443
+ });
444
+
445
+ test("lineage returns transitive dependencies (downstream)", () => {
446
+ const repo = makeRepo();
447
+ try {
448
+ const c = new CodegraphClient(repo);
449
+ const r = c.lineage({ node: "file:c.py" });
450
+ const ids = r.dependencies.map((d) => d.id).sort();
451
+ assert.deepEqual(ids, ["file:a.py", "file:b.py"]);
452
+ c.close();
453
+ } finally {
454
+ rmSync(repo, { recursive: true, force: true });
455
+ }
456
+ });
457
+
458
+ test("missing db -> engine unavailable, not an empty graph", () => {
459
+ const repo = mkdtempSync(join(tmpdir(), "cg-empty-"));
460
+ try {
461
+ const c = new CodegraphClient(repo);
462
+ const r = c.blastRadius({ node: "file:a.py" });
463
+ assert.equal(r.engine, "unavailable");
464
+ c.close();
465
+ } finally {
466
+ rmSync(repo, { recursive: true, force: true });
467
+ }
468
+ });
469
+ ```
470
+
471
+ - [ ] **Step 2: Run, verify failure**
472
+
473
+ Run: `node --test test/codegraph-client.test.mjs`
474
+ Expected: FAIL — module not found.
475
+
476
+ - [ ] **Step 3: Implement**
477
+
478
+ ```javascript
479
+ // server/lib/codegraph-client.mjs
480
+ import { existsSync } from "node:fs";
481
+ import Database from "better-sqlite3";
482
+ import { dbPath, staleness } from "./codegraph-index.mjs";
483
+
484
+ // Set from Task 1, Step 3. "target": dependents-of-X are edges WHERE target=X
485
+ // (collect `source`); dependencies-of-X are edges WHERE source=X (collect `target`).
486
+ const DEPENDENTS_BY = "target";
487
+ const DEPENDENCIES_BY = DEPENDENTS_BY === "target" ? "source" : "target";
488
+
489
+ export class CodegraphClient {
490
+ #sourcePath;
491
+ #db = null;
492
+
493
+ constructor(sourcePath) { this.#sourcePath = sourcePath; }
494
+
495
+ #open() {
496
+ if (this.#db) return this.#db;
497
+ const p = dbPath(this.#sourcePath);
498
+ if (!existsSync(p)) return null;
499
+ this.#db = new Database(p, { readonly: true });
500
+ return this.#db;
501
+ }
502
+
503
+ close() { if (this.#db) { this.#db.close(); this.#db = null; } }
504
+
505
+ #nodeRows(ids) {
506
+ if (ids.length === 0) return [];
507
+ const db = this.#db;
508
+ const ph = ids.map(() => "?").join(",");
509
+ return db.prepare(
510
+ `SELECT id, kind, name, file_path, start_line, end_line FROM nodes WHERE id IN (${ph})`
511
+ ).all(...ids);
512
+ }
513
+
514
+ // Generic BFS over edges. fromCol = the column we match the frontier on;
515
+ // toCol = the column we collect as the next frontier.
516
+ #walk(start, { fromCol, toCol, maxDepth }) {
517
+ const db = this.#db;
518
+ const stmt = db.prepare(`SELECT DISTINCT ${toCol} AS next FROM edges WHERE ${fromCol} = ?`);
519
+ const seen = new Set();
520
+ let frontier = [start];
521
+ let depth = 0;
522
+ while (frontier.length && depth < maxDepth) {
523
+ const nextFrontier = [];
524
+ for (const node of frontier) {
525
+ for (const row of stmt.all(node)) {
526
+ if (row.next && row.next !== start && !seen.has(row.next)) {
527
+ seen.add(row.next);
528
+ nextFrontier.push(row.next);
529
+ }
530
+ }
531
+ }
532
+ frontier = nextFrontier;
533
+ depth += 1;
534
+ }
535
+ return [...seen];
536
+ }
537
+
538
+ #unavailable() {
539
+ return { engine: "unavailable", reason: `no graph at ${dbPath(this.#sourcePath)} — run graph-index`,
540
+ staleness: staleness(this.#sourcePath) };
541
+ }
542
+
543
+ /** Transitive dependents of a node — "what breaks if I change X". */
544
+ blastRadius({ node, maxDepth = 25 }) {
545
+ if (!this.#open()) return this.#unavailable();
546
+ const ids = this.#walk(node, { fromCol: DEPENDENTS_BY,
547
+ toCol: DEPENDENTS_BY === "target" ? "source" : "target", maxDepth });
548
+ return { node, dependents: this.#nodeRows(ids), staleness: staleness(this.#sourcePath) };
549
+ }
550
+
551
+ /** Direct dependents only (depth 1). */
552
+ callers({ node }) {
553
+ if (!this.#open()) return this.#unavailable();
554
+ const ids = this.#walk(node, { fromCol: DEPENDENTS_BY,
555
+ toCol: DEPENDENTS_BY === "target" ? "source" : "target", maxDepth: 1 });
556
+ return { node, callers: this.#nodeRows(ids), staleness: staleness(this.#sourcePath) };
557
+ }
558
+
559
+ /** Transitive dependencies of a node — downstream lineage. */
560
+ lineage({ node, maxDepth = 25 }) {
561
+ if (!this.#open()) return this.#unavailable();
562
+ const ids = this.#walk(node, { fromCol: DEPENDENCIES_BY,
563
+ toCol: DEPENDENCIES_BY === "target" ? "source" : "target", maxDepth });
564
+ return { node, dependencies: this.#nodeRows(ids), staleness: staleness(this.#sourcePath) };
565
+ }
566
+ }
567
+ ```
568
+
569
+ > Note for the implementer: `#walk`'s `toCol` is derived inline so dependents collect the opposite column from the one matched. If Task 1 flips `DEPENDENTS_BY` to `"source"`, the derivations follow automatically — no other change needed.
570
+
571
+ - [ ] **Step 4: Run, verify pass**
572
+
573
+ Run: `node --test test/codegraph-client.test.mjs`
574
+ Expected: PASS (4 tests).
575
+
576
+ - [ ] **Step 5: Commit**
577
+
578
+ ```bash
579
+ git add server/lib/codegraph-client.mjs server/test/codegraph-client.test.mjs
580
+ git commit -m "feat(codegraph): graph client — blast-radius/callers/lineage over edges"
581
+ ```
582
+
583
+ ---
584
+
585
+ ## Task 5: Wire the `graph-*` server actions
586
+
587
+ **Files:**
588
+ - Modify: `server/bin/wicked-brain-server.mjs` (the `actions` object ~L135–306; `WRITE_ACTIONS` set ~L311–321)
589
+ - Test: `server/test/codegraph-actions.test.mjs` (Create)
590
+
591
+ > The server constructs collaborators once at startup (`db`, `lsp`) from `brainPath`/`sourcePath`. Add a codegraph client + index runner the same way and register four actions. `graph-index` mutates → add to `WRITE_ACTIONS`.
592
+
593
+ - [ ] **Step 1: Write the failing test (handlers are pure functions of params)**
594
+
595
+ ```javascript
596
+ // server/test/codegraph-actions.test.mjs
597
+ import { test } from "node:test";
598
+ import assert from "node:assert/strict";
599
+ import { mkdtempSync, mkdirSync, rmSync } from "node:fs";
600
+ import { tmpdir } from "node:os";
601
+ import { join } from "node:path";
602
+ import Database from "better-sqlite3";
603
+ import { makeGraphActions } from "../lib/codegraph-actions.mjs";
604
+
605
+ function repoWithGraph() {
606
+ const repo = mkdtempSync(join(tmpdir(), "cg-act-"));
607
+ mkdirSync(join(repo, ".codegraph"), { recursive: true });
608
+ const db = new Database(join(repo, ".codegraph", "codegraph.db"));
609
+ db.exec(`CREATE TABLE nodes (id TEXT PRIMARY KEY, kind TEXT, name TEXT, qualified_name TEXT,
610
+ file_path TEXT, language TEXT, start_line INT, end_line INT, start_column INT,
611
+ end_column INT, updated_at INT, signature TEXT);
612
+ CREATE TABLE edges (source TEXT, target TEXT, kind TEXT, metadata TEXT, provenance TEXT);`);
613
+ db.prepare(`INSERT INTO nodes (id,kind,name,qualified_name,file_path,language,start_line,end_line,start_column,end_column,updated_at,signature)
614
+ VALUES (?,?,?,?,?,?,1,1,0,0,0,NULL)`).run("file:a.py","file","a.py","a.py","a.py","python");
615
+ db.prepare(`INSERT INTO nodes (id,kind,name,qualified_name,file_path,language,start_line,end_line,start_column,end_column,updated_at,signature)
616
+ VALUES (?,?,?,?,?,?,1,1,0,0,0,NULL)`).run("file:b.py","file","b.py","b.py","b.py","python");
617
+ db.prepare("INSERT INTO edges (source,target,kind,metadata,provenance) VALUES (?,?,?,?,?)")
618
+ .run("file:b.py","file:a.py","imports",null,"static");
619
+ db.close();
620
+ return repo;
621
+ }
622
+
623
+ test("graph-blast-radius action returns dependents", () => {
624
+ const repo = repoWithGraph();
625
+ try {
626
+ const actions = makeGraphActions({ sourcePath: repo });
627
+ const r = actions["graph-blast-radius"]({ node: "file:a.py" });
628
+ assert.deepEqual(r.dependents.map((d) => d.id), ["file:b.py"]);
629
+ } finally {
630
+ rmSync(repo, { recursive: true, force: true });
631
+ }
632
+ });
633
+
634
+ test("graph-blast-radius on a graphless repo reports unavailable", () => {
635
+ const repo = mkdtempSync(join(tmpdir(), "cg-none-"));
636
+ try {
637
+ const actions = makeGraphActions({ sourcePath: repo });
638
+ assert.equal(actions["graph-blast-radius"]({ node: "x" }).engine, "unavailable");
639
+ } finally {
640
+ rmSync(repo, { recursive: true, force: true });
641
+ }
642
+ });
643
+ ```
644
+
645
+ - [ ] **Step 2: Run, verify failure**
646
+
647
+ Run: `node --test test/codegraph-actions.test.mjs`
648
+ Expected: FAIL — `Cannot find module '../lib/codegraph-actions.mjs'`.
649
+
650
+ - [ ] **Step 3: Implement the action factory**
651
+
652
+ ```javascript
653
+ // server/lib/codegraph-actions.mjs
654
+ import { CodegraphClient } from "./codegraph-client.mjs";
655
+ import { runIndex, staleness } from "./codegraph-index.mjs";
656
+
657
+ /**
658
+ * Build the graph-* action handlers bound to a source repo. A fresh client per
659
+ * call keeps the readonly DB handle short-lived and always reopens after a rebuild.
660
+ */
661
+ export function makeGraphActions({ sourcePath, brainPath } = {}) {
662
+ const withClient = (fn) => {
663
+ const c = new CodegraphClient(sourcePath);
664
+ try { return fn(c); } finally { c.close(); }
665
+ };
666
+ return {
667
+ "graph-blast-radius": (p = {}) => withClient((c) => c.blastRadius({ node: p.node, maxDepth: p.maxDepth })),
668
+ "graph-callers": (p = {}) => withClient((c) => c.callers({ node: p.node })),
669
+ "graph-lineage": (p = {}) => withClient((c) => c.lineage({ node: p.node, maxDepth: p.maxDepth })),
670
+ "graph-index": async () => {
671
+ const r = await runIndex(sourcePath, { brainPath, sourcePath });
672
+ return { ...r, staleness: staleness(sourcePath) };
673
+ },
674
+ };
675
+ }
676
+ ```
677
+
678
+ - [ ] **Step 4: Run, verify pass**
679
+
680
+ Run: `node --test test/codegraph-actions.test.mjs`
681
+ Expected: PASS (2 tests).
682
+
683
+ - [ ] **Step 5: Register actions in the server**
684
+
685
+ In `server/bin/wicked-brain-server.mjs`, near where `lsp`/`db` are constructed, add:
686
+
687
+ ```javascript
688
+ import { makeGraphActions } from "../lib/codegraph-actions.mjs";
689
+ // ... after sourcePath/brainPath are known:
690
+ const graphActions = makeGraphActions({ sourcePath, brainPath });
691
+ ```
692
+
693
+ Then spread the handlers into the `actions` object (alongside the `lsp-*` block ~L238–248):
694
+
695
+ ```javascript
696
+ ...graphActions, // graph-index, graph-blast-radius, graph-callers, graph-lineage
697
+ ```
698
+
699
+ And add the mutating one to the `WRITE_ACTIONS` set (~L311–321):
700
+
701
+ ```javascript
702
+ const WRITE_ACTIONS = new Set([
703
+ /* ...existing... */
704
+ "graph-index",
705
+ ]);
706
+ ```
707
+
708
+ - [ ] **Step 6: Smoke the live server action**
709
+
710
+ ```bash
711
+ cd /Users/michael.parcewski/Projects/wicked-brain/server
712
+ # in repo /tmp/cg-spike from Task 1, with .codegraph already built:
713
+ node bin/wicked-brain-server.mjs --brain /tmp/cg-spike-brain --port 4399 --source /tmp/cg-spike &
714
+ SRV=$!; sleep 1
715
+ curl -s -XPOST localhost:4399/api -H 'content-type: application/json' \
716
+ -d '{"action":"graph-blast-radius","params":{"node":"file:a.py"}}'
717
+ kill $SRV
718
+ ```
719
+ Expected: JSON with a `dependents` array containing `file:b.py` and a `staleness` object.
720
+
721
+ - [ ] **Step 7: Commit**
722
+
723
+ ```bash
724
+ git add server/lib/codegraph-actions.mjs server/test/codegraph-actions.test.mjs server/bin/wicked-brain-server.mjs
725
+ git commit -m "feat(codegraph): register graph-* server actions"
726
+ ```
727
+
728
+ ---
729
+
730
+ ## Task 6: `wicked-brain:graph` skill + trim the LSP skill
731
+
732
+ **Files:**
733
+ - Create: `skills/wicked-brain-graph/SKILL.md`
734
+ - Modify: `skills/wicked-brain-lsp/SKILL.md` (frontmatter description only)
735
+
736
+ - [ ] **Step 1: Create the graph skill**
737
+
738
+ ```markdown
739
+ ---
740
+ name: wicked-brain:graph
741
+ description: |
742
+ Code-relationship graph queries — blast radius, callers, and lineage — backed
743
+ by a codegraph static graph the brain owns. Answers "what breaks if I change X",
744
+ "who calls X", and "what does X depend on" across the whole repo, including
745
+ relationships a grep or single-file LSP lookup cannot see.
746
+
747
+ Use when: "blast radius", "what breaks if I change", "impact of changing X",
748
+ "who calls X", "what depends on X", "lineage", "what does X depend on",
749
+ "architecture map", "code relationship graph".
750
+ ---
751
+
752
+ # wicked-brain:graph
753
+
754
+ Relationship-graph intelligence over a codegraph-built SQLite graph. Distinct from
755
+ `wicked-brain:lsp` (live, single-symbol def/ref/hover/diagnostics) — this is the
756
+ whole-repo relationship graph and the home of blast-radius / lineage.
757
+
758
+ ## Queries (via `npx wicked-brain-call`)
759
+
760
+ - `graph-index` — build/refresh the graph (`codegraph index .`). Run once per repo,
761
+ then on demand when results report they are stale.
762
+ - `graph-blast-radius {node}` — transitive dependents of `node` ("what breaks if I change it").
763
+ - `graph-callers {node}` — direct dependents only.
764
+ - `graph-lineage {node}` — transitive dependencies (downstream).
765
+
766
+ `node` ids follow codegraph's convention (e.g. `file:src/app.py`, or a symbol id).
767
+ Every result carries a `staleness` stamp (`commits_behind`, `indexed_at`); if
768
+ `stale` is true, re-run `graph-index`.
769
+
770
+ ## Freshness
771
+
772
+ Lazy by design — the graph is never auto-rebuilt by a file watcher. Results tell you
773
+ when they are behind HEAD; rebuild with `graph-index` (or wire the optional commit hook).
774
+ ```
775
+
776
+ - [ ] **Step 2: Trim the LSP skill description**
777
+
778
+ In `skills/wicked-brain-lsp/SKILL.md` frontmatter, remove the `"blast radius"` and `"architecture map"` trigger phrases from the `Use when:` line (they were never implemented in LSP and now live in `wicked-brain:graph`). Add a one-line pointer in the body:
779
+
780
+ ```markdown
781
+ > For blast-radius / lineage / architecture (whole-repo relationships), use `wicked-brain:graph`.
782
+ ```
783
+
784
+ - [ ] **Step 3: Verify install picks up the new skill**
785
+
786
+ ```bash
787
+ cd /Users/michael.parcewski/Projects/wicked-brain
788
+ node install.mjs 2>&1 | grep -i "skills installed"
789
+ ls ~/.claude/skills/wicked-brain-graph/SKILL.md
790
+ ```
791
+ Expected: install reports the skill count incremented by one; the file exists.
792
+
793
+ - [ ] **Step 4: Commit**
794
+
795
+ ```bash
796
+ git add skills/wicked-brain-graph/SKILL.md skills/wicked-brain-lsp/SKILL.md
797
+ git commit -m "feat(codegraph): wicked-brain:graph skill; move blast-radius off lsp skill"
798
+ ```
799
+
800
+ ---
801
+
802
+ ## Task 7: End-to-end verification
803
+
804
+ **Files:** none (verification only)
805
+
806
+ - [ ] **Step 1: Full suite green**
807
+
808
+ Run: `cd /Users/michael.parcewski/Projects/wicked-brain/server && npm test`
809
+ Expected: all tests pass, including the four new files.
810
+
811
+ - [ ] **Step 2: Real-repo blast-radius**
812
+
813
+ ```bash
814
+ # Point at a real repo (e.g. wicked-brain itself), build, query.
815
+ cd /Users/michael.parcewski/Projects/wicked-brain
816
+ npx -y @colbymchenry/codegraph index .
817
+ node server/bin/wicked-brain-server.mjs --brain ~/.wicked-brain/projects/cg-e2e --port 4398 --source "$PWD" &
818
+ SRV=$!; sleep 1
819
+ curl -s -XPOST localhost:4398/api -H 'content-type: application/json' \
820
+ -d '{"action":"graph-callers","params":{"node":"file:server/lib/sqlite-search.mjs"}}' | head -c 400
821
+ kill $SRV
822
+ ```
823
+ Expected: a `callers` array (non-empty if anything imports that module) + a `staleness` stamp with `stale:false` right after indexing.
824
+
825
+ - [ ] **Step 3: Commit (if any doc tweaks)**
826
+
827
+ ```bash
828
+ git add -A && git commit -m "test(codegraph): phase-1a e2e verification notes" || echo "nothing to commit"
829
+ ```
830
+
831
+ ---
832
+
833
+ ## Self-review (done at write time)
834
+
835
+ - **Spec coverage:** D1 (brain owns queries) → Tasks 4–6. D2 (zero garden dep) → all code is brain-native `.mjs`, imports nothing from garden. D4 (codegraph=graph of record, LSP=live) → Task 6 moves blast-radius off LSP. D5 (lazy staleness, no watcher) → Task 3 staleness + Task 5 `graph-index` on demand, watcher untouched. D6 (DB stays codegraph-native) → `dbPath` = `<source>/.codegraph/codegraph.db`, opened readonly. D3 (extractor registry) + injected edges are **Phase 1b** — explicitly out of this plan.
836
+ - **Placeholder scan:** none — every step has runnable code/commands. The one empirical unknown (edge direction) is isolated to Task 1 + the `DEPENDENTS_BY` constant.
837
+ - **Type consistency:** `resolveCodegraph`, `dbPath`, `staleness`, `runIndex`, `CodegraphClient.{blastRadius,callers,lineage,close}`, `makeGraphActions` names are consistent across tasks and tests. Result shapes (`{dependents|callers|dependencies, staleness}` / `{engine:"unavailable"}`) match between client, actions, and their tests.
838
+ - **Scope:** single shippable subsystem (graph-core); injected edges and garden-side work deferred to named follow-on plans.