chati-dev 4.5.10 → 4.5.12

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 (47) hide show
  1. package/framework/agents/discover/brownfield-wu.md +1 -1
  2. package/framework/agents/plan/tasks.md +2 -2
  3. package/framework/config.yaml +2 -2
  4. package/framework/constitution.md +21 -22
  5. package/framework/context/governance.md +10 -10
  6. package/framework/context/quality.md +6 -6
  7. package/framework/context/root.md +1 -1
  8. package/framework/data/entity-registry.yaml +1 -1
  9. package/framework/domains/constitution.yaml +1 -1
  10. package/framework/domains/workflows/brownfield-fullstack.yaml +5 -3
  11. package/framework/domains/workflows/brownfield-service.yaml +2 -3
  12. package/framework/domains/workflows/brownfield-ui.yaml +2 -3
  13. package/framework/domains/workflows/greenfield-fullstack.yaml +5 -3
  14. package/framework/domains/workflows/quick-flow.yaml +7 -6
  15. package/framework/domains/workflows/standard-flow.yaml +4 -5
  16. package/framework/frameworks/quality-dimensions.yaml +3 -3
  17. package/framework/hooks/git-push-authority.js +8 -4
  18. package/framework/manifest.json +49 -49
  19. package/framework/manifest.sig +1 -1
  20. package/framework/orchestrator/chati.md +29 -20
  21. package/framework/schemas/session.schema.json +5 -5
  22. package/framework/workflows/brownfield-fullstack.yaml +17 -123
  23. package/framework/workflows/brownfield-service.yaml +15 -109
  24. package/framework/workflows/brownfield-ui.yaml +15 -115
  25. package/framework/workflows/greenfield-fullstack.yaml +17 -130
  26. package/framework/workflows/quick-flow.yaml +20 -111
  27. package/framework/workflows/standard-flow.yaml +14 -158
  28. package/package.json +1 -1
  29. package/src/config/claude-settings-generator.js +4 -3
  30. package/src/config/context-file-generator.js +10 -1
  31. package/src/config/framework-adapter.js +10 -2
  32. package/src/context/layers/l1-global.js +2 -0
  33. package/src/installer/core.js +94 -13
  34. package/src/installer/templates.js +5 -4
  35. package/src/installer/validator.js +8 -2
  36. package/src/intelligence/registry-manager.js +11 -4
  37. package/src/orchestrator/cli.js +158 -42
  38. package/src/orchestrator/pipeline-manager.js +2 -0
  39. package/src/orchestrator/runtime-installation-v2.js +38 -0
  40. package/src/orchestrator/session-manager.js +1 -1
  41. package/src/terminal/handoff-parser.js +23 -4
  42. package/src/terminal/prompt-builder.js +15 -1
  43. package/src/terminal/provider-preflight.js +78 -0
  44. package/src/terminal/run-agent.js +66 -23
  45. package/src/terminal/spawner.js +5 -1
  46. package/src/utils/schema-validator.js +5 -2
  47. package/src/wizard/index.js +1 -0
@@ -1,174 +1,30 @@
1
- # Standard Flow Workflow
2
- # Mid-tier pipeline for moderate tasks: new features, integrations, brownfield enhancements
3
- # Uses 8 agents — between Quick Flow (4) and Full Flow (12)
4
-
5
1
  workflow:
6
2
  id: standard-flow
7
- name: Standard Flow — Balanced Development
8
- version: "1.0.0"
3
+ name: Standard Flow
4
+ version: "2.0.0"
9
5
  type: any
10
6
  project_types: [feature, integration, enhancement, module, component, brownfield-moderate]
11
- description: >
12
- Balanced pipeline for moderate complexity tasks that need proper planning
13
- but not the full 12-agent pipeline. Skips WU (assumes existing codebase
14
- context), UX (no design-heavy work), and Phases (tasks agent handles
15
- scope directly). Ideal for 2-5 requirements in brownfield projects.
16
-
17
- detection:
18
- triggers:
19
- - "Moderate complexity feature with 2-5 requirements"
20
- - "Brownfield project enhancement or integration"
21
- - "New module or component within existing architecture"
22
- - "User explicitly requests standard flow"
23
- - "Feature that needs architecture review but not full UX design"
24
- - "API integration or service connection"
25
- - "Database-backed feature with clear data model"
26
- disqualifiers:
27
- - "Quick fix, hotfix, or single-line change (use Quick Flow)"
28
- - "Enterprise-scale project with compliance requirements (use Full Flow)"
29
- - "Greenfield project requiring full discovery (use Full Flow)"
30
- - "UX-heavy feature requiring design system work (use Full Flow)"
31
- - "Multi-service architecture changes (use Full Flow)"
32
- - "User explicitly requests full pipeline"
33
-
34
- confidence_threshold: 0.8
35
- user_confirmation: true
36
-
37
- agents:
38
- included:
39
- - brief
40
- - detail
41
- - architect
42
- - tasks
43
- - qa-planning # runs inside Planning Team; score synced via team dissolution
44
- - dev
45
- - qa-implementation
46
- - devops
47
- excluded:
48
- - greenfield-wu
49
- - brownfield-wu
50
- - ux
51
- - phases
7
+ execution_authority: rail
8
+ description: Balanced planning followed by the canonical RAIL and Release contracts.
52
9
 
53
10
  phases:
54
11
  - phase: 0
55
12
  name: Discovery
56
13
  category: DISCOVER
57
14
  sequence:
58
- - agent: brief
59
- action: extract-requirements
60
- creates: [artifacts/1-Brief/brief.md]
61
- notes: >
62
- Full brief extraction (5 phases). Since no WU precedes it,
63
- Brief must also capture codebase context from user input.
64
- config:
65
- max_rounds: 5
66
- require_approval: true
67
-
15
+ - { agent: brief, action: problem-extraction, creates: [artifacts/1-Brief/brief-report.md] }
68
16
  - phase: 1
69
17
  name: Planning
70
18
  category: PLAN
71
19
  sequence:
72
- - agent: detail
73
- action: expand-requirements
74
- creates: [artifacts/2-Detail/prd.md]
75
- notes: "Full PRD from brief output"
76
- parallel_with: [architect]
77
-
78
- - agent: architect
79
- action: design-architecture
80
- creates: [artifacts/3-Architecture/architecture.md]
81
- notes: "Architecture decisions, no UX constraints needed"
82
- parallel_with: [detail]
83
-
84
- - agent: tasks
85
- action: create-tasks
86
- creates: [artifacts/5-Tasks/tasks.md]
87
- notes: >
88
- Tasks agent works directly from PRD + Architecture.
89
- No phases agent — tasks agent determines task breakdown directly.
90
-
91
- - agent: qa-planning
92
- action: validate-plan
93
- creates: [artifacts/6-QA-Planning/qa-planning-report.md]
94
- notes: >
95
- Runs inside Planning Team (Article XXI), not as a standalone step.
96
- Activates after Detail, Architect complete. Score >= 95% required to advance.
97
- Score synced to session.yaml by orchestrator on team dissolution.
98
- config:
99
- minimum_score: 95
100
-
101
- - phase: 2
102
- name: Implementation
103
- category: BUILD
104
- sequence:
105
- - agent: dev
106
- action: implement-tasks
107
- notes: "Dev works from full PRD + architecture + tasks"
108
-
109
- - agent: qa-implementation
110
- action: validate-code
111
- creates: [artifacts/9-QA-Implementation/qa-implementation-report.md]
112
- notes: >
113
- Full QA-Implementation validation. Score >= 95% required.
114
- Adversarial review mandatory.
115
- config:
116
- adversarial_review: true
117
- minimum_findings: 5
118
- minimum_score: 95
119
-
120
- - phase: 3
121
- name: Deployment
122
- category: DEPLOY
123
- sequence:
124
- - agent: devops
125
- action: deploy
126
- creates: [artifacts/10-Deploy/deploy-report.md]
127
- notes: "Standard deployment process"
20
+ - { agent: detail, action: create-prd, creates: [artifacts/2-PRD/prd.md] }
21
+ - { agent: architect, action: focused-architecture, creates: [artifacts/3-Architecture/architecture.md] }
22
+ - { agent: tasks, action: seal-task-graph, creates: [artifacts/6-Tasks/tasks.md] }
23
+ - { agent: qa-planning, action: validate-planning, creates: [artifacts/7-QA-Planning/qa-planning-report.md] }
24
+ - { phase: 2, name: RAIL Execution, category: RAIL, runtime: project-local-rail }
25
+ - { phase: 3, name: Release Lane, category: RELEASE, requires: [rail_complete, independent_review_approved, explicit_human_authorization] }
128
26
 
129
27
  transitions:
130
- discover_to_plan:
131
- trigger: "brief.status == completed"
132
- type: automatic
133
- action: "Advance to PLAN phase"
134
- plan_to_build:
135
- trigger: "qa-planning.score >= 95"
136
- type: automatic
137
- action: "Advance to BUILD phase"
138
- build_to_validate:
139
- trigger: "dev.status == completed"
140
- type: automatic
141
- action: "Run QA-Implementation"
142
- validate_to_deploy:
143
- trigger: "qa-implementation.score >= 95"
144
- type: user_preview
145
- action: "User preview gate, then advance to DEPLOY"
146
- deploy_to_completed:
147
- trigger: "devops.status == completed"
148
- type: automatic
149
- action: "Pipeline complete"
150
-
151
- escalation:
152
- to_full_flow:
153
- triggers:
154
- - "Architect discovers multi-service complexity"
155
- - "QA-Planning finds UX requirements not addressed"
156
- - "Scope creep: more than 5 distinct requirements discovered"
157
- - "User requests full pipeline"
158
- action: >
159
- Pause standard-flow, notify user:
160
- "This task is more complex than the standard flow can handle.
161
- Options:
162
- 1. Switch to full pipeline (Recommended)
163
- 2. Continue with standard flow (document gaps)
164
- 3. Reduce scope and continue"
165
- to_quick_flow:
166
- triggers:
167
- - "Detail agent finds only 1 simple requirement"
168
- - "Architect confirms no architecture changes needed"
169
- action: >
170
- Suggest downgrade:
171
- "This task might be simpler than expected.
172
- Options:
173
- 1. Switch to quick flow (faster)
174
- 2. Continue with standard flow"
28
+ discover_to_plan: { trigger: "brief.status == completed", target: plan }
29
+ plan_to_rail: { trigger: "qa-planning.score >= 95 && tasks.handoff == sealed", target: rail }
30
+ rail_to_release: { trigger: "rail.all_tasks_approved == true", target: release }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chati-dev",
3
- "version": "4.5.10",
3
+ "version": "4.5.12",
4
4
  "description": "AI-Powered Multi-Agent Orchestration System - Structured vibe coding for Full Stack Development",
5
5
  "type": "module",
6
6
  "bin": {
@@ -176,10 +176,11 @@ const PERMISSIONS_DENY = [
176
176
  * Group HOOK_REGISTRY entries by event, then by matcher within each event.
177
177
  * Returns the shape Claude Code expects under the top-level "hooks" key.
178
178
  */
179
- function buildHooksObject() {
179
+ function buildHooksObject(options = {}) {
180
180
  const events = {};
181
181
 
182
182
  for (const entry of HOOK_REGISTRY) {
183
+ if (options.runtimeVersion === 2 && entry.name === 'post-dev') continue;
183
184
  if (!events[entry.event]) events[entry.event] = new Map();
184
185
  const matcherGroups = events[entry.event];
185
186
  if (!matcherGroups.has(entry.matcher)) {
@@ -208,7 +209,7 @@ function buildHooksObject() {
208
209
  *
209
210
  * @returns {string} JSON string with trailing newline, ready to write to disk.
210
211
  */
211
- export function generateClaudeSettings() {
212
+ export function generateClaudeSettings(options = {}) {
212
213
  const settings = {
213
214
  $schema: 'https://json.schemastore.org/claude-code-settings.json',
214
215
  permissions: {
@@ -216,7 +217,7 @@ export function generateClaudeSettings() {
216
217
  deny: PERMISSIONS_DENY,
217
218
  defaultMode: 'default',
218
219
  },
219
- hooks: buildHooksObject(),
220
+ hooks: buildHooksObject(options),
220
221
  };
221
222
 
222
223
  return JSON.stringify(settings, null, 2) + '\n';
@@ -68,10 +68,17 @@ function buildCodexReplacements(frameworkDir = 'chati.dev') {
68
68
  ['claude --print', 'codex exec'],
69
69
  ['claude -p', 'codex exec'],
70
70
  ['CLAUDE.local.md', 'AGENTS.override.md'],
71
- ['/chati', '$chati'],
72
71
  ];
73
72
  }
74
73
 
74
+ /**
75
+ * Convert the interactive slash command without touching filesystem paths such
76
+ * as `.chati.dev/orchestrator/chati.md`.
77
+ */
78
+ function adaptCodexInvocation(content) {
79
+ return content.replace(/(?<![\w/])\/chati(?=\s|$|[`'".,;:!?)]|\b)/gm, '$chati');
80
+ }
81
+
75
82
  // ---------------------------------------------------------------------------
76
83
  // Generators
77
84
  // ---------------------------------------------------------------------------
@@ -144,6 +151,7 @@ export function generateAgentsMd(content, contextFiles = null, frameworkDir = 'c
144
151
  for (const [search, replace] of replacements) {
145
152
  result = result.replaceAll(search, replace);
146
153
  }
154
+ result = adaptCodexInvocation(result);
147
155
 
148
156
  // Clean up any double blank lines left by stripping
149
157
  result = result.replace(/\n{3,}/g, '\n\n');
@@ -166,6 +174,7 @@ export function generateAgentsMd(content, contextFiles = null, frameworkDir = 'c
166
174
  for (const [search, replace] of replacements) {
167
175
  adapted = adapted.replaceAll(search, replace);
168
176
  }
177
+ adapted = adaptCodexInvocation(adapted);
169
178
  sections.push(adapted.trim());
170
179
  }
171
180
  }
@@ -201,11 +201,19 @@ function buildReplacementConfig(provider) {
201
201
  * @returns {string} Adapted content for the target provider
202
202
  */
203
203
  export function adaptFrameworkFile(content, filePath, provider) {
204
- if (provider === 'claude') return content;
205
204
  if (!content) return content;
206
205
 
207
- const config = buildReplacementConfig(provider);
208
206
  let result = content;
207
+ if (filePath === 'orchestrator/chati.md') {
208
+ result = result.replace(
209
+ /<!-- CHATI_LEGACY_BUILD_START -->[\s\S]*?<!-- CHATI_LEGACY_BUILD_END -->\s*/g,
210
+ 'For installations without `.chati/v2/installation.json`, use the separately bundled legacy compatibility runtime.\n\n',
211
+ );
212
+ }
213
+
214
+ if (provider === 'claude') return result;
215
+
216
+ const config = buildReplacementConfig(provider);
209
217
 
210
218
  // 1. Apply ordered string replacements (most specific first)
211
219
  for (const [search, replace] of config.strings) {
@@ -15,7 +15,9 @@ const STATE_TO_GOVERNANCE_MODE = {
15
15
  planning: 'planning',
16
16
  build: 'build',
17
17
  validate: 'build',
18
+ rail: 'build',
18
19
  deploy: 'deploy',
20
+ release: 'deploy',
19
21
  completed: 'deploy',
20
22
  };
21
23
 
@@ -1,4 +1,4 @@
1
- import { mkdirSync, writeFileSync, copyFileSync, existsSync, readFileSync, readdirSync, statSync } from 'fs';
1
+ import { mkdirSync, writeFileSync, copyFileSync, existsSync, readFileSync, readdirSync, statSync, rmSync } from 'fs';
2
2
  import { execFileSync } from 'child_process';
3
3
  import { join, dirname } from 'path';
4
4
  import { fileURLToPath } from 'url';
@@ -12,6 +12,7 @@ import { generateClaudeSettings } from '../config/claude-settings-generator.js';
12
12
  import { generateProviderOverlays } from './provider-overlay.js';
13
13
  import { applyInstalledPathReplacement } from './path-replacement.js';
14
14
  import { verifyManifest } from './manifest.js';
15
+ import * as yaml from 'js-yaml';
15
16
 
16
17
  const __dirname = dirname(fileURLToPath(import.meta.url));
17
18
 
@@ -70,7 +71,13 @@ export async function installFramework(config) {
70
71
 
71
72
  // 2b. Create artifacts/ at PROJECT ROOT (visible to user — this is their output)
72
73
  const artifactsDir = join(targetDir, 'artifacts');
73
- const artifactDirs = [
74
+ const isRuntimeV2 = config.runtimeVersion === 2;
75
+ const artifactDirs = isRuntimeV2 ? [
76
+ '0-WU', '1-Brief', '2-PRD',
77
+ '3-Architecture', '4-UX', '5-Phases',
78
+ '6-Tasks', '7-QA-Planning', '8-RAIL', '9-Release',
79
+ 'handoffs', 'decisions',
80
+ ] : [
74
81
  '0-WU', '1-Brief', '2-PRD',
75
82
  '3-Architecture', '4-UX', '5-Phases',
76
83
  '6-Tasks', '7-QA-Planning', '8-QA-Visual', '9-QA-Implementation', '10-Deploy',
@@ -96,7 +103,7 @@ export async function installFramework(config) {
96
103
 
97
104
  // Create .chati/memories/ directory tree for Memory Layer
98
105
  const memoriesBase = join(targetDir, '.chati', 'memories');
99
- const memoryDirs = [
106
+ const planningMemoryDirs = [
100
107
  'shared/durable', 'shared/daily', 'shared/session',
101
108
  'greenfield-wu/durable', 'greenfield-wu/daily',
102
109
  'brownfield-wu/durable', 'brownfield-wu/daily',
@@ -107,11 +114,16 @@ export async function installFramework(config) {
107
114
  'phases/durable', 'phases/daily',
108
115
  'tasks/durable', 'tasks/daily',
109
116
  'qa-planning/durable', 'qa-planning/daily',
117
+ ];
118
+ const legacyExecutionMemoryDirs = [
110
119
  'qa-implementation/durable', 'qa-implementation/daily',
111
120
  'qa-visual/durable', 'qa-visual/daily',
112
121
  'dev/durable', 'dev/daily',
113
122
  'devops/durable', 'devops/daily',
114
123
  ];
124
+ const memoryDirs = isRuntimeV2
125
+ ? [...planningMemoryDirs, 'rail/durable', 'rail/daily', 'release/durable', 'release/daily']
126
+ : [...planningMemoryDirs, ...legacyExecutionMemoryDirs];
115
127
  for (const dir of memoryDirs) {
116
128
  createDir(join(memoriesBase, dir));
117
129
  }
@@ -125,6 +137,11 @@ export async function installFramework(config) {
125
137
  generateProviderOverlays(targetDir, FRAMEWORK_SOURCE, allProviders);
126
138
  }
127
139
 
140
+ if (isRuntimeV2) {
141
+ pruneLegacyExecutionSurface(frameworkDir, allProviders || []);
142
+ pruneLegacyRegistryEntities(frameworkDir);
143
+ }
144
+
128
145
  // Bundle the CLI source into the framework dir so chati-router.js can run
129
146
  // commands locally without depending on `npx chati-dev` (which fetches from
130
147
  // the npm registry — version drift causes inconsistent behavior).
@@ -162,7 +179,7 @@ export async function installFramework(config) {
162
179
  // Write config.yaml
163
180
  writeFileSync(
164
181
  join(frameworkDir, 'config.yaml'),
165
- generateConfigYaml({ version, projectType, language, selectedIDEs, allProviders }),
182
+ generateConfigYaml({ version, projectType, language, selectedIDEs, allProviders, runtimeVersion: config.runtimeVersion }),
166
183
  'utf-8'
167
184
  );
168
185
 
@@ -174,7 +191,12 @@ export async function installFramework(config) {
174
191
  const orchestratorPath = hasProviderOverlay
175
192
  ? `.chati.dev/.adapted/${ideProvider}/orchestrator/chati.md`
176
193
  : '.chati.dev/orchestrator/chati.md';
177
- await configureIDE(targetDir, ideKey, selectedMCPs, { orchestratorPath, isSecondary: false, providerName: ideProvider });
194
+ await configureIDE(targetDir, ideKey, selectedMCPs, {
195
+ orchestratorPath,
196
+ isSecondary: false,
197
+ providerName: ideProvider,
198
+ runtimeVersion: config.runtimeVersion,
199
+ });
178
200
  }
179
201
 
180
202
  const hasClaude = selectedIDEs.includes('claude-code');
@@ -224,6 +246,55 @@ export async function installFramework(config) {
224
246
  ensureGitRepository(targetDir);
225
247
  }
226
248
 
249
+ function pruneLegacyRegistryEntities(frameworkDir) {
250
+ const registryPath = join(frameworkDir, 'data', 'entity-registry.yaml');
251
+ if (!existsSync(registryPath)) return;
252
+ const registry = yaml.load(readFileSync(registryPath, 'utf-8'));
253
+ if (!registry?.entities) return;
254
+ const legacyPath = /\/(?:agents\/(?:build|deploy)\/|agents\/quality\/qa-(?:implementation|visual)\.md$|hooks\/post-dev\.js$|templates\/team-build-tasks\.yaml$|quality-gates\/implementation-gate\.md$|domains\/agents\/(?:dev|devops|qa-implementation|qa-visual)\.yaml$|tasks\/(?:dev-|devops-|qa-impl-))/;
255
+ let count = 0;
256
+ for (const entities of Object.values(registry.entities)) {
257
+ if (!entities || typeof entities !== 'object') continue;
258
+ for (const [name, entity] of Object.entries(entities)) {
259
+ if (legacyPath.test(entity?.path || '')) delete entities[name];
260
+ else if (entity?.path) count += 1;
261
+ }
262
+ }
263
+ registry.metadata = { ...(registry.metadata || {}), entity_count: count };
264
+ writeFileSync(registryPath, yaml.dump(registry, { lineWidth: -1 }), 'utf-8');
265
+ }
266
+
267
+ const V2_LEGACY_EXECUTION_PATHS = [
268
+ 'agents/build',
269
+ 'agents/deploy',
270
+ 'agents/quality/qa-implementation.md',
271
+ 'agents/quality/qa-visual.md',
272
+ 'quality-gates/implementation-gate.md',
273
+ 'templates/team-build-tasks.yaml',
274
+ 'hooks/post-dev.js',
275
+ 'domains/agents/dev.yaml',
276
+ 'domains/agents/devops.yaml',
277
+ 'domains/agents/qa-implementation.yaml',
278
+ 'domains/agents/qa-visual.yaml',
279
+ ];
280
+
281
+ function pruneLegacyExecutionSurface(frameworkDir, providers) {
282
+ const roots = [frameworkDir, ...providers.map(provider => join(frameworkDir, '.adapted', provider))];
283
+ for (const root of roots) {
284
+ for (const relativePath of V2_LEGACY_EXECUTION_PATHS) {
285
+ rmSync(join(root, relativePath), { recursive: true, force: true });
286
+ }
287
+ const tasksDir = join(root, 'tasks');
288
+ if (existsSync(tasksDir)) {
289
+ for (const entry of readdirSync(tasksDir)) {
290
+ if (/^(?:dev-|devops-|qa-impl-)/.test(entry)) {
291
+ rmSync(join(tasksDir, entry), { force: true });
292
+ }
293
+ }
294
+ }
295
+ }
296
+ }
297
+
227
298
  export function ensureGitRepository(targetDir) {
228
299
  try {
229
300
  execFileSync('git', ['-C', targetDir, 'rev-parse', '--show-toplevel'], { stdio: 'ignore' });
@@ -415,7 +486,7 @@ Parse the JSON output. This single command already handled: license validation,
415
486
  // hook system and applies a baseline permission policy. THIS IS THE FILE
416
487
  // CLAUDE CODE READS — without it, every hook in chati.dev/hooks/ is dormant.
417
488
  // (Pre-v4.2.2 bug: this file was never written, hooks never ran.)
418
- writeClaudeSettingsWithMerge(join(targetDir, '.claude', 'settings.json'));
489
+ writeClaudeSettingsWithMerge(join(targetDir, '.claude', 'settings.json'), { runtimeVersion: options.runtimeVersion });
419
490
 
420
491
  // Claude project-scope MCP config lives at the project root. Preserve
421
492
  // unknown user-managed servers while replacing CHATI's known entries.
@@ -560,16 +631,16 @@ Governance rules are in \`.chati.dev/constitution.md\`.
560
631
  \`\`\`
561
632
  DISCOVER: WU -> Brief
562
633
  PLAN: [Planning Team: Detail + Architect + UX + QA-Planning] -> Phases -> Tasks
563
- BUILD: [Build Team: Dev + QA-Implementation] -> QA-Visual
564
- DEPLOY: DevOps
634
+ RAIL: Sealed task graph -> Execute -> Independent Review -> Bounded Rework
635
+ RELEASE: Evidence gate -> Explicit human authorization -> External action
565
636
  \`\`\`
566
637
 
567
638
  ## Agents
568
639
  - DISCOVER: .chati.dev/agents/discover/
569
640
  - PLAN: .chati.dev/agents/plan/
570
- - Quality: .chati.dev/agents/quality/
571
- - BUILD: .chati.dev/agents/build/
572
- - DEPLOY: .chati.dev/agents/deploy/
641
+ - Planning Quality: .chati.dev/agents/quality/qa-planning.md
642
+ - RAIL Runtime: .chati.dev/_cli/ and .chati/v2/rail/
643
+ - Release Lane: RAIL completion evidence plus explicit authorization
573
644
  `;
574
645
  }
575
646
 
@@ -883,9 +954,9 @@ export function copyCliDependencies(pkgDir, destNodeModules) {
883
954
  * If the file exists but is malformed: leave it alone, log a warning. We will
884
955
  * not silently destroy user data.
885
956
  */
886
- export function writeClaudeSettingsWithMerge(settingsPath) {
957
+ export function writeClaudeSettingsWithMerge(settingsPath, options = {}) {
887
958
  createDir(dirname(settingsPath));
888
- const fresh = JSON.parse(generateClaudeSettings());
959
+ const fresh = JSON.parse(generateClaudeSettings(options));
889
960
 
890
961
  if (!existsSync(settingsPath)) {
891
962
  writeFileSync(settingsPath, JSON.stringify(fresh, null, 2) + '\n', 'utf-8');
@@ -900,6 +971,16 @@ export function writeClaudeSettingsWithMerge(settingsPath) {
900
971
  return;
901
972
  }
902
973
 
974
+ if (options.runtimeVersion === 2 && existing.hooks) {
975
+ for (const groups of Object.values(existing.hooks)) {
976
+ if (!Array.isArray(groups)) continue;
977
+ for (const group of groups) {
978
+ if (Array.isArray(group.hooks)) {
979
+ group.hooks = group.hooks.filter(hook => !/\.chati\.dev\/hooks\/post-dev\.js$/.test(hook.command || ''));
980
+ }
981
+ }
982
+ }
983
+ }
903
984
  const merged = mergeClaudeSettings(existing, fresh);
904
985
  writeFileSync(settingsPath, JSON.stringify(merged, null, 2) + '\n', 'utf-8');
905
986
  }
@@ -62,11 +62,12 @@ export function generateSessionYaml(config) {
62
62
  reasoning_escalations: [],
63
63
  };
64
64
 
65
- // Initialize all 13 agent statuses
65
+ // V2 ends the classic agent pipeline at Tasks. RAIL owns implementation,
66
+ // independent review, bounded rework and the Release Lane after handoff.
66
67
  const agentNames = [
67
68
  'greenfield-wu', 'brownfield-wu', 'brief', 'detail',
68
69
  'architect', 'ux', 'phases', 'tasks',
69
- 'qa-planning', 'dev', 'qa-implementation', 'qa-visual', 'devops',
70
+ 'qa-planning',
70
71
  ];
71
72
 
72
73
  for (const agent of agentNames) {
@@ -174,14 +175,14 @@ export function generateConfigYaml(config) {
174
175
  model_fallback: true,
175
176
  frustration_detection: true,
176
177
  bash_security_checks: true,
177
- // Agent Teams (Article XXI) default ON in v4.2.2.
178
+ // Agent Teams are planning-only in runtime v2.
178
179
  // Only effective when the active session runs in Claude (gated in cli.js
179
180
  // isAgentTeamsEnabled). Gemini and Codex always fall back to sequential
180
181
  // pipeline silently. See plan: was previously false for "safe rollout"
181
182
  // but the v4.2.0 launch never actually shipped, so this is a fresh start.
182
183
  agent_teams: true,
183
184
  team_planning_size: 4,
184
- team_build_size: 2,
185
+ ...(config.runtimeVersion === 2 ? {} : { team_build_size: 2 }),
185
186
  team_echo_threshold: 0.92,
186
187
  team_correction_cycles_max: 2,
187
188
  };
@@ -17,6 +17,7 @@ function resolveFrameworkDir(targetDir) {
17
17
  * Checks all primary agents, constitution, session, schemas, etc.
18
18
  */
19
19
  export async function validateInstallation(targetDir) {
20
+ const isRuntimeV2 = existsSync(join(targetDir, '.chati', 'v2', 'installation.json'));
20
21
  const results = {
21
22
  agents: { pass: false, details: [] },
22
23
  constitution: { pass: false, details: [] },
@@ -35,7 +36,7 @@ export async function validateInstallation(targetDir) {
35
36
  };
36
37
 
37
38
  // Check all primary agents (orchestrator + 12 specialized, sub-agents validated by managers)
38
- const agentFiles = [
39
+ const planningAgentFiles = [
39
40
  'orchestrator/chati.md',
40
41
  'agents/discover/greenfield-wu.md',
41
42
  'agents/discover/brownfield-wu.md',
@@ -46,10 +47,15 @@ export async function validateInstallation(targetDir) {
46
47
  'agents/plan/phases.md',
47
48
  'agents/plan/tasks.md',
48
49
  'agents/quality/qa-planning.md',
50
+ ];
51
+ const legacyExecutionAgentFiles = [
49
52
  'agents/quality/qa-implementation.md',
50
53
  'agents/build/dev.md',
51
54
  'agents/deploy/devops.md',
52
55
  ];
56
+ const agentFiles = isRuntimeV2
57
+ ? planningAgentFiles
58
+ : [...planningAgentFiles, ...legacyExecutionAgentFiles];
53
59
 
54
60
  let agentCount = 0;
55
61
  for (const file of agentFiles) {
@@ -64,7 +70,7 @@ export async function validateInstallation(targetDir) {
64
70
  results.agents.details.push({ file, exists: false, hasProtocols: false });
65
71
  }
66
72
  }
67
- results.agents.pass = agentCount === 13;
73
+ results.agents.pass = agentCount === agentFiles.length;
68
74
  results.total += 1;
69
75
  if (results.agents.pass) results.passed += 1;
70
76
 
@@ -158,21 +158,28 @@ export function runHealthCheck(targetDir) {
158
158
  }
159
159
 
160
160
  // 4. Agent check
161
- const agentPaths = [
161
+ const planningAgentPaths = [
162
162
  'orchestrator/chati.md',
163
163
  'agents/discover/greenfield-wu.md', 'agents/discover/brownfield-wu.md',
164
164
  'agents/discover/brief.md', 'agents/plan/detail.md',
165
165
  'agents/plan/architect.md', 'agents/plan/ux.md',
166
166
  'agents/plan/phases.md', 'agents/plan/tasks.md',
167
- 'agents/quality/qa-planning.md', 'agents/quality/qa-implementation.md',
167
+ 'agents/quality/qa-planning.md',
168
+ ];
169
+ const legacyExecutionAgentPaths = [
170
+ 'agents/quality/qa-implementation.md',
168
171
  'agents/build/dev.md', 'agents/deploy/devops.md',
169
172
  ];
173
+ const isRuntimeV2 = existsSync(join(targetDir, '.chati', 'v2', 'installation.json'));
174
+ const agentPaths = isRuntimeV2
175
+ ? planningAgentPaths
176
+ : [...planningAgentPaths, ...legacyExecutionAgentPaths];
170
177
  let foundAgents = 0;
171
178
  for (const p of agentPaths) {
172
179
  if (existsSync(join(targetDir, fwDir, p))) foundAgents++;
173
180
  }
174
- checks.agents.pass = foundAgents === 13;
175
- checks.agents.details = `${foundAgents}/13 present`;
181
+ checks.agents.pass = foundAgents === agentPaths.length;
182
+ checks.agents.details = `${foundAgents}/${agentPaths.length} present`;
176
183
 
177
184
  // 5. Entity validation (registry vs filesystem)
178
185
  const entityResult = validateEntities(targetDir);