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,843 @@
1
+ # wicked-loom — Expand Phase, Plan A (compose skeleton) — 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:** Stand up the `wicked-loom` standalone package with its `compose` surface — peer manifest, the runtime resolution ladder, version-check, and install orchestration — publishable as `wicked-loom@0.1.0` and runnable as `npx wicked-loom`, with garden untouched.
6
+
7
+ **Architecture:** An **npm package** whose `bin` is a thin Node shim (`bin/loom.mjs`) that execs `python3` on a bundled Python module (`python/loom/`). The Python core holds all logic (CLI dispatch + compose). This matches garden's existing `npx wicked-*` consumption + resolution ladder while reusing garden's Python resolver code. **Compose only** — gate/flow/conduct is Plan B (do not build it here; YAGNI).
8
+
9
+ **Tech Stack:** Python 3.9+ (stdlib only — no third-party deps, mirroring garden's hook discipline), `pytest` for tests, a ~30-line Node ESM shim, `npm` packaging.
10
+
11
+ **Decisions locked for this plan (override in review):**
12
+ - Distribution: npm package + Node bin shim → bundled Python. (Alt: pip/pipx.)
13
+ - Scope: compose surface only — `loom resolve`, `loom doctor`, `loom compose install`. Conduct = Plan B.
14
+ - Target repo dir for execution: `~/Projects/wicked-loom` (a NEW git repo, sibling to wicked-garden). Adjust paths if you place it elsewhere.
15
+
16
+ **Source material to port (read these in wicked-garden before Task 3+):**
17
+ - `scripts/_integration_resolver.py`, `scripts/_capability_resolver.py` — the resolution ladder + kill-switch.
18
+ - `scripts/qe/vault_gate.py` (the `_resolve_vault` portion only) — the `WICKED_VAULT_BIN → config → PATH → node_modules → npx` ladder, verbatim pattern.
19
+ - `docs/required-peers.md` + `.claude-plugin/plugin.json` — the peer set, version pins (`testing ^0.3`, `vault ^0.3`, `brain ^0.14`, `bus ^2.0`) and install commands.
20
+
21
+ **Bulletproof standards:** R1–R6 (no dead code, no bare panics, no magic values, no swallowed errors, no unbounded ops, no god functions) and T1–T6 (determinism, no sleep-based sync, isolation, single-assertion focus, descriptive names, provenance). The resolution ladder must be deterministic and fully mockable — never hit the network or real `npx` in a unit test.
22
+
23
+ ---
24
+
25
+ ## File Structure
26
+
27
+ ```
28
+ wicked-loom/
29
+ ├── package.json # npm metadata + bin: { "loom": "bin/loom.mjs" }
30
+ ├── bin/loom.mjs # Node ESM shim → spawns python3 on python/loom
31
+ ├── python/loom/
32
+ │ ├── __init__.py # version constant
33
+ │ ├── __main__.py # `python3 -m loom` entry → cli.main(argv)
34
+ │ ├── cli.py # arg dispatch: resolve | doctor | compose
35
+ │ ├── manifest.py # Peer dataclass + PEERS registry (the peer set)
36
+ │ ├── resolve.py # the runtime resolution ladder + kill-switch
37
+ │ └── compose.py # version-check + install orchestration
38
+ ├── tests/
39
+ │ ├── test_manifest.py
40
+ │ ├── test_resolve.py
41
+ │ ├── test_compose.py
42
+ │ └── test_cli.py
43
+ ├── .gitignore
44
+ └── README.md
45
+ ```
46
+
47
+ Responsibilities: `manifest` = *what the peers are* (data). `resolve` = *find a peer's runnable command* (the ladder). `compose` = *check versions + install* (actions, built on resolve+manifest). `cli` = *argument dispatch only* (no logic). `bin/loom.mjs` = *launch python3* (no logic). One responsibility per file; `cli` and the shim stay logic-free so the Python modules are unit-testable without a process boundary.
48
+
49
+ ---
50
+
51
+ ## Task 1: Repo + package skeleton
52
+
53
+ **Files:**
54
+ - Create: `~/Projects/wicked-loom/package.json`
55
+ - Create: `~/Projects/wicked-loom/.gitignore`
56
+ - Create: `~/Projects/wicked-loom/python/loom/__init__.py`
57
+
58
+ - [ ] **Step 1: Init the repo**
59
+
60
+ ```bash
61
+ mkdir -p ~/Projects/wicked-loom/python/loom ~/Projects/wicked-loom/bin ~/Projects/wicked-loom/tests
62
+ cd ~/Projects/wicked-loom && git init
63
+ ```
64
+
65
+ - [ ] **Step 2: Write `package.json`**
66
+
67
+ ```json
68
+ {
69
+ "name": "wicked-loom",
70
+ "version": "0.1.0",
71
+ "description": "Local-first orchestration runtime for agent ecosystems: resolves, version-checks, and installs the wicked-* peer set (compose). Conduct (gate/flow) ships separately.",
72
+ "bin": { "loom": "bin/loom.mjs" },
73
+ "files": ["bin/", "python/", "README.md"],
74
+ "type": "module",
75
+ "engines": { "node": ">=18" },
76
+ "license": "MIT",
77
+ "repository": "https://github.com/mikeparcewski/wicked-loom",
78
+ "keywords": ["orchestration", "agents", "local-first", "compose", "wicked"]
79
+ }
80
+ ```
81
+
82
+ - [ ] **Step 3: Write `.gitignore`**
83
+
84
+ ```
85
+ __pycache__/
86
+ *.pyc
87
+ node_modules/
88
+ .pytest_cache/
89
+ ```
90
+
91
+ - [ ] **Step 4: Write `python/loom/__init__.py`**
92
+
93
+ ```python
94
+ """wicked-loom — orchestration runtime (compose surface)."""
95
+
96
+ __version__ = "0.1.0"
97
+ ```
98
+
99
+ - [ ] **Step 5: Commit**
100
+
101
+ ```bash
102
+ cd ~/Projects/wicked-loom
103
+ git add package.json .gitignore python/loom/__init__.py
104
+ git commit -m "chore: wicked-loom package skeleton"
105
+ ```
106
+
107
+ ---
108
+
109
+ ## Task 2: Node bin shim (launch python3)
110
+
111
+ **Files:**
112
+ - Create: `~/Projects/wicked-loom/bin/loom.mjs`
113
+ - Test: `~/Projects/wicked-loom/tests/test_cli.py` (the shim is smoke-tested via the CLI task; here we only assert it exists + is wired)
114
+
115
+ - [ ] **Step 1: Write the shim**
116
+
117
+ ```javascript
118
+ #!/usr/bin/env node
119
+ // Thin launcher: find python3 and exec `python3 -m loom <args>` with python/ on PYTHONPATH.
120
+ // All logic lives in the Python module; this file only bridges npx → python3.
121
+ import { spawnSync } from "node:child_process";
122
+ import { fileURLToPath } from "node:url";
123
+ import { dirname, join } from "node:path";
124
+
125
+ const here = dirname(fileURLToPath(import.meta.url));
126
+ const pyRoot = join(here, "..", "python");
127
+
128
+ function findPython() {
129
+ for (const cand of ["python3", "python", "py"]) {
130
+ const r = spawnSync(cand, ["--version"], { stdio: "ignore" });
131
+ if (r.status === 0) return cand;
132
+ }
133
+ return null;
134
+ }
135
+
136
+ const python = findPython();
137
+ if (!python) {
138
+ console.error("[wicked-loom] python3 is required but was not found on PATH.");
139
+ process.exit(127);
140
+ }
141
+
142
+ const env = { ...process.env, PYTHONPATH: pyRoot + (process.env.PYTHONPATH ? `:${process.env.PYTHONPATH}` : "") };
143
+ const res = spawnSync(python, ["-m", "loom", ...process.argv.slice(2)], { stdio: "inherit", env });
144
+ process.exit(res.status === null ? 1 : res.status);
145
+ ```
146
+
147
+ - [ ] **Step 2: Make it executable + smoke it (will fail until `__main__` exists)**
148
+
149
+ Run: `chmod +x ~/Projects/wicked-loom/bin/loom.mjs && node ~/Projects/wicked-loom/bin/loom.mjs --help`
150
+ Expected: a Python error (`No module named loom.__main__`) — proves the shim finds python3 and dispatches. (Green after Task 6.)
151
+
152
+ - [ ] **Step 3: Commit**
153
+
154
+ ```bash
155
+ cd ~/Projects/wicked-loom
156
+ git add bin/loom.mjs
157
+ git commit -m "feat: node bin shim launches bundled python"
158
+ ```
159
+
160
+ ---
161
+
162
+ ## Task 3: Peer manifest
163
+
164
+ **Files:**
165
+ - Create: `~/Projects/wicked-loom/python/loom/manifest.py`
166
+ - Test: `~/Projects/wicked-loom/tests/test_manifest.py`
167
+
168
+ - [ ] **Step 1: Write the failing test**
169
+
170
+ ```python
171
+ from loom import manifest
172
+
173
+
174
+ def test_known_peers_present():
175
+ assert set(manifest.PEERS) == {"vault", "testing", "brain", "bus"}
176
+
177
+
178
+ def test_each_peer_has_required_fields():
179
+ for name, peer in manifest.PEERS.items():
180
+ assert peer.name == name
181
+ assert peer.npm_package.startswith("wicked-")
182
+ assert peer.env_var.startswith("WICKED_") and peer.env_var.endswith("_BIN")
183
+ assert peer.version_pin # non-empty
184
+ assert isinstance(peer.install_cmd, list) and peer.install_cmd
185
+ assert isinstance(peer.probe_cmd, list) and peer.probe_cmd
186
+
187
+
188
+ def test_vault_pins_match_garden():
189
+ assert manifest.PEERS["vault"].version_pin == "0.3"
190
+ assert manifest.PEERS["vault"].env_var == "WICKED_VAULT_BIN"
191
+
192
+
193
+ def test_get_unknown_peer_returns_none():
194
+ assert manifest.get("nope") is None
195
+ ```
196
+
197
+ - [ ] **Step 2: Run test to verify it fails**
198
+
199
+ Run: `cd ~/Projects/wicked-loom && PYTHONPATH=python python3 -m pytest tests/test_manifest.py -v`
200
+ Expected: FAIL — `ModuleNotFoundError: No module named 'loom.manifest'`
201
+
202
+ - [ ] **Step 3: Write `manifest.py`**
203
+
204
+ ```python
205
+ """manifest.py — the wicked-* peer set: what each peer is and how to reach it.
206
+
207
+ Source of truth ported from wicked-garden docs/required-peers.md + plugin.json.
208
+ Version pins are the MAJOR.MINOR floor (the `^x.y` in plugin.json), compared by
209
+ compose.py. Install commands are headless (npm/npx) — the `/plugin install`
210
+ path is CC-UX sugar, not the only route.
211
+ """
212
+
213
+ from __future__ import annotations
214
+
215
+ from dataclasses import dataclass
216
+
217
+
218
+ @dataclass(frozen=True)
219
+ class Peer:
220
+ name: str
221
+ npm_package: str
222
+ env_var: str # runtime override env var, e.g. WICKED_VAULT_BIN
223
+ version_pin: str # MAJOR.MINOR floor, e.g. "0.3"
224
+ install_cmd: list[str] # headless install command
225
+ probe_cmd: list[str] # command to print the installed version
226
+
227
+
228
+ PEERS: dict[str, Peer] = {
229
+ "vault": Peer(
230
+ name="vault",
231
+ npm_package="wicked-vault",
232
+ env_var="WICKED_VAULT_BIN",
233
+ version_pin="0.3",
234
+ install_cmd=["npx", "wicked-vault-install"],
235
+ probe_cmd=["wicked-vault", "--version"],
236
+ ),
237
+ "testing": Peer(
238
+ name="testing",
239
+ npm_package="wicked-testing",
240
+ env_var="WICKED_TESTING_BIN",
241
+ version_pin="0.3",
242
+ install_cmd=["npx", "wicked-testing", "install"],
243
+ probe_cmd=["wicked-testing", "--version"],
244
+ ),
245
+ "brain": Peer(
246
+ name="brain",
247
+ npm_package="wicked-brain",
248
+ env_var="WICKED_BRAIN_BIN",
249
+ version_pin="0.14",
250
+ install_cmd=["npm", "install", "-g", "wicked-brain@latest"],
251
+ probe_cmd=["wicked-brain-server", "--version"],
252
+ ),
253
+ "bus": Peer(
254
+ name="bus",
255
+ npm_package="wicked-bus",
256
+ env_var="WICKED_BUS_BIN",
257
+ version_pin="2.0",
258
+ install_cmd=["npm", "install", "-g", "wicked-bus@latest"],
259
+ probe_cmd=["wicked-bus", "--version"],
260
+ ),
261
+ }
262
+
263
+
264
+ def get(name: str) -> "Peer | None":
265
+ """Return the Peer for ``name`` or None if unknown."""
266
+ return PEERS.get(name)
267
+ ```
268
+
269
+ - [ ] **Step 4: Run test to verify it passes**
270
+
271
+ Run: `cd ~/Projects/wicked-loom && PYTHONPATH=python python3 -m pytest tests/test_manifest.py -v`
272
+ Expected: PASS (4 tests)
273
+
274
+ - [ ] **Step 5: Commit**
275
+
276
+ ```bash
277
+ cd ~/Projects/wicked-loom
278
+ git add python/loom/manifest.py tests/test_manifest.py
279
+ git commit -m "feat: peer manifest (vault/testing/brain/bus)"
280
+ ```
281
+
282
+ ---
283
+
284
+ ## Task 4: Resolution ladder
285
+
286
+ **Files:**
287
+ - Create: `~/Projects/wicked-loom/python/loom/resolve.py`
288
+ - Test: `~/Projects/wicked-loom/tests/test_resolve.py`
289
+
290
+ The ladder, ported from `vault_gate.py`: `WICKED_<PEER>_BIN` env → `PATH` (shutil.which) → `npx <package>` fallback. Empty env var (`WICKED_VAULT_BIN=""`) is the **kill-switch** → returns None. (Garden also checks a config file + node_modules; omitted in 0.1 as YAGNI — add when a consumer needs them.)
291
+
292
+ - [ ] **Step 1: Write the failing test**
293
+
294
+ ```python
295
+ import shutil
296
+ from unittest.mock import patch
297
+
298
+ from loom import resolve
299
+
300
+
301
+ def test_env_var_override_wins(monkeypatch):
302
+ monkeypatch.setenv("WICKED_VAULT_BIN", "/opt/custom/vault")
303
+ assert resolve.resolve("vault") == ["/opt/custom/vault"]
304
+
305
+
306
+ def test_empty_env_var_is_killswitch(monkeypatch):
307
+ monkeypatch.setenv("WICKED_VAULT_BIN", "")
308
+ assert resolve.resolve("vault") is None
309
+
310
+
311
+ def test_path_lookup_when_no_env(monkeypatch):
312
+ monkeypatch.delenv("WICKED_VAULT_BIN", raising=False)
313
+ with patch.object(shutil, "which", return_value="/usr/local/bin/wicked-vault"):
314
+ assert resolve.resolve("vault") == ["/usr/local/bin/wicked-vault"]
315
+
316
+
317
+ def test_npx_fallback_when_not_on_path(monkeypatch):
318
+ monkeypatch.delenv("WICKED_VAULT_BIN", raising=False)
319
+ with patch.object(shutil, "which", return_value=None):
320
+ assert resolve.resolve("vault") == ["npx", "wicked-vault"]
321
+
322
+
323
+ def test_unknown_peer_returns_none():
324
+ assert resolve.resolve("nope") is None
325
+ ```
326
+
327
+ - [ ] **Step 2: Run test to verify it fails**
328
+
329
+ Run: `cd ~/Projects/wicked-loom && PYTHONPATH=python python3 -m pytest tests/test_resolve.py -v`
330
+ Expected: FAIL — `ModuleNotFoundError: No module named 'loom.resolve'`
331
+
332
+ - [ ] **Step 3: Write `resolve.py`**
333
+
334
+ ```python
335
+ """resolve.py — the runtime resolution ladder for a peer's runnable command.
336
+
337
+ Ladder (highest priority first):
338
+ 1. WICKED_<PEER>_BIN env var — explicit override. Empty string is a
339
+ deliberate kill-switch (returns None, resolution short-circuits cleanly).
340
+ 2. PATH — shutil.which(<npm_package>).
341
+ 3. npx fallback — ["npx", "<npm_package>"].
342
+
343
+ Returns a command as a list[str] (argv-ready) or None when unresolvable /
344
+ killed / unknown peer. Pure + deterministic: no process is spawned here.
345
+ """
346
+
347
+ from __future__ import annotations
348
+
349
+ import os
350
+ import shutil
351
+
352
+ from loom import manifest
353
+
354
+
355
+ def resolve(peer_name: str) -> "list[str] | None":
356
+ peer = manifest.get(peer_name)
357
+ if peer is None:
358
+ return None
359
+
360
+ if peer.env_var in os.environ:
361
+ override = os.environ[peer.env_var].strip()
362
+ if override == "":
363
+ return None # kill-switch
364
+ return [override]
365
+
366
+ on_path = shutil.which(peer.npm_package)
367
+ if on_path:
368
+ return [on_path]
369
+
370
+ return ["npx", peer.npm_package]
371
+ ```
372
+
373
+ - [ ] **Step 4: Run test to verify it passes**
374
+
375
+ Run: `cd ~/Projects/wicked-loom && PYTHONPATH=python python3 -m pytest tests/test_resolve.py -v`
376
+ Expected: PASS (5 tests)
377
+
378
+ - [ ] **Step 5: Commit**
379
+
380
+ ```bash
381
+ cd ~/Projects/wicked-loom
382
+ git add python/loom/resolve.py tests/test_resolve.py
383
+ git commit -m "feat: peer resolution ladder + kill-switch"
384
+ ```
385
+
386
+ ---
387
+
388
+ ## Task 5: Version-check + install orchestration
389
+
390
+ **Files:**
391
+ - Create: `~/Projects/wicked-loom/python/loom/compose.py`
392
+ - Test: `~/Projects/wicked-loom/tests/test_compose.py`
393
+
394
+ `check_peer` resolves the peer, runs its `probe_cmd`, parses a semver-ish version, and compares MAJOR.MINOR against the pin. `install_peer` runs the headless `install_cmd`. Both return structured dicts; neither raises (R4 — surface errors as data). A subprocess runner is injected so tests never spawn real processes (T1/T3).
395
+
396
+ - [ ] **Step 1: Write the failing test**
397
+
398
+ ```python
399
+ from unittest.mock import patch
400
+
401
+ from loom import compose
402
+
403
+
404
+ def _runner(stdout="", code=0):
405
+ def run(cmd, timeout=None):
406
+ return compose.RunResult(returncode=code, stdout=stdout, stderr="")
407
+ return run
408
+
409
+
410
+ def test_check_peer_satisfied_when_version_meets_pin():
411
+ with patch.object(compose, "resolve", return_value=["wicked-vault"]):
412
+ r = compose.check_peer("vault", run=_runner(stdout="wicked-vault 0.3.2\n"))
413
+ assert r["status"] == "ok"
414
+ assert r["installed"] == "0.3.2"
415
+ assert r["pin"] == "0.3"
416
+
417
+
418
+ def test_check_peer_below_pin_is_drift():
419
+ with patch.object(compose, "resolve", return_value=["wicked-vault"]):
420
+ r = compose.check_peer("vault", run=_runner(stdout="0.2.9"))
421
+ assert r["status"] == "drift"
422
+
423
+
424
+ def test_check_peer_unresolvable_is_missing():
425
+ with patch.object(compose, "resolve", return_value=None):
426
+ r = compose.check_peer("vault", run=_runner())
427
+ assert r["status"] == "missing"
428
+
429
+
430
+ def test_check_peer_probe_failure_is_error():
431
+ with patch.object(compose, "resolve", return_value=["wicked-vault"]):
432
+ r = compose.check_peer("vault", run=_runner(code=1))
433
+ assert r["status"] == "error"
434
+
435
+
436
+ def test_install_peer_runs_install_cmd_and_reports():
437
+ calls = []
438
+
439
+ def run(cmd, timeout=None):
440
+ calls.append(cmd)
441
+ return compose.RunResult(returncode=0, stdout="ok", stderr="")
442
+
443
+ r = compose.install_peer("vault", run=run)
444
+ assert calls == [["npx", "wicked-vault-install"]]
445
+ assert r["status"] == "installed"
446
+
447
+
448
+ def test_install_unknown_peer_is_error():
449
+ r = compose.install_peer("nope", run=_runner())
450
+ assert r["status"] == "error"
451
+
452
+
453
+ def test_check_all_returns_one_row_per_peer():
454
+ with patch.object(compose, "resolve", return_value=["x"]):
455
+ rows = compose.check_all(run=_runner(stdout="9.9.9"))
456
+ assert {row["peer"] for row in rows} == {"vault", "testing", "brain", "bus"}
457
+ ```
458
+
459
+ - [ ] **Step 2: Run test to verify it fails**
460
+
461
+ Run: `cd ~/Projects/wicked-loom && PYTHONPATH=python python3 -m pytest tests/test_compose.py -v`
462
+ Expected: FAIL — `ModuleNotFoundError: No module named 'loom.compose'`
463
+
464
+ - [ ] **Step 3: Write `compose.py`**
465
+
466
+ ```python
467
+ """compose.py — version-check + install orchestration over the peer set.
468
+
469
+ check_peer: resolve → probe → parse version → compare MAJOR.MINOR to the pin.
470
+ install_peer: run the peer's headless install command.
471
+ check_all: one check_peer row per known peer.
472
+
473
+ Subprocess execution is injected (the ``run`` parameter) so callers (and tests)
474
+ control side effects. Nothing here raises — failures are returned as status
475
+ rows ("ok" | "drift" | "missing" | "error" | "installed" | "install-failed").
476
+ """
477
+
478
+ from __future__ import annotations
479
+
480
+ import re
481
+ import subprocess
482
+ from dataclasses import dataclass
483
+ from typing import Callable
484
+
485
+ from loom import manifest
486
+ from loom.resolve import resolve
487
+
488
+ _VERSION_RE = re.compile(r"(\d+)\.(\d+)(?:\.(\d+))?")
489
+
490
+
491
+ @dataclass
492
+ class RunResult:
493
+ returncode: int
494
+ stdout: str
495
+ stderr: str
496
+
497
+
498
+ Runner = Callable[..., RunResult]
499
+
500
+
501
+ def _default_run(cmd: list[str], timeout: int = 30) -> RunResult:
502
+ p = subprocess.run(cmd, capture_output=True, text=True, timeout=timeout)
503
+ return RunResult(returncode=p.returncode, stdout=p.stdout, stderr=p.stderr)
504
+
505
+
506
+ def _parse_version(text: str) -> "str | None":
507
+ m = _VERSION_RE.search(text or "")
508
+ if not m:
509
+ return None
510
+ major, minor, patch = m.group(1), m.group(2), m.group(3) or "0"
511
+ return f"{major}.{minor}.{patch}"
512
+
513
+
514
+ def _meets_pin(installed: str, pin: str) -> bool:
515
+ iv = _parse_version(installed)
516
+ pv = _parse_version(pin) or pin
517
+ if iv is None:
518
+ return False
519
+ ip = [int(x) for x in iv.split(".")]
520
+ pp = [int(x) for x in (_parse_version(pin) or "0.0.0").split(".")]
521
+ # Compare MAJOR.MINOR floor.
522
+ return (ip[0], ip[1]) >= (pp[0], pp[1])
523
+
524
+
525
+ def check_peer(name: str, run: Runner = _default_run) -> dict:
526
+ peer = manifest.get(name)
527
+ if peer is None:
528
+ return {"peer": name, "status": "error", "detail": "unknown peer"}
529
+
530
+ cmd = resolve(name)
531
+ if cmd is None:
532
+ return {"peer": name, "status": "missing", "pin": peer.version_pin}
533
+
534
+ try:
535
+ result = run(cmd[:1] + peer.probe_cmd[1:] if cmd[0] == peer.probe_cmd[0]
536
+ else cmd + peer.probe_cmd[1:])
537
+ except Exception as e: # noqa: BLE001 — surface as data, never crash (R4)
538
+ return {"peer": name, "status": "error", "detail": str(e), "pin": peer.version_pin}
539
+
540
+ if result.returncode != 0:
541
+ return {"peer": name, "status": "error", "detail": result.stderr.strip(),
542
+ "pin": peer.version_pin}
543
+
544
+ installed = _parse_version(result.stdout)
545
+ if installed is None:
546
+ return {"peer": name, "status": "error", "detail": "unparseable version",
547
+ "pin": peer.version_pin}
548
+
549
+ status = "ok" if _meets_pin(installed, peer.version_pin) else "drift"
550
+ return {"peer": name, "status": status, "installed": installed, "pin": peer.version_pin}
551
+
552
+
553
+ def install_peer(name: str, run: Runner = _default_run) -> dict:
554
+ peer = manifest.get(name)
555
+ if peer is None:
556
+ return {"peer": name, "status": "error", "detail": "unknown peer"}
557
+ try:
558
+ result = run(peer.install_cmd, timeout=300)
559
+ except Exception as e: # noqa: BLE001
560
+ return {"peer": name, "status": "install-failed", "detail": str(e)}
561
+ if result.returncode != 0:
562
+ return {"peer": name, "status": "install-failed", "detail": result.stderr.strip()}
563
+ return {"peer": name, "status": "installed"}
564
+
565
+
566
+ def check_all(run: Runner = _default_run) -> list[dict]:
567
+ return [check_peer(name, run=run) for name in manifest.PEERS]
568
+ ```
569
+
570
+ > Note for the implementer: the `check_peer` `run(...)` argument constructs the probe command from the resolved command + the probe's trailing args. Keep it simple — if `resolve` returned `["npx", "wicked-vault"]`, the probe is `["npx", "wicked-vault", "--version"]`; if it returned `["/usr/local/bin/wicked-vault"]`, the probe is `["/usr/local/bin/wicked-vault", "--version"]`. The expression above does exactly that; if it reads awkwardly, refactor to an explicit `_probe_command(cmd, peer)` helper with its own test — but keep behavior identical.
571
+
572
+ - [ ] **Step 4: Run test to verify it passes**
573
+
574
+ Run: `cd ~/Projects/wicked-loom && PYTHONPATH=python python3 -m pytest tests/test_compose.py -v`
575
+ Expected: PASS (7 tests)
576
+
577
+ - [ ] **Step 5: Commit**
578
+
579
+ ```bash
580
+ cd ~/Projects/wicked-loom
581
+ git add python/loom/compose.py tests/test_compose.py
582
+ git commit -m "feat: compose version-check + install orchestration"
583
+ ```
584
+
585
+ ---
586
+
587
+ ## Task 6: CLI dispatch + `__main__`
588
+
589
+ **Files:**
590
+ - Create: `~/Projects/wicked-loom/python/loom/cli.py`
591
+ - Create: `~/Projects/wicked-loom/python/loom/__main__.py`
592
+ - Test: `~/Projects/wicked-loom/tests/test_cli.py`
593
+
594
+ `cli.main(argv)` dispatches `resolve <peer>`, `doctor`, `compose install [--peer X]` and prints JSON to stdout, returning an exit code. Logic stays in resolve/compose; cli only parses args + formats output (R6 — no god function).
595
+
596
+ - [ ] **Step 1: Write the failing test**
597
+
598
+ ```python
599
+ import io
600
+ import json
601
+ from contextlib import redirect_stdout
602
+ from unittest.mock import patch
603
+
604
+ from loom import cli
605
+
606
+
607
+ def _run(argv):
608
+ buf = io.StringIO()
609
+ with redirect_stdout(buf):
610
+ code = cli.main(argv)
611
+ return code, buf.getvalue()
612
+
613
+
614
+ def test_resolve_prints_command():
615
+ with patch("loom.cli.resolve", return_value=["npx", "wicked-vault"]):
616
+ code, out = _run(["resolve", "vault"])
617
+ assert code == 0
618
+ assert json.loads(out)["command"] == ["npx", "wicked-vault"]
619
+
620
+
621
+ def test_resolve_unresolvable_exits_nonzero():
622
+ with patch("loom.cli.resolve", return_value=None):
623
+ code, out = _run(["resolve", "vault"])
624
+ assert code == 1
625
+ assert json.loads(out)["command"] is None
626
+
627
+
628
+ def test_doctor_prints_all_rows():
629
+ rows = [{"peer": "vault", "status": "ok"}]
630
+ with patch("loom.cli.check_all", return_value=rows):
631
+ code, out = _run(["doctor"])
632
+ assert code == 0
633
+ assert json.loads(out)["peers"] == rows
634
+
635
+
636
+ def test_doctor_exits_nonzero_on_missing_peer():
637
+ rows = [{"peer": "vault", "status": "missing"}]
638
+ with patch("loom.cli.check_all", return_value=rows):
639
+ code, _ = _run(["doctor"])
640
+ assert code == 1
641
+
642
+
643
+ def test_compose_install_targets_one_peer():
644
+ with patch("loom.cli.install_peer", return_value={"peer": "vault", "status": "installed"}) as m:
645
+ code, out = _run(["compose", "install", "--peer", "vault"])
646
+ assert code == 0
647
+ m.assert_called_once_with("vault")
648
+ assert json.loads(out)["results"][0]["status"] == "installed"
649
+
650
+
651
+ def test_unknown_command_exits_two():
652
+ code, _ = _run(["frobnicate"])
653
+ assert code == 2
654
+ ```
655
+
656
+ - [ ] **Step 2: Run test to verify it fails**
657
+
658
+ Run: `cd ~/Projects/wicked-loom && PYTHONPATH=python python3 -m pytest tests/test_cli.py -v`
659
+ Expected: FAIL — `ModuleNotFoundError: No module named 'loom.cli'`
660
+
661
+ - [ ] **Step 3: Write `cli.py`**
662
+
663
+ ```python
664
+ """cli.py — argument dispatch + JSON output for the compose surface.
665
+
666
+ Commands:
667
+ loom resolve <peer> -> {"peer","command"} exit 0/1
668
+ loom doctor -> {"peers":[check rows]} exit 0/1
669
+ loom compose install [--peer X] -> {"results":[install rows]} exit 0/1
670
+
671
+ No business logic lives here — only parsing + formatting.
672
+ """
673
+
674
+ from __future__ import annotations
675
+
676
+ import json
677
+ import sys
678
+
679
+ from loom import manifest
680
+ from loom.compose import check_all, install_peer
681
+ from loom.resolve import resolve
682
+
683
+
684
+ def _emit(obj: dict) -> None:
685
+ sys.stdout.write(json.dumps(obj) + "\n")
686
+
687
+
688
+ def _cmd_resolve(args: list[str]) -> int:
689
+ if not args:
690
+ _emit({"error": "usage: loom resolve <peer>"})
691
+ return 2
692
+ cmd = resolve(args[0])
693
+ _emit({"peer": args[0], "command": cmd})
694
+ return 0 if cmd is not None else 1
695
+
696
+
697
+ def _cmd_doctor(_args: list[str]) -> int:
698
+ rows = check_all()
699
+ _emit({"peers": rows})
700
+ return 0 if all(r.get("status") == "ok" for r in rows) else 1
701
+
702
+
703
+ def _cmd_compose(args: list[str]) -> int:
704
+ if not args or args[0] != "install":
705
+ _emit({"error": "usage: loom compose install [--peer <name>]"})
706
+ return 2
707
+ target = None
708
+ if "--peer" in args:
709
+ i = args.index("--peer")
710
+ if i + 1 < len(args):
711
+ target = args[i + 1]
712
+ names = [target] if target else list(manifest.PEERS)
713
+ results = [install_peer(n) for n in names]
714
+ _emit({"results": results})
715
+ return 0 if all(r.get("status") == "installed" for r in results) else 1
716
+
717
+
718
+ _DISPATCH = {"resolve": _cmd_resolve, "doctor": _cmd_doctor, "compose": _cmd_compose}
719
+
720
+
721
+ def main(argv: "list[str] | None" = None) -> int:
722
+ argv = list(sys.argv[1:] if argv is None else argv)
723
+ if not argv or argv[0] in ("-h", "--help"):
724
+ _emit({"commands": list(_DISPATCH)})
725
+ return 0
726
+ handler = _DISPATCH.get(argv[0])
727
+ if handler is None:
728
+ _emit({"error": f"unknown command: {argv[0]}", "commands": list(_DISPATCH)})
729
+ return 2
730
+ return handler(argv[1:])
731
+ ```
732
+
733
+ - [ ] **Step 4: Write `__main__.py`**
734
+
735
+ ```python
736
+ """`python3 -m loom` entry point."""
737
+
738
+ import sys
739
+
740
+ from loom.cli import main
741
+
742
+ if __name__ == "__main__":
743
+ sys.exit(main())
744
+ ```
745
+
746
+ - [ ] **Step 5: Run test to verify it passes**
747
+
748
+ Run: `cd ~/Projects/wicked-loom && PYTHONPATH=python python3 -m pytest tests/test_cli.py -v`
749
+ Expected: PASS (6 tests)
750
+
751
+ - [ ] **Step 6: Smoke the full path through the Node shim**
752
+
753
+ Run: `cd ~/Projects/wicked-loom && node bin/loom.mjs doctor`
754
+ Expected: a JSON line `{"peers": [...]}` with one row per peer (statuses depend on what's installed locally; the point is the shim → python3 → cli path works end-to-end).
755
+
756
+ - [ ] **Step 7: Commit**
757
+
758
+ ```bash
759
+ cd ~/Projects/wicked-loom
760
+ git add python/loom/cli.py python/loom/__main__.py tests/test_cli.py
761
+ git commit -m "feat: compose CLI (resolve/doctor/compose install) + __main__"
762
+ ```
763
+
764
+ ---
765
+
766
+ ## Task 7: README + full suite + publish-readiness
767
+
768
+ **Files:**
769
+ - Create: `~/Projects/wicked-loom/README.md`
770
+
771
+ - [ ] **Step 1: Write `README.md`**
772
+
773
+ ```markdown
774
+ # wicked-loom
775
+
776
+ Local-first orchestration runtime for agent ecosystems. **0.1 ships the
777
+ `compose` surface** — it resolves, version-checks, and installs the `wicked-*`
778
+ peer set. Conduct (gate/flow) ships separately.
779
+
780
+ ## Use
781
+
782
+ npx wicked-loom doctor # check every peer
783
+ npx wicked-loom resolve vault # print vault's runnable command
784
+ npx wicked-loom compose install --peer bus # install one peer
785
+
786
+ Requires `python3` on PATH (the npm package launches a bundled Python core).
787
+
788
+ ## Resolution ladder
789
+
790
+ For each peer: `WICKED_<PEER>_BIN` env (empty = kill-switch) → `PATH` →
791
+ `npx <package>`.
792
+
793
+ ## Peers
794
+
795
+ vault · testing · brain · bus — pins mirror wicked-garden's `required-peers`.
796
+ ```
797
+
798
+ - [ ] **Step 2: Run the full suite**
799
+
800
+ Run: `cd ~/Projects/wicked-loom && PYTHONPATH=python python3 -m pytest -v`
801
+ Expected: PASS — 22 tests (4 manifest + 5 resolve + 7 compose + 6 cli).
802
+
803
+ - [ ] **Step 3: Dry-run the npm package contents**
804
+
805
+ Run: `cd ~/Projects/wicked-loom && npm pack --dry-run`
806
+ Expected: the tarball lists `bin/`, `python/`, `README.md`, `package.json` — and NOT `tests/` or `__pycache__/`.
807
+
808
+ - [ ] **Step 4: Commit**
809
+
810
+ ```bash
811
+ cd ~/Projects/wicked-loom
812
+ git add README.md
813
+ git commit -m "docs: README + publish-readiness"
814
+ ```
815
+
816
+ - [ ] **Step 5: STOP — publish is a human-gated outward action**
817
+
818
+ Do **not** run `npm publish` autonomously. Report to the operator that `wicked-loom@0.1.0` is publish-ready (suite green, `npm pack` clean) and let them publish + create the GitHub repo. Garden integration (the resolve cutover) is a later plan.
819
+
820
+ ---
821
+
822
+ ## Self-Review
823
+
824
+ **Spec coverage (Plan A scope = compose):**
825
+ - COMPOSE: declare (manifest, Task 3) · resolve ladder + kill-switch (Task 4) · version-check + install (Task 5) · CLI surface `resolve`/`doctor`/`compose install` (Task 6). ✓ matches spec §4.1 / §4.3.
826
+ - D5 (npm + python via subprocess): package.json bin → Node shim → python3 (Tasks 1–2, 6). ✓
827
+ - Standalone-usable by a non-garden consumer (success criterion #1): `npx wicked-loom doctor` works with zero garden present. ✓
828
+ - **Deferred (correctly out of scope for Plan A):** conduct/gate/flow/park (§4.2), bus event contract (§4.3 #2/#3), the archetype→flow seam (§3.1), garden cutover (§7 step 2). These belong to Plan B + the cutover plan. No gap — intentional decomposition.
829
+
830
+ **Placeholder scan:** No TBD/TODO; every code step has complete code; the one prose note (Task 5 probe-command construction) shows the exact expression + the refactor option with identical behavior. ✓
831
+
832
+ **Type consistency:** `Peer` fields (`name`, `npm_package`, `env_var`, `version_pin`, `install_cmd`, `probe_cmd`) are used identically in manifest/resolve/compose/cli. `resolve()` returns `list[str] | None` everywhere. `RunResult(returncode, stdout, stderr)` consistent across compose + tests. `check_peer`/`install_peer`/`check_all` signatures match their cli call sites. Status vocabulary (`ok`/`drift`/`missing`/`error`/`installed`/`install-failed`) consistent. ✓
833
+
834
+ ---
835
+
836
+ ## Execution Handoff
837
+
838
+ Plan complete. Two execution options:
839
+
840
+ 1. **Subagent-Driven (recommended)** — fresh subagent per task, review between tasks.
841
+ 2. **Inline Execution** — execute in this session with checkpoints.
842
+
843
+ Note: execution happens in a **new repo** (`~/Projects/wicked-loom`), not in wicked-garden.