@geraldmaron/construct 1.1.0 → 1.2.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 (425) hide show
  1. package/README.md +30 -18
  2. package/bin/construct +392 -91
  3. package/bin/construct-postinstall.mjs +30 -2
  4. package/examples/distribution/README.md +42 -0
  5. package/examples/distribution/manifest.json +53 -0
  6. package/examples/distribution/sources/adr.md +84 -0
  7. package/examples/distribution/sources/deck-one-pager.md +65 -0
  8. package/examples/distribution/sources/prd-platform.md +161 -0
  9. package/examples/distribution/sources/research-brief.md +80 -0
  10. package/examples/distribution/sources/rfc-platform.md +82 -0
  11. package/examples/distribution/sources/runbook.md +103 -0
  12. package/examples/distribution/sources/strategy.md +88 -0
  13. package/lib/adapters-sync.mjs +67 -0
  14. package/lib/artifact-gate-notice.mjs +38 -0
  15. package/lib/artifact-manifest.mjs +112 -0
  16. package/lib/artifact-release-gate.mjs +171 -0
  17. package/lib/artifact-reviewers.mjs +68 -0
  18. package/lib/artifact-type-from-path.mjs +79 -0
  19. package/lib/audit-skills.mjs +4 -0
  20. package/lib/audit-specialists.mjs +285 -0
  21. package/lib/audit-trail.mjs +77 -10
  22. package/lib/auto-docs.mjs +87 -18
  23. package/lib/beads/drift.mjs +27 -6
  24. package/lib/beads-client.mjs +49 -121
  25. package/lib/beads-optimistic.mjs +5 -12
  26. package/lib/brand-fonts.mjs +93 -0
  27. package/lib/brand-prose.mjs +214 -0
  28. package/lib/brand-tokens.mjs +92 -0
  29. package/lib/bridges/copilot-proxy.mjs +13 -26
  30. package/lib/capability-ledger.mjs +156 -0
  31. package/lib/certification/artifact-fixtures.mjs +132 -0
  32. package/lib/certification/artifact-gates.mjs +63 -0
  33. package/lib/certification/artifact-provenance.mjs +97 -0
  34. package/lib/certification/canonical-scenarios.mjs +78 -0
  35. package/lib/certification/cli.mjs +191 -0
  36. package/lib/certification/dashboard-api.mjs +71 -0
  37. package/lib/certification/demo-parity.mjs +116 -0
  38. package/lib/certification/document-io-fixtures.mjs +246 -0
  39. package/lib/certification/document-workflow.mjs +97 -0
  40. package/lib/certification/eval-bridge.mjs +77 -0
  41. package/lib/certification/model-routing.mjs +149 -0
  42. package/lib/certification/prompt-budget.mjs +119 -0
  43. package/lib/certification/rc-gate.mjs +206 -0
  44. package/lib/certification/real-llm-scenarios.mjs +303 -0
  45. package/lib/certification/role-cards.mjs +113 -0
  46. package/lib/certification/role-overlays.mjs +117 -0
  47. package/lib/certification/run.mjs +122 -0
  48. package/lib/certification/runner.mjs +323 -0
  49. package/lib/certification/scenarios.mjs +51 -0
  50. package/lib/certification/skill-inventory.mjs +289 -0
  51. package/lib/certification/skill-scenarios.mjs +147 -0
  52. package/lib/certification/specialist-contracts.mjs +85 -0
  53. package/lib/certification/specialist-scenarios.mjs +175 -0
  54. package/lib/certification/stale-impact.mjs +146 -0
  55. package/lib/certification/status.mjs +252 -0
  56. package/lib/certification/store.mjs +77 -0
  57. package/lib/chat/cli.mjs +333 -0
  58. package/lib/chat/command-suggest.mjs +161 -0
  59. package/lib/chat/commands.mjs +215 -0
  60. package/lib/chat/config.mjs +142 -0
  61. package/lib/chat/context-compactor.mjs +250 -0
  62. package/lib/chat/context-continuation.mjs +253 -0
  63. package/lib/chat/continuation-source.mjs +58 -0
  64. package/lib/chat/demo-guide.mjs +61 -0
  65. package/lib/chat/design-tokens.mjs +91 -0
  66. package/lib/chat/desktop-binary.mjs +79 -0
  67. package/lib/chat/desktop-build.mjs +130 -0
  68. package/lib/chat/desktop-launcher.mjs +133 -0
  69. package/lib/chat/evidence.mjs +145 -0
  70. package/lib/chat/export.mjs +74 -0
  71. package/lib/chat/harness/driver.mjs +91 -0
  72. package/lib/chat/list-picker.mjs +112 -0
  73. package/lib/chat/model-picker.mjs +356 -0
  74. package/lib/chat/openrouter-fallback.mjs +151 -0
  75. package/lib/chat/permission-prompt.mjs +33 -0
  76. package/lib/chat/picker-catalog.mjs +45 -0
  77. package/lib/chat/policy-telemetry.mjs +34 -0
  78. package/lib/chat/present.mjs +245 -0
  79. package/lib/chat/session-context.mjs +39 -0
  80. package/lib/chat/session-persist.mjs +73 -0
  81. package/lib/chat/session-restore.mjs +71 -0
  82. package/lib/chat/session-settings.mjs +53 -0
  83. package/lib/chat/system-prompt.mjs +52 -0
  84. package/lib/chat/transparency.mjs +93 -0
  85. package/lib/chat/tui/color-scheme.mjs +42 -0
  86. package/lib/chat/tui/markdown.mjs +123 -0
  87. package/lib/chat/tui/presentation.mjs +100 -0
  88. package/lib/chat/tui/render.mjs +500 -0
  89. package/lib/chat/tui/turn-block.mjs +284 -0
  90. package/lib/chat/tui/turn-present.mjs +18 -0
  91. package/lib/chat/tui/turn-state.mjs +88 -0
  92. package/lib/chat/tui/usage.mjs +122 -0
  93. package/lib/chat/web-commands.mjs +146 -0
  94. package/lib/chat/web-launcher.mjs +63 -0
  95. package/lib/chat/web-picker-keys.mjs +46 -0
  96. package/lib/chat/web-session.mjs +159 -0
  97. package/lib/cli-commands.mjs +232 -11
  98. package/lib/comment-lint.mjs +6 -4
  99. package/lib/config/schema.mjs +36 -5
  100. package/lib/contract-schemas/decision.json +50 -0
  101. package/lib/contract-schemas/implementation.json +51 -0
  102. package/lib/contract-schemas/review-report.json +32 -0
  103. package/lib/contract-schemas/test-report.json +43 -0
  104. package/lib/contracts/construct-handoff.mjs +60 -0
  105. package/lib/contracts/validate.mjs +32 -3
  106. package/lib/contracts/violation-log.mjs +58 -5
  107. package/lib/dashboard-demo.mjs +71 -0
  108. package/lib/dashboard-static.mjs +19 -5
  109. package/lib/decisions/registry.mjs +5 -3
  110. package/lib/deck-export-pptx.mjs +1152 -0
  111. package/lib/demo-recording.mjs +142 -0
  112. package/lib/demo-script.mjs +114 -0
  113. package/lib/demo-surface.mjs +249 -0
  114. package/lib/demo.mjs +703 -0
  115. package/lib/diagram-export.mjs +192 -0
  116. package/lib/diagram.mjs +302 -0
  117. package/lib/docs-verify.mjs +25 -7
  118. package/lib/doctor/index.mjs +4 -2
  119. package/lib/doctor/project-adapters.mjs +44 -0
  120. package/lib/doctor/watchers/cx-budget.mjs +98 -0
  121. package/lib/doctor/watchers/graph-staleness.mjs +52 -0
  122. package/lib/doctor/watchers/process-pressure.mjs +4 -3
  123. package/lib/doctor/watchers/service-health.mjs +1 -1
  124. package/lib/document-export.mjs +360 -36
  125. package/lib/document-extract.mjs +88 -0
  126. package/lib/document-ingest.mjs +32 -18
  127. package/lib/embed/cli.mjs +2 -2
  128. package/lib/embed/daemon.mjs +18 -46
  129. package/lib/embed/semantic.mjs +5 -2
  130. package/lib/embed/worker.mjs +2 -2
  131. package/lib/embedded-contract/model-resolve.mjs +10 -9
  132. package/lib/env-config.mjs +26 -0
  133. package/lib/evals/dataset.mjs +137 -0
  134. package/lib/evals/gates.mjs +175 -0
  135. package/lib/graph/build-co-change.mjs +54 -0
  136. package/lib/graph/build-from-registry.mjs +136 -0
  137. package/lib/graph/build-import-graph.mjs +153 -0
  138. package/lib/graph/cli.mjs +110 -0
  139. package/lib/graph/impact-cli.mjs +89 -0
  140. package/lib/graph/impact.mjs +108 -0
  141. package/lib/graph/staleness.mjs +44 -0
  142. package/lib/graph/store.mjs +172 -0
  143. package/lib/handoffs/cleanup.mjs +1 -1
  144. package/lib/health-check.mjs +90 -76
  145. package/lib/hooks/artifact-release-gate.mjs +43 -0
  146. package/lib/hooks/audit-trail.mjs +14 -28
  147. package/lib/hooks/brand-prose-lint.mjs +38 -0
  148. package/lib/hooks/graph-impact-advisory.mjs +62 -0
  149. package/lib/hooks/session-optimize.mjs +84 -207
  150. package/lib/hooks/session-start.mjs +4 -5
  151. package/lib/host-disposition.mjs +7 -0
  152. package/lib/improvement/cli.mjs +189 -0
  153. package/lib/improvement/controller.mjs +137 -0
  154. package/lib/improvement/proposal.mjs +120 -0
  155. package/lib/improvement/specialist-loop.mjs +192 -0
  156. package/lib/improvement/store.mjs +89 -0
  157. package/lib/improvement/surface.mjs +219 -0
  158. package/lib/ingest-tooling.mjs +97 -0
  159. package/lib/init/doc-lanes.mjs +165 -0
  160. package/lib/init-docs.mjs +31 -178
  161. package/lib/init-unified.mjs +27 -97
  162. package/lib/init-update-guide.mjs +102 -0
  163. package/lib/init-update.mjs +32 -1
  164. package/lib/init.mjs +8 -0
  165. package/lib/install/desktop-binary-download.mjs +85 -0
  166. package/lib/install/legacy-global-cleanup.mjs +189 -0
  167. package/lib/intake/daemon.mjs +2 -0
  168. package/lib/intake/git-queue.mjs +9 -8
  169. package/lib/intake/queue.mjs +2 -1
  170. package/lib/intake/session-prelude.mjs +90 -1
  171. package/lib/libreoffice-export.mjs +97 -0
  172. package/lib/logging/rotate.mjs +9 -0
  173. package/lib/maintenance/docker-reclaim.mjs +206 -0
  174. package/lib/mcp/external-schema-cost.mjs +74 -0
  175. package/lib/mcp/server.mjs +84 -9
  176. package/lib/mcp/stdio-mcp-probe.mjs +188 -0
  177. package/lib/mcp/tool-budget.mjs +55 -4
  178. package/lib/mcp/tools/document.mjs +18 -4
  179. package/lib/mcp/tools/skills.mjs +32 -3
  180. package/lib/mcp/tools/workflow.mjs +13 -1
  181. package/lib/model-free-selector.mjs +18 -0
  182. package/lib/model-registry.mjs +13 -229
  183. package/lib/model-router.mjs +425 -93
  184. package/lib/models/behavior-matrix.mjs +289 -0
  185. package/lib/models/catalog.mjs +209 -0
  186. package/lib/models/execution-capability-profile.mjs +196 -0
  187. package/lib/models/execution-policy.mjs +307 -0
  188. package/lib/models/provider-poll.mjs +383 -0
  189. package/lib/npm-spawn-env.mjs +17 -0
  190. package/lib/ollama/installed-models.mjs +129 -0
  191. package/lib/oracle/actions.mjs +187 -0
  192. package/lib/oracle/artifact-gate.mjs +99 -0
  193. package/lib/oracle/cli.mjs +204 -0
  194. package/lib/oracle/daemon-entry.mjs +14 -0
  195. package/lib/oracle/dispatch.mjs +81 -0
  196. package/lib/oracle/execute.mjs +143 -0
  197. package/lib/oracle/gaps.mjs +76 -0
  198. package/lib/oracle/index.mjs +84 -0
  199. package/lib/oracle/issues.mjs +164 -0
  200. package/lib/oracle/org-graph.mjs +170 -0
  201. package/lib/oracle/policy.mjs +80 -0
  202. package/lib/oracle/read-model.mjs +398 -0
  203. package/lib/oracle/reconcile.mjs +191 -0
  204. package/lib/oracle/routing.mjs +89 -0
  205. package/lib/oracle/synthesize.mjs +384 -0
  206. package/lib/oracle/verdicts.mjs +51 -0
  207. package/lib/orchestration/worker.mjs +88 -27
  208. package/lib/orchestration-policy.mjs +50 -0
  209. package/lib/parity.mjs +96 -2
  210. package/lib/persona-sections.mjs +66 -0
  211. package/lib/playwright-demo.mjs +252 -0
  212. package/lib/project-init-shared.mjs +4 -1
  213. package/lib/prompt-composer.js +9 -4
  214. package/lib/prompt-validation-contract.mjs +24 -0
  215. package/lib/provider-capabilities.js +57 -11
  216. package/lib/providers/contract/adapters/confluence/index.mjs +181 -0
  217. package/lib/providers/contract/adapters/git/index.mjs +115 -0
  218. package/lib/providers/contract/adapters/github/index.mjs +166 -0
  219. package/lib/providers/contract/adapters/jira/index.mjs +187 -0
  220. package/lib/providers/contract/adapters/slack/index.mjs +175 -0
  221. package/lib/providers/contract/contract-tests.mjs +57 -0
  222. package/lib/providers/contract/errors.mjs +48 -0
  223. package/lib/providers/contract/interface.mjs +50 -0
  224. package/lib/providers/contract/registry.mjs +102 -0
  225. package/lib/providers/copilot-auth.mjs +297 -0
  226. package/lib/providers/credential-bootstrap.mjs +178 -0
  227. package/lib/providers/credential-catalog.mjs +46 -0
  228. package/lib/providers/credential-sources.mjs +63 -0
  229. package/lib/providers/creds.mjs +5 -2
  230. package/lib/providers/op-run.mjs +59 -0
  231. package/lib/providers/secret-resolver.mjs +159 -0
  232. package/lib/publish-template.mjs +163 -0
  233. package/lib/publish-tooling.mjs +119 -0
  234. package/lib/publish.mjs +305 -0
  235. package/lib/registry/cli.mjs +82 -0
  236. package/lib/registry/consolidation.mjs +147 -0
  237. package/lib/registry/generate-docs.mjs +75 -0
  238. package/lib/registry/skill-verification.mjs +57 -0
  239. package/lib/registry/surface-map.mjs +76 -0
  240. package/lib/registry/validate.mjs +135 -0
  241. package/lib/resources/budget.mjs +82 -0
  242. package/lib/resources/process-budget.mjs +45 -0
  243. package/lib/rules-delivery.mjs +9 -2
  244. package/lib/rules-read.mjs +26 -0
  245. package/lib/runtime-env.mjs +23 -0
  246. package/lib/runtime-pressure.mjs +51 -7
  247. package/lib/schema-infer.mjs +13 -2
  248. package/lib/server/chat-loop.mjs +622 -0
  249. package/lib/server/demo-preview.mjs +63 -0
  250. package/lib/server/index.mjs +229 -8
  251. package/lib/server/langfuse-login.mjs +3 -3
  252. package/lib/service-manager.mjs +61 -9
  253. package/lib/session-store.mjs +1 -1
  254. package/lib/setup.mjs +102 -2
  255. package/lib/specialists/prompt-schema.mjs +19 -10
  256. package/lib/specialists/roster.mjs +43 -0
  257. package/lib/specialists/scaffold.mjs +56 -0
  258. package/lib/storage/backend.mjs +6 -6
  259. package/lib/storage/embeddings-local.mjs +6 -3
  260. package/lib/storage/file-lock.mjs +18 -11
  261. package/lib/storage/hybrid-query.mjs +7 -4
  262. package/lib/storage/state-source.mjs +5 -5
  263. package/lib/storage/sync.mjs +2 -3
  264. package/lib/telemetry/rule-calls.mjs +52 -0
  265. package/lib/template-registry.mjs +2 -2
  266. package/lib/templates/visual-requirements.mjs +27 -51
  267. package/lib/test-corpus-inventory.mjs +313 -0
  268. package/lib/uninstall/uninstall.mjs +19 -7
  269. package/lib/update.mjs +12 -0
  270. package/lib/upgrade.mjs +14 -0
  271. package/lib/wireframe.mjs +20 -14
  272. package/lib/worker/run.mjs +17 -4
  273. package/lib/worker/trace.mjs +11 -3
  274. package/package.json +29 -13
  275. package/personas/construct.md +13 -13
  276. package/platforms/claude/settings.template.json +36 -0
  277. package/rules/common/patterns.md +1 -1
  278. package/rules/common/release-gates.md +4 -3
  279. package/scripts/sync-specialists.mjs +187 -60
  280. package/skills/devops/data-engineering.md +1 -1
  281. package/skills/docs/adr-workflow.md +1 -0
  282. package/skills/docs/backlog-proposal-workflow.md +1 -0
  283. package/skills/docs/codebase-research-workflow.md +40 -0
  284. package/skills/docs/customer-profile-workflow.md +1 -0
  285. package/skills/docs/document-ingest-workflow.md +1 -0
  286. package/skills/docs/evidence-ingest-workflow.md +1 -0
  287. package/skills/docs/init-docs.md +2 -2
  288. package/skills/docs/init-project.md +8 -3
  289. package/skills/docs/prd-workflow.md +24 -1
  290. package/skills/docs/prfaq-workflow.md +1 -0
  291. package/skills/docs/product-intelligence-workflow.md +1 -0
  292. package/skills/docs/product-signal-workflow.md +1 -0
  293. package/skills/docs/research-workflow.md +54 -37
  294. package/skills/docs/runbook-workflow.md +1 -0
  295. package/skills/docs/strategy-workflow.md +1 -0
  296. package/skills/docs/user-research-workflow.md +40 -0
  297. package/skills/operating/orchestration-reference.md +1 -1
  298. package/skills/roles/architect.md +5 -0
  299. package/skills/roles/operator.docs.md +4 -0
  300. package/skills/routing.md +4 -2
  301. package/specialists/artifact-manifest.json +480 -0
  302. package/specialists/artifact-manifest.schema.json +53 -0
  303. package/specialists/audit-enrichments.json +454 -0
  304. package/specialists/contracts.json +37 -25
  305. package/specialists/prompts/_shared/validation-contract.md +26 -0
  306. package/specialists/prompts/cx-accessibility.md +21 -2
  307. package/specialists/prompts/cx-ai-engineer.md +24 -1
  308. package/specialists/prompts/cx-architect.md +4 -1
  309. package/specialists/prompts/cx-business-strategist.md +23 -2
  310. package/specialists/prompts/cx-data-analyst.md +22 -1
  311. package/specialists/prompts/cx-data-engineer.md +23 -2
  312. package/specialists/prompts/cx-debugger.md +21 -2
  313. package/specialists/prompts/cx-designer.md +26 -3
  314. package/specialists/prompts/cx-devil-advocate.md +19 -2
  315. package/specialists/prompts/cx-docs-keeper.md +28 -1
  316. package/specialists/prompts/cx-engineer.md +22 -1
  317. package/specialists/prompts/cx-evaluator.md +18 -1
  318. package/specialists/prompts/cx-explorer.md +21 -2
  319. package/specialists/prompts/cx-legal-compliance.md +21 -2
  320. package/specialists/prompts/cx-operations.md +21 -2
  321. package/specialists/prompts/cx-oracle.md +94 -0
  322. package/specialists/prompts/cx-orchestrator.md +20 -1
  323. package/specialists/prompts/cx-platform-engineer.md +25 -2
  324. package/specialists/prompts/cx-product-manager.md +32 -1
  325. package/specialists/prompts/cx-qa.md +24 -2
  326. package/specialists/prompts/cx-rd-lead.md +23 -2
  327. package/specialists/prompts/cx-release-manager.md +23 -2
  328. package/specialists/prompts/cx-researcher.md +22 -2
  329. package/specialists/prompts/cx-reviewer.md +18 -1
  330. package/specialists/prompts/cx-security.md +22 -2
  331. package/specialists/prompts/cx-sre.md +30 -3
  332. package/specialists/prompts/cx-test-automation.md +7 -1
  333. package/specialists/prompts/cx-trace-reviewer.md +22 -3
  334. package/specialists/prompts/cx-ux-researcher.md +21 -2
  335. package/specialists/registry.json +52 -173
  336. package/specialists/tone-profiles.json +42 -0
  337. package/templates/demos/playwright/demo-recording.config.mjs +47 -0
  338. package/templates/demos/recordings/agentic-platforms-prd.json +19 -0
  339. package/templates/demos/scripts/agentic-platforms-prd.json +44 -0
  340. package/templates/demos/specs/_helpers/scroll-artifact.ts +89 -0
  341. package/templates/demos/tapes/agentic-platforms-prd.tape +49 -0
  342. package/templates/demos/tapes/resource-guard-rails.tape +49 -0
  343. package/templates/demos/vhs/construct-cockpit.json +24 -0
  344. package/templates/distribution/construct-brand.typ +446 -0
  345. package/templates/distribution/construct-decision.typ +38 -0
  346. package/templates/distribution/construct-deck.html +95 -0
  347. package/templates/distribution/construct-pdf.typ +38 -0
  348. package/templates/distribution/construct-prd.typ +38 -0
  349. package/templates/distribution/construct-research.typ +38 -0
  350. package/templates/distribution/construct-web.html +92 -0
  351. package/templates/distribution/fonts/Geist-Bold.ttf +0 -0
  352. package/templates/distribution/fonts/Geist-Medium.ttf +0 -0
  353. package/templates/distribution/fonts/Geist-Regular.ttf +0 -0
  354. package/templates/distribution/fonts/Geist-SemiBold.ttf +0 -0
  355. package/templates/distribution/fonts/GeistMono-Medium.ttf +0 -0
  356. package/templates/distribution/fonts/GeistMono-Regular.ttf +0 -0
  357. package/templates/distribution/fonts/GeistMono-SemiBold.ttf +0 -0
  358. package/templates/distribution/fonts/IBMPlexMono-Regular.otf +0 -0
  359. package/templates/distribution/fonts/JetBrainsMono-Medium.ttf +0 -0
  360. package/templates/distribution/fonts/JetBrainsMono-Regular.ttf +0 -0
  361. package/templates/distribution/fonts/JetBrainsMono-SemiBold.ttf +0 -0
  362. package/templates/distribution/fonts/PlusJakartaSans-Bold.ttf +0 -0
  363. package/templates/distribution/fonts/PlusJakartaSans-Medium.ttf +0 -0
  364. package/templates/distribution/fonts/PlusJakartaSans-Regular.ttf +0 -0
  365. package/templates/distribution/fonts/PlusJakartaSans-SemiBold.ttf +0 -0
  366. package/templates/distribution/fonts/README.md +36 -0
  367. package/templates/distribution/fonts/SpaceGrotesk-Variable.ttf +0 -0
  368. package/templates/distribution/fonts/handwritten/Caveat.ttf +0 -0
  369. package/templates/distribution/fonts/legacy/IBMPlexMono-Regular.otf +0 -0
  370. package/templates/distribution/fonts/legacy/Inter-Medium.otf +0 -0
  371. package/templates/distribution/fonts/legacy/Inter-Regular.otf +0 -0
  372. package/templates/distribution/fonts/legacy/Inter-SemiBold.otf +0 -0
  373. package/templates/distribution/fonts/legacy/InterDisplay-SemiBold.otf +0 -0
  374. package/templates/distribution/fonts/legacy/SourceSerif4-Regular.otf +0 -0
  375. package/templates/distribution/fonts/legacy/SourceSerif4-Semibold.otf +0 -0
  376. package/templates/distribution/icons/activity.svg +15 -0
  377. package/templates/distribution/icons/alert-triangle.svg +17 -0
  378. package/templates/distribution/icons/book-open.svg +16 -0
  379. package/templates/distribution/icons/bot.svg +20 -0
  380. package/templates/distribution/icons/brain.svg +22 -0
  381. package/templates/distribution/icons/circle-check.svg +16 -0
  382. package/templates/distribution/icons/clipboard-check.svg +17 -0
  383. package/templates/distribution/icons/cpu.svg +28 -0
  384. package/templates/distribution/icons/database.svg +17 -0
  385. package/templates/distribution/icons/eye.svg +16 -0
  386. package/templates/distribution/icons/file-text.svg +19 -0
  387. package/templates/distribution/icons/gauge.svg +16 -0
  388. package/templates/distribution/icons/git-branch.svg +17 -0
  389. package/templates/distribution/icons/key.svg +17 -0
  390. package/templates/distribution/icons/layers.svg +17 -0
  391. package/templates/distribution/icons/list-checks.svg +19 -0
  392. package/templates/distribution/icons/lock.svg +16 -0
  393. package/templates/distribution/icons/message-square.svg +15 -0
  394. package/templates/distribution/icons/network.svg +19 -0
  395. package/templates/distribution/icons/route.svg +17 -0
  396. package/templates/distribution/icons/scale.svg +19 -0
  397. package/templates/distribution/icons/search.svg +16 -0
  398. package/templates/distribution/icons/send.svg +16 -0
  399. package/templates/distribution/icons/server.svg +18 -0
  400. package/templates/distribution/icons/shield-check.svg +16 -0
  401. package/templates/distribution/icons/users.svg +18 -0
  402. package/templates/distribution/icons/webhook.svg +17 -0
  403. package/templates/distribution/icons/workflow.svg +17 -0
  404. package/templates/distribution/icons/wrench.svg +15 -0
  405. package/templates/distribution/run.mjs +18 -1
  406. package/templates/docs/adr.md +7 -0
  407. package/templates/docs/construct_guide.md +10 -10
  408. package/templates/docs/customer-profile.md +4 -0
  409. package/templates/docs/one-pager.md +4 -0
  410. package/templates/docs/postmortem.md +31 -0
  411. package/templates/docs/prd-platform.md +19 -0
  412. package/templates/docs/prd.md +15 -0
  413. package/templates/docs/prfaq.md +7 -0
  414. package/templates/docs/qa-strategy.md +103 -0
  415. package/templates/docs/research-brief.md +8 -0
  416. package/templates/docs/rfc-platform.md +12 -0
  417. package/templates/docs/test-plan.md +7 -0
  418. package/lib/ingest/chunker.mjs +0 -94
  419. package/lib/ingest/pipeline.mjs +0 -53
  420. package/lib/ingest/store.mjs +0 -82
  421. package/lib/mode-commands.mjs +0 -122
  422. package/lib/policy/unified-gates.mjs +0 -96
  423. package/lib/profiles/validate-custom.mjs +0 -114
  424. package/lib/services/telemetry-backend.mjs +0 -177
  425. package/lib/storage/fusion.mjs +0 -95
@@ -13,8 +13,8 @@
13
13
  * global so hooks fire in every Claude Code session.
14
14
  *
15
15
  * Project scope (`<project>/.claude/`, `<project>/.codex/`, `<project>/.github/`, …)
16
- * - `construct` + all 28 `cx-*` specialists, slash commands, skills, MCP
17
- * wiring. Files version with the repo and travel with teammates via git.
16
+ * - `construct` front door only (Single Front Door), slash commands, skills, MCP
17
+ * wiring. Specialists dispatch internally via orchestration MCP tools.
18
18
  *
19
19
  * Flags:
20
20
  * --dry-run Print a diff of what would change without writing anything.
@@ -44,9 +44,11 @@ import {
44
44
  writeCodexConfig,
45
45
  } from "../lib/codex-config.mjs";
46
46
  import { findOpenCodeConfigPath, readOpenCodeConfig, writeOpenCodeConfig } from "../lib/opencode-config.mjs";
47
- import { HEAVY_EXTERNAL_MCP_IDS, LOCAL_SURFACE_MODES, decideTrim } from "../lib/mcp/tool-budget.mjs";
47
+ import { HEAVY_EXTERNAL_MCP_IDS, LOCAL_SURFACE_MODES, decideTrim, isLocalModel } from "../lib/mcp/tool-budget.mjs";
48
48
  import { emitCursorRules } from "../lib/rules-delivery.mjs";
49
- import { resolvePromptContract } from "../lib/prompt-composer.js";
49
+ import { resolvePromptContract, readPromptBody } from "../lib/prompt-composer.js";
50
+ import { renderPersonaForTier } from "../lib/persona-sections.mjs";
51
+ import { getModelVerdict } from "../lib/ollama/capability-store.mjs";
50
52
  import {
51
53
  buildClaudeMcpEntry,
52
54
  buildOpenCodeMcpEntry,
@@ -54,9 +56,10 @@ import {
54
56
  } from "../lib/mcp-platform-config.mjs";
55
57
  import { loadConstructEnv } from "../lib/env-config.mjs";
56
58
  import { inlineRoleAntiPatterns, PROMPT_WORD_CAP } from "../lib/role-preload.mjs";
59
+ import { inlineValidationContract } from "../lib/prompt-validation-contract.mjs";
57
60
  import { loadManifest } from "../lib/roles/manifest.mjs";
58
61
  import { resolveActiveProfile } from "../lib/profiles/loader.mjs";
59
- import { resolveTiersForPrimary } from "../lib/model-router.mjs";
62
+ import { resolveTiersForPrimary, resolveCapabilityTier, selectLocalEditorModel } from "../lib/model-router.mjs";
60
63
  import { stampFrontmatter } from "../lib/doc-stamp.mjs";
61
64
  import { buildSkillFrontmatter, stripLeadingFrontmatter } from "../lib/sync/skill-frontmatter.mjs";
62
65
 
@@ -152,6 +155,16 @@ if (validationErrors.length > 0) {
152
155
  }
153
156
  }
154
157
 
158
+ {
159
+ const { validatePromptFiles } = await import("../lib/specialists/prompt-schema.mjs");
160
+ const promptResult = validatePromptFiles({ rootDir: root, registry });
161
+ if (promptResult.errors.length > 0) {
162
+ console.error("Specialist prompt validation failed:");
163
+ for (const err of promptResult.errors) console.error(` - ${err}`);
164
+ process.exit(1);
165
+ }
166
+ }
167
+
155
168
  // --- Dry-run + lockfile + two-phase write infrastructure ---
156
169
 
157
170
  const DRY_RUN = process.argv.includes("--dry-run");
@@ -516,10 +529,6 @@ function loadPersonaPrompt(persona) {
516
529
  return prompt;
517
530
  }
518
531
 
519
- export function buildAgentRoster(allEntries) {
520
- return allEntries.map((e) => `- ${adapterName(e)}: ${e.when_to_use || e.description}`).join("\n");
521
- }
522
-
523
532
  function buildModelGuidanceBlock(entry) {
524
533
  const merged = { ...globalModelGuidance, ...(entry.modelGuidance ?? {}) };
525
534
  const families = Object.keys(merged);
@@ -602,7 +611,83 @@ export function renderRoleFrameworkSection(entry) {
602
611
  return `\n\n${lines.join("\n")}`;
603
612
  }
604
613
 
605
- function buildPrompt(entry, allEntries, platform) {
614
+ // The native-subagent orchestration micro-prompt. A worked tool-call example lifts
615
+ // small local models' tool-use reliability sharply (bead construct-c16l). Shared by the
616
+ // full path and the capability-tiered local path so both stay in sync.
617
+
618
+ const ORCHESTRATION_MICRO_PROMPT =
619
+ `You are the primary orchestrator. To discover available specialist agents, you MUST call the \`orchestration_policy\` MCP tool. Do not guess agent names.\n\n` +
620
+ `Example — the user says "add rate limiting to the API". Your first action is a tool call, not prose:\n` +
621
+ ` call orchestration_policy { "task": "add rate limiting to the API" }\n` +
622
+ `Then dispatch the specialists it returns. Always call the tool before answering.`;
623
+
624
+ // Directive for the local editor agent (construct-local). It executes bounded work on
625
+ // the cheap local model and hands planning/reasoning back to the construct architect —
626
+ // the aider architect/editor split. Kept short: a small model must actually obey it.
627
+
628
+ const LOCAL_EDITOR_DIRECTIVE =
629
+ `You are a focused execution agent running on a local model, dispatched by construct to do one bounded job. Do well-scoped edits for the current task and verify them; make the smallest correct change, never a broad rewrite.\n` +
630
+ `You do NOT plan, classify, orchestrate, or spawn other agents. For anything needing multi-file design, architecture or security judgment, dependency or contract changes, or research, STOP and return control to construct — report what needs deeper work and why, rather than attempting it yourself.`;
631
+
632
+ // Warn-and-emit capability advisory. Sizing already consumes the probe verdict
633
+ // (COLLAPSED → floor tier via resolveCapabilityTier); this only nudges the user toward a
634
+ // measured verdict and never suppresses emission. Notice-only, so it auto-suppresses in
635
+ // CI / test / non-TTY per the repo's wrong-context rule — no skip env var.
636
+
637
+ const localAdvisorySeen = new Set();
638
+ function adviseLocalModelCapability(model) {
639
+ if (!model || !isLocalModel(model)) return;
640
+ if (process.env.CI === "true" || process.env.NODE_ENV === "test" || !process.stderr.isTTY) return;
641
+ if (localAdvisorySeen.has(model)) return;
642
+ localAdvisorySeen.add(model);
643
+ const verdict = getModelVerdict(model)?.verdict ?? null;
644
+ if (verdict === "COLLAPSED") {
645
+ console.warn(`[sync] ${model} probed COLLAPSED — emitting at the floor tier with escalation to construct. Re-probe after a Modelfile change: construct doctor --probe-local`);
646
+ } else if (!verdict) {
647
+ console.warn(`[sync] ${model} is local with no coherence verdict — tier inferred from parameter count. For a measured tier: construct doctor --probe-local`);
648
+ }
649
+ }
650
+
651
+ function enforcePromptWordCap(prompt, entry) {
652
+ const wordCount = prompt.split(/\s+/).filter(Boolean).length;
653
+ const effectiveCap = Number(entry.wordCapOverride) > 0 ? entry.wordCapOverride : PROMPT_WORD_CAP;
654
+ if (wordCount > effectiveCap) {
655
+ const msg = `[sync] ${entry.name}: prompt is ${wordCount} words (cap ${effectiveCap})`;
656
+ if (process.env.CONSTRUCT_SYNC_FORCE === '1' || process.argv.includes('--force')) {
657
+ console.warn(`${msg} — proceeding due to --force / CONSTRUCT_SYNC_FORCE=1.`);
658
+ } else {
659
+ console.error(`${msg}`);
660
+ console.error(
661
+ `[sync] Hard cap exceeded. Options:\n` +
662
+ ` - trim the prompt body or move detail to a skill (preferred)\n` +
663
+ ` - set "wordCapOverride": <N> on this entry in specialists/registry.json with a written reason\n` +
664
+ ` - re-run with --force or CONSTRUCT_SYNC_FORCE=1 as a temporary escape hatch\n` +
665
+ `Prompt budget is a hard contract because every over-cap agent degrades every session that dispatches it.`,
666
+ );
667
+ process.exit(1);
668
+ }
669
+ }
670
+ return prompt;
671
+ }
672
+
673
+ function buildPrompt(entry, allEntries, platform, { capabilityTier = 'full' } = {}) {
674
+ const capabilities = { hasNativeSubagents: HOST_KEYS.includes(platform) ? hostHasNativeSubagents(platform) : false };
675
+
676
+ // Capability-tiered local path. A small local model follows a long multi-instruction
677
+ // persona poorly (instruction-following degrades before the window fills), so emit
678
+ // only the persona sections at/below its tier plus the orchestration micro-prompt, and
679
+ // skip the role footer, role-framework, operating-guidance, and model-family blocks —
680
+ // those add instruction load the model cannot track. Cloud models resolve to 'full'
681
+ // and take the unchanged path below, so cloud configs are never slimmed.
682
+
683
+ if (capabilityTier && capabilityTier !== 'full' && entry.promptFile) {
684
+ let slim = renderPersonaForTier(readPromptBody(entry.promptFile, root), capabilityTier);
685
+ if (entry.injectAgentRoster) {
686
+ slim = `${ORCHESTRATION_MICRO_PROMPT}\n\n${slim}`;
687
+ }
688
+ return enforcePromptWordCap(slim, entry);
689
+ }
690
+
606
691
  let prompt = resolvePromptContract(entry, {
607
692
  rootDir: root,
608
693
  registry,
@@ -610,29 +695,18 @@ function buildPrompt(entry, allEntries, platform) {
610
695
  }).prompt;
611
696
 
612
697
  prompt = inlineRoleAntiPatterns(prompt, root, entry.name, console.warn, { preload: entry.preloadRoleGuidance === true });
698
+ prompt = inlineValidationContract(prompt, root, entry.name);
613
699
 
614
- const capabilities = { hasNativeSubagents: HOST_KEYS.includes(platform) ? hostHasNativeSubagents(platform) : false };
615
-
616
- // Platform-Native Orchestration Alignment (ADR-0002). Hosts with native subagent
617
- // routing (OpenCode, VS Code, Cursor) do not get the static specialist roster
618
- // injected — on a small-context local model the roster alone is ~3-4k tokens and,
619
- // combined with MCP tool schemas, overruns the model's real context window and
620
- // collapses output. Those hosts get a tool-bound micro-prompt instead and resolve
621
- // the chain at runtime via the orchestration_policy MCP tool. Hosts without native
622
- // routing (Claude Code, Codex) still need the roster to simulate handoffs in text.
700
+ // Platform-Native Orchestration Alignment (ADR-0002). All hosts receive the
701
+ // tool-bound micro-prompt when injectAgentRoster is set; the static 29-line
702
+ // roster was removed (construct-ymp5). Specialists resolve at runtime via
703
+ // orchestration_policy, which returns a lazy specialistCatalog.
623
704
 
624
- if (entry.injectAgentRoster && allEntries && !capabilities.hasNativeSubagents) {
625
- const roster = buildAgentRoster(allEntries);
626
- prompt = `Available specialist agents:\n${roster}\n\n${prompt}`;
627
- } else if (entry.injectAgentRoster && capabilities.hasNativeSubagents) {
628
- // A worked tool-call example lifts small local models' tool-use reliability
629
- // sharply (bead construct-c16l). Keep it to one compact turn so it stays within
630
- // the prompt word cap; native-subagent hosts are exactly where local models run.
705
+ // Single Front Door: all hosts resolve specialists at runtime via
706
+ // orchestration_policy / orchestration_run — never inject the static roster.
631
707
 
632
- prompt = `You are the primary orchestrator. To discover available specialist agents, you MUST call the \`orchestration_policy\` MCP tool. Do not guess agent names.\n\n` +
633
- `Example the user says "add rate limiting to the API". Your first action is a tool call, not prose:\n` +
634
- ` call orchestration_policy { "task": "add rate limiting to the API" }\n` +
635
- `Then dispatch the specialists it returns. Always call the tool before answering.\n\n${prompt}`;
708
+ if (entry.injectAgentRoster) {
709
+ prompt = `${ORCHESTRATION_MICRO_PROMPT}\n\n${prompt}`;
636
710
  }
637
711
 
638
712
  prompt += buildRoleFooter(entry);
@@ -648,26 +722,7 @@ function buildPrompt(entry, allEntries, platform) {
648
722
 
649
723
  prompt += buildModelGuidanceBlock(entry);
650
724
 
651
- const wordCount = prompt.split(/\s+/).filter(Boolean).length;
652
- const effectiveCap = Number(entry.wordCapOverride) > 0 ? entry.wordCapOverride : PROMPT_WORD_CAP;
653
- if (wordCount > effectiveCap) {
654
- const msg = `[sync] ${entry.name}: prompt is ${wordCount} words (cap ${effectiveCap})`;
655
- if (process.env.CONSTRUCT_SYNC_FORCE === '1' || process.argv.includes('--force')) {
656
- console.warn(`${msg} — proceeding due to --force / CONSTRUCT_SYNC_FORCE=1.`);
657
- } else {
658
- console.error(`${msg}`);
659
- console.error(
660
- `[sync] Hard cap exceeded. Options:\n` +
661
- ` - trim the prompt body or move detail to a skill (preferred)\n` +
662
- ` - set "wordCapOverride": <N> on this entry in specialists/registry.json with a written reason\n` +
663
- ` - re-run with --force or CONSTRUCT_SYNC_FORCE=1 as a temporary escape hatch\n` +
664
- `Prompt budget is a hard contract because every over-cap agent degrades every session that dispatches it.`,
665
- );
666
- process.exit(1);
667
- }
668
- }
669
-
670
- return prompt;
725
+ return enforcePromptWordCap(prompt, entry);
671
726
  }
672
727
 
673
728
  function escapeRegExp(value) { return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); }
@@ -1382,12 +1437,10 @@ function syncCursor(targetDir = null, wants = true) {
1382
1437
 
1383
1438
  if (targetDir) {
1384
1439
  const rulesPath = path.join(targetDir, ".cursor", "rules", "construct.mdc");
1385
- if (!fs.existsSync(rulesPath)) {
1386
- const body = `---\ndescription: Construct front-door — invoke \`construct\` for orchestration\nalwaysApply: false\n---\n\nThis project uses Construct (\`@geraldmaron/construct\`) as the single agent\nentry point. Route work through the \`construct\` persona; specialists are\ninternal and dispatched by Construct itself.\n\nSee \`.claude/agents/\` for the registered agents in this project.\n`;
1387
- if (!DRY_RUN) {
1388
- mkdirp(path.dirname(rulesPath));
1389
- fs.writeFileSync(rulesPath, body);
1390
- }
1440
+ const body = `---\ndescription: Construct front-door — invoke \`construct\` for orchestration\nalwaysApply: false\n---\n\n<!-- Generated by construct sync — do not edit; re-run \`construct sync\` -->\n\nThis project uses Construct (\`@geraldmaron/construct\`) as the single agent\nentry point. Route work through the \`construct\` persona; specialists are\ninternal and dispatched via MCP \`orchestration_run\` (start \`construct dashboard\`).\n\nSkills load via MCP \`get_skill\`; see \`.claude/skills/\` for synced playbooks.\n`;
1441
+ if (!DRY_RUN) {
1442
+ mkdirp(path.dirname(rulesPath));
1443
+ fs.writeFileSync(rulesPath, body);
1391
1444
  }
1392
1445
 
1393
1446
  // Glob-scoped language rules land as managed per-rule .mdc files only when
@@ -1596,7 +1649,8 @@ function syncOpencode(entries, targetDir = null, wants = true) {
1596
1649
  }
1597
1650
  }
1598
1651
 
1599
- // Heavy external MCP servers serialize ~12k tokens of schema into EVERY
1652
+ // Heavy external MCP servers serialize a measured ~37k tokens of tool schema
1653
+ // into EVERY agent's request — github ~30k alone (fixtures 2026-06-22) —
1600
1654
  // agent's request — including the built-in Build/Plan agents the per-agent
1601
1655
  // permission prune cannot reach. OpenCode 1.15.4 has no per-session tool
1602
1656
  // filter (chat.params carries no tool list), so disabling the whole server in
@@ -1638,6 +1692,20 @@ function syncOpencode(entries, targetDir = null, wants = true) {
1638
1692
  }
1639
1693
 
1640
1694
  // Write agents — no model/modelFallback set; agents inherit the global model.
1695
+ //
1696
+ // Capability tier for the orchestrator prompt. Keyed ONLY to an EXPLICIT local default
1697
+ // model — that is a clear intent signal we can size against at sync time. With no
1698
+ // explicit default (the orchestrator runs whatever model the user picks at runtime) or
1699
+ // a cloud default, resolveCapabilityTier returns 'full', so cloud configs and unknown
1700
+ // selections are never slimmed. Per-model slimming of a known pinned model lands on the
1701
+ // construct-local editor agent.
1702
+
1703
+ const orchestratorDefaultModel = config.model || config.defaultModel || "";
1704
+ adviseLocalModelCapability(orchestratorDefaultModel);
1705
+ const orchestratorTier = resolveCapabilityTier({
1706
+ model: orchestratorDefaultModel,
1707
+ verdict: orchestratorDefaultModel ? (getModelVerdict(orchestratorDefaultModel)?.verdict ?? null) : null,
1708
+ });
1641
1709
 
1642
1710
  for (const entry of writeEntries) {
1643
1711
  const name = adapterName(entry);
@@ -1647,7 +1715,9 @@ function syncOpencode(entries, targetDir = null, wants = true) {
1647
1715
  ? `${entry.role} — ${entry.description}`
1648
1716
  : entry.description,
1649
1717
  mode: entry.isOrchestrator ? "all" : "subagent",
1650
- prompt: buildPrompt(entry, entries, "opencode"),
1718
+ prompt: buildPrompt(entry, entries, "opencode", {
1719
+ capabilityTier: entry.isOrchestrator ? orchestratorTier : "full",
1720
+ }),
1651
1721
  permission: {
1652
1722
  ...perms,
1653
1723
  task: opencodeTaskPermissions(entry),
@@ -1655,18 +1725,75 @@ function syncOpencode(entries, targetDir = null, wants = true) {
1655
1725
  };
1656
1726
  }
1657
1727
 
1728
+ // Hybrid split (aider architect/editor). When the fast tier is a LOCAL model, emit a
1729
+ // narrow `construct-local` editor: it does bounded edits on a cheap local model and hands
1730
+ // planning/reasoning back to `construct` (the architect, which stays on the user's chosen
1731
+ // model — we never pin it). The editor's model is NOT the generic fast-tier default
1732
+ // (which for an Ollama family resolves to a non-code generalist); it is the best-installed
1733
+ // CODE model from this config's DECLARED local inventory (OpenCode only uses declared
1734
+ // models), excluding probe-COLLAPSED ones, with the fast tier as a last resort. Its prompt
1735
+ // is sized to the chosen model's capability tier. Deterministic name, so manage it
1736
+ // explicitly: emit when fast is local, delete otherwise, so switching to cloud cleans up.
1737
+
1738
+ const orchestratorEntry = writeEntries.find((e) => e.isOrchestrator) || registry.orchestrator;
1739
+ const orchestratorName = orchestratorEntry ? adapterName(orchestratorEntry) : "construct";
1740
+ const localEditorName = `${orchestratorName}-local`;
1741
+ if (orchestratorEntry?.promptFile && isLocalModel(resolvedModels.fast)) {
1742
+ const declaredLocal = Object.entries(config.provider || {})
1743
+ .flatMap(([pid, pv]) => Object.keys(pv?.models || {}).map((mk) => `${pid}/${mk}`))
1744
+ .filter((id) => isLocalModel(id) && getModelVerdict(id)?.verdict !== "COLLAPSED");
1745
+ const editorModel = selectLocalEditorModel(declaredLocal) || resolvedModels.fast;
1746
+ adviseLocalModelCapability(editorModel);
1747
+ const editorVerdict = getModelVerdict(editorModel)?.verdict ?? null;
1748
+ const editorTier = resolveCapabilityTier({ model: editorModel, verdict: editorVerdict });
1749
+ const editorBody = renderPersonaForTier(readPromptBody(orchestratorEntry.promptFile, root), editorTier);
1750
+ config.agent[localEditorName] = {
1751
+ description: "Local execution agent — bounded edits on the local model; escalates planning and reasoning to construct.",
1752
+ mode: "subagent",
1753
+ model: editorModel,
1754
+ prompt: `${LOCAL_EDITOR_DIRECTIVE}\n\n${editorBody}`,
1755
+ permission: {
1756
+ edit: "allow",
1757
+ bash: { "*": "allow", "rm -rf *": "deny", "git push *": "ask", "git push --force*": "ask", "git reset --hard *": "ask" },
1758
+ "mcp__construct-mcp__orchestration_policy": "deny",
1759
+ "mcp__construct-mcp__agent_contract": "deny",
1760
+ "mcp__construct-mcp__broker_check": "deny",
1761
+ "mcp__github__*": "deny",
1762
+ "mcp__context7__*": "deny",
1763
+ "mcp__sequential-thinking__*": "deny",
1764
+ "mcp__memory__*": "deny",
1765
+ // OpenCode 1.15.4 disables the `task` tool entirely for any restrictive task map
1766
+ // (verified in a sterile run). For an editor that is exactly right: it spawns no
1767
+ // subagents and escalates by RETURNING to the construct agent that dispatched it,
1768
+ // not by dispatching. Deny-all states that intent directly.
1769
+ task: { "*": "deny" },
1770
+ },
1771
+ };
1772
+ } else {
1773
+ delete config.agent[localEditorName];
1774
+ }
1775
+
1658
1776
  // Pass current Construct model tiers to OpenCode config for native routing.
1659
1777
  config.construct = config.construct || {};
1660
1778
  config.construct.models = { ...resolvedModels };
1661
1779
 
1662
1780
  // Seed a cheap auxiliary model for titles and summaries when the user has not
1663
- // chosen one — a cost lever only. The primary `model` stays the user's choice
1664
- // and is never written. Global scope only; project configs inherit it.
1781
+ // chosen one — a cost lever only. Global scope only; project configs inherit it.
1665
1782
 
1666
1783
  if (!targetDir && config.small_model === undefined) {
1667
1784
  config.small_model = resolvedModels.fast || "anthropic/claude-haiku-4-5-20251001";
1668
1785
  }
1669
1786
 
1787
+ // Seed a text-capable primary model when the user has not pinned one, so chat
1788
+ // and routing never fall through to a host provider-default that happens to be
1789
+ // an image/non-text model. Seeds only when absent; an explicit user choice is
1790
+ // never overwritten. resolvedModels.standard is family-/registry-aware and
1791
+ // free-biased. Global scope only; project configs inherit it.
1792
+
1793
+ if (!targetDir && (config.model === undefined || config.model === null || config.model === "")) {
1794
+ config.model = resolvedModels.standard || resolvedModels.reasoning || resolvedModels.fast || "openrouter/qwen/qwen3-coder:free";
1795
+ }
1796
+
1670
1797
  writeOpenCodeConfig(config, configPath);
1671
1798
 
1672
1799
  const sourcePluginsDir = path.join(root, "platforms", "opencode", "plugins");
@@ -17,7 +17,7 @@ artifactType: data-pipeline
17
17
 
18
18
  ### ELT over ETL
19
19
 
20
- Modern data platforms (BigQuery, Snowflake, Redshift) are powerful enough to transform inside the warehouse. Prefer **ELT** (Extract → Load raw → Transform in warehouse):
20
+ Modern data platforms (BigQuery, Snowflake, Redshift) are capable enough to transform inside the warehouse. Prefer **ELT** (Extract → Load raw → Transform in warehouse):
21
21
 
22
22
  ```
23
23
  Source → Airbyte/Fivetran → Raw tables → dbt models → Mart/API
@@ -3,6 +3,7 @@ name: docs-adr-workflow
3
3
  description: "Use when: an architectural decision is made that affects the system structure, data model, API contracts, or technology choices."
4
4
  inputs: [decision-context]
5
5
  artifactType: adr
6
+ verificationBar: "Every load-bearing claim cites a verifiable source; label inference confidence; satisfy template structure requirements."
6
7
  ---
7
8
  # ADR Workflow
8
9
 
@@ -3,6 +3,7 @@ name: docs-backlog-proposal-workflow
3
3
  description: "Use when: product evidence should create or update Jira, Linear, GitHub Issues, or another tracker."
4
4
  inputs: [evidence-brief, prd, signal]
5
5
  artifactType: backlog-proposal
6
+ verificationBar: "Every load-bearing claim cites a verifiable source; label inference confidence; satisfy template structure requirements."
6
7
  ---
7
8
  # Backlog Proposal Workflow
8
9
 
@@ -0,0 +1,40 @@
1
+ ---
2
+ name: docs-codebase-research-workflow
3
+ description: "Use when: cx-explorer maps the repo — entry points, dependencies, hot paths, or unfamiliar subsystems."
4
+ inputs: [repository-path]
5
+ artifactType: research-brief
6
+ toneDefault: pedagogical
7
+ toneAllowed: [pedagogical, direct]
8
+ verificationBar: "Every claim cites file:line or command output; no assumed architecture."
9
+ ---
10
+ # Codebase Research Workflow
11
+
12
+ Use when: cx-explorer investigates **this repository** — structure, dependencies, behavior. Not for external vendor research or user interviews.
13
+
14
+ Call `get_skill("roles/researcher.explorer")` and `get_skill("exploration/repo-map")` before deep dives.
15
+
16
+ ## Steps
17
+
18
+ 1. **Clarify the map question**: what subsystem, entry point, or data flow must be understood?
19
+ 2. **Read before concluding**: grep, glob, read implicated files. No claims from memory.
20
+ 3. **Produce artifacts**:
21
+ - `.cx/codebase-map.md` for broad orientation (repo-map skill)
22
+ - `.cx/research/{slug}.md` for focused investigations using `get_template("research-brief")`
23
+ 4. **Source classes** (codebase-primary):
24
+
25
+ | Source | Class |
26
+ |---|---|
27
+ | Source file at commit | primary |
28
+ | Test asserting behavior | primary |
29
+ | Config / schema in repo | primary |
30
+ | Comment or doc in repo | secondary |
31
+ | External blog about the repo | tertiary — locate code, do not cite alone |
32
+
33
+ 5. **Cite as** `[source: path#Lnn]` or `[source: commit-sha]`.
34
+ 6. **Tone**: default `pedagogical` — teach the next reader the shape of the system.
35
+
36
+ ## Verification bar
37
+
38
+ - Every architectural claim traceable to file:line.
39
+ - Unknown paths marked `[unverified]` until read.
40
+ - cx-explorer must **not** answer product prioritization or user preference questions.
@@ -3,6 +3,7 @@ name: docs-customer-profile-workflow
3
3
  description: "Use when: customer evidence should update durable product memory."
4
4
  inputs: [signal, customer-profile]
5
5
  artifactType: customer-profile
6
+ verificationBar: "Every load-bearing claim cites a verifiable source; label inference confidence; satisfy template structure requirements."
6
7
  ---
7
8
  # Customer Profile Workflow
8
9
 
@@ -3,6 +3,7 @@ name: docs-document-ingest-workflow
3
3
  description: "Use when: the user points at a PDF, Word doc, spreadsheet, slide deck, export, or mixed document folder and wants a markdown version that Construct can search efficiently later."
4
4
  inputs: [document]
5
5
  artifactType: ingested-markdown
6
+ verificationBar: "Every load-bearing claim cites a verifiable source; label inference confidence; satisfy template structure requirements."
6
7
  ---
7
8
  # Document Ingest Workflow
8
9
 
@@ -3,6 +3,7 @@ name: docs-evidence-ingest-workflow
3
3
  description: "Use when: the user pastes customer notes, Slack threads, support tickets, sales notes, research snippets, RFCs, analytics summaries, or competitor signals."
4
4
  inputs: [signal, document]
5
5
  artifactType: evidence-brief
6
+ verificationBar: "Every load-bearing claim cites a verifiable source; label inference confidence; satisfy template structure requirements."
6
7
  ---
7
8
  # Evidence Ingest Workflow
8
9
 
@@ -46,7 +46,7 @@ docs/
46
46
 
47
47
  ## Interactive UX (TTY)
48
48
 
49
- When run interactively, `construct init-docs` renders a keyboard-driven **full-screen checkbox picker**: all available lanes listed with the default set pre-checked and context-suggested lanes highlighted in the UI. No typing required.
49
+ When run interactively, `construct init --docs-preset=*` renders a keyboard-driven **full-screen checkbox picker**: all available lanes listed with the default set pre-checked and context-suggested lanes highlighted in the UI. No typing required.
50
50
 
51
51
  - **↑ / ↓**: move cursor (details shown in a dedicated panel)
52
52
  - **Space**: toggle lane on/off
@@ -54,7 +54,7 @@ When run interactively, `construct init-docs` renders a keyboard-driven **full-s
54
54
  - **Enter**: confirm and scaffold
55
55
  - Follow-up choices use the same menu pattern instead of free-text answers
56
56
 
57
- If the user selects the `intake` lane, `construct init-docs` should also create `.cx/inbox/`. Both `.cx/inbox/` and `docs/intake/` act as drop zones for ingestable files, while `docs/intake/` also serves as the durable paper trail lane.
57
+ If the user selects the `intake` lane, `construct init` should also create `.cx/inbox/`. Both `.cx/inbox/` and `docs/intake/` act as drop zones for ingestable files, while `docs/intake/` also serves as the durable paper trail lane.
58
58
 
59
59
  When run non-interactively (`--yes` or piped stdin), the lean default set is used unless `--docs=` is supplied. `--docs=lean|product|full` or `--docs=adrs,prds,rfcs` both work.
60
60
 
@@ -10,9 +10,14 @@ Use when: starting work on a new project or joining an existing one without doc
10
10
 
11
11
  ## Command
12
12
  ```bash
13
- construct init-docs [path] # defaults to current directory
13
+ construct init --docs-preset=lean [path] # defaults to current directory; presets: lean | product | full
14
+ # or lane-specific init:
15
+ construct init [path] [--docs-preset=lean|product|full] # unified bootstrap (preferred)
16
+ construct init --docs-preset=lean [path] # docs-only lean preset
14
17
  ```
15
18
 
19
+ `npm run docs:init` is deprecated — use `construct init --docs-preset=*` instead.
20
+
16
21
  ## What it creates
17
22
  ```
18
23
  .cx/ ← agent session memory and decisions
@@ -32,10 +37,10 @@ docs/ ← human-readable project documentation
32
37
  1. Treat `.cx/context.md`, `.cx/context.json`, `.cx/workflow.json`, `docs/README.md`, and `docs/architecture.md` as required project state.
33
38
  2. Read them at the start of every meaningful session.
34
39
  3. Update them whenever work changes active reality: decisions, workflow phase, architecture assumptions, or documentation contract.
35
- 4. Run `construct serve` to see the project in the dashboard.
40
+ 4. Run `construct dashboard` to see the project in the dashboard.
36
41
 
37
42
  ## For cx-docs-keeper
38
- At session start, check the core docs set. If missing, suggest running `construct init-docs`.
43
+ At session start, check the core docs set. If missing, suggest running `construct init --docs-preset=lean` (or `construct init --docs-preset=full` for the full lane set).
39
44
  At session end, update the affected core docs so the next LLM session inherits current project reality.
40
45
 
41
46
  ## For all LLMs working in the repo
@@ -3,6 +3,7 @@ name: docs-prd-workflow
3
3
  description: "Use when: the user asks to create a PRD, platform spec, business case, RFC, or requirements document."
4
4
  inputs: [research-question, evidence-brief]
5
5
  artifactType: prd
6
+ verificationBar: "Every load-bearing claim cites a verifiable source; label inference confidence; satisfy template structure requirements."
6
7
  ---
7
8
  # PRD Workflow
8
9
 
@@ -10,6 +11,8 @@ Use when: the user asks to create a PRD, platform spec, business case, RFC, or r
10
11
 
11
12
  Choose the document type before drafting:
12
13
 
14
+ Resolve tone from `specialists/tone-profiles.json` and optional `.cx/brand-voice.json` override for the selected template.
15
+
13
16
  | Template | Use when |
14
17
  |---|---|
15
18
  | `prd` | Customer-facing product capabilities, user workflows, end-user requirements |
@@ -36,7 +39,10 @@ Style constraint: do not produce a wall of bullets. Use paragraphs for reasoning
36
39
  | `meta-prd` | `docs/meta-prd/{YYYY-MM-DD}-{slug}.md` |
37
40
  | `rfc` | `docs/rfc/{YYYY-MM-DD}-{slug}.md` |
38
41
  | `rfc-platform` | `docs/rfc/{YYYY-MM-DD}-{slug}.md` |
39
- 5. **cx-docs-keeper** updates `.cx/context.md` with a link to the PRD
42
+ 5. **cx-devil-advocate** runs the FMEA challenge pass (`roles/reviewer.devil-advocate`) on the draft; highest-RPN failure modes need a mitigation or explicit accept-with-rationale before ship. Their specialist id must appear in `.cx/agent-log.jsonl` (manifest `releaseGate.requiredReviewers` for PRD-family types).
43
+ 6. **cx-docs-keeper** updates `.cx/context.md` with a link to the PRD
44
+
45
+ Run `construct artifact validate <path> --type=<type>` before marking the artifact approved.
40
46
 
41
47
  ## File naming
42
48
  - `docs/{template-type}/{YYYY-MM-DD}-{slug}.md`
@@ -54,3 +60,20 @@ Style constraint: do not produce a wall of bullets. Use paragraphs for reasoning
54
60
  ## After approval → beads
55
61
 
56
62
  Once the PRD is approved, run `/plan feature {feature-slug}` to produce a structured implementation plan and import it as workflow task packets (beads) into `.cx/workflow.json`. Link the resulting `.cx/plans/` file back in the PRD as the implementation reference.
63
+
64
+ ## Distribution (publish pipeline)
65
+
66
+ **`construct workflow invoke` returns a plan only** — it does not draft the PRD. Run the listed specialists (cx-product-manager, cx-researcher, cx-ux-researcher as needed) to author the artifact from the template. **Do not hand-write a stub and publish.**
67
+
68
+ Before distribution:
69
+
70
+ ```bash
71
+ node bin/construct artifact validate docs/prd-platform/<slug>.md --type=prd-platform
72
+ node bin/construct publish docs/prd-platform/<slug>.md --strict --figures
73
+ ```
74
+
75
+ `construct publish` runs the artifact release gate by default. Thin or unscaffolded docs **exit 2** with remediation hints. Do not use `--no-gate` or `--no-strict` in demos or ship paths.
76
+
77
+ **Presentation is part of done.** Published PDFs use type-specific Typst templates (`construct-prd.typ`, `construct-research.typ`, `construct-decision.typ`) with violet editorial branding and Inter body typography. Lead with an `::: executive-summary` narrative paragraph — not a bullet wall. Diagrams on the publish path use D2 `--sketch` and Mermaid `handDrawn` styling with Construct violet accent.
78
+
79
+ `--strict` means **toolchain and release gate** both pass. Invoke alone is not "done."
@@ -3,6 +3,7 @@ name: docs-prfaq-workflow
3
3
  description: "Use when: the user asks for a PRFAQ, working-backwards doc, launch narrative, or FAQ grounded in product evidence."
4
4
  inputs: [prd, evidence-brief]
5
5
  artifactType: prfaq
6
+ verificationBar: "Every load-bearing claim cites a verifiable source; label inference confidence; satisfy template structure requirements."
6
7
  ---
7
8
  # PRFAQ Workflow
8
9
 
@@ -3,6 +3,7 @@ name: docs-product-intelligence-workflow
3
3
  description: "Use when: the request involves customer evidence, PM synthesis, product requirements, PRDs, PRFAQs, customer profiles, product signals, or backlog proposals."
4
4
  inputs: [signal, evidence-brief]
5
5
  artifactType: prd
6
+ verificationBar: "Every load-bearing claim cites a verifiable source; label inference confidence; satisfy template structure requirements."
6
7
  ---
7
8
  # Product Intelligence Workflow
8
9
 
@@ -3,6 +3,7 @@ name: docs-product-signal-workflow
3
3
  description: "Use when: the user asks what customers are asking for, what themes are emerging, whether evidence is strong enough, or what should become a PRD."
4
4
  inputs: [signal, evidence-brief]
5
5
  artifactType: signal-brief
6
+ verificationBar: "Every load-bearing claim cites a verifiable source; label inference confidence; satisfy template structure requirements."
6
7
  ---
7
8
  # Product Signal Workflow
8
9