@geraldmaron/construct 1.2.2 → 1.3.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 (497) hide show
  1. package/README.md +7 -10
  2. package/bin/construct +286 -220
  3. package/bin/construct-postinstall.mjs +0 -21
  4. package/commands/work/optimize-prompts.md +1 -1
  5. package/examples/distribution/sources/adr.md +2 -2
  6. package/examples/seed-observations/decisions.md +1 -1
  7. package/lib/artifact-loop-core.mjs +412 -0
  8. package/lib/artifact-manifest.mjs +6 -0
  9. package/lib/artifact-release-gate.mjs +115 -49
  10. package/lib/audit-rules.mjs +2 -4
  11. package/lib/audit-skills.mjs +32 -20
  12. package/lib/audit-specialists.mjs +44 -26
  13. package/lib/auto-docs.mjs +6 -5
  14. package/lib/brand-prose.mjs +3 -3
  15. package/lib/brand-tokens.mjs +2 -2
  16. package/lib/certification/artifact-fixtures.mjs +4 -1
  17. package/lib/certification/demo-parity.mjs +6 -32
  18. package/lib/certification/real-llm-scenarios.mjs +58 -13
  19. package/lib/certification/role-cards.mjs +7 -6
  20. package/lib/certification/role-overlays.mjs +4 -4
  21. package/lib/certification/runner.mjs +9 -2
  22. package/lib/certification/skill-inventory.mjs +34 -22
  23. package/lib/certification/skill-scenarios.mjs +21 -8
  24. package/lib/certification/specialist-contracts.mjs +4 -3
  25. package/lib/certification/specialist-scenarios.mjs +7 -6
  26. package/lib/certification/status.mjs +5 -4
  27. package/lib/cli-commands.mjs +56 -57
  28. package/lib/comment-lint.mjs +1 -5
  29. package/lib/completions.mjs +20 -2
  30. package/lib/config/legacy-config-migration.mjs +125 -0
  31. package/lib/config/schema.mjs +5 -5
  32. package/lib/config/source-targets.mjs +80 -0
  33. package/lib/contracts/validate.mjs +119 -51
  34. package/lib/decisions/golden.mjs +3 -2
  35. package/lib/decisions/registry.mjs +11 -6
  36. package/lib/demo-project.mjs +188 -0
  37. package/lib/demo-recording.mjs +9 -34
  38. package/lib/demo-script.mjs +2 -2
  39. package/lib/demo-surface.mjs +13 -131
  40. package/lib/demo-tour-renderer.mjs +92 -0
  41. package/lib/demo.mjs +69 -54
  42. package/lib/diagram-export.mjs +63 -14
  43. package/lib/doctor/source-checkout.mjs +3 -4
  44. package/lib/doctor/watchers/consistency.mjs +90 -22
  45. package/lib/doctor/watchers/credential-parity.mjs +97 -0
  46. package/lib/doctor/watchers/mcp-protocol.mjs +1 -1
  47. package/lib/doctor/watchers/service-health.mjs +4 -32
  48. package/lib/document-export.mjs +73 -9
  49. package/lib/document-extract.mjs +10 -198
  50. package/lib/embed/artifact.mjs +2 -3
  51. package/lib/embed/cli.mjs +1 -1
  52. package/lib/embed/config.mjs +1 -2
  53. package/lib/embed/customer-profiles.mjs +1 -1
  54. package/lib/embed/daemon.mjs +5 -6
  55. package/lib/embed/demand-fetch.mjs +114 -2
  56. package/lib/embed/docs-lifecycle.mjs +9 -5
  57. package/lib/embed/intake-metrics.mjs +2 -2
  58. package/lib/embed/notifications.mjs +2 -3
  59. package/lib/embed/recommendation-store.mjs +25 -22
  60. package/lib/embed/role-framing.mjs +4 -9
  61. package/lib/embedded-contract/capability.mjs +4 -2
  62. package/lib/embedded-contract/contract-version.mjs +1 -1
  63. package/lib/env-config.mjs +2 -2
  64. package/lib/flavors/loader.mjs +21 -19
  65. package/lib/graph/build-from-registry.mjs +31 -7
  66. package/lib/graph/staleness.mjs +1 -1
  67. package/lib/headhunt.mjs +82 -35
  68. package/lib/hooks/agent-tracker.mjs +2 -2
  69. package/lib/hooks/config-protection.mjs +1 -1
  70. package/lib/hooks/registry-sync.mjs +3 -3
  71. package/lib/host-capabilities.mjs +5 -5
  72. package/lib/improvement/controller.mjs +2 -2
  73. package/lib/init-unified.mjs +19 -21
  74. package/lib/intake/classify.mjs +26 -0
  75. package/lib/intake/daemon.mjs +2 -3
  76. package/lib/intake/prepare.mjs +10 -3
  77. package/lib/intake/session-prelude.mjs +1 -1
  78. package/lib/intake/tables/creative.mjs +9 -9
  79. package/lib/intake/tables/operations.mjs +4 -4
  80. package/lib/intake/tables/research.mjs +2 -2
  81. package/lib/integrations/intake-integrations.mjs +9 -10
  82. package/lib/knowledge/research-store.mjs +2 -2
  83. package/lib/mcp/server.mjs +104 -61
  84. package/lib/mcp/tool-budget.mjs +1 -46
  85. package/lib/mcp/tool-recovery.mjs +44 -0
  86. package/lib/mcp/tools/artifact-author.mjs +36 -0
  87. package/lib/mcp/tools/find-tool.mjs +86 -0
  88. package/lib/mcp/tools/orchestration-run.mjs +107 -69
  89. package/lib/mcp/tools/project.mjs +4 -3
  90. package/lib/mcp/tools/{profile.mjs → scope.mjs} +54 -52
  91. package/lib/mcp/tools/skills.mjs +39 -22
  92. package/lib/mcp/tools/telemetry.mjs +2 -1
  93. package/lib/mcp/tools/workflow.mjs +1 -1
  94. package/lib/mcp-platform-config.mjs +7 -5
  95. package/lib/migrations/index.mjs +4 -2
  96. package/lib/migrations/v2-unified-registry.mjs +35 -0
  97. package/lib/model-router.mjs +203 -36
  98. package/lib/models/catalog.mjs +25 -9
  99. package/lib/models/execution-capability-profile.mjs +3 -3
  100. package/lib/models/execution-policy.mjs +7 -6
  101. package/lib/models/provider-poll.mjs +18 -4
  102. package/lib/opencode-config.mjs +56 -1
  103. package/lib/opencode-runtime-plugin.mjs +13 -10
  104. package/lib/oracle/artifact-gate.mjs +14 -4
  105. package/lib/oracle/cli.mjs +2 -0
  106. package/lib/oracle/dispatch.mjs +18 -1
  107. package/lib/oracle/execute.mjs +39 -7
  108. package/lib/oracle/index.mjs +1 -1
  109. package/lib/oracle/org-graph.mjs +10 -5
  110. package/lib/oracle/policy.mjs +6 -0
  111. package/lib/oracle/read-model.mjs +103 -6
  112. package/lib/oracle/reconcile.mjs +31 -4
  113. package/lib/oracle/remediation-dispatch.mjs +53 -0
  114. package/lib/oracle/routing.mjs +5 -0
  115. package/lib/oracle/synthesize.mjs +80 -3
  116. package/lib/orchestration/routing-tables.mjs +44 -10
  117. package/lib/orchestration/runtime.mjs +2 -0
  118. package/lib/orchestration/worker.mjs +1 -1
  119. package/lib/orchestration-policy.mjs +351 -62
  120. package/lib/overrides/resolver.mjs +1 -12
  121. package/lib/parity.mjs +37 -11
  122. package/lib/policy/engine.mjs +80 -15
  123. package/lib/prompt-composer.js +51 -15
  124. package/lib/prompt-metadata.mjs +3 -2
  125. package/lib/providers/connection-probe.mjs +58 -0
  126. package/lib/providers/copilot-auth.mjs +1 -1
  127. package/lib/providers/credential-bootstrap.mjs +1 -1
  128. package/lib/providers/op-run.mjs +3 -4
  129. package/lib/providers/secret-resolver.mjs +31 -0
  130. package/lib/publish-tooling.mjs +3 -11
  131. package/lib/publish.mjs +12 -29
  132. package/lib/reconcile/mcp-entry-reconcile.mjs +14 -9
  133. package/lib/reflect.mjs +2 -2
  134. package/lib/registry/agent-manifest.mjs +190 -0
  135. package/lib/registry/assemble.mjs +133 -0
  136. package/lib/registry/catalog.mjs +171 -0
  137. package/lib/registry/cli.mjs +590 -6
  138. package/lib/registry/consolidation.mjs +5 -4
  139. package/lib/registry/docs-sync.mjs +67 -0
  140. package/lib/registry/loader.mjs +147 -0
  141. package/lib/registry/org-io.mjs +76 -0
  142. package/lib/registry/retired-paths.mjs +71 -0
  143. package/lib/registry/surface-map.mjs +5 -7
  144. package/lib/registry/validator.mjs +438 -0
  145. package/lib/research-execution-policy.mjs +173 -0
  146. package/lib/roles/catalog.mjs +4 -9
  147. package/lib/roles/fence.mjs +107 -1
  148. package/lib/roles/flavor-bindings.mjs +68 -0
  149. package/lib/roles/gateway.mjs +140 -29
  150. package/lib/roles/manifest.mjs +22 -13
  151. package/lib/roles/router.mjs +1 -1
  152. package/lib/runtime-env.mjs +1 -1
  153. package/lib/scopes/enrich.mjs +67 -0
  154. package/lib/scopes/hooks.mjs +12 -0
  155. package/lib/{profiles → scopes}/lifecycle.mjs +70 -70
  156. package/lib/scopes/loader.mjs +104 -0
  157. package/lib/scopes/rebrand.mjs +32 -0
  158. package/lib/scopes/research-profile.mjs +16 -0
  159. package/lib/scopes/teams.mjs +98 -0
  160. package/lib/service-manager.mjs +1 -117
  161. package/lib/setup-prompts.mjs +1 -1
  162. package/lib/setup.mjs +17 -28
  163. package/lib/skills/composition-graph.mjs +98 -0
  164. package/lib/skills/router.mjs +80 -0
  165. package/lib/specialist-contracts.mjs +17 -18
  166. package/lib/specialists/postconditions.mjs +2 -2
  167. package/lib/specialists/prompt-schema.mjs +6 -5
  168. package/lib/specialists/roster.mjs +7 -12
  169. package/lib/specialists/schema.mjs +9 -6
  170. package/lib/status.mjs +25 -90
  171. package/lib/storage/file-lock.mjs +6 -3
  172. package/lib/telemetry/skill-calls.mjs +1 -1
  173. package/lib/templates/doc-presentation.mjs +63 -0
  174. package/lib/templates/visual-requirements.mjs +35 -2
  175. package/lib/term-format.mjs +107 -2
  176. package/lib/test-env-setup.mjs +21 -0
  177. package/lib/ui/components.mjs +42 -0
  178. package/lib/ui/glyphs.mjs +58 -0
  179. package/lib/ui/links.mjs +115 -0
  180. package/lib/ui/theme.mjs +108 -0
  181. package/lib/uninstall/uninstall.mjs +2 -1
  182. package/lib/validator.mjs +45 -8
  183. package/lib/validators/skill-effectiveness.mjs +174 -0
  184. package/lib/validators/skills.mjs +1 -1
  185. package/package.json +12 -7
  186. package/personas/construct.md +12 -3
  187. package/platforms/claude/CLAUDE.md +1 -1
  188. package/rules/common/beads-hygiene.md +52 -0
  189. package/rules/common/neurodivergent-output.md +4 -7
  190. package/rules/common/research.md +2 -0
  191. package/scripts/sync-specialists.mjs +260 -49
  192. package/skills/ai/prompt-optimizer.md +3 -3
  193. package/skills/brand/output-vibe.md +48 -0
  194. package/skills/docs/adr-workflow.md +3 -0
  195. package/skills/docs/backlog-proposal-workflow.md +3 -0
  196. package/skills/docs/codebase-research-workflow.md +5 -2
  197. package/skills/docs/customer-profile-workflow.md +3 -0
  198. package/skills/docs/document-ingest-workflow.md +3 -0
  199. package/skills/docs/evidence-ingest-workflow.md +4 -1
  200. package/skills/docs/init-project.md +1 -1
  201. package/skills/docs/prd-workflow.md +1 -1
  202. package/skills/docs/prfaq-workflow.md +3 -0
  203. package/skills/docs/product-intelligence-workflow.md +4 -1
  204. package/skills/docs/product-signal-workflow.md +3 -0
  205. package/skills/docs/research-workflow.md +13 -6
  206. package/skills/docs/runbook-workflow.md +3 -0
  207. package/skills/docs/strategy-workflow.md +3 -0
  208. package/skills/docs/user-research-workflow.md +6 -3
  209. package/skills/operating/orchestration-reference.md +1 -1
  210. package/skills/roles/{engineer.ai.md → ai-engineer.md} +2 -2
  211. package/skills/roles/architect.ai-systems.md +1 -1
  212. package/skills/roles/architect.data.md +1 -1
  213. package/skills/roles/architect.enterprise.md +1 -1
  214. package/skills/roles/architect.integration.md +1 -1
  215. package/skills/roles/architect.md +1 -1
  216. package/skills/roles/architect.platform.md +1 -1
  217. package/skills/roles/{product-manager.business-strategy.md → business-strategist.md} +3 -3
  218. package/skills/roles/data-analyst.experiment.md +1 -1
  219. package/skills/roles/data-analyst.md +1 -1
  220. package/skills/roles/data-analyst.product-intelligence.md +1 -1
  221. package/skills/roles/data-analyst.product.md +1 -1
  222. package/skills/roles/data-analyst.telemetry.md +1 -1
  223. package/skills/roles/{engineer.data.md → data-engineer.md} +2 -2
  224. package/skills/roles/data-engineer.pipeline.md +2 -2
  225. package/skills/roles/data-engineer.vector-retrieval.md +2 -2
  226. package/skills/roles/data-engineer.warehouse.md +2 -2
  227. package/skills/roles/debugger.md +1 -1
  228. package/skills/roles/designer.accessibility.md +1 -1
  229. package/skills/roles/designer.md +1 -1
  230. package/skills/roles/{reviewer.devil-advocate.md → devil-advocate.md} +2 -2
  231. package/skills/roles/{operator.docs.md → docs-keeper.md} +3 -3
  232. package/skills/roles/engineer.md +3 -7
  233. package/skills/roles/{reviewer.evaluator.md → evaluator.md} +2 -2
  234. package/skills/roles/{researcher.explorer.md → explorer.md} +2 -2
  235. package/skills/roles/{operator.md → operations.md} +2 -5
  236. package/skills/roles/orchestrator.md +1 -1
  237. package/skills/roles/{engineer.platform.md → platform-engineer.md} +2 -2
  238. package/skills/roles/product-manager.ai-product.md +1 -1
  239. package/skills/roles/product-manager.enterprise.md +1 -1
  240. package/skills/roles/product-manager.growth.md +1 -2
  241. package/skills/roles/product-manager.md +1 -2
  242. package/skills/roles/product-manager.platform.md +1 -1
  243. package/skills/roles/product-manager.product.md +1 -1
  244. package/skills/roles/qa.ai-eval.md +1 -1
  245. package/skills/roles/qa.api-contract.md +1 -1
  246. package/skills/roles/qa.data-pipeline.md +1 -1
  247. package/skills/roles/qa.md +1 -1
  248. package/skills/roles/qa.web-ui.md +1 -1
  249. package/skills/roles/{operator.release.md → release-manager.md} +3 -3
  250. package/skills/roles/researcher.md +1 -1
  251. package/skills/roles/reviewer.md +1 -1
  252. package/skills/roles/security.ai.md +1 -1
  253. package/skills/roles/security.appsec.md +1 -1
  254. package/skills/roles/security.cloud.md +1 -1
  255. package/skills/roles/security.legal-compliance.md +1 -1
  256. package/skills/roles/security.md +1 -1
  257. package/skills/roles/security.privacy.md +1 -1
  258. package/skills/roles/security.supply-chain.md +1 -1
  259. package/skills/roles/{operator.sre.md → sre.md} +3 -3
  260. package/skills/roles/{qa.test-automation.md → test-automation.md} +2 -2
  261. package/skills/roles/{reviewer.trace.md → trace-reviewer.md} +2 -2
  262. package/skills/roles/{researcher.ux.md → ux-researcher.md} +2 -2
  263. package/skills/routing.json +18 -0
  264. package/skills/routing.md +1 -1
  265. package/specialists/artifact-manifest.json +2 -1
  266. package/specialists/audit-enrichments.json +14 -14
  267. package/specialists/org/contracts/accessibility-to-qa.json +37 -0
  268. package/specialists/org/contracts/any-to-business-strategist.json +57 -0
  269. package/specialists/org/contracts/any-to-debugger.json +38 -0
  270. package/specialists/org/contracts/any-to-designer.json +33 -0
  271. package/specialists/org/contracts/any-to-docs-keeper.json +34 -0
  272. package/specialists/org/contracts/any-to-explorer.json +39 -0
  273. package/specialists/org/contracts/any-to-sre-incident.json +33 -0
  274. package/specialists/org/contracts/any-to-trace-reviewer.json +32 -0
  275. package/specialists/org/contracts/architect-to-ai-engineer.json +32 -0
  276. package/specialists/org/contracts/architect-to-data-engineer.json +52 -0
  277. package/specialists/org/contracts/architect-to-devil-advocate.json +38 -0
  278. package/specialists/org/contracts/architect-to-engineer.json +34 -0
  279. package/specialists/org/contracts/architect-to-evaluator.json +59 -0
  280. package/specialists/org/contracts/architect-to-legal-compliance.json +55 -0
  281. package/specialists/org/contracts/architect-to-operations.json +45 -0
  282. package/specialists/org/contracts/architect-to-platform-engineer.json +42 -0
  283. package/specialists/org/contracts/business-strategist-to-product-manager.json +39 -0
  284. package/specialists/org/contracts/construct-to-orchestrator.json +36 -0
  285. package/specialists/org/contracts/construct-to-rd-lead.json +53 -0
  286. package/specialists/org/contracts/data-analyst-to-product-manager.json +43 -0
  287. package/specialists/org/contracts/data-engineer-to-platform-engineer.json +36 -0
  288. package/specialists/org/contracts/designer-to-accessibility.json +36 -0
  289. package/specialists/org/contracts/engineer-to-qa.json +34 -0
  290. package/specialists/org/contracts/engineer-to-reviewer.json +52 -0
  291. package/specialists/org/contracts/explorer-to-engineer.json +38 -0
  292. package/specialists/org/contracts/legal-compliance-to-release-manager.json +43 -0
  293. package/specialists/org/contracts/platform-engineer-to-engineer.json +31 -0
  294. package/specialists/org/contracts/product-manager-to-architect.json +71 -0
  295. package/specialists/org/contracts/product-manager-to-data-analyst.json +49 -0
  296. package/specialists/org/contracts/product-manager-to-ux-researcher.json +51 -0
  297. package/specialists/org/contracts/qa-to-release-manager.json +42 -0
  298. package/specialists/org/contracts/qa-to-test-automation.json +42 -0
  299. package/specialists/org/contracts/rd-lead-to-architect.json +38 -0
  300. package/specialists/org/contracts/researcher-to-architect.json +40 -0
  301. package/specialists/org/contracts/researcher-to-product-manager.json +57 -0
  302. package/specialists/org/contracts/reviewer-to-security.json +41 -0
  303. package/specialists/org/contracts/sre-to-release-manager.json +36 -0
  304. package/specialists/org/contracts/test-automation-to-engineer.json +34 -0
  305. package/specialists/org/contracts/trace-reviewer-to-sre.json +41 -0
  306. package/specialists/org/contracts/user-to-construct.json +30 -0
  307. package/specialists/org/groups/engineering-group.json +43 -0
  308. package/specialists/org/groups/governance-group.json +38 -0
  309. package/specialists/org/groups/operations-group.json +41 -0
  310. package/specialists/org/groups/product-group.json +46 -0
  311. package/specialists/org/groups/quality-group.json +42 -0
  312. package/specialists/org/groups/strategy-group.json +41 -0
  313. package/specialists/org/policies/action-approval.json +13 -0
  314. package/specialists/org/policies/agents-routing.json +13 -0
  315. package/specialists/org/policies/architecture.json +20 -0
  316. package/specialists/org/policies/bash-safety.json +13 -0
  317. package/specialists/org/policies/beads-hygiene.json +13 -0
  318. package/specialists/org/policies/bootstrap-state.json +13 -0
  319. package/specialists/org/policies/code-review.json +13 -0
  320. package/specialists/org/policies/coding-style.json +13 -0
  321. package/specialists/org/policies/comments.json +13 -0
  322. package/specialists/org/policies/commit-approval.json +13 -0
  323. package/specialists/org/policies/contract-preconditions.json +13 -0
  324. package/specialists/org/policies/deployment.json +20 -0
  325. package/specialists/org/policies/description.json +14 -0
  326. package/specialists/org/policies/design-approval.json +19 -0
  327. package/specialists/org/policies/doc-ownership.json +13 -0
  328. package/specialists/org/policies/file-path-fence.json +13 -0
  329. package/specialists/org/policies/framing.json +13 -0
  330. package/specialists/org/policies/git-workflow.json +13 -0
  331. package/specialists/org/policies/incident-response.json +15 -0
  332. package/specialists/org/policies/intake-triage.json +15 -0
  333. package/specialists/org/policies/neurodivergent-output.json +13 -0
  334. package/specialists/org/policies/no-fabrication.json +13 -0
  335. package/specialists/org/policies/patterns.json +13 -0
  336. package/specialists/org/policies/quality-gate-approval.json +17 -0
  337. package/specialists/org/policies/release-gates.json +13 -0
  338. package/specialists/org/policies/research-evidence.json +13 -0
  339. package/specialists/org/policies/review-before-change.json +13 -0
  340. package/specialists/org/policies/rollback.json +15 -0
  341. package/specialists/org/policies/scope-change.json +20 -0
  342. package/specialists/org/policies/secret-scan.json +13 -0
  343. package/specialists/org/policies/security-approval.json +17 -0
  344. package/specialists/org/policies/security.json +13 -0
  345. package/specialists/org/policies/session-efficiency.json +13 -0
  346. package/specialists/org/policies/skill-routing.json +13 -0
  347. package/specialists/org/policies/strategic-prioritization.json +17 -0
  348. package/specialists/org/policies/testing.json +13 -0
  349. package/specialists/org/policies/tool-invisibility.json +14 -0
  350. package/specialists/org/scopes/creative.json +54 -0
  351. package/specialists/org/scopes/operations.json +51 -0
  352. package/specialists/org/scopes/research.json +60 -0
  353. package/specialists/org/scopes/rnd.json +81 -0
  354. package/specialists/org/specialists/cx-accessibility.json +69 -0
  355. package/specialists/org/specialists/cx-ai-engineer.json +75 -0
  356. package/specialists/org/specialists/cx-architect.json +89 -0
  357. package/specialists/org/specialists/cx-business-strategist.json +72 -0
  358. package/specialists/org/specialists/cx-data-analyst.json +68 -0
  359. package/specialists/org/specialists/cx-data-engineer.json +71 -0
  360. package/specialists/org/specialists/cx-debugger.json +75 -0
  361. package/specialists/org/specialists/cx-designer.json +85 -0
  362. package/specialists/org/specialists/cx-devil-advocate.json +71 -0
  363. package/specialists/org/specialists/cx-docs-keeper.json +82 -0
  364. package/specialists/org/specialists/cx-engineer.json +106 -0
  365. package/specialists/org/specialists/cx-evaluator.json +69 -0
  366. package/specialists/org/specialists/cx-explorer.json +69 -0
  367. package/specialists/org/specialists/cx-legal-compliance.json +74 -0
  368. package/specialists/org/specialists/cx-operations.json +72 -0
  369. package/specialists/org/specialists/cx-oracle.json +46 -0
  370. package/specialists/org/specialists/cx-orchestrator.json +81 -0
  371. package/specialists/org/specialists/cx-platform-engineer.json +80 -0
  372. package/specialists/org/specialists/cx-product-manager.json +102 -0
  373. package/specialists/org/specialists/cx-qa.json +79 -0
  374. package/specialists/org/specialists/cx-rd-lead.json +73 -0
  375. package/specialists/org/specialists/cx-release-manager.json +77 -0
  376. package/specialists/org/specialists/cx-researcher.json +82 -0
  377. package/specialists/org/specialists/cx-reviewer.json +71 -0
  378. package/specialists/org/specialists/cx-security.json +91 -0
  379. package/specialists/org/specialists/cx-sre.json +94 -0
  380. package/specialists/org/specialists/cx-test-automation.json +69 -0
  381. package/specialists/org/specialists/cx-trace-reviewer.json +69 -0
  382. package/specialists/org/specialists/cx-ux-researcher.json +68 -0
  383. package/specialists/org/teams/accessibility-team.json +39 -0
  384. package/specialists/org/teams/design-team.json +40 -0
  385. package/specialists/org/teams/engineering-team.json +50 -0
  386. package/specialists/org/teams/governance-team.json +41 -0
  387. package/specialists/org/teams/operations-team.json +46 -0
  388. package/specialists/org/teams/product-management-team.json +45 -0
  389. package/specialists/org/teams/quality-team.json +49 -0
  390. package/specialists/org/teams/research-team.json +39 -0
  391. package/specialists/org/teams/strategy-team.json +48 -0
  392. package/specialists/org/teams/ux-research-team.json +39 -0
  393. package/specialists/prompts/_shared/validation-contract.md +1 -1
  394. package/specialists/prompts/_team-template.md +10 -0
  395. package/specialists/prompts/cx-accessibility.md +1 -0
  396. package/specialists/prompts/cx-ai-engineer.md +1 -1
  397. package/specialists/prompts/cx-business-strategist.md +1 -1
  398. package/specialists/prompts/cx-data-engineer.md +1 -1
  399. package/specialists/prompts/cx-designer.md +1 -0
  400. package/specialists/prompts/cx-devil-advocate.md +1 -1
  401. package/specialists/prompts/cx-docs-keeper.md +1 -1
  402. package/specialists/prompts/cx-evaluator.md +1 -1
  403. package/specialists/prompts/cx-explorer.md +1 -1
  404. package/specialists/prompts/cx-operations.md +1 -1
  405. package/specialists/prompts/cx-oracle.md +7 -3
  406. package/specialists/prompts/cx-orchestrator.md +17 -1
  407. package/specialists/prompts/cx-platform-engineer.md +1 -1
  408. package/specialists/prompts/cx-product-manager.md +2 -0
  409. package/specialists/prompts/cx-release-manager.md +1 -1
  410. package/specialists/prompts/cx-researcher.md +7 -4
  411. package/specialists/prompts/cx-sre.md +1 -1
  412. package/specialists/prompts/cx-test-automation.md +2 -2
  413. package/specialists/prompts/cx-trace-reviewer.md +3 -3
  414. package/specialists/prompts/cx-ux-researcher.md +2 -1
  415. package/templates/demos/scripts/architecture-review-adr.json +30 -0
  416. package/templates/demos/scripts/capability-contract.json +25 -0
  417. package/templates/demos/scripts/intake-triage.json +25 -0
  418. package/templates/demos/scripts/profile-doctor-health.json +25 -0
  419. package/templates/demos/tapes/agentic-platforms-prd.tape +2 -2
  420. package/templates/demos/tapes/architecture-review-adr.tape +44 -0
  421. package/templates/demos/tapes/capability-contract.tape +39 -0
  422. package/templates/demos/tapes/intake-triage.tape +39 -0
  423. package/templates/demos/tapes/profile-doctor-health.tape +39 -0
  424. package/templates/distribution/construct-brand.typ +23 -18
  425. package/templates/distribution/construct-decision.typ +1 -1
  426. package/templates/distribution/construct-pdf.typ +1 -1
  427. package/templates/distribution/construct-prd.typ +1 -1
  428. package/templates/distribution/construct-research.typ +1 -1
  429. package/templates/distribution/mermaid-puppeteer.json +8 -0
  430. package/templates/docs/persona-artifact.md +1 -1
  431. package/templates/docs/prd.md +6 -0
  432. package/lib/boundary.mjs +0 -127
  433. package/lib/certification/dashboard-api.mjs +0 -71
  434. package/lib/chat/cli.mjs +0 -333
  435. package/lib/chat/command-suggest.mjs +0 -161
  436. package/lib/chat/commands.mjs +0 -215
  437. package/lib/chat/config.mjs +0 -142
  438. package/lib/chat/context-compactor.mjs +0 -250
  439. package/lib/chat/context-continuation.mjs +0 -253
  440. package/lib/chat/continuation-source.mjs +0 -58
  441. package/lib/chat/demo-guide.mjs +0 -61
  442. package/lib/chat/design-tokens.mjs +0 -91
  443. package/lib/chat/desktop-binary.mjs +0 -81
  444. package/lib/chat/desktop-build.mjs +0 -130
  445. package/lib/chat/desktop-launcher.mjs +0 -133
  446. package/lib/chat/evidence.mjs +0 -145
  447. package/lib/chat/export.mjs +0 -74
  448. package/lib/chat/harness/driver.mjs +0 -91
  449. package/lib/chat/list-picker.mjs +0 -112
  450. package/lib/chat/model-picker.mjs +0 -356
  451. package/lib/chat/openrouter-fallback.mjs +0 -151
  452. package/lib/chat/permission-prompt.mjs +0 -33
  453. package/lib/chat/picker-catalog.mjs +0 -45
  454. package/lib/chat/policy-telemetry.mjs +0 -34
  455. package/lib/chat/present.mjs +0 -246
  456. package/lib/chat/session-context.mjs +0 -39
  457. package/lib/chat/session-persist.mjs +0 -73
  458. package/lib/chat/session-restore.mjs +0 -71
  459. package/lib/chat/session-settings.mjs +0 -53
  460. package/lib/chat/system-prompt.mjs +0 -52
  461. package/lib/chat/transparency.mjs +0 -93
  462. package/lib/chat/tui/color-scheme.mjs +0 -42
  463. package/lib/chat/tui/markdown.mjs +0 -123
  464. package/lib/chat/tui/presentation.mjs +0 -100
  465. package/lib/chat/tui/render.mjs +0 -500
  466. package/lib/chat/tui/turn-block.mjs +0 -284
  467. package/lib/chat/tui/turn-present.mjs +0 -18
  468. package/lib/chat/tui/turn-state.mjs +0 -88
  469. package/lib/chat/tui/usage.mjs +0 -122
  470. package/lib/chat/web-commands.mjs +0 -146
  471. package/lib/chat/web-launcher.mjs +0 -63
  472. package/lib/chat/web-picker-keys.mjs +0 -46
  473. package/lib/chat/web-session.mjs +0 -159
  474. package/lib/config/alias.mjs +0 -57
  475. package/lib/dashboard-demo.mjs +0 -71
  476. package/lib/dashboard-static.mjs +0 -175
  477. package/lib/install/desktop-binary-download.mjs +0 -88
  478. package/lib/profiles/loader.mjs +0 -123
  479. package/lib/profiles/rebrand.mjs +0 -46
  480. package/lib/server/auth.mjs +0 -169
  481. package/lib/server/chat-loop.mjs +0 -622
  482. package/lib/server/chat.mjs +0 -336
  483. package/lib/server/cors.mjs +0 -77
  484. package/lib/server/csrf.mjs +0 -103
  485. package/lib/server/demo-preview.mjs +0 -63
  486. package/lib/server/index.mjs +0 -2641
  487. package/lib/server/insights.mjs +0 -780
  488. package/lib/server/langfuse-login.mjs +0 -58
  489. package/lib/server/rate-limit.mjs +0 -93
  490. package/lib/server/telemetry-login.mjs +0 -100
  491. package/lib/server/webhook.mjs +0 -512
  492. package/specialists/contracts.json +0 -1032
  493. package/specialists/contracts.schema.json +0 -83
  494. package/specialists/policy-inventory.json +0 -188
  495. package/specialists/registry.json +0 -1412
  496. package/specialists/role-manifests.json +0 -217
  497. package/specialists/teams.json +0 -94
@@ -6,19 +6,24 @@
6
6
  * 2. framing/research/doc-ownership gates (what must be true before work starts)
7
7
  * 3. contract chain (resolveContractChain) (what the typed handoffs are)
8
8
  *
9
- * Agent-to-agent contracts are defined in specialists/contracts.json and loaded via
10
- * lib/specialist-contracts.mjs. That file is the source of truth for
11
- * producer→consumer typed handoffs.
9
+ * Agent-to-agent contracts are declared in specialists/org
10
+ * (registry.contracts) and resolved via lib/specialist-contracts.mjs. The
11
+ * unified registry is the source of truth for producer→consumer typed handoffs.
12
12
  *
13
13
  * Event ownership, doc-artifact ownership, and watch-condition routing live
14
- * declaratively on specialist entries in specialists/registry.json and are
14
+ * declaratively on specialist entries in specialists/org and are
15
15
  * resolved by lib/orchestration/routing-tables.mjs. Hardcoded maps here
16
16
  * would create a second source of truth.
17
17
  */
18
18
  import { resolveContractChain } from './specialist-contracts.mjs';
19
19
  import { verifyRoute } from './intent-classifier.mjs';
20
20
  import { ownerForEvent, ownerForDoc, evaluateWatchConditions, knownDocTypes } from './orchestration/routing-tables.mjs';
21
- import { getArtifactEntry } from './artifact-manifest.mjs';
21
+ import { getArtifactEntry, resolveArtifactWorkflowContract } from './artifact-manifest.mjs';
22
+ import { loadRegistry } from './registry/loader.mjs';
23
+ import { buildResearchExecutionPolicy } from './research-execution-policy.mjs';
24
+ import { resolveActiveScope } from './scopes/loader.mjs';
25
+ import { scopeTeamsById, resolveIntentTeamForScope, resolveScopeTeamMeta } from './scopes/teams.mjs';
26
+ import { formatOverlayLine } from './roles/flavor-bindings.mjs';
22
27
 
23
28
  export const EXECUTION_TRACKS = {
24
29
  immediate: 'immediate',
@@ -34,6 +39,20 @@ export const INTENT_CLASSES = {
34
39
  fix: 'fix',
35
40
  };
36
41
 
42
+ // RFC-0004 §2: each intent class maps to the team that naturally owns that work.
43
+ // The primary team drives ownership in teamRouting; specialist selection stays
44
+ // flavor-driven. Domain refinements the RFC notes (investigation/fix can fall to
45
+ // operations-group, research to product-group) layer on as the decision matrix
46
+ // grows — the base mapping is deterministic so routing is testable.
47
+
48
+ export const INTENT_TO_TEAM = Object.freeze({
49
+ research: 'strategy-team',
50
+ implementation: 'engineering-team',
51
+ investigation: 'engineering-team',
52
+ evaluation: 'quality-team',
53
+ fix: 'engineering-team',
54
+ });
55
+
37
56
  export const WORK_CATEGORIES = {
38
57
  visual: 'visual',
39
58
  deep: 'deep',
@@ -44,7 +63,7 @@ export const WORK_CATEGORIES = {
44
63
 
45
64
  export const TERMINAL_STATES = ['DONE', 'BLOCKED', 'NEEDS_MAIN_INPUT'];
46
65
 
47
- // Event and doc-artifact ownership are resolved from specialists/registry.json
66
+ // Event and doc-artifact ownership are resolved from specialists/org
48
67
  // via routing-tables.mjs. Re-exported here so callers that historically
49
68
  // imported from this module keep working.
50
69
 
@@ -77,7 +96,18 @@ const DOC_AUTHORING_PATTERNS = [
77
96
  { pattern: /\bchangelog/i, docType: 'changelog' },
78
97
  ];
79
98
 
80
- const AUTHORING_VERBS = /\b(write|writing|draft|drafting|create|creating|author|authoring|produce|producing|compose|composing|prepare|preparing)\b/i;
99
+ const AUTHORING_VERBS = /\b(write|writing|draft|drafting|create|creating|author|authoring|produce|producing|compose|composing|prepare|preparing|generate|generating)\b/i;
100
+
101
+ /**
102
+ * Resolves a document type mentioned in text without requiring an authoring verb.
103
+ */
104
+ export function resolveDocTypeMention(request = '') {
105
+ const text = String(request);
106
+ for (const { pattern, docType } of DOC_AUTHORING_PATTERNS) {
107
+ if (pattern.test(text)) return docType;
108
+ }
109
+ return null;
110
+ }
81
111
 
82
112
  /**
83
113
  * Detects whether the request is asking for authorship of a typed document
@@ -205,6 +235,13 @@ const SPECIALIST_MAP = {
205
235
  research: ['cx-researcher'],
206
236
  };
207
237
 
238
+ const WORKFLOW_SKILL_TO_TYPE = {
239
+ 'docs/prd-workflow': 'prd-draft',
240
+ 'docs/adr-workflow': 'architecture-review',
241
+ 'docs/research-workflow': 'research-synthesis',
242
+ 'docs/evidence-ingest-workflow': 'evidence-ingest',
243
+ };
244
+
208
245
  function includesAny(text, patterns) {
209
246
  return patterns.some((pattern) => pattern.test(text));
210
247
  }
@@ -292,7 +329,7 @@ export function classifyEngineerFlavor(request = '') {
292
329
  const text = String(request).toLowerCase();
293
330
  if (containsAny(text, ['llm', 'agent', 'prompt', 'eval', 'hallucination', 'rag', 'model behavior', 'model routing'])) return 'ai';
294
331
  if (containsAny(text, ['vector', 'embedding', 'retrieval', 'warehouse', 'etl', 'elt', 'pipeline', 'streaming', 'data contract'])) return 'data';
295
- if (containsAny(text, ['ci', 'build', 'deploy', 'docker', 'kubernetes', 'terraform', 'helm', 'release pipeline', 'platform tooling', 'developer experience'])) return 'platform';
332
+ if (containsAny(text, ['ci/cd', ' ci ', 'build pipeline', 'build system', 'deploy', 'docker', 'kubernetes', 'terraform', 'helm', 'release pipeline', 'platform tooling', 'developer experience'])) return 'platform';
296
333
  return null;
297
334
  }
298
335
 
@@ -377,28 +414,32 @@ export function isVisualDeliverableRequest(request = '') {
377
414
  }
378
415
 
379
416
  export function classifyRoleFlavors(request = '') {
417
+ const engineerFlavor = classifyEngineerFlavor(request);
418
+ const dataEngineerFlavor = classifyDataEngineerFlavor(request);
380
419
  return {
381
- engineer: classifyEngineerFlavor(request),
420
+ engineer: engineerFlavor && !['ai', 'platform', 'data'].includes(engineerFlavor) ? engineerFlavor : null,
421
+ aiEngineer: engineerFlavor === 'ai' ? 'core' : null,
422
+ platformEngineer: engineerFlavor === 'platform' ? 'core' : null,
382
423
  architect: classifyArchitectFlavor(request),
383
424
  productManager: isProductIntelligenceRequest(request) ? classifyProductManagerFlavor(request) : null,
384
425
  qa: classifyQaFlavor(request),
385
426
  security: classifySecurityFlavor(request),
386
427
  dataAnalyst: classifyDataAnalystFlavor(request),
387
- dataEngineer: classifyDataEngineerFlavor(request),
428
+ dataEngineer: dataEngineerFlavor,
429
+ businessStrategist: isBusinessStrategyRequest(request) ? 'core' : null,
388
430
  };
389
431
  }
390
432
 
391
433
  // One line per non-null flavor: "cx-<role>: loaded <role>.<flavor>
392
- // overlay". Verbose chat surface + cx_trace span attribute; lets a
434
+ // overlay". Verbose host surfaces + cx_trace span attribute; lets a
393
435
  // post-hoc reviewer see which overlays drove a given dispatch.
394
436
 
395
437
  export function formatOverlaySelection(roleFlavors) {
396
438
  if (!roleFlavors || typeof roleFlavors !== 'object') return [];
397
439
  const lines = [];
398
- for (const [role, flavor] of Object.entries(roleFlavors)) {
399
- if (!flavor) continue;
400
- const specialist = `cx-${role.replace(/([A-Z])/g, '-$1').toLowerCase()}`;
401
- lines.push(`${specialist}: loaded ${role}.${flavor} overlay`);
440
+ for (const [classifierKey, flavor] of Object.entries(roleFlavors)) {
441
+ const line = formatOverlayLine(classifierKey, flavor);
442
+ if (line) lines.push(line);
402
443
  }
403
444
  return lines;
404
445
  }
@@ -444,8 +485,16 @@ export function determineExecutionTrack({
444
485
  } = {}) {
445
486
  const intent = classifyIntent(request);
446
487
  const workCategory = classifyWorkCategory(request, riskFlags);
488
+ const text = String(request).toLowerCase();
489
+ const localWalkthrough = isExplorerRequest(request)
490
+ || /\b(?:explain|understand|what does|what is)\b[\s\S]{0,60}\b(?:how\b|do\b|does\b|works?\b|flow\b|path\b|layer\b|module\b|implementation\b|code\b|function\b)/i.test(text)
491
+ || /\bhow\b[\s\S]{0,40}\bworks?\b/i.test(text);
447
492
  if (explicitDrive) return EXECUTION_TRACKS.orchestrated;
448
- if (intent === INTENT_CLASSES.research && fileCount <= 1 && moduleCount <= 1) return EXECUTION_TRACKS.immediate;
493
+ if (intent === INTENT_CLASSES.research) {
494
+ if (localWalkthrough && fileCount <= 1 && moduleCount <= 1) return EXECUTION_TRACKS.immediate;
495
+ if (fileCount <= 1 && moduleCount <= 1) return EXECUTION_TRACKS.focused;
496
+ return EXECUTION_TRACKS.orchestrated;
497
+ }
449
498
  if (introducesContract || fileCount >= 3 || moduleCount >= 2) return EXECUTION_TRACKS.orchestrated;
450
499
  if (riskFlags.architecture || riskFlags.security || riskFlags.dataIntegrity || riskFlags.ai) return EXECUTION_TRACKS.orchestrated;
451
500
  if (workCategory === WORK_CATEGORIES.visual) return EXECUTION_TRACKS.focused;
@@ -465,6 +514,36 @@ export function determineExecutionTrack({
465
514
  return EXECUTION_TRACKS.focused;
466
515
  }
467
516
 
517
+ function refineEngineeringSpecialists(specialists, request = '') {
518
+ const engineerFlavor = classifyEngineerFlavor(request);
519
+ if (!engineerFlavor || !['ai', 'platform', 'data'].includes(engineerFlavor)) return specialists;
520
+ const replacement = {
521
+ ai: 'cx-ai-engineer',
522
+ platform: 'cx-platform-engineer',
523
+ data: 'cx-data-engineer',
524
+ }[engineerFlavor];
525
+ const set = new Set(specialists);
526
+ set.delete('cx-engineer');
527
+ set.add(replacement);
528
+ return [...set];
529
+ }
530
+
531
+ function suggestWorkflowType({ intent, request = '', docAuthoring } = {}) {
532
+ const text = String(request).toLowerCase();
533
+ const localWalkthrough = isExplorerRequest(request)
534
+ || /\b(?:explain|understand|what does|what is)\b[\s\S]{0,60}\b(?:how\b|do\b|does\b|works?\b|flow\b|path\b|layer\b|module\b|implementation\b|code\b|function\b)/i.test(text)
535
+ || /\bhow\b[\s\S]{0,40}\bworks?\b/i.test(text);
536
+ if (intent === INTENT_CLASSES.research && !localWalkthrough) {
537
+ return 'research-synthesis';
538
+ }
539
+ if (docAuthoring?.docType) {
540
+ const contract = resolveArtifactWorkflowContract(docAuthoring.docType);
541
+ const workflowType = WORKFLOW_SKILL_TO_TYPE[contract?.workflowSkill];
542
+ if (workflowType) return workflowType;
543
+ }
544
+ return null;
545
+ }
546
+
468
547
  export function selectSpecialists({ request = '', intent, track, riskFlags = detectRiskFlags(request), workCategory = classifyWorkCategory(request, riskFlags) } = {}) {
469
548
  const text = String(request).toLowerCase();
470
549
  const productRequest = isProductIntelligenceRequest(text);
@@ -474,6 +553,8 @@ export function selectSpecialists({ request = '', intent, track, riskFlags = det
474
553
  if (track === EXECUTION_TRACKS.focused) {
475
554
  if (workCategory === WORK_CATEGORIES.visual || riskFlags.ui) return ['cx-designer'];
476
555
  if (productRequest) return ['cx-product-manager'];
556
+ const docAuthoring = detectDocAuthoringIntent(text);
557
+ if (docAuthoring?.owner) return [docAuthoring.owner];
477
558
  if (dataEngineeringRequest) return ['cx-data-engineer'];
478
559
  if (dataAnalysisRequest) return ['cx-data-analyst'];
479
560
  if (isLegalComplianceRequest(text)) return ['cx-legal-compliance'];
@@ -482,13 +563,15 @@ export function selectSpecialists({ request = '', intent, track, riskFlags = det
482
563
  if (isRdLeadRequest(text)) return ['cx-rd-lead'];
483
564
  if (isExplorerRequest(text)) return ['cx-explorer'];
484
565
  if (riskFlags.docs) return ['cx-docs-keeper'];
485
- if (riskFlags.security && intent === INTENT_CLASSES.evaluation) return ['cx-security'];
486
- return SPECIALIST_MAP[intent] || ['cx-engineer'];
566
+ if (riskFlags.security && intent === INTENT_CLASSES.evaluation) return refineEngineeringSpecialists(['cx-security'], request);
567
+ return refineEngineeringSpecialists(SPECIALIST_MAP[intent] || ['cx-engineer'], request);
487
568
  }
488
569
 
489
570
  const specialists = ['cx-architect'];
490
571
  if (intent === INTENT_CLASSES.fix || intent === INTENT_CLASSES.investigation) specialists.push('cx-debugger');
491
572
  if (intent === INTENT_CLASSES.research) specialists.push('cx-researcher');
573
+ const docAuthoring = detectDocAuthoringIntent(text);
574
+ if (docAuthoring?.owner) specialists.push(docAuthoring.owner);
492
575
  if (workCategory === WORK_CATEGORIES.visual || riskFlags.ui) specialists.push('cx-designer');
493
576
  if (productRequest) specialists.push('cx-product-manager');
494
577
  if (dataAnalysisRequest) specialists.push('cx-data-analyst');
@@ -496,7 +579,56 @@ export function selectSpecialists({ request = '', intent, track, riskFlags = det
496
579
  else if (riskFlags.docs) specialists.push('cx-docs-keeper');
497
580
  specialists.push('cx-engineer', 'cx-reviewer', 'cx-qa');
498
581
  if (riskFlags.security || riskFlags.dataIntegrity) specialists.push('cx-security');
499
- return Array.from(new Set(specialists));
582
+ return refineEngineeringSpecialists(Array.from(new Set(specialists)), request);
583
+ }
584
+
585
+ export function augmentSpecialists(
586
+ specialists = [],
587
+ {
588
+ request = '',
589
+ docAuthoring = null,
590
+ externalResearch = null,
591
+ framingChallenge = null,
592
+ artifactReview = null,
593
+ triggers = [],
594
+ } = {},
595
+ ) {
596
+ let list = [...specialists];
597
+ if (docAuthoring?.owner && !list.includes(docAuthoring.owner)) {
598
+ list = [docAuthoring.owner, ...list];
599
+ }
600
+ if (externalResearch?.required && !list.includes('cx-researcher')) {
601
+ list = ['cx-researcher', ...list];
602
+ }
603
+ if (framingChallenge?.required && !list.includes('cx-devil-advocate')) {
604
+ list = ['cx-devil-advocate', ...list];
605
+ }
606
+ for (const reviewer of artifactReview?.requiredReviewers || []) {
607
+ if (!list.includes(reviewer)) list = [...list, reviewer];
608
+ }
609
+ if (isLegalComplianceRequest(request) && !list.includes('cx-legal-compliance')) {
610
+ list = ['cx-legal-compliance', ...list];
611
+ }
612
+ if (isRdLeadRequest(request) && !list.includes('cx-rd-lead')) {
613
+ list = ['cx-rd-lead', ...list];
614
+ }
615
+ if (isBusinessStrategyRequest(request) && !list.includes('cx-business-strategist')) {
616
+ list = ['cx-business-strategist', ...list];
617
+ }
618
+ for (const { specialist } of triggers) {
619
+ if (!list.includes(specialist)) list = [specialist, ...list];
620
+ }
621
+ return Array.from(new Set(list));
622
+ }
623
+
624
+ function enrichPolicyForProjectQuestion(request, policySpecialists = []) {
625
+ if (!/\b(what is this (project|repo|codebase)|what('s| is) this (project|repo|codebase)|describe this (project|repo|codebase))\b/i.test(String(request))) {
626
+ return policySpecialists;
627
+ }
628
+ const list = [...policySpecialists];
629
+ if (!list.includes('cx-explorer')) list.unshift('cx-explorer');
630
+ if (!list.includes('cx-researcher')) list.splice(list.indexOf('cx-explorer') + 1, 0, 'cx-researcher');
631
+ return Array.from(new Set(list));
500
632
  }
501
633
 
502
634
  /**
@@ -598,7 +730,7 @@ export function requestSignals(request = '', context = {}) {
598
730
  // pairs for specialists that should engage PRE-DISPATCH based on signals —
599
731
  // separate from the keyword-only paths in selectSpecialists. The watch
600
732
  // predicates and their specialist owners are declared in
601
- // specialists/registry.json (watchConditions) and evaluated by
733
+ // specialists/org (watchConditions) and evaluated by
602
734
  // orchestration/routing-tables.mjs.
603
735
 
604
736
  export function proactiveTriggers(signals) {
@@ -667,6 +799,159 @@ function resolveArtifactReviewRequirements(docAuthoring) {
667
799
  };
668
800
  }
669
801
 
802
+ // Map a free-text request to the decision names that gate it. Keyed against the
803
+ // union of every team's forbiddenDecisions so a BLOCKED status fires only when
804
+ // the request actually asks for a decision the primary team cannot make. Ordered
805
+ // most-specific-first (deployment-timing before deployment) so the narrow match
806
+ // wins.
807
+
808
+ const REQUESTED_DECISION_PATTERNS = [
809
+ [/\bsecurity[ -]?override\b|\boverride\s+(the\s+)?security\b/i, 'security-override'],
810
+ [/\bdeployment[ -]?timing\b|\bwhen\s+to\s+deploy\b|\bdeploy\s+(?:immediately|now)\b/i, 'deployment-timing'],
811
+ [/\bdeployment[ -]?readiness\b/i, 'deployment-readiness'],
812
+ [/\bdeploy(?:ment|ing|s)?\b|\brelease\s+to\s+prod/i, 'deployment'],
813
+ [/\binfra(?:structure)?[ -]?change\b|\bchange\s+(?:the\s+)?infra/i, 'infra-change'],
814
+ [/\bscope[ -]?change\b|\bchange\s+(?:the\s+)?scope\b|\bre-?scope\b/i, 'scope-change'],
815
+ [/\bproduct[ -]?scope\b/i, 'product-scope'],
816
+ [/\buser[ -]?research\s+method/i, 'user-research-methods'],
817
+ [/\buser[ -]?research\b/i, 'user-research'],
818
+ [/\bimplementation[ -]?approach\b/i, 'implementation-approach'],
819
+ [/\bimplementation[ -]?detail/i, 'implementation-details'],
820
+ [/\bsecurity[ -]?policy\b/i, 'security-policy'],
821
+ [/\bops[ -]?procedure|operational\s+procedure/i, 'ops-procedures'],
822
+ [/\barchitect/i, 'architecture'],
823
+ ];
824
+
825
+ function detectRequestedDecisions(request = '') {
826
+ const text = String(request || '');
827
+ const found = new Set();
828
+ for (const [pattern, decision] of REQUESTED_DECISION_PATTERNS) {
829
+ if (pattern.test(text)) found.add(decision);
830
+ }
831
+ return Array.from(found);
832
+ }
833
+
834
+ /**
835
+ * Build team-aware routing metadata (RFC-0004 §2).
836
+ * Returns { primaryTeam, involvedTeams, requiredApprovals, escalationPath, blockedStatus }.
837
+ *
838
+ * The primary team is intent-driven (INTENT_TO_TEAM), falling back to the first
839
+ * specialist's team when the intent has no mapping. involvedTeams unions the
840
+ * primary team with every selected specialist's team. blockedStatus fires when
841
+ * the primary team's forbiddenDecisions intersect the decisions the request asks
842
+ * for; escalation walks the primary team's path first. Team membership and team
843
+ * metadata resolve from specialists/org.
844
+ */
845
+ export function teamRoutingForSpecialists(specialists = [], { intent = null, request = '', cwd = null, docAuthoring = null } = {}) {
846
+ let registry = null;
847
+ try {
848
+ registry = loadRegistry();
849
+ } catch {
850
+ return {
851
+ primaryTeam: null,
852
+ involvedTeams: [],
853
+ requiredApprovals: [],
854
+ escalationPath: [],
855
+ blockedStatus: null,
856
+ };
857
+ }
858
+
859
+ const profile = cwd ? resolveActiveScope(cwd) : null;
860
+ const profileTeams = scopeTeamsById(profile);
861
+
862
+ const teams = new Map();
863
+ const involvedTeamIds = new Set();
864
+ const addTeam = (teamId) => {
865
+ if (!teamId) return;
866
+ involvedTeamIds.add(teamId);
867
+ if (teams.has(teamId)) return;
868
+ const profileTeam = profileTeams ? resolveScopeTeamMeta(teamId, profile) : null;
869
+ teams.set(teamId, profileTeam || registry.teams?.[teamId] || null);
870
+ };
871
+
872
+ for (const specialistId of specialists) {
873
+ const cxId = specialistId.startsWith('cx-') ? specialistId : `cx-${specialistId}`;
874
+ const specialist = registry.specialists?.[cxId];
875
+ if (specialist?.team) addTeam(specialist.team);
876
+ }
877
+
878
+ // RFC-0004 §2 step 2: intent selects the primary owning team. It always counts
879
+ // as involved even if no selected specialist sits on it yet.
880
+ const profileIntentTeam = resolveIntentTeamForScope(intent, profile);
881
+ const intentTeam = profileIntentTeam
882
+ ?? (intent && INTENT_TO_TEAM[intent] ? INTENT_TO_TEAM[intent] : null);
883
+ addTeam(intentTeam);
884
+
885
+ const involvedTeams = Array.from(involvedTeamIds).sort();
886
+ let primaryTeam = intentTeam || (involvedTeams.length > 0 ? involvedTeams[0] : null);
887
+
888
+ if (docAuthoring?.owner) {
889
+ const cxId = docAuthoring.owner.startsWith('cx-') ? docAuthoring.owner : `cx-${docAuthoring.owner}`;
890
+ const ownerTeam = registry.specialists?.[cxId]?.team;
891
+ if (ownerTeam) {
892
+ addTeam(ownerTeam);
893
+ primaryTeam = ownerTeam;
894
+ }
895
+ }
896
+
897
+ // Collect required approvals from involved teams' decision rights.
898
+ const requiredApprovals = new Set();
899
+ for (const teamId of involvedTeamIds) {
900
+ const team = teams.get(teamId);
901
+ if (team?.decisionRights) {
902
+ for (const decision of team.decisionRights) requiredApprovals.add(decision);
903
+ }
904
+ }
905
+
906
+ // RFC-0004 §2 step 5: BLOCKED when the primary team forbids a decision the
907
+ // request actually asks for. Escalate via that team's path.
908
+ let blockedStatus = null;
909
+ const primaryTeamObj = primaryTeam ? (teams.get(primaryTeam) || registry.teams?.[primaryTeam]) : null;
910
+ if (Array.isArray(primaryTeamObj?.forbiddenDecisions)) {
911
+ const blocked = detectRequestedDecisions(request)
912
+ .filter((decision) => primaryTeamObj.forbiddenDecisions.includes(decision));
913
+ if (blocked.length > 0) {
914
+ blockedStatus = {
915
+ team: primaryTeam,
916
+ forbiddenDecisions: blocked,
917
+ escalationPath: primaryTeamObj.escalationPath || [],
918
+ };
919
+ }
920
+ }
921
+
922
+ // Concatenate escalation paths, primary team first, de-duplicated.
923
+ const escalationPath = [];
924
+ const seen = new Set();
925
+ const orderedTeams = primaryTeam
926
+ ? [primaryTeam, ...involvedTeams.filter((t) => t !== primaryTeam)]
927
+ : involvedTeams;
928
+ for (const teamId of orderedTeams) {
929
+ const team = teams.get(teamId) || registry.teams?.[teamId];
930
+ if (Array.isArray(team?.escalationPath)) {
931
+ for (const role of team.escalationPath) {
932
+ if (!seen.has(role)) {
933
+ escalationPath.push(role);
934
+ seen.add(role);
935
+ }
936
+ }
937
+ }
938
+ }
939
+
940
+ const squadId = primaryTeamObj?.kind === 'squad' ? primaryTeam : null;
941
+ const groupId = primaryTeamObj?.kind === 'group' ? primaryTeam : (primaryTeamObj?.groupId ?? null);
942
+
943
+ return {
944
+ primaryTeam,
945
+ squadId,
946
+ groupId,
947
+ collaborators: primaryTeamObj?.collaborators || [],
948
+ involvedTeams,
949
+ requiredApprovals: Array.from(requiredApprovals).sort(),
950
+ escalationPath,
951
+ blockedStatus,
952
+ };
953
+ }
954
+
670
955
  export function routeRequest(options = {}) {
671
956
  const intent = classifyIntent(options.request);
672
957
  const riskFlags = detectRiskFlags(options.request);
@@ -676,67 +961,65 @@ export function routeRequest(options = {}) {
676
961
  : null;
677
962
  const workCategory = classifyWorkCategory(options.request, riskFlags);
678
963
  const track = determineExecutionTrack({ ...options, riskFlags });
679
- let specialists = selectSpecialists({ ...options, intent, track, riskFlags, workCategory });
680
964
  const docAuthoring = detectDocAuthoringIntent(options.request);
681
965
  const externalResearch = requiresExternalResearch({ request: options.request, workCategory, riskFlags });
682
966
  const framingChallenge = requiresFramingChallenge({ request: options.request, workCategory, riskFlags, introducesContract: options.introducesContract });
683
-
684
- // Doc ownership: the owning specialist authors; orchestrator routes.
685
- if (docAuthoring?.owner && !specialists.includes(docAuthoring.owner)) {
686
- specialists = [docAuthoring.owner, ...specialists];
687
- }
688
- // External research must precede authoring.
689
- if (externalResearch.required && !specialists.includes('cx-researcher')) {
690
- specialists = ['cx-researcher', ...specialists];
691
- }
692
- // Framing challenge must precede scaffolding.
693
- if (framingChallenge.required && !specialists.includes('cx-devil-advocate')) {
694
- specialists = ['cx-devil-advocate', ...specialists];
695
- }
696
-
697
967
  const artifactReview = resolveArtifactReviewRequirements(docAuthoring);
698
- for (const reviewer of artifactReview.requiredReviewers) {
699
- if (!specialists.includes(reviewer)) specialists = [...specialists, reviewer];
700
- }
701
- // Pre-dispatch specialists that surface concerns before architecture locks in.
702
- // Order matters: business framing → R&D validation → legal/compliance review,
703
- // each prepended so it runs earliest in the chain.
704
- if (isLegalComplianceRequest(options.request) && !specialists.includes('cx-legal-compliance')) {
705
- specialists = ['cx-legal-compliance', ...specialists];
706
- }
707
- if (isRdLeadRequest(options.request) && !specialists.includes('cx-rd-lead')) {
708
- specialists = ['cx-rd-lead', ...specialists];
709
- }
710
- if (isBusinessStrategyRequest(options.request) && !specialists.includes('cx-business-strategist')) {
711
- specialists = ['cx-business-strategist', ...specialists];
712
- }
713
-
714
- // Signal-driven proactive triggers — surfaces specialists whose engagement
715
- // hinges on structured signals rather than literal keyword matches. The
716
- // routing list is union'd with the keyword paths so neither dimension
717
- // drops a legitimate dispatch.
718
-
968
+ const suggestedWorkflowType = suggestWorkflowType({ intent, request: options.request, docAuthoring });
969
+ const researchExecutionPolicy = intent === INTENT_CLASSES.research || externalResearch?.required
970
+ ? buildResearchExecutionPolicy({ request: options.request })
971
+ : null;
719
972
  const signals = requestSignals(options.request, options.context);
720
973
  const triggers = proactiveTriggers(signals);
721
974
  const reasons = {};
722
975
  for (const { specialist, reason } of triggers) {
723
- if (!specialists.includes(specialist)) specialists = [specialist, ...specialists];
724
976
  reasons[specialist] = reason;
725
977
  }
726
- specialists = Array.from(new Set(specialists));
978
+
979
+ const augmentOpts = {
980
+ request: options.request,
981
+ docAuthoring,
982
+ externalResearch,
983
+ framingChallenge,
984
+ artifactReview,
985
+ triggers,
986
+ };
987
+
988
+ let specialists = augmentSpecialists(
989
+ selectSpecialists({ ...options, intent, track, riskFlags, workCategory }),
990
+ augmentOpts,
991
+ );
992
+
993
+ const policyTrack = track === EXECUTION_TRACKS.immediate ? EXECUTION_TRACKS.focused : track;
994
+ let policySpecialists = augmentSpecialists(
995
+ selectSpecialists({ ...options, intent, track: policyTrack, riskFlags, workCategory }),
996
+ augmentOpts,
997
+ );
998
+ policySpecialists = enrichPolicyForProjectQuestion(options.request, policySpecialists);
999
+
1000
+ const displaySpecialists = specialists.length ? specialists : policySpecialists;
727
1001
 
728
1002
  const contractChain = resolveContractChain({
729
1003
  intent,
730
1004
  workCategory,
731
1005
  track,
732
1006
  riskFlags,
733
- specialists,
1007
+ specialists: displaySpecialists,
734
1008
  framingChallenge,
735
1009
  externalResearch,
736
1010
  docAuthoring,
737
1011
  artifactReview,
738
1012
  });
739
1013
 
1014
+ // Team-aware routing: analyze specialist-to-team mapping and identify
1015
+ // team involvement, primary owner, required approvals, and escalation paths.
1016
+ const teamRouting = teamRoutingForSpecialists(displaySpecialists, {
1017
+ intent,
1018
+ request: options.request,
1019
+ cwd: options.cwd ?? null,
1020
+ docAuthoring,
1021
+ });
1022
+
740
1023
  const route = {
741
1024
  intent,
742
1025
  workCategory,
@@ -745,6 +1028,8 @@ export function routeRequest(options = {}) {
745
1028
  productFlavor,
746
1029
  roleFlavors,
747
1030
  specialists,
1031
+ policySpecialists,
1032
+ displaySpecialists,
748
1033
  signals,
749
1034
  triggers,
750
1035
  dispatchReasons: reasons,
@@ -752,9 +1037,12 @@ export function routeRequest(options = {}) {
752
1037
  externalResearch,
753
1038
  framingChallenge,
754
1039
  artifactReview,
1040
+ suggestedWorkflowType,
1041
+ researchExecutionPolicy,
755
1042
  contractChain,
756
- dispatchPlan: buildDispatchPlan({ track, intent, specialists }),
757
- dispatchSummary: buildDispatchSummary({ specialists, reasons }),
1043
+ teamRouting,
1044
+ dispatchPlan: buildDispatchPlan({ track, intent, specialists: displaySpecialists }),
1045
+ dispatchSummary: buildDispatchSummary({ specialists: displaySpecialists, reasons }),
758
1046
  };
759
1047
 
760
1048
  if (process.env.CONSTRUCT_VERBOSE === '1' && triggers.length > 0) {
@@ -777,7 +1065,7 @@ export function routeRequestVerified(options = {}) {
777
1065
  }
778
1066
 
779
1067
  /**
780
- * Build the construct→orchestrator contract packet (specialists/contracts.json).
1068
+ * Build the construct→orchestrator contract packet (specialists/org).
781
1069
  * Callers must pass this object to agent_contract — not a bare goal string.
782
1070
  */
783
1071
  export function buildConstructToOrchestratorPacket(options = {}) {
@@ -801,6 +1089,7 @@ export function buildConstructToOrchestratorPacket(options = {}) {
801
1089
  intent: route.intent,
802
1090
  workCategory: route.workCategory,
803
1091
  riskFlags: route.riskFlags || {},
1092
+ suggestedWorkflowType: route.suggestedWorkflowType || null,
804
1093
  acceptanceCriteria,
805
1094
  };
806
1095
  }
@@ -1,7 +1,6 @@
1
1
  /**
2
2
  * lib/overrides/resolver.mjs — single override + backup helper for every
3
- * user-customizable Construct primitive (personas, skills, rules,
4
- * contracts, role manifests).
3
+ * user-customizable Construct primitive (personas, agents, skills, rules).
5
4
  *
6
5
  * Convention:
7
6
  * - Original lives in the install (`personas/<n>.md`, `skills/.../<n>.md`, …)
@@ -32,8 +31,6 @@ export const SUPPORTED_CATEGORIES = Object.freeze([
32
31
  'agents',
33
32
  'skills',
34
33
  'rules',
35
- 'contracts',
36
- 'role-manifests',
37
34
  ]);
38
35
 
39
36
  const CATEGORY_RULES = {
@@ -41,8 +38,6 @@ const CATEGORY_RULES = {
41
38
  agents: { originalDir: 'specialists/prompts', defaultExt: '.md' },
42
39
  skills: { originalDir: 'skills', defaultExt: '.md' },
43
40
  rules: { originalDir: 'rules', defaultExt: '.md' },
44
- contracts: { originalDir: 'specialists', defaultExt: '.json', singleFile: 'contracts.json' },
45
- 'role-manifests': { originalDir: 'specialists', defaultExt: '.json', singleFile: 'role-manifests.json' },
46
41
  };
47
42
 
48
43
  function categoryRule(category) {
@@ -69,18 +64,12 @@ function ensureCxIgnore(projectRoot) {
69
64
 
70
65
  function originalPath(projectRoot, category, name) {
71
66
  const rule = categoryRule(category);
72
- if (rule.singleFile) {
73
- return path.join(projectRoot, rule.originalDir, rule.singleFile);
74
- }
75
67
  const ext = name.includes('.') ? '' : rule.defaultExt;
76
68
  return path.join(projectRoot, rule.originalDir, `${name}${ext}`);
77
69
  }
78
70
 
79
71
  function overridePath(projectRoot, category, name) {
80
72
  const rule = categoryRule(category);
81
- if (rule.singleFile) {
82
- return path.join(projectRoot, '.cx', category, rule.singleFile);
83
- }
84
73
  const ext = name.includes('.') ? '' : rule.defaultExt;
85
74
  return path.join(projectRoot, '.cx', category, `${name}${ext}`);
86
75
  }