chati-dev 4.5.28 → 4.5.29

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 (172) hide show
  1. package/bin/chati.js +151 -123
  2. package/framework/agents/build/dev.md +4 -4
  3. package/framework/agents/deploy/devops.md +3 -3
  4. package/framework/agents/discover/brief.md +18 -6
  5. package/framework/agents/discover/brownfield-wu.md +3 -3
  6. package/framework/agents/discover/greenfield-wu.md +4 -4
  7. package/framework/agents/plan/architect.md +2 -2
  8. package/framework/agents/plan/detail.md +4 -4
  9. package/framework/agents/plan/phases.md +3 -3
  10. package/framework/agents/plan/tasks.md +47 -19
  11. package/framework/agents/plan/ux-brand-architect.md +1 -1
  12. package/framework/agents/plan/ux.md +26 -2
  13. package/framework/agents/quality/qa-implementation.md +8 -8
  14. package/framework/agents/quality/qa-planning.md +58 -4
  15. package/framework/agents/quality/qa-visual.md +4 -4
  16. package/framework/config.yaml +2 -2
  17. package/framework/constitution.md +12 -1
  18. package/framework/context/governance.md +2 -1
  19. package/framework/context/root.md +3 -1
  20. package/framework/domains/constitution.yaml +1 -1
  21. package/framework/domains/global.yaml +1 -1
  22. package/framework/domains/workflows/standard-flow.yaml +7 -8
  23. package/framework/hooks/advance-trigger.js +3 -2
  24. package/framework/hooks/brief-validator.js +1 -1
  25. package/framework/hooks/post-dev.js +1 -1
  26. package/framework/hooks/team-quality-gate.js +9 -2
  27. package/framework/i18n/en.yaml +1 -0
  28. package/framework/i18n/es.yaml +1 -0
  29. package/framework/i18n/fr.yaml +1 -0
  30. package/framework/i18n/pt.yaml +1 -0
  31. package/framework/manifest.json +83 -83
  32. package/framework/manifest.sig +1 -1
  33. package/framework/orchestrator/chati-router.js +14 -6
  34. package/framework/orchestrator/chati.md +61 -23
  35. package/framework/rules/human-writing-style.md +7 -0
  36. package/framework/schemas/session.schema.json +25 -2
  37. package/framework/schemas/task.schema.json +26 -0
  38. package/framework/tasks/orchestrator-handoff.md +10 -10
  39. package/framework/tasks/orchestrator-resume.md +3 -3
  40. package/framework/workflows/brownfield-fullstack.yaml +6 -3
  41. package/framework/workflows/brownfield-service.yaml +5 -3
  42. package/framework/workflows/brownfield-ui.yaml +5 -3
  43. package/framework/workflows/greenfield-fullstack.yaml +6 -3
  44. package/framework/workflows/standard-flow.yaml +8 -3
  45. package/node_modules/@chati/core/native/browser-proof-wire.h +29 -0
  46. package/node_modules/@chati/core/native/darwin-browser-listener.c +36 -0
  47. package/node_modules/@chati/core/native/darwin-browser-listener.h +32 -0
  48. package/node_modules/@chati/core/native/darwin-browser-proof.h +86 -0
  49. package/node_modules/@chati/core/native/darwin-code-identity.h +35 -0
  50. package/node_modules/@chati/core/native/darwin-launch-messages.h +37 -0
  51. package/node_modules/@chati/core/native/darwin-launcher.c +312 -0
  52. package/node_modules/@chati/core/native/descriptor-fs.c +407 -0
  53. package/node_modules/@chati/core/native/execution-admission.h +59 -0
  54. package/node_modules/@chati/core/native/execution-gate.c +41 -0
  55. package/node_modules/@chati/core/native/linux-process.c +41 -0
  56. package/node_modules/@chati/core/native/prebuilds/darwin-arm64/darwin-launcher +0 -0
  57. package/node_modules/@chati/core/native/prebuilds/darwin-arm64/descriptor-fs.node +0 -0
  58. package/node_modules/@chati/core/native/prebuilds/darwin-arm64/execution-gate +0 -0
  59. package/node_modules/@chati/core/native/prebuilds/linux-x64/descriptor-fs.node +0 -0
  60. package/node_modules/@chati/core/native/prebuilds/linux-x64/execution-gate +0 -0
  61. package/node_modules/@chati/core/native/process-info-pipe.c +91 -0
  62. package/node_modules/@chati/core/package.json +2 -1
  63. package/node_modules/@chati/core/scripts/build-native.js +36 -0
  64. package/node_modules/@chati/core/src/darwin-browser-proof.js +87 -0
  65. package/node_modules/@chati/core/src/darwin-host-boot.js +58 -0
  66. package/node_modules/@chati/core/src/darwin-process.js +79 -0
  67. package/node_modules/@chati/core/src/darwin-supervisor-channels.js +82 -0
  68. package/node_modules/@chati/core/src/darwin-terminal-receipt.js +111 -0
  69. package/node_modules/@chati/core/src/descriptor-fs.js +222 -0
  70. package/node_modules/@chati/core/src/execution-gate.js +8 -0
  71. package/node_modules/@chati/core/src/host-boot-marker.js +45 -0
  72. package/node_modules/@chati/core/src/index.js +18 -0
  73. package/node_modules/@chati/core/src/linux-host-boot.js +218 -0
  74. package/node_modules/@chati/core/src/linux-process.js +133 -0
  75. package/node_modules/@chati/planning/src/browser-verification-plan.js +71 -0
  76. package/node_modules/@chati/planning/src/index.js +33 -0
  77. package/node_modules/@chati/planning/src/planning-material.js +64 -0
  78. package/node_modules/@chati/planning/src/verification-plan.js +57 -0
  79. package/node_modules/@chati/rail/package.json +1 -0
  80. package/node_modules/@chati/rail/src/execution-restoration.js +92 -0
  81. package/node_modules/@chati/rail/src/index.js +812 -167
  82. package/node_modules/@chati/rail/src/provider-processing.js +118 -0
  83. package/node_modules/@chati/rail/src/terminal-containment.js +23 -0
  84. package/node_modules/@chati/release-lane/src/index.js +40 -43
  85. package/node_modules/@chati/review-council/src/index.js +223 -0
  86. package/node_modules/@chati/tracking-clickup/src/index.js +67 -58
  87. package/package-artifact-manifest.json +1 -1
  88. package/package-artifact-manifest.sig +1 -1
  89. package/package.json +3 -2
  90. package/scripts/verify-real-harness-e2e.js +20 -8
  91. package/src/installer/core.js +147 -107
  92. package/src/installer/package-artifact.js +7 -0
  93. package/src/installer/preflight.js +13 -0
  94. package/src/installer/provider-overlay.js +1 -2
  95. package/src/installer/templates.js +58 -0
  96. package/src/installer-v2/catalog-client.js +31 -1
  97. package/src/installer-v2/clickup-connection-storage.js +92 -0
  98. package/src/installer-v2/clickup-mcp-client.js +155 -0
  99. package/src/installer-v2/clickup-oauth-loopback.js +96 -0
  100. package/src/installer-v2/clickup-oauth.js +233 -0
  101. package/src/installer-v2/index.js +141 -15
  102. package/src/installer-v2/installation-authority.js +98 -4
  103. package/src/installer-v2/provider-executable.js +117 -12
  104. package/src/installer-v2/wizard-installation.js +11 -0
  105. package/src/orchestrator/agent-selector.js +39 -1
  106. package/src/orchestrator/browser-artifact-store.js +131 -0
  107. package/src/orchestrator/cli.js +762 -205
  108. package/src/orchestrator/clickup-mcp-observer.js +226 -0
  109. package/src/orchestrator/clickup-runtime.js +45 -24
  110. package/src/orchestrator/council-gate-runtime.js +903 -0
  111. package/src/orchestrator/evidence-authority-enrollment.js +75 -0
  112. package/src/orchestrator/evidence-authority-request.js +46 -0
  113. package/src/orchestrator/handoff-engine.js +4 -11
  114. package/src/orchestrator/pipeline-manager.js +42 -4
  115. package/src/orchestrator/planning-contract-revision.js +711 -0
  116. package/src/orchestrator/planning-reconciliation.js +302 -0
  117. package/src/orchestrator/planning-runtime.js +476 -29
  118. package/src/orchestrator/rail-adjudication-evidence.js +15 -24
  119. package/src/orchestrator/rail-human-effort-authority.js +46 -0
  120. package/src/orchestrator/rail-human-effort.js +149 -0
  121. package/src/orchestrator/rail-runtime.js +291 -47
  122. package/src/orchestrator/rail-verification.js +278 -0
  123. package/src/orchestrator/review-runtime.js +37 -2
  124. package/src/orchestrator/runtime-installation-v2.js +143 -24
  125. package/src/orchestrator/session-manager.js +1457 -29
  126. package/src/tasks/handoff.js +57 -33
  127. package/src/terminal/adapters/claude-adapter.js +3 -0
  128. package/src/terminal/adapters/codex-adapter.js +13 -0
  129. package/src/terminal/adapters/grok-adapter.js +1 -0
  130. package/src/terminal/agent-attempt-budget.js +35 -0
  131. package/src/terminal/browser-endpoint-proxy.js +174 -0
  132. package/src/terminal/browser-observer-driver.js +94 -0
  133. package/src/terminal/browser-observer-supervisor.js +73 -0
  134. package/src/terminal/browser-observer.js +95 -0
  135. package/src/terminal/browser-process-facts.js +75 -0
  136. package/src/terminal/browser-runtime.js +131 -0
  137. package/src/terminal/darwin-authority-policy.js +213 -0
  138. package/src/terminal/darwin-browser-application.js +116 -0
  139. package/src/terminal/darwin-browser-observer.js +57 -0
  140. package/src/terminal/darwin-execution.js +185 -0
  141. package/src/terminal/executable-snapshot.js +202 -0
  142. package/src/terminal/handoff-parser.js +48 -2
  143. package/src/terminal/isolation.js +14 -13
  144. package/src/terminal/prompt-builder.js +176 -15
  145. package/src/terminal/provider-preflight.js +47 -27
  146. package/src/terminal/rail-execution-worktree.js +22 -6
  147. package/src/terminal/rail-process-observer.js +10 -0
  148. package/src/terminal/rail-prompts.js +21 -3
  149. package/src/terminal/rail-readonly-workspace.js +54 -5
  150. package/src/terminal/rail-worktree-checkpoint.js +315 -0
  151. package/src/terminal/rail-worktree-restoration.js +485 -0
  152. package/src/terminal/run-agent.js +164 -42
  153. package/src/terminal/run-council-gate.js +338 -0
  154. package/src/terminal/run-planning-reconciliation.js +49 -0
  155. package/src/terminal/run-rail-adjudication.js +29 -7
  156. package/src/terminal/run-rail-recovery.js +97 -0
  157. package/src/terminal/run-rail-review.js +36 -15
  158. package/src/terminal/run-rail-rework.js +26 -15
  159. package/src/terminal/run-rail-task.js +22 -9
  160. package/src/terminal/runtime-native-helper.js +85 -0
  161. package/src/terminal/spawner.js +899 -142
  162. package/src/terminal/verification-process-facts.js +49 -0
  163. package/src/upgrade/entrypoints.js +68 -0
  164. package/src/upgrade/generation.js +194 -0
  165. package/src/upgrade/maintenance.js +79 -0
  166. package/src/upgrade/paths.js +81 -0
  167. package/src/upgrade/upgrade.js +267 -0
  168. package/src/utils/execution-role.js +15 -0
  169. package/src/utils/handoff-paths.js +59 -0
  170. package/src/wizard/i18n.js +1 -0
  171. package/src/wizard/index.js +17 -5
  172. package/src/wizard/questions.js +24 -12
package/bin/chati.js CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  import { resolve } from 'path';
4
4
  import { randomUUID } from 'crypto';
5
- import { readFileSync } from 'fs';
5
+ import { existsSync, readFileSync } from 'fs';
6
6
  import { fileURLToPath } from 'url';
7
7
  import { dirname, join } from 'path';
8
8
 
@@ -10,7 +10,6 @@ const __dirname = dirname(fileURLToPath(import.meta.url));
10
10
  const pkg = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf-8'));
11
11
 
12
12
  import { logBanner } from '../src/utils/logger.js';
13
- import { resolveFrameworkDir } from '../src/utils/framework-dir.js';
14
13
 
15
14
  function showBanner() {
16
15
  let logoText;
@@ -27,6 +26,8 @@ const command = args[0] || 'init';
27
26
  // Known subcommands and agent names that should NOT be mistaken for targetDir paths.
28
27
  // Without this, `chati orchestrate advance --agent detail` resolves targetDir to `<cwd>/detail/`.
29
28
  const KNOWN_SUBCOMMANDS = new Set([
29
+ 'rail-authority-enroll', 'rail-authority-request', 'rail-verify', 'rail-effort',
30
+ 'rail-browser-artifact', 'rail-browser-prune',
30
31
  // CLI subcommands
31
32
  'next', 'advance', 'init', 'status', 'validate-handoff', 'deviation', 'exit', 'activate-harness',
32
33
  'install-v2', 'migrate-v2', 'rail-import', 'rail-next', 'rail-dispatch', 'rail-review-run', 'rail-rework', 'rail-adjudicate', 'rail-release-ready', 'rail-recover', 'rail-complete', 'rail-tracking-reconcile', 'rail-tracking-pending', 'rail-tracking-ack', 'rail-tracking-lookup',
@@ -56,6 +57,22 @@ const targetDir = resolve(
56
57
  );
57
58
 
58
59
  async function main() {
60
+ // v2 mutators acquire maintenance only after authorization in their common
61
+ // API. Migration previews must not create maintenance bookkeeping at all.
62
+ const projectCommand = command.startsWith('rail-') || ['init', 'install',
63
+ 'status', 'check-update', 'memory', 'context', 'registry', 'health', 'telemetry', 'scaffold', '--reconfigure'].includes(command);
64
+ // `init <new-project>` scaffolds a directory that does not exist yet; the
65
+ // installer bootstraps its own lease once it creates `.chati`. Maintenance
66
+ // can only wrap commands whose project root already exists.
67
+ const scaffoldingNewDirectory = ['init', 'install'].includes(command) && !existsSync(targetDir);
68
+ if (projectCommand && !scaffoldingNewDirectory) {
69
+ const { withUpgradeMaintenance } = await import('../src/upgrade/maintenance.js');
70
+ return withUpgradeMaintenance(targetDir, executeCommand);
71
+ }
72
+ return executeCommand();
73
+ }
74
+
75
+ async function executeCommand() {
59
76
  switch (command) {
60
77
  case 'init':
61
78
  case 'install': {
@@ -80,7 +97,7 @@ async function main() {
80
97
  }
81
98
  const { installV2 } = await import('../src/installer-v2/index.js');
82
99
  try {
83
- const result = installV2(input, { projectDir: targetDir });
100
+ const result = await installV2(input, { projectDir: targetDir });
84
101
  console.log(JSON.stringify(result, null, 2));
85
102
  } catch (error) {
86
103
  console.error(`Error: ${error.code || 'INSTALL_V2_FAILED'}: ${error.message}`);
@@ -105,7 +122,7 @@ async function main() {
105
122
  }
106
123
  try {
107
124
  const { migrateV2 } = await import('../src/installer-v2/index.js');
108
- const result = migrateV2(input, { projectDir: targetDir, authorize: args.includes('--apply') });
125
+ const result = await migrateV2(input, { projectDir: targetDir, authorize: args.includes('--apply') });
109
126
  console.log(JSON.stringify(result, null, 2));
110
127
  } catch (error) {
111
128
  console.error(`Error: ${error.code || 'MIGRATE_V2_FAILED'}: ${error.message}`);
@@ -262,23 +279,20 @@ async function main() {
262
279
  }
263
280
  const attemptId = value('--attempt-id');
264
281
  try {
265
- const { resolveRailAttemptContext } = await import('../src/orchestrator/rail-runtime.js');
266
- const { executeReadyRailTask } = await import('../src/terminal/run-rail-task.js');
267
- const context = resolveRailAttemptContext({
268
- projectDir: targetDir,
269
- handoff_id: value('--handoff-id'),
270
- attempt_id: attemptId,
271
- });
272
- const result = await executeReadyRailTask({
282
+ const { recoverAndResumeRailTask } = await import('../src/terminal/run-rail-recovery.js');
283
+ const result = await recoverAndResumeRailTask({
273
284
  projectDir: targetDir,
274
285
  handoff_id: value('--handoff-id'),
275
- task_id: context.task.task_id,
276
286
  attempt_id: attemptId,
277
287
  operator_id: value('--operator-id'),
278
288
  git_dir: value('--git-dir') || targetDir,
279
- recover_expired: true,
280
289
  ...(value('--timeout') ? { timeout: Number(value('--timeout')) } : {}),
281
290
  ...(value('--browser-request-json') ? { browser_request: JSON.parse(value('--browser-request-json')) } : {}),
291
+ // macOS only: the operator explicitly attests that no process of the
292
+ // interrupted launch remains, instead of waiting for a reboot.
293
+ ...(args.includes('--attest-terminated') ? { termination_attestation: {
294
+ operator_id: value('--operator-id'), attested_at: new Date().toISOString(), statement: 'no-launch-processes-remain',
295
+ } } : {}),
282
296
  });
283
297
  console.log(JSON.stringify(result, null, 2));
284
298
  if (!result.ok) process.exitCode = 1;
@@ -286,13 +300,104 @@ async function main() {
286
300
  console.error(JSON.stringify({
287
301
  ok: false, action: 'error', error: error.code || 'RAIL_RECOVERY_FAILED',
288
302
  detail: error.message, attempt_id: error.details?.attempt_id || attemptId,
289
- next_required_action: 'rail_recover_and_dispatch_same_attempt',
303
+ next_required_action: error.details?.next_required_action || 'rail_recover_and_dispatch_same_attempt',
304
+ ...(error.details?.interruption_event_id ? { interruption_event_id: error.details.interruption_event_id } : {}),
305
+ ...(error.details?.checkpoint_event_id ? { checkpoint_event_id: error.details.checkpoint_event_id } : {}),
290
306
  }));
291
307
  process.exitCode = 1;
292
308
  }
293
309
  break;
294
310
  }
295
311
 
312
+ case 'rail-effort':
313
+ case 'rail-verify': {
314
+ try {
315
+ const values = new Map();
316
+ for (let index = 1; index < args.length; index += 2) {
317
+ const flag = args[index];
318
+ const value = args[index + 1];
319
+ if (!['--project-dir', '--handoff-id', '--attempt-id'].includes(flag)
320
+ || values.has(flag) || !value || value.startsWith('-')) {
321
+ throw Object.assign(new Error(`${command} accepts --project-dir, --handoff-id and --attempt-id only`), {
322
+ code: command === 'rail-effort' ? 'HUMAN_EFFORT_INPUT_INVALID' : 'RAIL_VERIFICATION_INPUT_INVALID' });
323
+ }
324
+ values.set(flag, value);
325
+ }
326
+ const run = command === 'rail-effort'
327
+ ? (await import('../src/orchestrator/rail-human-effort.js')).runHumanEffortTerminal
328
+ : (await import('../src/orchestrator/rail-verification.js')).observeRailVerification;
329
+ const result = await run({ projectDir: targetDir,
330
+ handoff_id: values.get('--handoff-id'), attempt_id: values.get('--attempt-id') });
331
+ console.log(JSON.stringify(result, null, 2));
332
+ if (!result.ok) process.exitCode = 1;
333
+ } catch (error) {
334
+ console.error(`Error: ${error.code || 'RAIL_VERIFICATION_FAILED'}: ${error.message}`);
335
+ process.exitCode = 1;
336
+ }
337
+ break;
338
+ }
339
+
340
+ case 'rail-browser-artifact':
341
+ case 'rail-browser-prune': {
342
+ try {
343
+ const values = new Map();
344
+ const allowed = command === 'rail-browser-artifact' ? ['--project-dir', '--ref'] : ['--project-dir'];
345
+ for (let index = 1; index < args.length; index += 2) {
346
+ const flag = args[index]; const value = args[index + 1];
347
+ if (!allowed.includes(flag) || values.has(flag) || !value || value.startsWith('-')) {
348
+ throw Object.assign(new Error(`${command} accepts ${allowed.join(', ')} only`), { code: 'BROWSER_ARTIFACT_INPUT_INVALID' });
349
+ }
350
+ values.set(flag, value);
351
+ }
352
+ const { loadRuntimeInstallationV2 } = await import('../src/orchestrator/runtime-installation-v2.js');
353
+ const installation = loadRuntimeInstallationV2(targetDir);
354
+ if (!installation) throw Object.assign(new Error('browser artifact access requires a verified installation'), { code: 'V2_INSTALLATION_REQUIRED' });
355
+ const store = await import('../src/orchestrator/browser-artifact-store.js');
356
+ const options = { projectDir: targetDir, projectId: installation.project_id };
357
+ const result = command === 'rail-browser-artifact'
358
+ ? store.readBrowserArtifact({ ...options, ref: values.get('--ref') }) : store.pruneBrowserArtifacts(options);
359
+ console.log(JSON.stringify(result, null, 2));
360
+ if (result.ok === false) process.exitCode = 1;
361
+ } catch (error) {
362
+ console.error(`Error: ${error.code || 'BROWSER_ARTIFACT_FAILED'}: ${error.message}`);
363
+ process.exitCode = 1;
364
+ }
365
+ break;
366
+ }
367
+
368
+ case 'rail-authority-request': {
369
+ const kindIndex = args.indexOf('--kind');
370
+ const kind = kindIndex === -1 ? null : args[kindIndex + 1];
371
+ try {
372
+ const { createEvidenceAuthorityRequest } = await import('../src/orchestrator/evidence-authority-request.js');
373
+ console.log(JSON.stringify(createEvidenceAuthorityRequest({ projectDir: targetDir, kind }), null, 2));
374
+ } catch (error) {
375
+ console.error(`Error: ${error.code || 'AUTHORITY_REQUEST_FAILED'}: ${error.message}`);
376
+ process.exitCode = 1;
377
+ }
378
+ break;
379
+ }
380
+
381
+ case 'rail-authority-enroll': {
382
+ const certificateIndex = args.indexOf('--certificate');
383
+ const certificatePath = certificateIndex === -1 ? null : args[certificateIndex + 1];
384
+ if (!certificatePath || certificatePath.startsWith('--')) {
385
+ console.error('Error: rail-authority-enroll requires --certificate <CHATI-signed-public-certificate.json>');
386
+ process.exitCode = 1;
387
+ break;
388
+ }
389
+ try {
390
+ const { enrollProjectEvidenceAuthorityFile } = await import('../src/orchestrator/evidence-authority-enrollment.js');
391
+ console.log(JSON.stringify(enrollProjectEvidenceAuthorityFile({
392
+ projectDir: targetDir, certificatePath: resolve(certificatePath), replace: args.includes('--replace'),
393
+ }), null, 2));
394
+ } catch (error) {
395
+ console.error(`Error: ${error.code || 'AUTHORITY_ENROLLMENT_FAILED'}: ${error.message}`);
396
+ process.exitCode = 1;
397
+ }
398
+ break;
399
+ }
400
+
296
401
  case 'rail-complete': {
297
402
  const value = (flag) => { const index = args.indexOf(flag); return index === -1 ? null : args[index + 1]; };
298
403
  if (!value('--handoff-id') || !value('--completion')) {
@@ -303,10 +408,11 @@ async function main() {
303
408
  try {
304
409
  const completion = JSON.parse(readFileSync(resolve(value('--completion')), 'utf8'));
305
410
  const { completeRailTask } = await import('../src/orchestrator/rail-runtime.js');
306
- const { completion_id, attempt_id, claim_id, operator_id, state, git, ci, reviews, acceptance_evidence_refs, acceptance_authority_receipt, completed_at, metrics } = completion;
411
+ const { completion_id, attempt_id, claim_id, operator_id, state, git, ci, reviews, acceptance_evidence_refs, acceptance_authority_receipt, browser_evidence, completed_at, metrics } = completion;
307
412
  console.log(JSON.stringify(completeRailTask({
308
413
  projectDir: targetDir, handoff_id: value('--handoff-id'), completion_id, attempt_id, claim_id, operator_id, state, git, ci,
309
- reviews, acceptance_evidence_refs, acceptance_authority_receipt, ...(completed_at === undefined ? {} : { completed_at }), ...(metrics === undefined ? {} : { metrics }),
414
+ reviews, acceptance_evidence_refs, acceptance_authority_receipt, ...(browser_evidence === undefined ? {} : { browser_evidence }),
415
+ ...(completed_at === undefined ? {} : { completed_at }), ...(metrics === undefined ? {} : { metrics }),
310
416
  }), null, 2));
311
417
  } catch (error) {
312
418
  console.error(`Error: ${error.code || 'RAIL_COMPLETION_FAILED'}: ${error.message}`);
@@ -423,112 +529,21 @@ async function main() {
423
529
  case 'upgrade': {
424
530
  const versionFlag = args.indexOf('--version');
425
531
  const targetVersion = versionFlag !== -1 ? args[versionFlag + 1] : pkg.version;
426
-
427
- const { getCurrentVersion, updateConfigVersion } = await import('../src/upgrade/checker.js');
428
- const { createBackup, restoreFromBackup } = await import('../src/upgrade/backup.js');
429
- const { runMigrations } = await import('../src/upgrade/migrator.js');
430
- const { validateInstallation } = await import('../src/installer/validator.js');
431
-
432
- const currentVersion = getCurrentVersion(targetDir);
433
- if (!currentVersion) {
434
- console.error('No Chati.dev installation found. Run `npx chati-dev init` first.');
435
- process.exit(1);
436
- }
437
-
438
- console.log(`Upgrading Chati.dev v${currentVersion} -> v${targetVersion}...`);
439
-
440
- // 1. Create backup
441
- console.log(' Creating backup...');
442
- const backupDir = createBackup(targetDir, currentVersion);
443
- console.log(` Backup created at: ${backupDir}`);
444
-
445
- // 2. Run migrations
446
- console.log(' Running migrations...');
447
- const migrationResult = await runMigrations(targetDir, currentVersion, targetVersion);
448
-
449
- if (!migrationResult.success) {
450
- console.error(` Migration failed at: ${migrationResult.failedAt}`);
451
- console.error(` Error: ${migrationResult.error}`);
452
- console.log(' Rolling back...');
453
- restoreFromBackup(targetDir, currentVersion);
454
- console.log(' Rollback complete.');
455
- process.exit(1);
456
- }
457
-
458
- console.log(` ${migrationResult.migrationsRun} migration(s) applied.`);
459
-
460
- // 2.5. Sync framework files (copy new/updated agents, templates, hooks, etc.)
461
- console.log(' Syncing framework files...');
462
- try {
463
- const { copyFrameworkFiles } = await import('../src/installer/core.js');
464
- copyFrameworkFiles(join(targetDir, resolveFrameworkDir(targetDir)));
465
- console.log(' Framework files synced.');
466
- } catch (err) {
467
- console.log(` Framework sync skipped: ${err.message}`);
468
- }
469
-
470
- // 2.55. Refresh .claude/settings.json (merge-safe) so hook registrations
471
- // added in newer versions reach existing installs. Without this, projects
472
- // installed before a hook was added to the generator never receive it
473
- // (reasoning-escalator and git-push-authority were missing for everyone).
474
- try {
475
- const { writeClaudeSettingsWithMerge } = await import('../src/installer/core.js');
476
- const { existsSync: ex } = await import('fs');
477
- const settingsPath = join(targetDir, '.claude', 'settings.json');
478
- if (ex(join(targetDir, '.claude'))) {
479
- writeClaudeSettingsWithMerge(settingsPath);
480
- console.log(' Claude settings refreshed (hooks re-registered).');
481
- }
482
- } catch (err) {
483
- console.log(` Settings refresh skipped: ${err.message}`);
532
+ if (targetVersion !== pkg.version) {
533
+ console.error(`UPGRADE_PACKAGE_VERSION_MISMATCH: this command contains v${pkg.version}; --version cannot fetch or relabel another package.`);
534
+ process.exitCode = 1;
535
+ break;
484
536
  }
485
-
486
- // 2.6. Re-bundle CLI (Bug 4 part 3, v4.3.1+) — refreshes .chati.dev/_cli/
487
- // and writes version.json so chati-router.js mismatch detection clears
488
- // on the next invocation.
489
- console.log(' Re-bundling CLI...');
490
537
  try {
491
- const { copyCliSource, copyCliDependencies } = await import('../src/installer/core.js');
492
- const { writeFileSync } = await import('fs');
493
- const fwDir = resolveFrameworkDir(targetDir);
494
- const frameworkDir = join(targetDir, fwDir);
495
- copyCliSource(join(__dirname, '..', 'src'), join(frameworkDir, '_cli'));
496
- copyCliDependencies(join(__dirname, '..'), join(frameworkDir, '_cli', 'node_modules'));
497
- writeFileSync(
498
- join(frameworkDir, '_cli', 'version.json'),
499
- JSON.stringify({ version: pkg.version, bundled_at: new Date().toISOString() }, null, 2),
500
- );
501
- console.log(' CLI re-bundled.');
502
- } catch (err) {
503
- console.log(` CLI rebundle skipped: ${err.message}`);
504
- }
505
-
506
- // 2.6. Detect tracked framework files and warn user (non-blocking)
507
- try {
508
- const { detectTrackedFrameworkFiles } = await import('../src/upgrade/tracked-files-detector.js');
509
- const { renderTrackedFilesWarning } = await import('../src/upgrade/user-messages.js');
510
- const trackedFiles = detectTrackedFrameworkFiles(targetDir);
511
- if (trackedFiles.length > 0) {
512
- process.stdout.write(renderTrackedFilesWarning(trackedFiles));
513
- }
514
- } catch {
515
- // Non-critical — skip silently if git is unavailable
516
- }
517
-
518
- // 3. Validate
519
- console.log(' Validating...');
520
- const validation = await validateInstallation(targetDir);
521
- console.log(` Validation: ${validation.passed}/${validation.total} checks passed.`);
522
-
523
- if (validation.passed < validation.total) {
524
- console.log(' Some validation checks failed. Installation may need manual review.');
538
+ const { upgradeProject } = await import('../src/upgrade/upgrade.js');
539
+ const result = await upgradeProject(targetDir, { targetVersion, offline: args.includes('--offline') });
540
+ console.log(`Validation: ${result.validation.passed}/${result.validation.total} checks passed.`);
541
+ console.log(`Previous generation retained at: ${result.backupDir}`);
542
+ console.log(`Chati.dev upgraded to v${result.version} successfully.`);
543
+ } catch (error) {
544
+ console.error(`${error.code || 'UPGRADE_FAILED'}: ${error.message}`);
545
+ process.exitCode = 1;
525
546
  }
526
-
527
- // 4. Update config.yaml with new version
528
- updateConfigVersion(targetDir, targetVersion);
529
-
530
- console.log();
531
- console.log(`Chati.dev upgraded to v${targetVersion} successfully.`);
532
547
  break;
533
548
  }
534
549
 
@@ -751,6 +766,19 @@ Orchestration:
751
766
  npx chati-dev orchestrate deviation --type rollback --target X Analyze deviation
752
767
  npx chati-dev orchestrate exit Save and exit session
753
768
 
769
+ RAIL evidence authority:
770
+ npx chati-dev rail-verify --handoff-id ID --attempt-id ID [--project-dir PATH]
771
+ npx chati-dev rail-effort --handoff-id ID --attempt-id ID [--project-dir PATH]
772
+ npx chati-dev rail-browser-artifact --ref REF [--project-dir PATH]
773
+ npx chati-dev rail-browser-prune [--project-dir PATH]
774
+ Observe approved checks on the canonical result
775
+ npx chati-dev rail-authority-request --kind rail-evidence|clickup-mcp [--project-dir PATH]
776
+ Create a public certification request
777
+ npx chati-dev rail-authority-enroll --certificate FILE [--project-dir PATH]
778
+ Enroll a CHATI-signed public certificate
779
+ npx chati-dev rail-authority-enroll --certificate FILE --replace
780
+ Explicitly rotate the enrolled certificate
781
+
754
782
  Intelligence:
755
783
  npx chati-dev memory [stats|list|search|clean] Memory management
756
784
  npx chati-dev context Context bracket status
@@ -918,9 +946,9 @@ Telemetry:
918
946
  console.error('orchestrate subcommands accept only --flag arguments. To set the project name, use --name "<name>".');
919
947
  process.exit(1);
920
948
  }
921
- // targetDir for orchestrate is ALWAYS cwd (or auto-resolved by handleInit)
949
+ // Honor the same explicit project directory as the other public commands.
922
950
  const { runOrchestrate } = await import('../src/orchestrator/cli.js');
923
- await runOrchestrate(subCommand, args.slice(1), process.cwd());
951
+ await runOrchestrate(subCommand, args.slice(1), targetDir);
924
952
  break;
925
953
  }
926
954
 
@@ -933,6 +961,6 @@ Telemetry:
933
961
  }
934
962
 
935
963
  main().catch(err => {
936
- console.error('Fatal error:', err.message);
964
+ console.error('Fatal error:', err.code ? `${err.code}: ${err.message}` : err.message);
937
965
  process.exit(1);
938
966
  });
@@ -892,7 +892,7 @@ and proceed directly to handoff.
892
892
  ---
893
893
 
894
894
  ### Handoff (Protocol 5.5)
895
- Save to: `artifacts/handoffs/dev-handoff.md`
895
+ Save to: `artifacts/handoffs/dev/dev-handoff.md`
896
896
 
897
897
  When ALL tasks in current phase are complete AND user confirmed preview:
898
898
  - Transition to QA-Implementation
@@ -1002,13 +1002,13 @@ This agent supports TASK-LEVEL parallelization (all modes):
1002
1002
  ### Receives
1003
1003
  - **From**: QA-Planning agent (BUILD phase transition)
1004
1004
  - **Artifact**: `artifacts/7-QA-Planning/qa-planning-report.md` (APPROVED status required)
1005
- - **Handoff file**: `artifacts/handoffs/qa-planning-handoff.md`
1005
+ - **Handoff file**: `artifacts/handoffs/qa-planning/qa-planning-handoff.md`
1006
1006
  - **Expected content**: Validation result (APPROVED), traceability summary, adversarial review findings, state transition to BUILD
1007
1007
 
1008
1008
  ### Sends
1009
1009
  - **To**: QA-Implementation agent
1010
1010
  - **Artifact**: Implementation code + `artifacts/8-Implementation/dev-summary.md`
1011
- - **Handoff file**: `artifacts/handoffs/dev-handoff.md`
1011
+ - **Handoff file**: `artifacts/handoffs/dev/dev-handoff.md`
1012
1012
  - **Handoff content**: Implementation summary, per-task completion status, per-task scores, commit hashes, blocker resolutions, self-critique findings, duration per task, total tasks completed vs planned
1013
1013
 
1014
1014
  ---
@@ -1149,7 +1149,7 @@ The dev preview step still runs after ALL tasks complete. QA-Implementation's fi
1149
1149
  **Mandatory Handoff:**
1150
1150
 
1151
1151
  When you receive a CLEANUP WAVE or when the orchestrator tells you this is the LAST wave:
1152
- you MUST write your handoff to `artifacts/handoffs/dev-handoff.md` before returning.
1152
+ you MUST write your handoff to `artifacts/handoffs/dev/dev-handoff.md` before returning.
1153
1153
 
1154
1154
  The handoff must include:
1155
1155
  - All tasks completed with scores
@@ -140,7 +140,7 @@ Validation:
140
140
 
141
141
  ### Step 5: Finalize
142
142
  ```
143
- 1. Complete your handoff document (artifacts/handoffs/devops-handoff.md) with final state.
143
+ 1. Complete your handoff document (artifacts/handoffs/devops/devops-handoff.md) with final state.
144
144
  Do NOT edit session.yaml directly — the mode-governance hook blocks this.
145
145
  The CLI records completion in canonical state when you run:
146
146
  node chati.dev/orchestrator/chati-router.js advance --agent devops --score <N>
@@ -362,13 +362,13 @@ Rules:
362
362
  ### Receives
363
363
  - **From**: QA-Implementation agent (DEPLOY phase transition)
364
364
  - **Artifact**: `artifacts/9-QA-Implementation/qa-implementation-report.md` (APPROVED status required)
365
- - **Handoff file**: `artifacts/handoffs/qa-implementation-handoff.md`
365
+ - **Handoff file**: `artifacts/handoffs/qa-implementation/qa-implementation-handoff.md`
366
366
  - **Expected content**: Validation result (APPROVED), weighted score, test results, security scan summary, code review findings, state transition to DEPLOY
367
367
 
368
368
  ### Sends
369
369
  - **To**: None (final agent in pipeline)
370
370
  - **Artifact**: `artifacts/10-Deploy/deploy-report.md`
371
- - **Handoff file**: `artifacts/handoffs/devops-handoff.md`
371
+ - **Handoff file**: `artifacts/handoffs/devops/devops-handoff.md`
372
372
  - **Handoff content**: Deployment result (DEPLOYED/FAILED/ROLLED BACK), deployment URL, git summary (branch, commits, PR URL), build results, security pre-deploy check results, documentation generated, session finalization status
373
373
 
374
374
  ---
@@ -129,6 +129,16 @@ Output: Raw, unfiltered user input captured (initial_context + any follow-up ans
129
129
 
130
130
  ### Visual Quality Signal (MANDATORY - ask in Phase 1)
131
131
 
132
+ First establish whether the product has a user-facing visual/rendering surface.
133
+ For an explicitly confirmed library/service-only scope with no visual surface,
134
+ do not invent a visual preference: record `visual_quality: not_applicable` in
135
+ the canonical `## Visual Quality` YAML block and `visual_references: []` in
136
+ `## Visual References`, with the no-visual-surface rationale in
137
+ `reference_synthesis`. Keep exactly one declaration of each field. This is an
138
+ upstream scope decision for council review, not a UX self-exemption or a passed
139
+ browser gate. Missing or ambiguous scope is not N/A. Visual requirements,
140
+ premium references or non-empty visual references conflict with N/A.
141
+
132
142
  Ask the user: "What level of visual experience are you looking for?"
133
143
 
134
144
  1. **Functional** - Clean, professional, focus on usability. Minimal animations.
@@ -140,7 +150,9 @@ Record the answer in the Brief output under a new `visual_quality` field:
140
150
  visual_quality: premium # functional | premium | showcase
141
151
  ```
142
152
 
143
- If the user doesn't express a preference, DEFAULT to **premium**.
153
+ For a product with a visual surface, if the user doesn't express a preference,
154
+ DEFAULT to **premium**. This default never creates a visual surface in an
155
+ explicitly non-visual product.
144
156
  This field flows downstream to Architect (animation tech stack), UX (motion system scope), and QA-Planning (validation).
145
157
 
146
158
  ### Visual Reference Analysis (MANDATORY when user provides reference URLs)
@@ -441,7 +453,7 @@ If no visual_references exist in the brief: skip all 3 steps, proceed to handoff
441
453
  **IMPORTANT:** Do NOT present completion options before the Visualizer returns. The user must see the complete brief (text + visual analysis) before approving.
442
454
 
443
455
  ### Handoff (Protocol 5.5)
444
- Save to: `artifacts/handoffs/brief-handoff.md`
456
+ Save to: `artifacts/handoffs/brief/brief-handoff.md`
445
457
 
446
458
  - **Layer 1**: Problem summary, key decisions, artifacts, critical context for Detail/Architect
447
459
  - **Layer 2**: Only if conflicting stakeholder needs or complex problem landscape discovered
@@ -455,7 +467,7 @@ agents:
455
467
  criteria_count: 9
456
468
  completed_at: "{timestamp}"
457
469
  next_parallel_group: [detail, architect, ux, qa-planning] # PARALLEL GROUP - see Transition Logic 4.5
458
- last_handoff: artifacts/handoffs/brief-handoff.md
470
+ last_handoff: artifacts/handoffs/brief/brief-handoff.md
459
471
  ```
460
472
 
461
473
  ---
@@ -561,7 +573,7 @@ domains:
561
573
  - global.yaml
562
574
  - rules/human-writing-style.md
563
575
  - agents/brief.yaml
564
- - artifacts/handoffs/greenfield-wu-handoff.md # or brownfield-wu-handoff.md
576
+ - artifacts/handoffs/greenfield-wu/greenfield-wu-handoff.md # or brownfield-wu-handoff.md
565
577
  ```
566
578
 
567
579
  ---
@@ -588,7 +600,7 @@ Input data:
588
600
 
589
601
  ### Sending (to Detail agent or Architect agent)
590
602
  ```
591
- Handoff file: artifacts/handoffs/brief-handoff.md
603
+ Handoff file: artifacts/handoffs/brief/brief-handoff.md
592
604
  Contents:
593
605
  - brief.yaml with 5 requirement categories:
594
606
  1. Functional requirements (features, capabilities)
@@ -652,7 +664,7 @@ On failure:
652
664
  2. Functional and non-functional requirements must be clearly separated
653
665
  3. Never assume requirements - always validate with user
654
666
  4. Contradictions between categories must be resolved before compilation
655
- 5. User brain dump must be preserved verbatim for traceability
667
+ 5. Brain Dump (Raw) is clearly identified quoted original input: preserve it verbatim in its source language for traceability; do not translate or rewrite the original input. All authored summaries and analysis remain English. Both handoff layers, including Summary and Deep Context, must be English. A quote label does not exempt newly authored prose, and the localized terminal envelope is not the Markdown handoff file.
656
668
  6. Negative scope is mandatory - explicitly document what will NOT be built
657
669
  7. Adapt question depth to user level (vibecoder = guided, power user = direct)
658
670
  8. Maximum 5 interaction rounds before compiling brief draft
@@ -262,7 +262,7 @@ These rules are passed to Dev agent via handoff to prevent convention violations
262
262
  ```
263
263
 
264
264
  ### Handoff (Protocol 5.5)
265
- Save to: `artifacts/handoffs/brownfield-wu-handoff.md`
265
+ Save to: `artifacts/handoffs/brownfield-wu/brownfield-wu-handoff.md`
266
266
 
267
267
  - **Layer 1 (Summary)**: Mission completed, key findings, tech stack, critical debt items
268
268
  - **Layer 2 (Deep Context)**: Full scout findings, detailed debt inventory, integration complexity
@@ -276,7 +276,7 @@ agents:
276
276
  criteria_count: 8
277
277
  completed_at: "{timestamp}"
278
278
  current_agent: brief
279
- last_handoff: artifacts/handoffs/brownfield-wu-handoff.md
279
+ last_handoff: artifacts/handoffs/brownfield-wu/brownfield-wu-handoff.md
280
280
  ```
281
281
 
282
282
  ---
@@ -400,7 +400,7 @@ Input data:
400
400
 
401
401
  ### Sending (to Brief agent)
402
402
  ```
403
- Handoff file: artifacts/handoffs/brownfield-wu-handoff.md
403
+ Handoff file: artifacts/handoffs/brownfield-wu/brownfield-wu-handoff.md
404
404
  Contents:
405
405
  Layer 1 (Summary):
406
406
  - Codebase map (folder structure, file counts, patterns)
@@ -157,7 +157,7 @@ Save to: `artifacts/0-WU/wu-operational-report.md`
157
157
  ```
158
158
 
159
159
  ### Handoff (Protocol 5.5)
160
- Save to: `artifacts/handoffs/greenfield-wu-handoff.md`
160
+ Save to: `artifacts/handoffs/greenfield-wu/greenfield-wu-handoff.md`
161
161
 
162
162
  Follow Two-Layer Handoff structure:
163
163
  - **Layer 1 (Summary)**: Mission completed, key findings, artifacts, critical context for Brief agent
@@ -177,7 +177,7 @@ agents:
177
177
  criteria_count: 7
178
178
  completed_at: "{timestamp}"
179
179
  current_agent: brief
180
- last_handoff: artifacts/handoffs/greenfield-wu-handoff.md
180
+ last_handoff: artifacts/handoffs/greenfield-wu/greenfield-wu-handoff.md
181
181
  ```
182
182
 
183
183
  ### Project Context Update
@@ -353,7 +353,7 @@ brand-architect agent confirms the intent via Signal 2.
353
353
 
354
354
  ### How to write the signal
355
355
  Append a `## Scaffold Candidates` section to your handoff file
356
- (`artifacts/handoffs/greenfield-wu-handoff.md`). The CLI parser
356
+ (`artifacts/handoffs/greenfield-wu/greenfield-wu-handoff.md`). The CLI parser
357
357
  (`parseHandoffScaffoldCandidates` in `src/orchestrator/session-manager.js`)
358
358
  reads this block on `advance greenfield-wu` and merges the preset ids into
359
359
  `session.scaffold_candidates` (idempotent — no duplicate push).
@@ -398,7 +398,7 @@ Input data:
398
398
 
399
399
  ### Sending (to Brief agent)
400
400
  ```
401
- Handoff file: artifacts/handoffs/greenfield-wu-handoff.md
401
+ Handoff file: artifacts/handoffs/greenfield-wu/greenfield-wu-handoff.md
402
402
  Contents:
403
403
  - Project type confirmation
404
404
  - Tech stack assessment (frameworks, languages, tools)
@@ -180,12 +180,12 @@ Score = criteria met / 10. Threshold: >= 90% (9/10 minimum).
180
180
  ### Receives
181
181
  - **From**: Detail agent (greenfield) or Brief agent (brownfield parallel)
182
182
  - **Artifacts**: `prd.md`, `brief-report.md`
183
- - **Handoff**: `artifacts/handoffs/detail-handoff.md` or `brief-handoff.md`
183
+ - **Handoff**: `artifacts/handoffs/detail/detail-handoff.md` or `artifacts/handoffs/brief/brief-handoff.md`
184
184
 
185
185
  ### Sends
186
186
  - **To**: UX agent
187
187
  - **Artifacts**: `architecture.md` (10 sections)
188
- - **Handoff**: `artifacts/handoffs/architect-handoff.md`
188
+ - **Handoff**: `artifacts/handoffs/architect/architect-handoff.md`
189
189
  - **Content**: Architecture summary, tech stack overview, API contract summary, data model summary, security posture, self-validation score
190
190
 
191
191
  ---
@@ -230,7 +230,7 @@ Use template: `chati.dev/templates/prd-tmpl.yaml` (or brownfield-prd-tmpl.yaml)
230
230
  ```
231
231
 
232
232
  ### Handoff (Protocol 5.5)
233
- Save to: `artifacts/handoffs/detail-handoff.md`
233
+ Save to: `artifacts/handoffs/detail/detail-handoff.md`
234
234
 
235
235
  ### Session Update
236
236
  ```yaml
@@ -327,7 +327,7 @@ Rules:
327
327
  | L1 | `chati.dev/constitution.md` | Protocols, validation thresholds, handoff rules |
328
328
  | L1.5 | `chati.dev/rules/human-writing-style.md` | Anti-AI prose rules for human-facing PRD sections |
329
329
  | L2 | `artifacts/1-Brief/brief-report.md` | Problems, desired outcomes, constraints, target users |
330
- | L3 | `artifacts/handoffs/brief-handoff.md` | Brief agent handoff with decisions and open questions |
330
+ | L3 | `artifacts/handoffs/brief/brief-handoff.md` | Brief agent handoff with decisions and open questions |
331
331
 
332
332
  **Workflow Awareness**: Use the validated session context in the activation prompt to understand pipeline position and whether the flow is greenfield or brownfield. If that context is missing, return `needs_input`; never inspect the session file directly.
333
333
 
@@ -338,13 +338,13 @@ Rules:
338
338
  ### Receives
339
339
  - **From**: Brief agent
340
340
  - **Artifact**: `artifacts/1-Brief/brief-report.md` (brief.yaml format)
341
- - **Handoff file**: `artifacts/handoffs/brief-handoff.md`
341
+ - **Handoff file**: `artifacts/handoffs/brief/brief-handoff.md`
342
342
  - **Expected content**: Validated problem statements, target users, constraints, desired outcomes
343
343
 
344
344
  ### Sends
345
345
  - **To**: Architect agent (greenfield) or UX agent (brownfield)
346
346
  - **Artifact**: `artifacts/2-PRD/prd.md`
347
- - **Handoff file**: `artifacts/handoffs/detail-handoff.md`
347
+ - **Handoff file**: `artifacts/handoffs/detail/detail-handoff.md`
348
348
  - **Handoff content**: PRD summary, key decisions made, open questions, self-validation score, traceability matrix summary
349
349
 
350
350
  ---
@@ -212,7 +212,7 @@ Save to: `artifacts/5-Phases/phases.md`
212
212
  ```
213
213
 
214
214
  ### Handoff (Protocol 5.5)
215
- Save to: `artifacts/handoffs/phases-handoff.md`
215
+ Save to: `artifacts/handoffs/phases/phases-handoff.md`
216
216
 
217
217
  ### Session Update
218
218
  ```yaml
@@ -309,13 +309,13 @@ Rules:
309
309
  ### Receives
310
310
  - **From**: UX agent
311
311
  - **Artifact**: `artifacts/4-UX/ux-specification.md` (screen inventory, component complexity)
312
- - **Handoff file**: `artifacts/handoffs/ux-handoff.md`
312
+ - **Handoff file**: `artifacts/handoffs/ux/ux-handoff.md`
313
313
  - **Expected content**: UX specification summary, Design System token overview, screen inventory, accessibility compliance status
314
314
 
315
315
  ### Sends
316
316
  - **To**: Tasks agent
317
317
  - **Artifact**: `artifacts/5-Phases/phases.md`
318
- - **Handoff file**: `artifacts/handoffs/phases-handoff.md`
318
+ - **Handoff file**: `artifacts/handoffs/phases/phases-handoff.md`
319
319
  - **Handoff content**: Phase breakdown summary, MVP scope, dependency map, wave structure, timeline estimates, traceability matrix (PRD to Phases), self-validation score
320
320
 
321
321
  ---