@geraldmaron/construct 1.2.3 → 1.3.1
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.
- package/README.md +7 -10
- package/bin/construct +235 -209
- package/bin/construct-postinstall.mjs +0 -21
- package/commands/work/optimize-prompts.md +1 -1
- package/examples/distribution/sources/adr.md +2 -2
- package/examples/seed-observations/decisions.md +1 -1
- package/lib/artifact-loop-core.mjs +412 -0
- package/lib/artifact-manifest.mjs +6 -0
- package/lib/artifact-release-gate.mjs +115 -49
- package/lib/audit-rules.mjs +2 -4
- package/lib/audit-skills.mjs +32 -20
- package/lib/audit-specialists.mjs +44 -26
- package/lib/auto-docs.mjs +6 -5
- package/lib/brand-prose.mjs +3 -3
- package/lib/brand-tokens.mjs +2 -2
- package/lib/certification/artifact-fixtures.mjs +4 -1
- package/lib/certification/demo-parity.mjs +6 -32
- package/lib/certification/real-llm-scenarios.mjs +58 -13
- package/lib/certification/role-cards.mjs +7 -6
- package/lib/certification/role-overlays.mjs +4 -4
- package/lib/certification/runner.mjs +9 -2
- package/lib/certification/skill-inventory.mjs +34 -22
- package/lib/certification/skill-scenarios.mjs +21 -8
- package/lib/certification/specialist-contracts.mjs +4 -3
- package/lib/certification/specialist-scenarios.mjs +7 -6
- package/lib/certification/status.mjs +5 -4
- package/lib/cli-commands.mjs +55 -54
- package/lib/comment-lint.mjs +1 -5
- package/lib/completions.mjs +20 -2
- package/lib/config/legacy-config-migration.mjs +90 -24
- package/lib/config/schema.mjs +5 -5
- package/lib/config/source-targets.mjs +80 -0
- package/lib/contracts/validate.mjs +119 -51
- package/lib/decisions/golden.mjs +3 -2
- package/lib/decisions/registry.mjs +11 -6
- package/lib/demo-project.mjs +188 -0
- package/lib/demo-recording.mjs +9 -34
- package/lib/demo-script.mjs +2 -2
- package/lib/demo-surface.mjs +13 -131
- package/lib/demo-tour-renderer.mjs +92 -0
- package/lib/demo.mjs +69 -54
- package/lib/diagram-export.mjs +63 -14
- package/lib/doctor/cli.mjs +12 -2
- package/lib/doctor/source-checkout.mjs +3 -4
- package/lib/doctor/watchers/consistency.mjs +148 -43
- package/lib/doctor/watchers/credential-parity.mjs +97 -0
- package/lib/doctor/watchers/mcp-protocol.mjs +1 -1
- package/lib/doctor/watchers/service-health.mjs +4 -32
- package/lib/document-export.mjs +73 -9
- package/lib/document-extract.mjs +10 -198
- package/lib/embed/artifact.mjs +2 -3
- package/lib/embed/cli.mjs +1 -1
- package/lib/embed/config.mjs +1 -2
- package/lib/embed/customer-profiles.mjs +1 -1
- package/lib/embed/daemon.mjs +5 -6
- package/lib/embed/demand-fetch.mjs +114 -2
- package/lib/embed/docs-lifecycle.mjs +9 -5
- package/lib/embed/intake-metrics.mjs +2 -2
- package/lib/embed/notifications.mjs +2 -3
- package/lib/embed/recommendation-store.mjs +25 -22
- package/lib/embed/role-framing.mjs +4 -9
- package/lib/embedded-contract/capability.mjs +4 -2
- package/lib/embedded-contract/contract-version.mjs +1 -1
- package/lib/env-config.mjs +2 -2
- package/lib/flavors/loader.mjs +21 -19
- package/lib/graph/build-from-registry.mjs +31 -7
- package/lib/graph/staleness.mjs +1 -1
- package/lib/headhunt.mjs +82 -35
- package/lib/hooks/agent-tracker.mjs +2 -2
- package/lib/hooks/config-protection.mjs +1 -1
- package/lib/hooks/registry-sync.mjs +3 -3
- package/lib/host-capabilities.mjs +5 -5
- package/lib/improvement/controller.mjs +2 -2
- package/lib/init-unified.mjs +19 -21
- package/lib/intake/classify.mjs +26 -0
- package/lib/intake/daemon.mjs +2 -3
- package/lib/intake/prepare.mjs +10 -3
- package/lib/intake/session-prelude.mjs +1 -1
- package/lib/intake/tables/creative.mjs +9 -9
- package/lib/intake/tables/operations.mjs +4 -4
- package/lib/intake/tables/research.mjs +2 -2
- package/lib/integrations/intake-integrations.mjs +9 -10
- package/lib/knowledge/research-store.mjs +2 -2
- package/lib/mcp/server.mjs +104 -61
- package/lib/mcp/tool-budget.mjs +1 -46
- package/lib/mcp/tool-recovery.mjs +44 -0
- package/lib/mcp/tools/artifact-author.mjs +36 -0
- package/lib/mcp/tools/find-tool.mjs +86 -0
- package/lib/mcp/tools/orchestration-run.mjs +107 -69
- package/lib/mcp/tools/project.mjs +4 -3
- package/lib/mcp/tools/{profile.mjs → scope.mjs} +54 -52
- package/lib/mcp/tools/skills.mjs +39 -22
- package/lib/mcp/tools/telemetry.mjs +2 -1
- package/lib/mcp/tools/workflow.mjs +1 -1
- package/lib/mcp-platform-config.mjs +7 -5
- package/lib/migrations/index.mjs +4 -2
- package/lib/migrations/v2-unified-registry.mjs +35 -0
- package/lib/model-router.mjs +203 -36
- package/lib/models/catalog.mjs +25 -9
- package/lib/models/execution-capability-profile.mjs +3 -3
- package/lib/models/execution-policy.mjs +7 -6
- package/lib/models/provider-poll.mjs +18 -4
- package/lib/opencode-config.mjs +56 -1
- package/lib/opencode-runtime-plugin.mjs +13 -10
- package/lib/oracle/artifact-gate.mjs +14 -4
- package/lib/oracle/cli.mjs +2 -0
- package/lib/oracle/dispatch.mjs +18 -1
- package/lib/oracle/execute.mjs +39 -7
- package/lib/oracle/index.mjs +1 -1
- package/lib/oracle/org-graph.mjs +10 -5
- package/lib/oracle/policy.mjs +6 -0
- package/lib/oracle/read-model.mjs +103 -6
- package/lib/oracle/reconcile.mjs +31 -4
- package/lib/oracle/remediation-dispatch.mjs +53 -0
- package/lib/oracle/routing.mjs +5 -0
- package/lib/oracle/synthesize.mjs +80 -3
- package/lib/orchestration/routing-tables.mjs +44 -10
- package/lib/orchestration/runtime.mjs +2 -0
- package/lib/orchestration/worker.mjs +1 -1
- package/lib/orchestration-policy.mjs +351 -62
- package/lib/overrides/resolver.mjs +1 -12
- package/lib/parity.mjs +37 -11
- package/lib/policy/engine.mjs +80 -15
- package/lib/prompt-composer.js +51 -15
- package/lib/prompt-metadata.mjs +3 -2
- package/lib/providers/connection-probe.mjs +58 -0
- package/lib/providers/copilot-auth.mjs +1 -1
- package/lib/providers/credential-bootstrap.mjs +1 -1
- package/lib/providers/op-run.mjs +3 -4
- package/lib/providers/secret-resolver.mjs +31 -0
- package/lib/publish-tooling.mjs +3 -11
- package/lib/publish.mjs +12 -29
- package/lib/reconcile/mcp-entry-reconcile.mjs +14 -9
- package/lib/reflect.mjs +2 -2
- package/lib/registry/agent-manifest.mjs +190 -0
- package/lib/registry/assemble.mjs +133 -0
- package/lib/registry/catalog.mjs +171 -0
- package/lib/registry/cli.mjs +590 -6
- package/lib/registry/consolidation.mjs +5 -4
- package/lib/registry/docs-sync.mjs +67 -0
- package/lib/registry/loader.mjs +147 -0
- package/lib/registry/org-io.mjs +76 -0
- package/lib/registry/retired-paths.mjs +71 -0
- package/lib/registry/surface-map.mjs +5 -7
- package/lib/registry/validator.mjs +438 -0
- package/lib/research-execution-policy.mjs +173 -0
- package/lib/roles/catalog.mjs +4 -9
- package/lib/roles/fence.mjs +107 -1
- package/lib/roles/flavor-bindings.mjs +68 -0
- package/lib/roles/gateway.mjs +140 -29
- package/lib/roles/manifest.mjs +22 -13
- package/lib/roles/router.mjs +1 -1
- package/lib/scopes/enrich.mjs +67 -0
- package/lib/scopes/hooks.mjs +12 -0
- package/lib/{profiles → scopes}/lifecycle.mjs +70 -70
- package/lib/scopes/loader.mjs +104 -0
- package/lib/scopes/rebrand.mjs +32 -0
- package/lib/scopes/research-profile.mjs +16 -0
- package/lib/scopes/teams.mjs +98 -0
- package/lib/service-manager.mjs +1 -117
- package/lib/setup-prompts.mjs +1 -1
- package/lib/setup.mjs +6 -26
- package/lib/skills/composition-graph.mjs +98 -0
- package/lib/skills/router.mjs +80 -0
- package/lib/specialist-contracts.mjs +17 -18
- package/lib/specialists/postconditions.mjs +2 -2
- package/lib/specialists/prompt-schema.mjs +6 -5
- package/lib/specialists/roster.mjs +7 -12
- package/lib/specialists/schema.mjs +9 -6
- package/lib/status.mjs +25 -90
- package/lib/storage/file-lock.mjs +6 -3
- package/lib/telemetry/skill-calls.mjs +1 -1
- package/lib/templates/doc-presentation.mjs +63 -0
- package/lib/templates/visual-requirements.mjs +35 -2
- package/lib/term-format.mjs +107 -2
- package/lib/test-env-setup.mjs +21 -0
- package/lib/ui/components.mjs +42 -0
- package/lib/ui/glyphs.mjs +58 -0
- package/lib/ui/links.mjs +115 -0
- package/lib/ui/theme.mjs +108 -0
- package/lib/uninstall/uninstall.mjs +2 -1
- package/lib/validator.mjs +45 -8
- package/lib/validators/skill-effectiveness.mjs +174 -0
- package/lib/validators/skills.mjs +1 -1
- package/package.json +12 -8
- package/personas/construct.md +12 -3
- package/platforms/claude/CLAUDE.md +1 -1
- package/rules/common/beads-hygiene.md +52 -0
- package/rules/common/neurodivergent-output.md +4 -7
- package/rules/common/research.md +2 -0
- package/scripts/sync-specialists.mjs +269 -51
- package/skills/ai/prompt-optimizer.md +3 -3
- package/skills/brand/output-vibe.md +48 -0
- package/skills/docs/adr-workflow.md +3 -0
- package/skills/docs/backlog-proposal-workflow.md +3 -0
- package/skills/docs/codebase-research-workflow.md +5 -2
- package/skills/docs/customer-profile-workflow.md +3 -0
- package/skills/docs/document-ingest-workflow.md +3 -0
- package/skills/docs/evidence-ingest-workflow.md +4 -1
- package/skills/docs/init-project.md +1 -1
- package/skills/docs/prd-workflow.md +1 -1
- package/skills/docs/prfaq-workflow.md +3 -0
- package/skills/docs/product-intelligence-workflow.md +4 -1
- package/skills/docs/product-signal-workflow.md +3 -0
- package/skills/docs/research-workflow.md +13 -6
- package/skills/docs/runbook-workflow.md +3 -0
- package/skills/docs/strategy-workflow.md +3 -0
- package/skills/docs/user-research-workflow.md +6 -3
- package/skills/operating/orchestration-reference.md +1 -1
- package/skills/roles/{engineer.ai.md → ai-engineer.md} +2 -2
- package/skills/roles/architect.ai-systems.md +1 -1
- package/skills/roles/architect.data.md +1 -1
- package/skills/roles/architect.enterprise.md +1 -1
- package/skills/roles/architect.integration.md +1 -1
- package/skills/roles/architect.md +1 -1
- package/skills/roles/architect.platform.md +1 -1
- package/skills/roles/{product-manager.business-strategy.md → business-strategist.md} +3 -3
- package/skills/roles/data-analyst.experiment.md +1 -1
- package/skills/roles/data-analyst.md +1 -1
- package/skills/roles/data-analyst.product-intelligence.md +1 -1
- package/skills/roles/data-analyst.product.md +1 -1
- package/skills/roles/data-analyst.telemetry.md +1 -1
- package/skills/roles/{engineer.data.md → data-engineer.md} +2 -2
- package/skills/roles/data-engineer.pipeline.md +2 -2
- package/skills/roles/data-engineer.vector-retrieval.md +2 -2
- package/skills/roles/data-engineer.warehouse.md +2 -2
- package/skills/roles/debugger.md +1 -1
- package/skills/roles/designer.accessibility.md +1 -1
- package/skills/roles/designer.md +1 -1
- package/skills/roles/{reviewer.devil-advocate.md → devil-advocate.md} +2 -2
- package/skills/roles/{operator.docs.md → docs-keeper.md} +3 -3
- package/skills/roles/engineer.md +3 -7
- package/skills/roles/{reviewer.evaluator.md → evaluator.md} +2 -2
- package/skills/roles/{researcher.explorer.md → explorer.md} +2 -2
- package/skills/roles/{operator.md → operations.md} +2 -5
- package/skills/roles/orchestrator.md +1 -1
- package/skills/roles/{engineer.platform.md → platform-engineer.md} +2 -2
- package/skills/roles/product-manager.ai-product.md +1 -1
- package/skills/roles/product-manager.enterprise.md +1 -1
- package/skills/roles/product-manager.growth.md +1 -2
- package/skills/roles/product-manager.md +1 -2
- package/skills/roles/product-manager.platform.md +1 -1
- package/skills/roles/product-manager.product.md +1 -1
- package/skills/roles/qa.ai-eval.md +1 -1
- package/skills/roles/qa.api-contract.md +1 -1
- package/skills/roles/qa.data-pipeline.md +1 -1
- package/skills/roles/qa.md +1 -1
- package/skills/roles/qa.web-ui.md +1 -1
- package/skills/roles/{operator.release.md → release-manager.md} +3 -3
- package/skills/roles/researcher.md +1 -1
- package/skills/roles/reviewer.md +1 -1
- package/skills/roles/security.ai.md +1 -1
- package/skills/roles/security.appsec.md +1 -1
- package/skills/roles/security.cloud.md +1 -1
- package/skills/roles/security.legal-compliance.md +1 -1
- package/skills/roles/security.md +1 -1
- package/skills/roles/security.privacy.md +1 -1
- package/skills/roles/security.supply-chain.md +1 -1
- package/skills/roles/{operator.sre.md → sre.md} +3 -3
- package/skills/roles/{qa.test-automation.md → test-automation.md} +2 -2
- package/skills/roles/{reviewer.trace.md → trace-reviewer.md} +2 -2
- package/skills/roles/{researcher.ux.md → ux-researcher.md} +2 -2
- package/skills/routing.json +18 -0
- package/skills/routing.md +1 -1
- package/specialists/artifact-manifest.json +2 -1
- package/specialists/audit-enrichments.json +14 -14
- package/specialists/org/contracts/accessibility-to-qa.json +37 -0
- package/specialists/org/contracts/any-to-business-strategist.json +57 -0
- package/specialists/org/contracts/any-to-debugger.json +38 -0
- package/specialists/org/contracts/any-to-designer.json +33 -0
- package/specialists/org/contracts/any-to-docs-keeper.json +34 -0
- package/specialists/org/contracts/any-to-explorer.json +39 -0
- package/specialists/org/contracts/any-to-sre-incident.json +33 -0
- package/specialists/org/contracts/any-to-trace-reviewer.json +32 -0
- package/specialists/org/contracts/architect-to-ai-engineer.json +32 -0
- package/specialists/org/contracts/architect-to-data-engineer.json +52 -0
- package/specialists/org/contracts/architect-to-devil-advocate.json +38 -0
- package/specialists/org/contracts/architect-to-engineer.json +34 -0
- package/specialists/org/contracts/architect-to-evaluator.json +59 -0
- package/specialists/org/contracts/architect-to-legal-compliance.json +55 -0
- package/specialists/org/contracts/architect-to-operations.json +45 -0
- package/specialists/org/contracts/architect-to-platform-engineer.json +42 -0
- package/specialists/org/contracts/business-strategist-to-product-manager.json +39 -0
- package/specialists/org/contracts/construct-to-orchestrator.json +36 -0
- package/specialists/org/contracts/construct-to-rd-lead.json +53 -0
- package/specialists/org/contracts/data-analyst-to-product-manager.json +43 -0
- package/specialists/org/contracts/data-engineer-to-platform-engineer.json +36 -0
- package/specialists/org/contracts/designer-to-accessibility.json +36 -0
- package/specialists/org/contracts/engineer-to-qa.json +34 -0
- package/specialists/org/contracts/engineer-to-reviewer.json +52 -0
- package/specialists/org/contracts/explorer-to-engineer.json +38 -0
- package/specialists/org/contracts/legal-compliance-to-release-manager.json +43 -0
- package/specialists/org/contracts/platform-engineer-to-engineer.json +31 -0
- package/specialists/org/contracts/product-manager-to-architect.json +71 -0
- package/specialists/org/contracts/product-manager-to-data-analyst.json +49 -0
- package/specialists/org/contracts/product-manager-to-ux-researcher.json +51 -0
- package/specialists/org/contracts/qa-to-release-manager.json +42 -0
- package/specialists/org/contracts/qa-to-test-automation.json +42 -0
- package/specialists/org/contracts/rd-lead-to-architect.json +38 -0
- package/specialists/org/contracts/researcher-to-architect.json +40 -0
- package/specialists/org/contracts/researcher-to-product-manager.json +57 -0
- package/specialists/org/contracts/reviewer-to-security.json +41 -0
- package/specialists/org/contracts/sre-to-release-manager.json +36 -0
- package/specialists/org/contracts/test-automation-to-engineer.json +34 -0
- package/specialists/org/contracts/trace-reviewer-to-sre.json +41 -0
- package/specialists/org/contracts/user-to-construct.json +30 -0
- package/specialists/org/groups/engineering-group.json +43 -0
- package/specialists/org/groups/governance-group.json +38 -0
- package/specialists/org/groups/operations-group.json +41 -0
- package/specialists/org/groups/product-group.json +46 -0
- package/specialists/org/groups/quality-group.json +42 -0
- package/specialists/org/groups/strategy-group.json +41 -0
- package/specialists/org/policies/action-approval.json +13 -0
- package/specialists/org/policies/agents-routing.json +13 -0
- package/specialists/org/policies/architecture.json +20 -0
- package/specialists/org/policies/bash-safety.json +13 -0
- package/specialists/org/policies/beads-hygiene.json +13 -0
- package/specialists/org/policies/bootstrap-state.json +13 -0
- package/specialists/org/policies/code-review.json +13 -0
- package/specialists/org/policies/coding-style.json +13 -0
- package/specialists/org/policies/comments.json +13 -0
- package/specialists/org/policies/commit-approval.json +13 -0
- package/specialists/org/policies/contract-preconditions.json +13 -0
- package/specialists/org/policies/deployment.json +20 -0
- package/specialists/org/policies/description.json +14 -0
- package/specialists/org/policies/design-approval.json +19 -0
- package/specialists/org/policies/doc-ownership.json +13 -0
- package/specialists/org/policies/file-path-fence.json +13 -0
- package/specialists/org/policies/framing.json +13 -0
- package/specialists/org/policies/git-workflow.json +13 -0
- package/specialists/org/policies/incident-response.json +15 -0
- package/specialists/org/policies/intake-triage.json +15 -0
- package/specialists/org/policies/neurodivergent-output.json +13 -0
- package/specialists/org/policies/no-fabrication.json +13 -0
- package/specialists/org/policies/patterns.json +13 -0
- package/specialists/org/policies/quality-gate-approval.json +17 -0
- package/specialists/org/policies/release-gates.json +13 -0
- package/specialists/org/policies/research-evidence.json +13 -0
- package/specialists/org/policies/review-before-change.json +13 -0
- package/specialists/org/policies/rollback.json +15 -0
- package/specialists/org/policies/scope-change.json +20 -0
- package/specialists/org/policies/secret-scan.json +13 -0
- package/specialists/org/policies/security-approval.json +17 -0
- package/specialists/org/policies/security.json +13 -0
- package/specialists/org/policies/session-efficiency.json +13 -0
- package/specialists/org/policies/skill-routing.json +13 -0
- package/specialists/org/policies/strategic-prioritization.json +17 -0
- package/specialists/org/policies/testing.json +13 -0
- package/specialists/org/policies/tool-invisibility.json +14 -0
- package/specialists/org/scopes/creative.json +54 -0
- package/specialists/org/scopes/operations.json +51 -0
- package/specialists/org/scopes/research.json +60 -0
- package/specialists/org/scopes/rnd.json +81 -0
- package/specialists/org/specialists/cx-accessibility.json +69 -0
- package/specialists/org/specialists/cx-ai-engineer.json +75 -0
- package/specialists/org/specialists/cx-architect.json +89 -0
- package/specialists/org/specialists/cx-business-strategist.json +72 -0
- package/specialists/org/specialists/cx-data-analyst.json +68 -0
- package/specialists/org/specialists/cx-data-engineer.json +71 -0
- package/specialists/org/specialists/cx-debugger.json +75 -0
- package/specialists/org/specialists/cx-designer.json +85 -0
- package/specialists/org/specialists/cx-devil-advocate.json +71 -0
- package/specialists/org/specialists/cx-docs-keeper.json +82 -0
- package/specialists/org/specialists/cx-engineer.json +106 -0
- package/specialists/org/specialists/cx-evaluator.json +69 -0
- package/specialists/org/specialists/cx-explorer.json +69 -0
- package/specialists/org/specialists/cx-legal-compliance.json +74 -0
- package/specialists/org/specialists/cx-operations.json +72 -0
- package/specialists/org/specialists/cx-oracle.json +46 -0
- package/specialists/org/specialists/cx-orchestrator.json +81 -0
- package/specialists/org/specialists/cx-platform-engineer.json +80 -0
- package/specialists/org/specialists/cx-product-manager.json +102 -0
- package/specialists/org/specialists/cx-qa.json +79 -0
- package/specialists/org/specialists/cx-rd-lead.json +73 -0
- package/specialists/org/specialists/cx-release-manager.json +77 -0
- package/specialists/org/specialists/cx-researcher.json +82 -0
- package/specialists/org/specialists/cx-reviewer.json +71 -0
- package/specialists/org/specialists/cx-security.json +91 -0
- package/specialists/org/specialists/cx-sre.json +94 -0
- package/specialists/org/specialists/cx-test-automation.json +69 -0
- package/specialists/org/specialists/cx-trace-reviewer.json +69 -0
- package/specialists/org/specialists/cx-ux-researcher.json +68 -0
- package/specialists/org/teams/accessibility-team.json +39 -0
- package/specialists/org/teams/design-team.json +40 -0
- package/specialists/org/teams/engineering-team.json +50 -0
- package/specialists/org/teams/governance-team.json +41 -0
- package/specialists/org/teams/operations-team.json +46 -0
- package/specialists/org/teams/product-management-team.json +45 -0
- package/specialists/org/teams/quality-team.json +49 -0
- package/specialists/org/teams/research-team.json +39 -0
- package/specialists/org/teams/strategy-team.json +48 -0
- package/specialists/org/teams/ux-research-team.json +39 -0
- package/specialists/prompts/_shared/validation-contract.md +1 -1
- package/specialists/prompts/_team-template.md +10 -0
- package/specialists/prompts/cx-accessibility.md +1 -0
- package/specialists/prompts/cx-ai-engineer.md +1 -1
- package/specialists/prompts/cx-business-strategist.md +1 -1
- package/specialists/prompts/cx-data-engineer.md +1 -1
- package/specialists/prompts/cx-designer.md +1 -0
- package/specialists/prompts/cx-devil-advocate.md +1 -1
- package/specialists/prompts/cx-docs-keeper.md +1 -1
- package/specialists/prompts/cx-evaluator.md +1 -1
- package/specialists/prompts/cx-explorer.md +1 -1
- package/specialists/prompts/cx-operations.md +1 -1
- package/specialists/prompts/cx-oracle.md +7 -3
- package/specialists/prompts/cx-orchestrator.md +17 -1
- package/specialists/prompts/cx-platform-engineer.md +1 -1
- package/specialists/prompts/cx-product-manager.md +2 -0
- package/specialists/prompts/cx-release-manager.md +1 -1
- package/specialists/prompts/cx-researcher.md +7 -4
- package/specialists/prompts/cx-sre.md +1 -1
- package/specialists/prompts/cx-test-automation.md +2 -2
- package/specialists/prompts/cx-trace-reviewer.md +3 -3
- package/specialists/prompts/cx-ux-researcher.md +2 -1
- package/templates/demos/scripts/architecture-review-adr.json +30 -0
- package/templates/demos/scripts/capability-contract.json +25 -0
- package/templates/demos/scripts/intake-triage.json +25 -0
- package/templates/demos/scripts/profile-doctor-health.json +25 -0
- package/templates/demos/tapes/agentic-platforms-prd.tape +2 -2
- package/templates/demos/tapes/architecture-review-adr.tape +44 -0
- package/templates/demos/tapes/capability-contract.tape +39 -0
- package/templates/demos/tapes/intake-triage.tape +39 -0
- package/templates/demos/tapes/profile-doctor-health.tape +39 -0
- package/templates/distribution/construct-brand.typ +23 -18
- package/templates/distribution/construct-decision.typ +1 -1
- package/templates/distribution/construct-pdf.typ +1 -1
- package/templates/distribution/construct-prd.typ +1 -1
- package/templates/distribution/construct-research.typ +1 -1
- package/templates/distribution/mermaid-puppeteer.json +8 -0
- package/templates/docs/persona-artifact.md +1 -1
- package/templates/docs/prd.md +6 -0
- package/apps/chat/engine/ai-sdk-agent.mjs +0 -183
- package/apps/chat/engine/loop-driver.mjs +0 -211
- package/apps/chat/engine/models.mjs +0 -122
- package/apps/chat/engine/provider-adapters.mjs +0 -171
- package/apps/chat/engine/tools/permission.mjs +0 -54
- package/apps/chat/engine/tools/primitives.mjs +0 -180
- package/apps/chat/engine/tools/registry.mjs +0 -122
- package/apps/chat/engine/turn-controls.mjs +0 -70
- package/lib/boundary.mjs +0 -127
- package/lib/certification/dashboard-api.mjs +0 -71
- package/lib/chat/cli.mjs +0 -333
- package/lib/chat/command-suggest.mjs +0 -161
- package/lib/chat/commands.mjs +0 -215
- package/lib/chat/config.mjs +0 -142
- package/lib/chat/context-compactor.mjs +0 -250
- package/lib/chat/context-continuation.mjs +0 -253
- package/lib/chat/continuation-source.mjs +0 -58
- package/lib/chat/demo-guide.mjs +0 -61
- package/lib/chat/design-tokens.mjs +0 -91
- package/lib/chat/desktop-binary.mjs +0 -81
- package/lib/chat/desktop-build.mjs +0 -130
- package/lib/chat/desktop-launcher.mjs +0 -133
- package/lib/chat/evidence.mjs +0 -145
- package/lib/chat/export.mjs +0 -74
- package/lib/chat/harness/driver.mjs +0 -91
- package/lib/chat/list-picker.mjs +0 -112
- package/lib/chat/model-picker.mjs +0 -356
- package/lib/chat/openrouter-fallback.mjs +0 -151
- package/lib/chat/permission-prompt.mjs +0 -33
- package/lib/chat/picker-catalog.mjs +0 -45
- package/lib/chat/policy-telemetry.mjs +0 -34
- package/lib/chat/present.mjs +0 -246
- package/lib/chat/session-context.mjs +0 -39
- package/lib/chat/session-persist.mjs +0 -73
- package/lib/chat/session-restore.mjs +0 -71
- package/lib/chat/session-settings.mjs +0 -53
- package/lib/chat/system-prompt.mjs +0 -52
- package/lib/chat/transparency.mjs +0 -93
- package/lib/chat/tui/color-scheme.mjs +0 -42
- package/lib/chat/tui/markdown.mjs +0 -123
- package/lib/chat/tui/presentation.mjs +0 -100
- package/lib/chat/tui/render.mjs +0 -500
- package/lib/chat/tui/turn-block.mjs +0 -284
- package/lib/chat/tui/turn-present.mjs +0 -18
- package/lib/chat/tui/turn-state.mjs +0 -88
- package/lib/chat/tui/usage.mjs +0 -122
- package/lib/chat/web-commands.mjs +0 -146
- package/lib/chat/web-launcher.mjs +0 -63
- package/lib/chat/web-picker-keys.mjs +0 -46
- package/lib/chat/web-session.mjs +0 -159
- package/lib/config/alias.mjs +0 -57
- package/lib/dashboard-demo.mjs +0 -71
- package/lib/dashboard-static.mjs +0 -175
- package/lib/install/desktop-binary-download.mjs +0 -88
- package/lib/profiles/loader.mjs +0 -123
- package/lib/profiles/rebrand.mjs +0 -46
- package/lib/server/auth.mjs +0 -169
- package/lib/server/chat-loop.mjs +0 -622
- package/lib/server/chat.mjs +0 -336
- package/lib/server/cors.mjs +0 -77
- package/lib/server/csrf.mjs +0 -103
- package/lib/server/demo-preview.mjs +0 -63
- package/lib/server/index.mjs +0 -2641
- package/lib/server/insights.mjs +0 -780
- package/lib/server/langfuse-login.mjs +0 -58
- package/lib/server/rate-limit.mjs +0 -93
- package/lib/server/telemetry-login.mjs +0 -100
- package/lib/server/webhook.mjs +0 -512
- package/specialists/contracts.json +0 -1032
- package/specialists/contracts.schema.json +0 -83
- package/specialists/policy-inventory.json +0 -188
- package/specialists/registry.json +0 -1412
- package/specialists/role-manifests.json +0 -217
- package/specialists/teams.json +0 -94
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* sync-specialists.mjs — regenerate agent adapters for all platforms from specialists/
|
|
3
|
+
* sync-specialists.mjs — regenerate agent adapters for all platforms from specialists/org.
|
|
4
4
|
*
|
|
5
5
|
* Two scopes, modelled on every host's own convention (global = personal default,
|
|
6
6
|
* project = team-shared):
|
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
import fs from "node:fs";
|
|
32
32
|
import path from "node:path";
|
|
33
33
|
import os from "node:os";
|
|
34
|
+
import { fileURLToPath } from "node:url";
|
|
34
35
|
import { generateCompletions } from "../lib/completions.mjs";
|
|
35
36
|
import {
|
|
36
37
|
buildCodexMcpEntry,
|
|
@@ -43,7 +44,7 @@ import {
|
|
|
43
44
|
tomlString,
|
|
44
45
|
writeCodexConfig,
|
|
45
46
|
} from "../lib/codex-config.mjs";
|
|
46
|
-
import { findOpenCodeConfigPath, readOpenCodeConfig, writeOpenCodeConfig } from "../lib/opencode-config.mjs";
|
|
47
|
+
import { findOpenCodeConfigPath, readOpenCodeConfig, writeOpenCodeConfig, ensureOpenRouterProviderAuth } from "../lib/opencode-config.mjs";
|
|
47
48
|
import { HEAVY_EXTERNAL_MCP_IDS, LOCAL_SURFACE_MODES, decideTrim, isLocalModel } from "../lib/mcp/tool-budget.mjs";
|
|
48
49
|
import { emitCursorRules } from "../lib/rules-delivery.mjs";
|
|
49
50
|
import { resolvePromptContract, readPromptBody } from "../lib/prompt-composer.js";
|
|
@@ -59,21 +60,67 @@ import { configDir } from "../lib/config/xdg.mjs";
|
|
|
59
60
|
import { inlineRoleAntiPatterns, PROMPT_WORD_CAP } from "../lib/role-preload.mjs";
|
|
60
61
|
import { inlineValidationContract } from "../lib/prompt-validation-contract.mjs";
|
|
61
62
|
import { loadManifest } from "../lib/roles/manifest.mjs";
|
|
62
|
-
import {
|
|
63
|
+
import { resolveActiveScope } from "../lib/scopes/loader.mjs";
|
|
63
64
|
import { resolveTiersForPrimary, resolveCapabilityTier, selectLocalEditorModel } from "../lib/model-router.mjs";
|
|
64
65
|
import { stampFrontmatter } from "../lib/doc-stamp.mjs";
|
|
65
66
|
import { buildSkillFrontmatter, stripLeadingFrontmatter } from "../lib/sync/skill-frontmatter.mjs";
|
|
67
|
+
import { loadRegistry, clearCache } from "../lib/registry/loader.mjs";
|
|
68
|
+
import { loadPluginRegistry } from "../lib/plugin-registry.mjs";
|
|
66
69
|
|
|
67
70
|
const home = os.homedir();
|
|
68
71
|
const root = path.resolve(import.meta.dirname, "..");
|
|
72
|
+
const isMain = process.argv[1] ? path.resolve(process.argv[1]) === fileURLToPath(import.meta.url) : false;
|
|
69
73
|
|
|
70
74
|
const mergedEnv = loadConstructEnv({ rootDir: root, homeDir: home, env: process.env });
|
|
71
75
|
for (const [key, value] of Object.entries(mergedEnv)) {
|
|
72
76
|
if (!(key in process.env)) process.env[key] = value;
|
|
73
77
|
}
|
|
74
78
|
if (!process.env.CX_TOOLKIT_DIR) process.env.CX_TOOLKIT_DIR = root;
|
|
75
|
-
|
|
76
|
-
|
|
79
|
+
|
|
80
|
+
function unifiedToLegacyRegistry(unified) {
|
|
81
|
+
const orchestrator = Object.values(unified.specialists || {}).find(s => s.role === 'orchestrator') || {};
|
|
82
|
+
const specialists = Object.values(unified.specialists || {}).filter(s => s.role !== 'orchestrator');
|
|
83
|
+
return {
|
|
84
|
+
version: 1,
|
|
85
|
+
system: 'construct',
|
|
86
|
+
prefix: 'cx',
|
|
87
|
+
orchestrator: {
|
|
88
|
+
name: 'construct',
|
|
89
|
+
displayName: orchestrator.displayName || orchestrator.description?.split('—')[0].trim() || 'Construct',
|
|
90
|
+
description: orchestrator.description || '',
|
|
91
|
+
promptFile: orchestrator.promptFile || 'specialists/prompts/cx-orchestrator.md',
|
|
92
|
+
modelTier: orchestrator.modelTier || 'standard',
|
|
93
|
+
skills: orchestrator.skills || [],
|
|
94
|
+
injectAgentRoster: orchestrator.injectAgentRoster ?? false,
|
|
95
|
+
},
|
|
96
|
+
specialists: specialists.map(s => ({
|
|
97
|
+
name: s.name,
|
|
98
|
+
displayName: s.displayName || s.description?.split('—')[0].trim() || s.name,
|
|
99
|
+
description: s.description || '',
|
|
100
|
+
promptFile: s.promptFile,
|
|
101
|
+
modelTier: s.modelTier || 'standard',
|
|
102
|
+
claudeTools: s.claudeTools || 'Read,Grep,Glob,LS',
|
|
103
|
+
internal: s.internal,
|
|
104
|
+
wordCapOverride: s.wordCapOverride,
|
|
105
|
+
skills: s.skills || [],
|
|
106
|
+
team: s.team,
|
|
107
|
+
role: s.role,
|
|
108
|
+
docArtifacts: s.docArtifacts || [],
|
|
109
|
+
subscriptions: s.events || [],
|
|
110
|
+
watchConditions: s.watchConditions || [],
|
|
111
|
+
fence: s.fence || {},
|
|
112
|
+
})),
|
|
113
|
+
sharedGuidance: unified.sharedGuidance || [],
|
|
114
|
+
models: unified.models || { reasoning: { primary: null }, standard: { primary: null }, fast: { primary: null } },
|
|
115
|
+
providers: unified.providers || {},
|
|
116
|
+
mcpServers: unified.mcpServers || {},
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
clearCache();
|
|
121
|
+
clearCache();
|
|
122
|
+
const unified = loadRegistry({ rootDir: root });
|
|
123
|
+
const registry = unifiedToLegacyRegistry(unified);
|
|
77
124
|
|
|
78
125
|
function validateRegistry(registry) {
|
|
79
126
|
const errors = [];
|
|
@@ -378,15 +425,15 @@ const sharedGuidance = registry.sharedGuidance ?? [];
|
|
|
378
425
|
const platformGuidance = registry.platformGuidance ?? {};
|
|
379
426
|
const globalModelGuidance = registry.modelGuidance ?? {};
|
|
380
427
|
|
|
381
|
-
const generatedHeader = `# Generated by ${systemName}/sync-specialists.mjs. Edit specialists/
|
|
428
|
+
const generatedHeader = `# Generated by ${systemName}/sync-specialists.mjs. Edit specialists/org instead.`;
|
|
382
429
|
const generatedMarkdownNote = [
|
|
383
430
|
'<!--',
|
|
384
|
-
`Generated by construct sync from specialists/
|
|
431
|
+
`Generated by construct sync from specialists/org.`,
|
|
385
432
|
'Do not edit this file directly — changes will be overwritten on next sync.',
|
|
386
433
|
'Regenerate: construct sync',
|
|
387
434
|
'-->',
|
|
388
435
|
'',
|
|
389
|
-
'> Generated from `specialists/
|
|
436
|
+
'> Generated from `specialists/org`. Edit the registry, then run `construct sync`.',
|
|
390
437
|
].join('\n');
|
|
391
438
|
|
|
392
439
|
const standardConstructTools = [
|
|
@@ -432,6 +479,96 @@ function resolveArgs(args) {
|
|
|
432
479
|
: a));
|
|
433
480
|
}
|
|
434
481
|
|
|
482
|
+
function resolveTemplateStrings(value) {
|
|
483
|
+
if (typeof value === "string") {
|
|
484
|
+
return value.replace(/__([A-Z0-9_]+)__/g, (_, name) => {
|
|
485
|
+
if (process.env[name] !== undefined && process.env[name] !== "") return process.env[name];
|
|
486
|
+
if (name === "CX_TOOLKIT_DIR") return root;
|
|
487
|
+
if (name === "MEMORY_PORT") return process.env.MEMORY_PORT || "8765";
|
|
488
|
+
if (name === "CONSTRUCT_MEMORY_BRIDGE_URL") {
|
|
489
|
+
return process.env.CONSTRUCT_MEMORY_BRIDGE_URL || "http://127.0.0.1:8765/";
|
|
490
|
+
}
|
|
491
|
+
if (name === "GITHUB_TOKEN" && process.env.GITHUB_PERSONAL_ACCESS_TOKEN) {
|
|
492
|
+
return process.env.GITHUB_PERSONAL_ACCESS_TOKEN;
|
|
493
|
+
}
|
|
494
|
+
if (/(?:TOKEN|SECRET|API_KEY|PUBLIC_KEY|PRIVATE_KEY)$/.test(name)) {
|
|
495
|
+
return `{env:${name}}`;
|
|
496
|
+
}
|
|
497
|
+
return `__${name}__`;
|
|
498
|
+
});
|
|
499
|
+
}
|
|
500
|
+
if (Array.isArray(value)) return value.map((item) => resolveTemplateStrings(item));
|
|
501
|
+
if (value && typeof value === "object") {
|
|
502
|
+
return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, resolveTemplateStrings(item)]));
|
|
503
|
+
}
|
|
504
|
+
return value;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
function constructMcpDefinition() {
|
|
508
|
+
return {
|
|
509
|
+
id: "construct-mcp",
|
|
510
|
+
name: "Construct MCP",
|
|
511
|
+
category: "core",
|
|
512
|
+
description: "Construct stdio MCP server for orchestration, skills, templates, and project context.",
|
|
513
|
+
command: "node",
|
|
514
|
+
args: ["__CX_TOOLKIT_DIR__/lib/mcp/server.mjs"],
|
|
515
|
+
env: {
|
|
516
|
+
CONSTRUCT_TRACE_BACKEND: "__CONSTRUCT_TRACE_BACKEND__",
|
|
517
|
+
CONSTRUCT_TELEMETRY_URL: "__CONSTRUCT_TELEMETRY_URL__",
|
|
518
|
+
CONSTRUCT_TELEMETRY_PUBLIC_KEY: "__CONSTRUCT_TELEMETRY_PUBLIC_KEY__",
|
|
519
|
+
CONSTRUCT_TELEMETRY_SECRET_KEY: "__CONSTRUCT_TELEMETRY_SECRET_KEY__",
|
|
520
|
+
},
|
|
521
|
+
requiredEnv: [],
|
|
522
|
+
setupModes: ["auto"],
|
|
523
|
+
hostSupport: {
|
|
524
|
+
claude: { mode: "managed" },
|
|
525
|
+
opencode: { mode: "managed" },
|
|
526
|
+
codex: { mode: "managed" },
|
|
527
|
+
},
|
|
528
|
+
usedBy: ["construct"],
|
|
529
|
+
};
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
function managedMcpDefs() {
|
|
533
|
+
const pluginRegistry = loadPluginRegistry({ cwd: root, homeDir: home, rootDir: root, env: process.env });
|
|
534
|
+
const defs = Object.fromEntries(
|
|
535
|
+
(pluginRegistry.mcps ?? []).map((mcp) => [mcp.id, {
|
|
536
|
+
type: mcp.type,
|
|
537
|
+
url: mcp.url,
|
|
538
|
+
command: mcp.command,
|
|
539
|
+
args: mcp.args,
|
|
540
|
+
env: mcp.env,
|
|
541
|
+
headers: mcp.headers,
|
|
542
|
+
hostSupport: mcp.hostSupport,
|
|
543
|
+
category: mcp.category,
|
|
544
|
+
}]),
|
|
545
|
+
);
|
|
546
|
+
defs["construct-mcp"] = constructMcpDefinition();
|
|
547
|
+
return { ...defs, ...(registry.mcpServers ?? {}) };
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
function scopedManagedMcpDefs({ projectScope = false } = {}) {
|
|
551
|
+
const defs = managedMcpDefs();
|
|
552
|
+
if (!projectScope) return defs;
|
|
553
|
+
return Object.fromEntries(
|
|
554
|
+
Object.entries(defs).filter(([id]) => PROJECT_DEFAULT_MCP_IDS.has(id)),
|
|
555
|
+
);
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
function mergeMissingObjectDefaults(current, defaults) {
|
|
559
|
+
if (Array.isArray(defaults)) {
|
|
560
|
+
return current === undefined ? [...defaults] : current;
|
|
561
|
+
}
|
|
562
|
+
if (!defaults || typeof defaults !== "object") {
|
|
563
|
+
return current === undefined ? defaults : current;
|
|
564
|
+
}
|
|
565
|
+
const next = current && typeof current === "object" && !Array.isArray(current) ? { ...current } : {};
|
|
566
|
+
for (const [key, value] of Object.entries(defaults)) {
|
|
567
|
+
next[key] = mergeMissingObjectDefaults(next[key], value);
|
|
568
|
+
}
|
|
569
|
+
return next;
|
|
570
|
+
}
|
|
571
|
+
|
|
435
572
|
function extractFallbackChain(tierDef) {
|
|
436
573
|
if (typeof tierDef === "string") return [tierDef];
|
|
437
574
|
if (tierDef && typeof tierDef === "object") {
|
|
@@ -554,7 +691,7 @@ function buildRoleFooter(entry) {
|
|
|
554
691
|
return `\n\n${lines.join("\n")}`;
|
|
555
692
|
}
|
|
556
693
|
|
|
557
|
-
// Fence + handoff data is the source of truth in specialists/
|
|
694
|
+
// Fence + handoff data is the source of truth in specialists/org
|
|
558
695
|
// (events, fence.allowedPaths, fence.allowedBdLabels, fence.approvalRequired,
|
|
559
696
|
// handoffCandidates, outputs.docTypes). Restating that JSON inside each
|
|
560
697
|
// specialist prompt would invite drift across 28 files; the renderer below
|
|
@@ -599,7 +736,7 @@ export function renderRoleFrameworkSection(entry) {
|
|
|
599
736
|
"",
|
|
600
737
|
`Construct may dispatch you in response to ${eventList} events. A bd issue with the event payload exists when dispatched: read it first via \`bd show <id>\`.`,
|
|
601
738
|
"",
|
|
602
|
-
`**Fence** (source of truth: \`specialists/
|
|
739
|
+
`**Fence** (source of truth: \`specialists/org\` → \`${personaName}\`):`,
|
|
603
740
|
`- Allowed paths: ${pathList}`,
|
|
604
741
|
`- Allowed bd labels: ${labelList}`,
|
|
605
742
|
`- Approval required: ${approvalList}`,
|
|
@@ -616,11 +753,21 @@ export function renderRoleFrameworkSection(entry) {
|
|
|
616
753
|
// small local models' tool-use reliability sharply (bead construct-c16l). Shared by the
|
|
617
754
|
// full path and the capability-tiered local path so both stay in sync.
|
|
618
755
|
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
756
|
+
function orchestrationToolName(platform, toolName) {
|
|
757
|
+
if (platform === "opencode") return `construct-mcp_${toolName}`;
|
|
758
|
+
return toolName;
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
function orchestrationMicroPrompt(platform) {
|
|
762
|
+
const policyTool = orchestrationToolName(platform, "orchestration_policy");
|
|
763
|
+
const runTool = orchestrationToolName(platform, "orchestration_run");
|
|
764
|
+
return (
|
|
765
|
+
`You are the primary orchestrator. Before any non-trivial answer, call \`${policyTool}\` with the user's \`request\`. Do not guess agent names or workflow types.\n\n` +
|
|
766
|
+
`Example — the user says "add rate limiting to the API". Your first action is a tool call, not prose:\n` +
|
|
767
|
+
` call ${policyTool} { "request": "add rate limiting to the API" }\n` +
|
|
768
|
+
`If the route is focused/orchestrated specialist work, call \`${runTool}\` with the same request. If the route suggests a workflow such as \`research-synthesis\`, pass it as \`workflow_type\`. Do not narrate completed research unless \`${runTool}\` or evidence tools actually ran.`
|
|
769
|
+
);
|
|
770
|
+
}
|
|
624
771
|
|
|
625
772
|
// Directive for the local editor agent (construct-local). It executes bounded work on
|
|
626
773
|
// the cheap local model and hands planning/reasoning back to the construct architect —
|
|
@@ -661,7 +808,7 @@ function enforcePromptWordCap(prompt, entry) {
|
|
|
661
808
|
console.error(
|
|
662
809
|
`[sync] Hard cap exceeded. Options:\n` +
|
|
663
810
|
` - trim the prompt body or move detail to a skill (preferred)\n` +
|
|
664
|
-
` - set "wordCapOverride": <N> on this entry in specialists/
|
|
811
|
+
` - set "wordCapOverride": <N> on this entry in specialists/org with a written reason\n` +
|
|
665
812
|
` - re-run with --force or CONSTRUCT_SYNC_FORCE=1 as a temporary escape hatch\n` +
|
|
666
813
|
`Prompt budget is a hard contract because every over-cap agent degrades every session that dispatches it.`,
|
|
667
814
|
);
|
|
@@ -684,7 +831,7 @@ function buildPrompt(entry, allEntries, platform, { capabilityTier = 'full' } =
|
|
|
684
831
|
if (capabilityTier && capabilityTier !== 'full' && entry.promptFile) {
|
|
685
832
|
let slim = renderPersonaForTier(readPromptBody(entry.promptFile, root), capabilityTier);
|
|
686
833
|
if (entry.injectAgentRoster) {
|
|
687
|
-
slim = `${
|
|
834
|
+
slim = `${orchestrationMicroPrompt(platform)}\n\n${slim}`;
|
|
688
835
|
}
|
|
689
836
|
return enforcePromptWordCap(slim, entry);
|
|
690
837
|
}
|
|
@@ -707,7 +854,7 @@ function buildPrompt(entry, allEntries, platform, { capabilityTier = 'full' } =
|
|
|
707
854
|
// orchestration_policy / orchestration_run — never inject the static roster.
|
|
708
855
|
|
|
709
856
|
if (entry.injectAgentRoster) {
|
|
710
|
-
prompt = `${
|
|
857
|
+
prompt = `${orchestrationMicroPrompt(platform)}\n\n${prompt}`;
|
|
711
858
|
}
|
|
712
859
|
|
|
713
860
|
prompt += buildRoleFooter(entry);
|
|
@@ -811,7 +958,7 @@ function buildEntries() {
|
|
|
811
958
|
// so behavior is unchanged for the default; non-RND profiles emit only the
|
|
812
959
|
// specialists they declare. Profiles whose role list is empty (legacy/test)
|
|
813
960
|
// fall through to no filter so callers don't get a silent empty registry.
|
|
814
|
-
const activeProfile =
|
|
961
|
+
const activeProfile = resolveActiveScope(process.cwd());
|
|
815
962
|
const profileRoles = Array.isArray(activeProfile?.roles) && activeProfile.roles.length > 0
|
|
816
963
|
? new Set(activeProfile.roles)
|
|
817
964
|
: null;
|
|
@@ -855,13 +1002,20 @@ ${buildPrompt(entry, allEntries, "claude")}
|
|
|
855
1002
|
* Rewrite the home-mode hook command pattern
|
|
856
1003
|
* node "$HOME/.config/construct/lib/hooks/<name>.mjs"
|
|
857
1004
|
* into the project-portable form
|
|
858
|
-
* node
|
|
1005
|
+
* node "${CLAUDE_PROJECT_DIR:-.}/.construct/run.mjs" hook <name>
|
|
859
1006
|
* so the resulting settings.json works on any clone where the project ships
|
|
860
1007
|
* the .construct/ launcher (committed by `npm install`'s postinstall or by
|
|
861
1008
|
* `construct init`). The launcher resolves Construct via node_modules → npx
|
|
862
1009
|
* → globally-installed CLI → cached binary → docker, in that order, so it
|
|
863
1010
|
* works for non-Node ecosystems too. Other commands (inline node -e
|
|
864
1011
|
* snippets, npx block-no-verify@…) are left untouched.
|
|
1012
|
+
*
|
|
1013
|
+
* The `${CLAUDE_PROJECT_DIR:-.}` anchor matters: Claude Code invokes hooks with
|
|
1014
|
+
* a working directory that is not guaranteed to be the project root (observed:
|
|
1015
|
+
* $HOME), and a bare relative `.construct/run.mjs` then fails with MODULE_NOT_FOUND
|
|
1016
|
+
* at node:internal/modules/cjs/loader. CLAUDE_PROJECT_DIR is the project root Claude
|
|
1017
|
+
* Code exports to every hook (same var lib/hooks/*.mjs already read); the `:-.`
|
|
1018
|
+
* fallback preserves the prior relative behavior wherever the var is unset.
|
|
865
1019
|
*/
|
|
866
1020
|
function makeHooksPortable(hooksJson) {
|
|
867
1021
|
// Operate on the in-memory object so we don't fight JSON string escaping.
|
|
@@ -870,7 +1024,7 @@ function makeHooksPortable(hooksJson) {
|
|
|
870
1024
|
const m = cmd.match(/^node\s+"?\$HOME\/\.config\/construct\/lib\/hooks\/([a-z0-9-]+)\.mjs"?\s*(.*)$/);
|
|
871
1025
|
if (!m) return cmd;
|
|
872
1026
|
const [, name, rest] = m;
|
|
873
|
-
return `node
|
|
1027
|
+
return `node "\${CLAUDE_PROJECT_DIR:-.}/.construct/run.mjs" hook ${name}${rest ? ' ' + rest.trim() : ''}`;
|
|
874
1028
|
};
|
|
875
1029
|
|
|
876
1030
|
const walk = (node) => {
|
|
@@ -920,12 +1074,6 @@ function filterGlobalClaudeHooks(hooksJson) {
|
|
|
920
1074
|
|
|
921
1075
|
function syncGlobalClaudeMcpServers(settings, registryMcp) {
|
|
922
1076
|
settings.mcpServers ??= {};
|
|
923
|
-
for (const id of Object.keys(settings.mcpServers)) {
|
|
924
|
-
if (id in registryMcp && !GLOBAL_CLAUDE_MCP_IDS.has(id)) {
|
|
925
|
-
delete settings.mcpServers[id];
|
|
926
|
-
}
|
|
927
|
-
}
|
|
928
|
-
|
|
929
1077
|
for (const [id, mcpDef] of Object.entries(registryMcp)) {
|
|
930
1078
|
if (!GLOBAL_CLAUDE_MCP_IDS.has(id)) continue;
|
|
931
1079
|
const existingEntry = settings.mcpServers[id];
|
|
@@ -979,7 +1127,7 @@ function writeProjectClaudeSettings(targetDir) {
|
|
|
979
1127
|
// Claude Code as the only selected tool without the construct config. Merge the
|
|
980
1128
|
// registry on top of the template seed; existing entries win so user edits stick,
|
|
981
1129
|
// and buildClaudeMcpEntry resolves each server's path/env.
|
|
982
|
-
const registryMcp =
|
|
1130
|
+
const registryMcp = scopedManagedMcpDefs({ projectScope: true });
|
|
983
1131
|
existing.mcpServers ??= {};
|
|
984
1132
|
for (const [id, mcpDef] of Object.entries(registryMcp)) {
|
|
985
1133
|
if (existing.mcpServers[id]) continue;
|
|
@@ -1057,7 +1205,7 @@ ${personaList}
|
|
|
1057
1205
|
settings.hooks = JSON.parse(hookStr);
|
|
1058
1206
|
}
|
|
1059
1207
|
}
|
|
1060
|
-
const registryMcp =
|
|
1208
|
+
const registryMcp = scopedManagedMcpDefs({ projectScope: false });
|
|
1061
1209
|
syncGlobalClaudeMcpServers(settings, registryMcp);
|
|
1062
1210
|
if (!DRY_RUN) fs.writeFileSync(claudeSettingsPath, JSON.stringify(settings, null, 2) + "\n");
|
|
1063
1211
|
}
|
|
@@ -1135,7 +1283,7 @@ function syncCodex(entries, targetDir = null, wants = true) {
|
|
|
1135
1283
|
: getCodexConfigPath(home);
|
|
1136
1284
|
const existing = removeDanglingConstructMcpMarkers(removeDanglingConstructMcpTimeouts(readCodexConfig(configPath)));
|
|
1137
1285
|
const entryNames = writeEntries.map(adapterName);
|
|
1138
|
-
const registryMcp =
|
|
1286
|
+
const registryMcp = scopedManagedMcpDefs({ projectScope: Boolean(targetDir) });
|
|
1139
1287
|
// Seed every supported MCP server (parity with Claude/OpenCode/VS Code/Cursor),
|
|
1140
1288
|
// not just tables already present — otherwise Codex never receives `construct-mcp`
|
|
1141
1289
|
// and the orchestration tool is unreachable there. existingMcpIds still drives
|
|
@@ -1285,7 +1433,7 @@ function getVSCodeUserMcpPaths() {
|
|
|
1285
1433
|
}
|
|
1286
1434
|
|
|
1287
1435
|
function syncVSCode(targetDir = null, wants = true) {
|
|
1288
|
-
const registryMcp =
|
|
1436
|
+
const registryMcp = scopedManagedMcpDefs({ projectScope: Boolean(targetDir) });
|
|
1289
1437
|
if (Object.keys(registryMcp).length === 0) return false;
|
|
1290
1438
|
|
|
1291
1439
|
// Project scope writes a dedicated `.vscode/mcp.json` (VS Code's documented
|
|
@@ -1369,7 +1517,7 @@ function syncVSCode(targetDir = null, wants = true) {
|
|
|
1369
1517
|
// --- Cursor adapter ---
|
|
1370
1518
|
|
|
1371
1519
|
function syncCursor(targetDir = null, wants = true) {
|
|
1372
|
-
const registryMcp =
|
|
1520
|
+
const registryMcp = scopedManagedMcpDefs({ projectScope: Boolean(targetDir) });
|
|
1373
1521
|
if (Object.keys(registryMcp).length === 0) return false;
|
|
1374
1522
|
|
|
1375
1523
|
const cursorDir = targetDir
|
|
@@ -1567,16 +1715,72 @@ function syncOpencode(entries, targetDir = null, wants = true) {
|
|
|
1567
1715
|
|
|
1568
1716
|
const writeEntries = globalEntries(entries);
|
|
1569
1717
|
|
|
1718
|
+
const hadExistingConfig = fs.existsSync(configPath);
|
|
1570
1719
|
const { config } = targetDir
|
|
1571
|
-
? { config:
|
|
1720
|
+
? { config: hadExistingConfig ? JSON.parse(fs.readFileSync(configPath, "utf8")) : {} }
|
|
1572
1721
|
: readOpenCodeConfig();
|
|
1722
|
+
const opencodeTemplatePath = path.join(root, "platforms", "opencode", "config.template.json");
|
|
1723
|
+
const opencodeTemplate = fs.existsSync(opencodeTemplatePath)
|
|
1724
|
+
? JSON.parse(fs.readFileSync(opencodeTemplatePath, "utf8"))
|
|
1725
|
+
: {};
|
|
1573
1726
|
if (!config.agent) config.agent = {};
|
|
1727
|
+
if (!config.mcp) config.mcp = {};
|
|
1574
1728
|
if (!Array.isArray(config.plugin)) config.plugin = [];
|
|
1575
1729
|
config.plugin = config.plugin.filter((entry) => {
|
|
1576
1730
|
if (typeof entry !== "string") return true;
|
|
1577
1731
|
return entry !== managedPluginPath && entry !== toolkitPluginPath;
|
|
1578
1732
|
});
|
|
1579
1733
|
|
|
1734
|
+
if (opencodeTemplate.$schema && !config.$schema) config.$schema = opencodeTemplate.$schema;
|
|
1735
|
+
if (opencodeTemplate.model && !config.model && !config.defaultModel && !hadExistingConfig) {
|
|
1736
|
+
config.model = opencodeTemplate.model;
|
|
1737
|
+
}
|
|
1738
|
+
if (Array.isArray(opencodeTemplate.enabled_providers) && !Array.isArray(config.enabled_providers)) {
|
|
1739
|
+
config.enabled_providers = [...opencodeTemplate.enabled_providers];
|
|
1740
|
+
}
|
|
1741
|
+
if (opencodeTemplate.provider && typeof opencodeTemplate.provider === "object") {
|
|
1742
|
+
config.provider ??= {};
|
|
1743
|
+
for (const [id, providerDef] of Object.entries(opencodeTemplate.provider)) {
|
|
1744
|
+
config.provider[id] = mergeMissingObjectDefaults(config.provider[id], resolveTemplateStrings(providerDef));
|
|
1745
|
+
}
|
|
1746
|
+
}
|
|
1747
|
+
if (config.provider?.ollama?.options?.headers?.Authorization === "Bearer ollama") {
|
|
1748
|
+
delete config.provider.ollama.options.headers.Authorization;
|
|
1749
|
+
if (Object.keys(config.provider.ollama.options.headers).length === 0) {
|
|
1750
|
+
delete config.provider.ollama.options.headers;
|
|
1751
|
+
}
|
|
1752
|
+
}
|
|
1753
|
+
|
|
1754
|
+
const templateMcp = opencodeTemplate.mcp && typeof opencodeTemplate.mcp === "object"
|
|
1755
|
+
? resolveTemplateStrings(opencodeTemplate.mcp)
|
|
1756
|
+
: {};
|
|
1757
|
+
for (const [id, entry] of Object.entries(templateMcp)) {
|
|
1758
|
+
if (!PROJECT_DEFAULT_MCP_IDS.has(id)) continue;
|
|
1759
|
+
if (!config.mcp[id]) config.mcp[id] = entry;
|
|
1760
|
+
}
|
|
1761
|
+
if (config.mcp["construct-mcp"]) {
|
|
1762
|
+
config.mcp["construct-mcp"] = templateMcp["construct-mcp"] ?? config.mcp["construct-mcp"];
|
|
1763
|
+
}
|
|
1764
|
+
|
|
1765
|
+
const memoryBridgeEntry = buildOpenCodeMcpEntry("memory", {
|
|
1766
|
+
command: "node",
|
|
1767
|
+
args: ["__CX_TOOLKIT_DIR__/lib/mcp/memory-bridge.mjs"],
|
|
1768
|
+
env: { CONSTRUCT_MEMORY_BRIDGE_URL: "__CONSTRUCT_MEMORY_BRIDGE_URL__" },
|
|
1769
|
+
}, {
|
|
1770
|
+
...process.env,
|
|
1771
|
+
CONSTRUCT_MEMORY_BRIDGE_URL:
|
|
1772
|
+
config.mcp.memory?.url
|
|
1773
|
+
|| config.mcp.cass?.url
|
|
1774
|
+
|| process.env.CONSTRUCT_MEMORY_BRIDGE_URL
|
|
1775
|
+
|| "http://127.0.0.1:8765/",
|
|
1776
|
+
}).entry;
|
|
1777
|
+
const staleMemoryRemote = config.mcp.memory && (config.mcp.memory.type === "remote" || config.mcp.memory.type === "http");
|
|
1778
|
+
const staleCassRemote = config.mcp.cass && (config.mcp.cass.type === "remote" || config.mcp.cass.type === "http");
|
|
1779
|
+
if (staleMemoryRemote || staleCassRemote) {
|
|
1780
|
+
config.mcp.memory = memoryBridgeEntry;
|
|
1781
|
+
delete config.mcp.cass;
|
|
1782
|
+
}
|
|
1783
|
+
|
|
1580
1784
|
// Sync providers
|
|
1581
1785
|
const registryProviders = registry.providers ?? {};
|
|
1582
1786
|
if (Object.keys(registryProviders).length > 0) {
|
|
@@ -1589,8 +1793,10 @@ function syncOpencode(entries, targetDir = null, wants = true) {
|
|
|
1589
1793
|
...providerDef,
|
|
1590
1794
|
options: {
|
|
1591
1795
|
...providerDef.options,
|
|
1796
|
+
...existing.options,
|
|
1592
1797
|
headers: {
|
|
1593
1798
|
...providerDef.options?.headers,
|
|
1799
|
+
...existing.options?.headers,
|
|
1594
1800
|
...(existingAuth ? { Authorization: existingAuth } : {}),
|
|
1595
1801
|
},
|
|
1596
1802
|
},
|
|
@@ -1602,6 +1808,8 @@ function syncOpencode(entries, targetDir = null, wants = true) {
|
|
|
1602
1808
|
}
|
|
1603
1809
|
}
|
|
1604
1810
|
|
|
1811
|
+
ensureOpenRouterProviderAuth(config);
|
|
1812
|
+
|
|
1605
1813
|
// Derive anthropic models from registry tier definitions
|
|
1606
1814
|
const tierModels = Object.values(registry.models ?? {}).flatMap((t) =>
|
|
1607
1815
|
[t.primary, ...(t.fallback ?? [])].filter((m) => m?.startsWith('anthropic/'))
|
|
@@ -1627,7 +1835,7 @@ function syncOpencode(entries, targetDir = null, wants = true) {
|
|
|
1627
1835
|
}
|
|
1628
1836
|
|
|
1629
1837
|
// Sync MCP servers
|
|
1630
|
-
const registryMcp =
|
|
1838
|
+
const registryMcp = scopedManagedMcpDefs({ projectScope: Boolean(targetDir) });
|
|
1631
1839
|
if (Object.keys(registryMcp).length > 0) {
|
|
1632
1840
|
if (!config.mcp) config.mcp = {};
|
|
1633
1841
|
for (const [id, mcpDef] of Object.entries(registryMcp)) {
|
|
@@ -1656,7 +1864,7 @@ function syncOpencode(entries, targetDir = null, wants = true) {
|
|
|
1656
1864
|
// into EVERY agent's request — github ~30k alone (fixtures 2026-06-22) —
|
|
1657
1865
|
// agent's request — including the built-in Build/Plan agents the per-agent
|
|
1658
1866
|
// permission prune cannot reach. OpenCode 1.15.4 has no per-session tool
|
|
1659
|
-
// filter (chat.params carries no tool list), so disabling the whole server in
|
|
1867
|
+
// filter (OpenCode chat.params carries no tool list), so disabling the whole server in
|
|
1660
1868
|
// opencode.json is the only lever. The decision is INTENT-driven: trim only
|
|
1661
1869
|
// when this config's own default model is local (or a local Ollama provider is
|
|
1662
1870
|
// registered in it), so a cloud session on a machine that merely also has
|
|
@@ -1689,7 +1897,8 @@ function syncOpencode(entries, targetDir = null, wants = true) {
|
|
|
1689
1897
|
for (const key of Object.keys(config.agent)) {
|
|
1690
1898
|
const isManaged = prefixes.some((p) => key.startsWith(p));
|
|
1691
1899
|
const isOrchestrator = registry.orchestrator?.name === key;
|
|
1692
|
-
|
|
1900
|
+
const isStaleOrchestratorAlias = key === 'orchestrator' && registry.orchestrator?.name === 'construct';
|
|
1901
|
+
if ((isManaged || isOrchestrator || isStaleOrchestratorAlias) && !writeEntries.find((e) => adapterName(e) === key)) {
|
|
1693
1902
|
delete config.agent[key];
|
|
1694
1903
|
}
|
|
1695
1904
|
}
|
|
@@ -1780,21 +1989,28 @@ function syncOpencode(entries, targetDir = null, wants = true) {
|
|
|
1780
1989
|
config.construct = config.construct || {};
|
|
1781
1990
|
config.construct.models = { ...resolvedModels };
|
|
1782
1991
|
|
|
1783
|
-
//
|
|
1784
|
-
//
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
//
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1992
|
+
// OpenCode's primary `model` is user-owned. Remove the legacy Construct seed
|
|
1993
|
+
// when we find it so the app can fall back to its own remembered selection
|
|
1994
|
+
// instead of a stale pin. New syncs never write this key back.
|
|
1995
|
+
const legacyPinnedModels = new Set([
|
|
1996
|
+
opencodeTemplate.model,
|
|
1997
|
+
hardDefaults.standard,
|
|
1998
|
+
].filter(Boolean));
|
|
1999
|
+
if (!targetDir && legacyPinnedModels.has(config.model)) {
|
|
2000
|
+
delete config.model;
|
|
2001
|
+
}
|
|
2002
|
+
|
|
2003
|
+
// OpenCode's built-in helper agents drive session naming, summaries, and
|
|
2004
|
+
// compaction. Keep them on a stronger auxiliary model so those surfaces do not
|
|
2005
|
+
// inherit the main chat model's selection history or a low-end coder default.
|
|
2006
|
+
const auxiliaryModel = resolvedModels.reasoning || resolvedModels.standard || resolvedModels.fast;
|
|
2007
|
+
if (auxiliaryModel) {
|
|
2008
|
+
for (const key of ["title", "summary", "compaction"]) {
|
|
2009
|
+
config.agent[key] = {
|
|
2010
|
+
...(config.agent[key] && typeof config.agent[key] === "object" ? config.agent[key] : {}),
|
|
2011
|
+
model: auxiliaryModel,
|
|
2012
|
+
};
|
|
2013
|
+
}
|
|
1798
2014
|
}
|
|
1799
2015
|
|
|
1800
2016
|
writeOpenCodeConfig(config, configPath);
|
|
@@ -1943,6 +2159,7 @@ function syncSkills(targetDir = null) {
|
|
|
1943
2159
|
|
|
1944
2160
|
// --- Main ---
|
|
1945
2161
|
|
|
2162
|
+
if (isMain) {
|
|
1946
2163
|
const entries = buildEntries();
|
|
1947
2164
|
|
|
1948
2165
|
if (COMPRESS_PERSONAS) {
|
|
@@ -2035,3 +2252,4 @@ try {
|
|
|
2035
2252
|
} finally {
|
|
2036
2253
|
releaseLock();
|
|
2037
2254
|
}
|
|
2255
|
+
}
|
|
@@ -6,7 +6,7 @@ artifactType: prompt
|
|
|
6
6
|
---
|
|
7
7
|
# Prompt Auto-Optimization Loop
|
|
8
8
|
|
|
9
|
-
Construct's prompt improvement system uses telemetry traces and quality scores as the feedback signal, Claude as the optimizer, and the
|
|
9
|
+
Construct's prompt improvement system uses telemetry traces and quality scores as the feedback signal, Claude as the optimizer, and the modular org registry (`specialists/org/`, assembled at runtime via `loadRegistry()`) as the deployment layer. This is a closed loop: production data → failure analysis → improved prompt → staging → promotion.
|
|
10
10
|
|
|
11
11
|
## Running the optimizer
|
|
12
12
|
|
|
@@ -34,7 +34,7 @@ The optimizer requires Python 3.12+ (`pip3` must be available). It will auto-ins
|
|
|
34
34
|
|
|
35
35
|
## Step 1: Gather signal
|
|
36
36
|
|
|
37
|
-
Retrieve the current production prompt for the target agent from `specialists/
|
|
37
|
+
Retrieve the current production prompt for the target agent from the specialist entry under `specialists/org/specialists/` (or the corresponding `promptFile` if using extracted prompts).
|
|
38
38
|
|
|
39
39
|
Then retrieve recent traces via the telemetry backend REST API:
|
|
40
40
|
|
|
@@ -76,7 +76,7 @@ Write an improved prompt that directly addresses the diagnosed failures. Rules:
|
|
|
76
76
|
|
|
77
77
|
## Step 4: Push to staging
|
|
78
78
|
|
|
79
|
-
Update the agent's prompt in `specialists/
|
|
79
|
+
Update the agent's prompt in `specialists/org/specialists/<agent>.json` (or the corresponding `promptFile`) with a staging marker comment. Tag the version by writing to `.cx/decisions/prompt-staging-{agent}-{date}.md`.
|
|
80
80
|
|
|
81
81
|
Log the candidate prompt as a span attribute on a test run batch using `cx_trace`. Tag spans with `promptVersion: staging-{timestamp}` and score them with `cx_score` as traces complete.
|
|
82
82
|
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: brand-output-vibe
|
|
3
|
+
description: Use when drafting or exporting customer-facing artifacts (PRD, deck, brief, runbook). Sets typography, prose rhythm, sketch diagrams, and export consistency.
|
|
4
|
+
inputs: [artifact-draft, export-target]
|
|
5
|
+
artifactType: style-guide
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Output vibe (construct-modern)
|
|
9
|
+
|
|
10
|
+
Apply this skill before drafting or exporting any customer-facing artifact (PRD, deck, brief, runbook, video script). User instructions always win; this sets the default feel.
|
|
11
|
+
|
|
12
|
+
## Typography and color
|
|
13
|
+
|
|
14
|
+
- Sans: Space Grotesk (400–700). Mono: JetBrains Mono for code, IDs, and tables.
|
|
15
|
+
- Monochrome ink ramp only for page furniture: near-black body (`#23272e`), muted labels (`#565c66`), hairline rules (`#e3e4e8`). Color belongs in diagrams and data, not chrome.
|
|
16
|
+
- Do not stamp "Construct" on external deliverables unless the user asks.
|
|
17
|
+
|
|
18
|
+
## Prose rhythm
|
|
19
|
+
|
|
20
|
+
- Lead with a short declarative paragraph, then structure (headings, one compact table, selective bullets).
|
|
21
|
+
- Avoid bullet walls; never more than seven bullets in a row without a prose bridge.
|
|
22
|
+
- Rare em dashes; prefer commas or parentheses.
|
|
23
|
+
|
|
24
|
+
## Diagrams (sketch-forward)
|
|
25
|
+
|
|
26
|
+
- Prefer hand-drawn / sketch aesthetic over rigid box-and-arrow clipart.
|
|
27
|
+
- In Mermaid, open with a sketch theme block:
|
|
28
|
+
|
|
29
|
+
```mermaid
|
|
30
|
+
%%{init: {'theme': 'base', 'themeVariables': { 'primaryColor': '#fafafa', 'primaryBorderColor': '#565c66', 'lineColor': '#23272e', 'fontFamily': 'Space Grotesk'}}}%%
|
|
31
|
+
flowchart LR
|
|
32
|
+
User --> Product
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
- For high-touch user flows, an Excalidraw embed (`*.excalidraw` beside the doc) is acceptable when Mermaid feels too mechanical.
|
|
36
|
+
- Every flowchart shows at least one non-happy path (error, escalation, or rollback).
|
|
37
|
+
|
|
38
|
+
## Tables and metrics
|
|
39
|
+
|
|
40
|
+
- Use tables for metrics, acceptance criteria, and comparisons — not for narrative.
|
|
41
|
+
- Pin baselines and targets; cite sources or mark `[unverified]`.
|
|
42
|
+
|
|
43
|
+
## Export parity
|
|
44
|
+
|
|
45
|
+
- PDF/HTML/PPTX inherit the same fonts and ink ramp from distribution templates.
|
|
46
|
+
- No stock clip-art icons; use simple line icons or typographic labels.
|
|
47
|
+
|
|
48
|
+
When invoked at the start of a workflow skill, restate which vibe choices apply to this artifact type in one sentence, then proceed.
|
|
@@ -30,3 +30,6 @@ Use when: an architectural decision is made that affects the system structure, d
|
|
|
30
30
|
## Cross-referencing
|
|
31
31
|
- If this ADR supersedes another: update the old ADR's status field
|
|
32
32
|
- If this ADR depends on another: add a References link
|
|
33
|
+
## Release gate
|
|
34
|
+
|
|
35
|
+
Run `construct artifact validate <path> --type=<type>` before marking the artifact approved.
|
|
@@ -21,3 +21,6 @@ Use when: product evidence should create or update Jira, Linear, GitHub Issues,
|
|
|
21
21
|
## Rules
|
|
22
22
|
|
|
23
23
|
Never write externally from weak evidence without making the risk explicit. Never create duplicate issues when an existing issue can be updated.
|
|
24
|
+
## Release gate
|
|
25
|
+
|
|
26
|
+
Run `construct artifact validate <path> --type=<type>` before marking the artifact approved.
|