@geraldmaron/construct 1.0.5 → 1.0.6

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 (209) hide show
  1. package/README.md +8 -4
  2. package/agents/prompts/cx-accessibility.md +3 -3
  3. package/agents/prompts/cx-ai-engineer.md +7 -7
  4. package/agents/prompts/cx-architect.md +6 -6
  5. package/agents/prompts/cx-business-strategist.md +6 -6
  6. package/agents/prompts/cx-data-analyst.md +7 -7
  7. package/agents/prompts/cx-data-engineer.md +3 -3
  8. package/agents/prompts/cx-debugger.md +6 -6
  9. package/agents/prompts/cx-designer.md +5 -5
  10. package/agents/prompts/cx-devil-advocate.md +4 -4
  11. package/agents/prompts/cx-docs-keeper.md +5 -5
  12. package/agents/prompts/cx-engineer.md +5 -5
  13. package/agents/prompts/cx-evaluator.md +2 -2
  14. package/agents/prompts/cx-explorer.md +8 -8
  15. package/agents/prompts/cx-legal-compliance.md +2 -2
  16. package/agents/prompts/cx-operations.md +5 -5
  17. package/agents/prompts/cx-orchestrator.md +10 -10
  18. package/agents/prompts/cx-platform-engineer.md +5 -5
  19. package/agents/prompts/cx-product-manager.md +4 -4
  20. package/agents/prompts/cx-qa.md +8 -8
  21. package/agents/prompts/cx-rd-lead.md +9 -9
  22. package/agents/prompts/cx-release-manager.md +5 -5
  23. package/agents/prompts/cx-researcher.md +22 -22
  24. package/agents/prompts/cx-reviewer.md +7 -7
  25. package/agents/prompts/cx-security.md +10 -10
  26. package/agents/prompts/cx-sre.md +7 -7
  27. package/agents/prompts/cx-test-automation.md +3 -3
  28. package/agents/prompts/cx-trace-reviewer.md +8 -8
  29. package/agents/prompts/cx-ux-researcher.md +3 -3
  30. package/bin/construct +235 -21
  31. package/commands/build/feature.md +4 -4
  32. package/commands/build/fix.md +8 -8
  33. package/commands/design/access.md +3 -3
  34. package/commands/design/flow.md +3 -3
  35. package/commands/design/ui.md +4 -4
  36. package/commands/measure/experiment.md +5 -5
  37. package/commands/measure/metrics.md +3 -3
  38. package/commands/measure/results.md +4 -4
  39. package/commands/plan/api.md +3 -3
  40. package/commands/plan/challenge.md +3 -3
  41. package/commands/plan/decide.md +3 -3
  42. package/commands/plan/feature.md +7 -7
  43. package/commands/plan/requirements.md +3 -3
  44. package/commands/remember/context.md +5 -5
  45. package/commands/remember/handoff.md +3 -3
  46. package/commands/remember/runbook.md +3 -3
  47. package/commands/review/code.md +8 -8
  48. package/commands/review/quality.md +4 -4
  49. package/commands/review/security.md +3 -3
  50. package/commands/ship/ready.md +3 -3
  51. package/commands/ship/release.md +3 -3
  52. package/commands/ship/status.md +4 -4
  53. package/commands/understand/docs.md +3 -3
  54. package/commands/understand/this.md +4 -4
  55. package/commands/understand/why.md +8 -8
  56. package/commands/work/clean.md +14 -14
  57. package/commands/work/drive.md +10 -10
  58. package/commands/work/optimize-prompts.md +9 -9
  59. package/commands/work/parallel-review.md +8 -8
  60. package/db/schema/006_graph.sql +24 -0
  61. package/examples/provider-plugin/README.md +7 -7
  62. package/examples/seed-observations/README.md +6 -6
  63. package/examples/seed-observations/anti-patterns.md +14 -14
  64. package/examples/seed-observations/decisions.md +4 -4
  65. package/examples/seed-observations/patterns.md +14 -14
  66. package/lib/auto-docs.mjs +8 -3
  67. package/lib/cli-commands.mjs +2 -2
  68. package/lib/flavors/loader.mjs +1 -1
  69. package/lib/knowledge/graph.mjs +213 -0
  70. package/lib/mcp/server.mjs +187 -1
  71. package/lib/mcp/tools/profile.mjs +270 -0
  72. package/package.json +1 -1
  73. package/platforms/claude/CLAUDE.md +6 -6
  74. package/rules/common/agents.md +2 -2
  75. package/rules/common/beads-hygiene.md +11 -11
  76. package/rules/common/code-review.md +1 -1
  77. package/rules/common/coding-style.md +1 -1
  78. package/rules/common/comments.md +8 -8
  79. package/rules/common/commit-approval.md +4 -4
  80. package/rules/common/cx-agent-routing.md +2 -2
  81. package/rules/common/cx-skill-routing.md +2 -2
  82. package/rules/common/development-workflow.md +1 -1
  83. package/rules/common/doc-ownership.md +2 -2
  84. package/rules/common/efficiency.md +3 -3
  85. package/rules/common/framing.md +1 -1
  86. package/rules/common/git-workflow.md +1 -1
  87. package/rules/common/patterns.md +1 -1
  88. package/rules/common/performance.md +1 -1
  89. package/rules/common/release-gates.md +7 -7
  90. package/rules/common/research.md +4 -4
  91. package/rules/common/security.md +1 -1
  92. package/rules/common/skill-composition.md +8 -8
  93. package/rules/common/testing.md +1 -1
  94. package/rules/golang/coding-style.md +2 -2
  95. package/rules/golang/hooks.md +1 -1
  96. package/rules/golang/patterns.md +1 -1
  97. package/rules/golang/security.md +1 -1
  98. package/rules/golang/testing.md +1 -1
  99. package/rules/python/coding-style.md +1 -1
  100. package/rules/python/hooks.md +1 -1
  101. package/rules/python/patterns.md +1 -1
  102. package/rules/python/security.md +1 -1
  103. package/rules/python/testing.md +1 -1
  104. package/rules/swift/coding-style.md +3 -3
  105. package/rules/swift/hooks.md +2 -2
  106. package/rules/swift/patterns.md +2 -2
  107. package/rules/swift/security.md +4 -4
  108. package/rules/swift/testing.md +2 -2
  109. package/rules/typescript/coding-style.md +1 -1
  110. package/rules/typescript/hooks.md +1 -1
  111. package/rules/typescript/patterns.md +1 -1
  112. package/rules/typescript/security.md +1 -1
  113. package/rules/typescript/testing.md +1 -1
  114. package/rules/web/coding-style.md +1 -1
  115. package/rules/web/design-quality.md +1 -1
  116. package/rules/web/hooks.md +1 -1
  117. package/rules/web/patterns.md +1 -1
  118. package/rules/web/performance.md +1 -1
  119. package/rules/web/security.md +1 -1
  120. package/rules/web/testing.md +1 -1
  121. package/skills/ai/agent-dev.md +1 -1
  122. package/skills/ai/llm-security.md +1 -1
  123. package/skills/ai/ml-ops.md +6 -6
  124. package/skills/ai/orchestration-workflow.md +1 -1
  125. package/skills/ai/prompt-and-eval.md +1 -1
  126. package/skills/ai/prompt-optimizer.md +13 -13
  127. package/skills/ai/rag-system.md +1 -1
  128. package/skills/architecture/api-design.md +1 -1
  129. package/skills/architecture/caching.md +1 -1
  130. package/skills/architecture/cloud-native.md +1 -1
  131. package/skills/architecture/message-queue.md +1 -1
  132. package/skills/architecture/security-arch.md +1 -1
  133. package/skills/compliance/ai-disclosure.md +1 -1
  134. package/skills/compliance/data-privacy.md +1 -1
  135. package/skills/compliance/license-audit.md +2 -2
  136. package/skills/compliance/regulatory-review.md +1 -1
  137. package/skills/development/cpp.md +1 -1
  138. package/skills/development/go.md +1 -1
  139. package/skills/development/java.md +1 -1
  140. package/skills/development/kotlin.md +9 -9
  141. package/skills/development/mobile-crossplatform.md +13 -13
  142. package/skills/development/python.md +1 -1
  143. package/skills/development/rust.md +1 -1
  144. package/skills/development/shell.md +1 -1
  145. package/skills/development/swift.md +6 -6
  146. package/skills/development/typescript.md +1 -1
  147. package/skills/devops/ci-cd.md +5 -5
  148. package/skills/devops/containerization.md +9 -9
  149. package/skills/devops/cost-optimization.md +1 -1
  150. package/skills/devops/data-engineering.md +2 -2
  151. package/skills/devops/database.md +1 -1
  152. package/skills/devops/dependency-management.md +3 -3
  153. package/skills/devops/devsecops.md +1 -1
  154. package/skills/devops/git-workflow.md +1 -1
  155. package/skills/devops/incident-response.md +18 -18
  156. package/skills/devops/monorepo.md +5 -5
  157. package/skills/devops/observability.md +1 -1
  158. package/skills/devops/performance.md +1 -1
  159. package/skills/devops/testing.md +1 -1
  160. package/skills/docs/adr-workflow.md +2 -2
  161. package/skills/docs/backlog-proposal-workflow.md +1 -1
  162. package/skills/docs/customer-profile-workflow.md +1 -1
  163. package/skills/docs/document-ingest-workflow.md +1 -1
  164. package/skills/docs/evidence-ingest-workflow.md +1 -1
  165. package/skills/docs/init-docs.md +15 -15
  166. package/skills/docs/init-project.md +1 -1
  167. package/skills/docs/prd-workflow.md +3 -3
  168. package/skills/docs/prfaq-workflow.md +1 -1
  169. package/skills/docs/product-intelligence-review.md +1 -1
  170. package/skills/docs/product-intelligence-workflow.md +1 -1
  171. package/skills/docs/product-signal-workflow.md +9 -9
  172. package/skills/docs/research-workflow.md +10 -10
  173. package/skills/docs/runbook-workflow.md +2 -2
  174. package/skills/docs/strategy-workflow.md +3 -3
  175. package/skills/exploration/repo-map.md +11 -11
  176. package/skills/frameworks/django.md +15 -15
  177. package/skills/frameworks/nextjs.md +16 -16
  178. package/skills/frameworks/react.md +12 -12
  179. package/skills/frameworks/spring-boot.md +12 -12
  180. package/skills/frontend-design/accessibility.md +6 -6
  181. package/skills/frontend-design/component-patterns.md +1 -1
  182. package/skills/frontend-design/engineering.md +1 -1
  183. package/skills/frontend-design/state-management.md +1 -1
  184. package/skills/frontend-design/ui-aesthetics.md +1 -1
  185. package/skills/frontend-design/ux-principles.md +1 -1
  186. package/skills/operating/orchestration-reference.md +27 -27
  187. package/skills/quality-gates/review-work.md +3 -3
  188. package/skills/quality-gates/verify-change.md +1 -1
  189. package/skills/quality-gates/verify-module.md +1 -1
  190. package/skills/quality-gates/verify-quality.md +1 -1
  191. package/skills/quality-gates/verify-security.md +1 -1
  192. package/skills/routing.md +14 -14
  193. package/skills/security/blue-team.md +1 -1
  194. package/skills/security/code-audit.md +1 -1
  195. package/skills/security/pentest.md +1 -1
  196. package/skills/security/red-team.md +1 -1
  197. package/skills/security/threat-intel.md +1 -1
  198. package/skills/security/vuln-research.md +1 -1
  199. package/skills/utility/clean-code.md +2 -2
  200. package/templates/docs/changelog-entry.md +1 -1
  201. package/templates/docs/construct_guide.md +13 -13
  202. package/templates/docs/meta-prd.md +16 -16
  203. package/templates/docs/one-pager.md +1 -1
  204. package/templates/docs/prd-business.md +1 -1
  205. package/templates/docs/prd-platform.md +1 -1
  206. package/templates/docs/prd.md +17 -17
  207. package/templates/docs/research-brief.md +8 -8
  208. package/templates/docs/rfc.md +1 -1
  209. package/templates/docs/strategy.md +1 -1
package/bin/construct CHANGED
@@ -3994,18 +3994,85 @@ const handlers = new Map([
3994
3994
  }
3995
3995
  if (sub === 'set') {
3996
3996
  const id = args[1];
3997
- if (!id) { errorln('Usage: construct profile set <id>'); process.exit(1); }
3997
+ if (!id) {
3998
+ errorln('Usage: construct profile set <id> [--yes] [--dry-run]');
3999
+ process.exit(1);
4000
+ }
3998
4001
  const target = loadProfile(id);
3999
4002
  if (!target) {
4000
4003
  errorln(`Unknown profile: ${id}. Available: ${listProfiles().join(', ')}`);
4001
4004
  process.exit(1);
4002
4005
  }
4006
+ const skipConfirm = args.includes('--yes') || args.includes('-y') || args.includes('--non-interactive');
4007
+ const dryRun = args.includes('--dry-run');
4008
+ const isTTY = process.stdin.isTTY && process.stdout.isTTY;
4009
+
4003
4010
  const { findProjectConfigPath, loadProjectConfig, writeProjectConfig, PROJECT_CONFIG_FILENAME } = await import('../lib/config/project-config.mjs');
4004
- const fsMod = await import('node:fs');
4005
4011
  const pathMod = await import('node:path');
4006
4012
  const found = findProjectConfigPath(process.cwd());
4007
4013
  const cfgPath = found || pathMod.join(process.cwd(), PROJECT_CONFIG_FILENAME);
4008
- const cfg = found ? (loadProjectConfig(process.cwd()) || { version: 1 }) : { version: 1 };
4014
+ // loadProjectConfig returns a wrapper { path, raw, config, source, errors };
4015
+ // operate on the raw user-authored object so the write call sees the
4016
+ // version field that validateProjectConfig requires.
4017
+ const loaded = found ? loadProjectConfig(process.cwd()) : null;
4018
+ const cfg = loaded?.raw ? structuredClone(loaded.raw) : { version: 1 };
4019
+ if (!cfg.version) cfg.version = 1;
4020
+
4021
+ const currentId = cfg.profile || 'rnd';
4022
+ if (currentId === id) {
4023
+ println(`Profile already set to ${id} (${target.displayName}). Nothing to do.`);
4024
+ return;
4025
+ }
4026
+ const current = loadProfile(currentId) || { id: currentId, displayName: currentId, roles: [], intake: { types: [], stages: [] }, departments: [] };
4027
+
4028
+ // Render a structural diff so the operator sees what loop they are switching into.
4029
+ const setDiff = (label, before, after) => {
4030
+ const b = new Set(before || []);
4031
+ const a = new Set(after || []);
4032
+ const added = [...a].filter((x) => !b.has(x));
4033
+ const removed = [...b].filter((x) => !a.has(x));
4034
+ const unchanged = [...a].filter((x) => b.has(x));
4035
+ println(` ${label}:`);
4036
+ if (added.length) println(` + ${added.join(', ')}`);
4037
+ if (removed.length) println(` - ${removed.join(', ')}`);
4038
+ if (!added.length && !removed.length) println(` (no change, ${unchanged.length} entr${unchanged.length === 1 ? 'y' : 'ies'})`);
4039
+ };
4040
+
4041
+ println('');
4042
+ println(`About to switch active profile:`);
4043
+ println(` from: ${currentId} (${current.displayName})`);
4044
+ println(` to: ${id} (${target.displayName})`);
4045
+ println('');
4046
+ println(`Structural diff:`);
4047
+ setDiff('roles', current.roles, target.roles);
4048
+ setDiff('intake.types', current.intake?.types, target.intake?.types);
4049
+ setDiff('intake.stages', current.intake?.stages, target.intake?.stages);
4050
+ const cDept = (current.departments || []).map((d) => d.id);
4051
+ const tDept = (target.departments || []).map((d) => d.id);
4052
+ setDiff('departments', cDept, tDept);
4053
+ println('');
4054
+ println(`Files that will change:`);
4055
+ println(` ${pathMod.relative(process.cwd(), cfgPath)} (profile field: ${currentId} -> ${id})`);
4056
+ println('');
4057
+ println(`The change only writes the profile field. No specialists are added or removed.`);
4058
+ println(`Sync runs against the new profile on next \`construct sync\`.`);
4059
+ println('');
4060
+
4061
+ if (dryRun) {
4062
+ println(`[dry-run] No files were written.`);
4063
+ return;
4064
+ }
4065
+ if (!skipConfirm && isTTY) {
4066
+ const readline = await import('node:readline');
4067
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
4068
+ const answer = await new Promise((res) => rl.question(`Switch profile to ${id}? (Y/n) `, (a) => res(a.trim().toLowerCase())));
4069
+ rl.close();
4070
+ if (answer && answer !== 'y' && answer !== 'yes') {
4071
+ println('Aborted. No config was changed.');
4072
+ return;
4073
+ }
4074
+ }
4075
+
4009
4076
  cfg.profile = id;
4010
4077
  writeProjectConfig(cfgPath, cfg, { validate: true });
4011
4078
  process.stdout.write(`✓ profile set to ${id} (${target.displayName})\n`);
@@ -4014,36 +4081,111 @@ const handlers = new Map([
4014
4081
  if (sub === 'create') {
4015
4082
  const id = args[1];
4016
4083
  if (!id) {
4017
- errorln('Usage: construct profile create <id> [--display="..."] [--role=<id>...] [--department=<id>:<displayName>...]');
4084
+ errorln('Usage: construct profile create <id> [--display="..."] [--role=<id>...] [--department=<id>:<displayName>...] [--yes]');
4085
+ errorln(' Run with no flags for interactive mode; pass --yes to skip the confirmation prompt.');
4018
4086
  process.exit(1);
4019
4087
  }
4088
+ if (!/^[a-z][a-z0-9-]{1,30}$/.test(id)) {
4089
+ errorln(`Invalid id "${id}". Must match ^[a-z][a-z0-9-]{1,30}$.`);
4090
+ process.exit(1);
4091
+ }
4092
+
4020
4093
  const displayArg = args.find((a) => a.startsWith('--display='));
4021
- const displayName = displayArg ? displayArg.split('=')[1] : id;
4022
- const seedRoles = args
4094
+ const skipConfirm = args.includes('--yes') || args.includes('-y') || args.includes('--non-interactive');
4095
+ const dryRun = args.includes('--dry-run');
4096
+ const isTTY = process.stdin.isTTY && process.stdout.isTTY;
4097
+
4098
+ let displayName = displayArg ? displayArg.split('=')[1] : null;
4099
+ let seedRoles = args
4023
4100
  .filter((a) => a.startsWith('--role='))
4024
4101
  .map((a) => a.slice('--role='.length))
4025
4102
  .filter(Boolean);
4026
- const seedDepartments = args
4103
+ let seedDepartments = args
4027
4104
  .filter((a) => a.startsWith('--department='))
4028
4105
  .map((a) => a.slice('--department='.length))
4029
4106
  .map((spec) => {
4030
4107
  const [deptId, deptDisplay] = spec.split(':');
4031
4108
  return { id: deptId, displayName: deptDisplay || deptId };
4032
4109
  });
4110
+
4111
+ // Interactive gather. Only prompt when stdin is a real terminal and the
4112
+ // operator did not pass enough flags to scaffold without input. A
4113
+ // non-TTY invocation with no flags falls through to an empty scaffold
4114
+ // so scripts and CI can still create drafts non-interactively.
4115
+ const needsInteractive = isTTY && !skipConfirm && (!displayName || (seedRoles.length === 0 && seedDepartments.length === 0));
4116
+ if (needsInteractive) {
4117
+ const readline = await import('node:readline');
4118
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
4119
+ const ask = (q, def = '') => new Promise((res) => rl.question(`${q}${def ? ` [${def}]` : ''} `, (a) => res(a.trim() || def)));
4120
+
4121
+ println('');
4122
+ println(`Scaffolding a new profile draft. Three questions, then a preview.`);
4123
+ println(`Background: docs/concepts/persona-research.md and docs/concepts/profile-lifecycle.md`);
4124
+ println('');
4125
+ if (!displayName) displayName = await ask('Display name?', id);
4126
+ if (seedDepartments.length === 0) {
4127
+ const dInput = await ask('Departments (id:Name, id:Name, ...)?', '');
4128
+ if (dInput) seedDepartments = dInput.split(',').map((s) => s.trim()).filter(Boolean).map((spec) => {
4129
+ const [dId, dName] = spec.split(':').map((x) => x.trim());
4130
+ return { id: dId, displayName: dName || dId };
4131
+ });
4132
+ }
4133
+ if (seedRoles.length === 0) {
4134
+ const rInput = await ask('Roles (role-id, role-id, ...)?', '');
4135
+ if (rInput) seedRoles = rInput.split(',').map((s) => s.trim()).filter(Boolean);
4136
+ }
4137
+ rl.close();
4138
+ }
4139
+ if (!displayName) displayName = id;
4140
+
4141
+ const pathMod = await import('node:path');
4142
+ const draftRoot = pathMod.join(process.cwd(), '.cx', 'profiles', `draft-${id}`);
4143
+
4144
+ println('');
4145
+ println(`About to scaffold a draft profile:`);
4146
+ println(` id: ${id}`);
4147
+ println(` displayName: ${displayName}`);
4148
+ println(` departments: ${seedDepartments.length}${seedDepartments.length ? ` (${seedDepartments.map((d) => d.id).join(', ')})` : ''}`);
4149
+ println(` roles: ${seedRoles.length}${seedRoles.length ? ` (${seedRoles.join(', ')})` : ''}`);
4150
+ println('');
4151
+ println(`Files that will be written under ${pathMod.relative(process.cwd(), draftRoot)}/:`);
4152
+ println(` profile.json structural manifest`);
4153
+ println(` requirements.md research brief naming each cx-* specialist`);
4154
+ for (const r of seedRoles) println(` personas/${r}.md`.padEnd(40) + ` persona artifact (filled during discover)`);
4155
+ for (const d of seedDepartments) println(` departments/${d.id}.md`.padEnd(40) + ` department charter (filled during frame)`);
4156
+ println('');
4157
+ println(`Nothing else is touched. No config is changed, no active profile is switched.`);
4158
+ println(`To activate this profile after promotion: construct profile set ${id}`);
4159
+ println('');
4160
+
4161
+ if (dryRun) {
4162
+ println(`[dry-run] No files were written.`);
4163
+ return;
4164
+ }
4165
+ if (!skipConfirm && isTTY) {
4166
+ const readline = await import('node:readline');
4167
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
4168
+ const answer = await new Promise((res) => rl.question('Create draft? (Y/n) ', (a) => res(a.trim().toLowerCase())));
4169
+ rl.close();
4170
+ if (answer && answer !== 'y' && answer !== 'yes') {
4171
+ println('Aborted. Nothing was written.');
4172
+ return;
4173
+ }
4174
+ }
4175
+
4033
4176
  const { createDraftProfile } = await import('../lib/profiles/lifecycle.mjs');
4034
4177
  try {
4035
4178
  const result = createDraftProfile({ cwd: process.cwd(), id, displayName, seedRoles, seedDepartments });
4036
- const pathMod = await import('node:path');
4037
- process.stdout.write(`✓ draft created for ${id}\n`);
4038
- process.stdout.write(` brief: ${pathMod.relative(process.cwd(), result.briefPath)}\n`);
4039
- process.stdout.write(` draft: ${pathMod.relative(process.cwd(), result.draftPath)}\n`);
4040
- if (result.personaPaths.length) process.stdout.write(` personas: ${result.personaPaths.length} scaffold(s) under personas/\n`);
4041
- if (result.departmentPaths.length) process.stdout.write(` departments: ${result.departmentPaths.length} charter(s) under departments/\n`);
4042
- process.stdout.write(`\nNext steps (in order, per docs/concepts/profile-lifecycle.md):\n`);
4043
- process.stdout.write(` 1. Discover: dispatch cx-ux-researcher to fill personas/<role>.md from interviews + primary sources.\n`);
4044
- process.stdout.write(` 2. Frame: dispatch cx-product-manager to fill departments/<dept>.md charters and the intake taxonomy in profile.json.\n`);
4045
- process.stdout.write(` 3. Architect: dispatch cx-architect to reconcile role reuse vs new, and to populate departments[].\n`);
4046
- process.stdout.write(` 4. Validate: dispatch cx-evaluator to run persona-eval and classifier-eval against representative signals.\n`);
4179
+ println('');
4180
+ println(`✓ draft created at ${pathMod.relative(process.cwd(), result.dir)}`);
4181
+ println('');
4182
+ println(`Next steps (in order, per docs/concepts/profile-lifecycle.md):`);
4183
+ println(` 1. Discover (cx-ux-researcher): fill personas/<role>.md from interviews + primary sources.`);
4184
+ println(` 2. Frame (cx-product-manager): fill departments/<dept>.md charters and intake taxonomy.`);
4185
+ println(` 3. Architect (cx-architect): reconcile role reuse vs new; populate departments[] in profile.json.`);
4186
+ println(` 4. Validate (cx-evaluator): run persona-eval and classifier-eval against representative signals.`);
4187
+ println('');
4188
+ println(`Inspect the brief: open ${pathMod.relative(process.cwd(), result.briefPath)}`);
4047
4189
  return;
4048
4190
  } catch (err) {
4049
4191
  errorln(err.message);
@@ -4063,12 +4205,84 @@ const handlers = new Map([
4063
4205
  if (sub === 'archive') {
4064
4206
  const id = args[1];
4065
4207
  const reasonArg = args.find((a) => a.startsWith('--reason='));
4066
- const reason = reasonArg ? reasonArg.split('=')[1] : '';
4067
- if (!id) { errorln('Usage: construct profile archive <id> --reason="..."'); process.exit(1); }
4208
+ let reason = reasonArg ? reasonArg.split('=')[1] : '';
4209
+ if (!id) {
4210
+ errorln('Usage: construct profile archive <id> --reason="..." [--yes] [--dry-run]');
4211
+ process.exit(1);
4212
+ }
4213
+ const skipConfirm = args.includes('--yes') || args.includes('-y') || args.includes('--non-interactive');
4214
+ const dryRun = args.includes('--dry-run');
4215
+ const isTTY = process.stdin.isTTY && process.stdout.isTTY;
4216
+
4217
+ const pathMod = await import('node:path');
4218
+ const fsMod = await import('node:fs');
4219
+ const target = loadProfile(id);
4220
+ if (!target) {
4221
+ errorln(`Unknown profile: ${id}. Curated catalog: ${listProfiles().join(', ')}`);
4222
+ process.exit(1);
4223
+ }
4224
+ const fileURL = await import('node:url');
4225
+ const moduleDir = pathMod.dirname(fileURL.fileURLToPath(import.meta.url));
4226
+ const repoRoot = pathMod.resolve(moduleDir, '..');
4227
+ const srcProfile = pathMod.join(repoRoot, 'profiles', `${id}.json`);
4228
+ const tableRel = typeof target?.intake?.classificationTable === 'string' ? target.intake.classificationTable : null;
4229
+ const srcTable = tableRel ? pathMod.join(repoRoot, tableRel) : null;
4230
+ const dstDir = pathMod.join(repoRoot, 'archive', 'profiles', id);
4231
+
4232
+ // Gather reason interactively if missing. The lifecycle module already
4233
+ // enforces a >= 8 char reason, but the operator should see why before
4234
+ // the call fails.
4235
+ if (!reason && isTTY && !skipConfirm) {
4236
+ const readline = await import('node:readline');
4237
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
4238
+ reason = await new Promise((res) => rl.question('Archive reason (>= 8 chars): ', (a) => res(a.trim())));
4239
+ rl.close();
4240
+ }
4241
+ if (!reason || reason.trim().length < 8) {
4242
+ errorln('A substantive --reason (>= 8 chars) is required. Archiving is permanent in repo history; the reason becomes the archive note.');
4243
+ process.exit(1);
4244
+ }
4245
+
4246
+ println('');
4247
+ println(`About to archive curated profile:`);
4248
+ println(` id: ${id}`);
4249
+ println(` displayName: ${target.displayName || id}`);
4250
+ println(` reason: ${reason}`);
4251
+ println('');
4252
+ println(`Files that will move:`);
4253
+ println(` ${pathMod.relative(process.cwd(), srcProfile)}`);
4254
+ println(` -> ${pathMod.relative(process.cwd(), pathMod.join(dstDir, `${id}.json`))}`);
4255
+ if (srcTable && fsMod.existsSync(srcTable)) {
4256
+ println(` ${pathMod.relative(process.cwd(), srcTable)}`);
4257
+ println(` -> ${pathMod.relative(process.cwd(), pathMod.join(dstDir, pathMod.basename(srcTable)))}`);
4258
+ }
4259
+ println(` ${pathMod.relative(process.cwd(), pathMod.join(dstDir, 'archive-note.md'))} (new)`);
4260
+ println('');
4261
+ println(`What stays:`);
4262
+ println(` Observations under .cx/observations/ are not touched.`);
4263
+ println(` Outcomes under .cx/outcomes/ are not touched.`);
4264
+ println(` Any project still configured with profile=${id} will fall back to rnd on next load.`);
4265
+ println('');
4266
+
4267
+ if (dryRun) {
4268
+ println(`[dry-run] No files were moved.`);
4269
+ return;
4270
+ }
4271
+ if (!skipConfirm && isTTY) {
4272
+ const readline = await import('node:readline');
4273
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
4274
+ const answer = await new Promise((res) => rl.question(`Archive ${id}? (y/N) `, (a) => res(a.trim().toLowerCase())));
4275
+ rl.close();
4276
+ if (answer !== 'y' && answer !== 'yes') {
4277
+ println('Aborted. Nothing was archived.');
4278
+ return;
4279
+ }
4280
+ }
4281
+
4068
4282
  const { archiveProfile } = await import('../lib/profiles/lifecycle.mjs');
4069
4283
  try {
4070
4284
  const { archived } = archiveProfile({ id, reason });
4071
- process.stdout.write(`✓ archived ${id} to ${archived}\n`);
4285
+ process.stdout.write(`✓ archived ${id} to ${pathMod.relative(process.cwd(), archived)}\n`);
4072
4286
  return;
4073
4287
  } catch (err) {
4074
4288
  errorln(err.message);
@@ -1,10 +1,10 @@
1
1
  <!--
2
- commands/build/feature.md Build a feature implement it end to end, tested and ready to ship
2
+ commands/build/feature.md (Build a feature) implement it end to end, tested and ready to ship
3
3
 
4
- Build a feature implement it end to end, tested and ready to ship
4
+ Build a feature: implement it end to end, tested and ready to ship
5
5
  -->
6
6
  ---
7
- description: Build a feature implement it end to end, tested and ready to ship
7
+ description: Build a feature: implement it end to end, tested and ready to ship
8
8
  ---
9
9
 
10
10
  You are Construct. Build the following: $ARGUMENTS
@@ -18,4 +18,4 @@ produces no output or tool activity within two minutes, surface it to the user w
18
18
  agent description and elapsed time rather than waiting silently. Do not re-dispatch until
19
19
  the user confirms the prior invocation is not still running.
20
20
 
21
- Verification protocol is owned by `cx-engineer` apply its checklist before declaring done.
21
+ Verification protocol is owned by `cx-engineer`: apply its checklist before declaring done.
@@ -1,20 +1,20 @@
1
1
  <!--
2
- commands/build/fix.md Fix something broken reproduce, find the root cause, apply the smallest safe change
2
+ commands/build/fix.md (Fix something broken) reproduce, find the root cause, apply the smallest safe change
3
3
 
4
- Fix something broken reproduce, find the root cause, apply the smallest safe change
4
+ Fix something broken: reproduce, find the root cause, apply the smallest safe change
5
5
  -->
6
6
  ---
7
- description: Fix something broken reproduce, find the root cause, apply the smallest safe change
7
+ description: Fix something broken: reproduce, find the root cause, apply the smallest safe change
8
8
  ---
9
9
 
10
10
  You are Construct.
11
11
 
12
12
  Debugging protocol for: $ARGUMENTS
13
13
 
14
- 1. Reproduce confirm the failure is real and consistent
15
- 2. Isolate narrow to the smallest failing case
16
- 3. Trace follow execution to where the invariant breaks
17
- 4. Root cause the one upstream cause that prevents the failure when fixed
18
- 5. Fix the smallest safe change that restores the invariant
14
+ 1. Reproduce: confirm the failure is real and consistent
15
+ 2. Isolate: narrow to the smallest failing case
16
+ 3. Trace: follow execution to where the invariant breaks
17
+ 4. Root cause: the one upstream cause that prevents the failure when fixed
18
+ 5. Fix: the smallest safe change that restores the invariant
19
19
 
20
20
  Do not propose a fix until root cause is confirmed. After 3 failed attempts, stop and escalate.
@@ -1,10 +1,10 @@
1
1
  <!--
2
- commands/design/access.md Accessibility audit WCAG 2.1 AA, keyboard, screen readers, contrast, motion
2
+ commands/design/access.md (Accessibility audit) WCAG 2.1 AA, keyboard, screen readers, contrast, motion
3
3
 
4
- Accessibility audit WCAG 2.1 AA, keyboard, screen readers, contrast, motion
4
+ Accessibility audit: WCAG 2.1 AA, keyboard, screen readers, contrast, motion
5
5
  -->
6
6
  ---
7
- description: Accessibility audit WCAG 2.1 AA, keyboard, screen readers, contrast, motion
7
+ description: Accessibility audit: WCAG 2.1 AA, keyboard, screen readers, contrast, motion
8
8
  ---
9
9
 
10
10
  You are Construct. Audit: $ARGUMENTS
@@ -1,10 +1,10 @@
1
1
  <!--
2
- commands/design/flow.md Map the user flow entry to success, friction points, jobs-to-be-done
2
+ commands/design/flow.md (Map the user flow) entry to success, friction points, jobs-to-be-done
3
3
 
4
- Map the user flow entry to success, friction points, jobs-to-be-done
4
+ Map the user flow: entry to success, friction points, jobs-to-be-done
5
5
  -->
6
6
  ---
7
- description: Map the user flow entry to success, friction points, jobs-to-be-done
7
+ description: Map the user flow: entry to success, friction points, jobs-to-be-done
8
8
  ---
9
9
 
10
10
  You are Construct. Map the user flow for: $ARGUMENTS
@@ -1,16 +1,16 @@
1
1
  <!--
2
- commands/design/ui.md Design or review UI visual hierarchy, states, interaction model, accessibility baseline
2
+ commands/design/ui.md (Design or review UI) visual hierarchy, states, interaction model, accessibility baseline
3
3
 
4
- Design or review UI visual hierarchy, states, interaction model, accessibility baseline
4
+ Design or review UI: visual hierarchy, states, interaction model, accessibility baseline
5
5
  -->
6
6
  ---
7
- description: Design or review UI visual hierarchy, states, interaction model, accessibility baseline
7
+ description: Design or review UI: visual hierarchy, states, interaction model, accessibility baseline
8
8
  ---
9
9
 
10
10
  You are Construct. Design or review the UI for: $ARGUMENTS
11
11
 
12
12
  Every meaningful UI surface needs:
13
- - Clear hierarchy through scale contrast not uniform emphasis
13
+ - Clear hierarchy through scale contrast: not uniform emphasis
14
14
  - Every component state defined: empty, loading, error, success, edge cases
15
15
  - Hover, focus, and active states that feel designed
16
16
  - WCAG AA baseline: keyboard-navigable, 4.5:1 contrast, visible focus, ARIA labels
@@ -1,10 +1,10 @@
1
1
  <!--
2
- commands/measure/experiment.md Design an experiment hypothesis, test, evidence threshold, go/no-go decision
2
+ commands/measure/experiment.md (Design an experiment) hypothesis, test, evidence threshold, go/no-go decision
3
3
 
4
- Design an experiment hypothesis, test, evidence threshold, go/no-go decision
4
+ Design an experiment: hypothesis, test, evidence threshold, go/no-go decision
5
5
  -->
6
6
  ---
7
- description: Design an experiment hypothesis, test, evidence threshold, go/no-go decision
7
+ description: Design an experiment: hypothesis, test, evidence threshold, go/no-go decision
8
8
  ---
9
9
 
10
10
  You are Construct. Design an experiment for: $ARGUMENTS
@@ -12,7 +12,7 @@ You are Construct. Design an experiment for: $ARGUMENTS
12
12
  Produce:
13
13
  - HYPOTHESIS: "We believe [X] will result in [Y] because [Z]."
14
14
  - KEY UNKNOWNS: a small set of questions (typically 3-7) whose answers most change the decision
15
- - EXPERIMENT: cheapest useful test per unknown inputs, method, output artifact
15
+ - EXPERIMENT: cheapest useful test per unknown: inputs, method, output artifact
16
16
  - EVIDENCE THRESHOLD: what result confirms or disconfirms? Be specific.
17
- - RECOMMENDATION: explore | prototype | build | kill with rationale
17
+ - RECOMMENDATION: explore | prototype | build | kill: with rationale
18
18
  - WHAT NOT TO LOCK IN YET: decisions that must not harden before evidence arrives
@@ -1,10 +1,10 @@
1
1
  <!--
2
- commands/measure/metrics.md Define metrics what to measure, baselines, success thresholds, instrumentation needed
2
+ commands/measure/metrics.md (Define metrics) what to measure, baselines, success thresholds, instrumentation needed
3
3
 
4
- Define metrics what to measure, baselines, success thresholds, instrumentation needed
4
+ Define metrics: what to measure, baselines, success thresholds, instrumentation needed
5
5
  -->
6
6
  ---
7
- description: Define metrics what to measure, baselines, success thresholds, instrumentation needed
7
+ description: Define metrics: what to measure, baselines, success thresholds, instrumentation needed
8
8
  ---
9
9
 
10
10
  You are Construct. Define metrics for: $ARGUMENTS
@@ -1,17 +1,17 @@
1
1
  <!--
2
- commands/measure/results.md Analyze results interpret data, separate signal from noise, produce a recommendation
2
+ commands/measure/results.md (Analyze results) interpret data, separate signal from noise, produce a recommendation
3
3
 
4
- Analyze results interpret data, separate signal from noise, produce a recommendation
4
+ Analyze results: interpret data, separate signal from noise, produce a recommendation
5
5
  -->
6
6
  ---
7
- description: Analyze results interpret data, separate signal from noise, produce a recommendation
7
+ description: Analyze results: interpret data, separate signal from noise, produce a recommendation
8
8
  ---
9
9
 
10
10
  You are Construct. Analyze: $ARGUMENTS
11
11
 
12
12
  For each finding:
13
13
  - FINDING: what the data shows (with specific numbers)
14
- - CONFIDENCE: high / medium / low based on sample size and data quality
14
+ - CONFIDENCE: high / medium / low: based on sample size and data quality
15
15
  - INFERENCE: what this means for the decision (clearly labeled as interpretation)
16
16
  - GAPS: what additional data would increase confidence
17
17
 
@@ -1,10 +1,10 @@
1
1
  <!--
2
- commands/plan/api.md Design an API contracts, endpoints, error model, data schema
2
+ commands/plan/api.md (Design an API) contracts, endpoints, error model, data schema
3
3
 
4
- Design an API contracts, endpoints, error model, data schema
4
+ Design an API: contracts, endpoints, error model, data schema
5
5
  -->
6
6
  ---
7
- description: Design an API contracts, endpoints, error model, data schema
7
+ description: Design an API: contracts, endpoints, error model, data schema
8
8
  ---
9
9
 
10
10
  You are Construct. Design the API for: $ARGUMENTS
@@ -1,10 +1,10 @@
1
1
  <!--
2
- commands/plan/challenge.md Challenge a plan stress-test assumptions, surface failure modes and risks
2
+ commands/plan/challenge.md (Challenge a plan) stress-test assumptions, surface failure modes and risks
3
3
 
4
- Challenge a plan stress-test assumptions, surface failure modes and risks
4
+ Challenge a plan: stress-test assumptions, surface failure modes and risks
5
5
  -->
6
6
  ---
7
- description: Challenge a plan stress-test assumptions, surface failure modes and risks
7
+ description: Challenge a plan: stress-test assumptions, surface failure modes and risks
8
8
  ---
9
9
 
10
10
  You are Construct. Challenge the following: $ARGUMENTS
@@ -1,10 +1,10 @@
1
1
  <!--
2
- commands/plan/decide.md Record a decision context, options considered, consequences, what it locks in
2
+ commands/plan/decide.md (Record a decision) context, options considered, consequences, what it locks in
3
3
 
4
- Record a decision context, options considered, consequences, what it locks in
4
+ Record a decision: context, options considered, consequences, what it locks in
5
5
  -->
6
6
  ---
7
- description: Record a decision context, options considered, consequences, what it locks in
7
+ description: Record a decision: context, options considered, consequences, what it locks in
8
8
  ---
9
9
 
10
10
  You are Construct. Document the decision about: $ARGUMENTS
@@ -1,30 +1,30 @@
1
1
  <!--
2
- commands/plan/feature.md Plan a feature and turn it into a tracker-linked implementation plan
2
+ commands/plan/feature.md: Plan a feature and turn it into a tracker-linked implementation plan
3
3
 
4
4
  Produces a structured spec using the canonical Construct plan format, saves it
5
5
  to .cx/plans/ as a durable planning artifact linked to the active tracker slice.
6
6
  -->
7
7
  ---
8
- description: Plan a feature produce a structured spec and link it to the active tracker-backed plan
8
+ description: Plan a feature: produce a structured spec and link it to the active tracker-backed plan
9
9
  ---
10
10
 
11
11
  You are Construct. Plan the following: $ARGUMENTS
12
12
 
13
13
  Use the code-backed orchestration policy for routing/escalation decisions; this prompt only defines the plan artifact shape.
14
14
 
15
- ## Step 1 Scope
15
+ ## Step 1: Scope
16
16
  Produce:
17
17
  - **GOAL**: restate the objective in one sentence
18
18
  - **APPROACH**: chosen strategy and why (alternatives considered)
19
19
  - **RISKS**: top 3 risks and mitigations
20
20
 
21
- ## Step 2 Task breakdown
21
+ ## Step 2: Task breakdown
22
22
 
23
23
  Produce tasks in the canonical Construct plan format:
24
24
 
25
25
  ## Tasks
26
26
 
27
- ### T1 {Task title}
27
+ ### T1: {Task title}
28
28
  - **Owner**: {cx-specialist}
29
29
  - **Phase**: implement
30
30
  - **Files**: {comma-separated list of files this task will touch}
@@ -38,12 +38,12 @@ Produce tasks in the canonical Construct plan format:
38
38
  (repeat for each task)
39
39
 
40
40
  Rules:
41
- - Each task is atomic one agent, one deliverable
41
+ - Each task is atomic: one agent, one deliverable
42
42
  - Files lists must be disjoint across parallel tasks
43
43
  - Acceptance criteria are binary: pass or fail, no "it should be good"
44
44
  - Do not change must list every file outside scope that could be accidentally touched
45
45
 
46
- ## Step 3 Save and import
46
+ ## Step 3: Save and import
47
47
  1. Save this full plan to `.cx/plans/{slug}-plan.md`
48
48
  2. If the project uses Beads or another external tracker, include the issue id in the plan and keep the current `plan.md` aligned with it
49
49
  3. Declare file ownership explicitly so parallel work still follows the single-writer rule
@@ -1,10 +1,10 @@
1
1
  <!--
2
- commands/plan/requirements.md Define requirements what needs to be true for this to be done
2
+ commands/plan/requirements.md (Define requirements) what needs to be true for this to be done
3
3
 
4
- Define requirements what needs to be true for this to be done
4
+ Define requirements: what needs to be true for this to be done
5
5
  -->
6
6
  ---
7
- description: Define requirements what needs to be true for this to be done
7
+ description: Define requirements: what needs to be true for this to be done
8
8
  ---
9
9
 
10
10
  You are Construct. Define requirements for: $ARGUMENTS
@@ -1,10 +1,10 @@
1
1
  <!--
2
- commands/remember/context.md Save project context update .cx/context.md so the next session picks up where this one left off
2
+ commands/remember/context.md (Save project context) update .cx/context.md so the next session picks up where this one left off
3
3
 
4
- Save project context update .cx/context.md so the next session picks up where this one left off
4
+ Save project context: update .cx/context.md so the next session picks up where this one left off
5
5
  -->
6
6
  ---
7
- description: Save project context update .cx/context.md so the next session picks up where this one left off
7
+ description: Save project context: update .cx/context.md so the next session picks up where this one left off
8
8
  ---
9
9
 
10
10
  You are Construct. Save context for: $ARGUMENTS
@@ -12,10 +12,10 @@ You are Construct. Save context for: $ARGUMENTS
12
12
  Update `.cx/context.json` as canonical state and refresh `.cx/context.md` as the readable mirror:
13
13
 
14
14
  ## Active Work
15
- - [title] [status: in-progress | blocked | in-review]
15
+ - [title]: [status: in-progress | blocked | in-review]
16
16
 
17
17
  ## Recent Decisions
18
- - [date] [decision] [rationale]
18
+ - [date] [decision]: [rationale]
19
19
 
20
20
  ## Architecture Notes
21
21
  - [constraint or invariant future contributors need to know]
@@ -1,10 +1,10 @@
1
1
  <!--
2
- commands/remember/handoff.md Write a handoff transfer context so the next session or person can continue without loss
2
+ commands/remember/handoff.md (Write a handoff) transfer context so the next session or person can continue without loss
3
3
 
4
- Write a handoff transfer context so the next session or person can continue without loss
4
+ Write a handoff: transfer context so the next session or person can continue without loss
5
5
  -->
6
6
  ---
7
- description: Write a handoff transfer context so the next session or person can continue without loss
7
+ description: Write a handoff: transfer context so the next session or person can continue without loss
8
8
  ---
9
9
 
10
10
  You are Construct. Write a handoff for: $ARGUMENTS
@@ -1,10 +1,10 @@
1
1
  <!--
2
- commands/remember/runbook.md Write a runbook step-by-step procedure for a recurring task or incident
2
+ commands/remember/runbook.md (Write a runbook) step-by-step procedure for a recurring task or incident
3
3
 
4
- Write a runbook step-by-step procedure for a recurring task or incident
4
+ Write a runbook: step-by-step procedure for a recurring task or incident
5
5
  -->
6
6
  ---
7
- description: Write a runbook step-by-step procedure for a recurring task or incident
7
+ description: Write a runbook: step-by-step procedure for a recurring task or incident
8
8
  ---
9
9
 
10
10
  You are Construct. Write a runbook for: $ARGUMENTS