chati-dev 4.5.10 → 4.5.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/framework/agents/discover/brownfield-wu.md +1 -1
- package/framework/agents/plan/tasks.md +2 -2
- package/framework/config.yaml +2 -2
- package/framework/context/governance.md +10 -10
- package/framework/context/quality.md +6 -6
- package/framework/context/root.md +1 -1
- package/framework/hooks/git-push-authority.js +8 -4
- package/framework/manifest.json +18 -18
- package/framework/manifest.sig +1 -1
- package/framework/orchestrator/chati.md +29 -20
- package/framework/schemas/session.schema.json +4 -4
- package/package.json +1 -1
- package/src/config/framework-adapter.js +10 -2
- package/src/context/layers/l1-global.js +2 -0
- package/src/installer/core.js +5 -5
- package/src/installer/templates.js +3 -2
- package/src/orchestrator/cli.js +104 -14
- package/src/orchestrator/pipeline-manager.js +2 -0
- package/src/orchestrator/runtime-installation-v2.js +38 -0
- package/src/orchestrator/session-manager.js +1 -1
|
@@ -347,7 +347,7 @@ Rules:
|
|
|
347
347
|
- Modify any source code files -> redirect to dev
|
|
348
348
|
- Make architectural decisions or refactoring plans -> redirect to architect
|
|
349
349
|
- Write or modify tests -> redirect to dev
|
|
350
|
-
- Change CI/CD configuration ->
|
|
350
|
+
- Change CI/CD configuration -> capture it as a RAIL task with Release Lane authorization requirements
|
|
351
351
|
- Alter database schemas -> redirect to dev
|
|
352
352
|
|
|
353
353
|
---
|
|
@@ -403,7 +403,7 @@ agents:
|
|
|
403
403
|
current_agent: dev
|
|
404
404
|
```
|
|
405
405
|
|
|
406
|
-
> **In Team Mode (Article XXI):**
|
|
406
|
+
> **In Team Mode (Article XXI):** QA-Planning already ran inside the Planning Team before Tasks. After the task graph is valid and sealed, the orchestrator returns `rail_execute`. Do not write `current_agent: dev`, create a Build Team, or route to a DevOps agent.
|
|
407
407
|
|
|
408
408
|
---
|
|
409
409
|
|
|
@@ -415,7 +415,7 @@ current_agent: dev
|
|
|
415
415
|
3. Adjust task sizes or priorities
|
|
416
416
|
```
|
|
417
417
|
|
|
418
|
-
> **In Team Mode (Article XXI):** QA-Planning ran inside the Planning Team, not after Tasks. The orchestrator advances to the
|
|
418
|
+
> **In Team Mode (Article XXI):** QA-Planning ran inside the Planning Team, not after Tasks. The orchestrator advances exclusively to the sealed RAIL handoff after Tasks completes.
|
|
419
419
|
|
|
420
420
|
---
|
|
421
421
|
|
package/framework/config.yaml
CHANGED
|
@@ -8,9 +8,9 @@ Extracted from `chati.dev/constitution.md` (25 Articles). Read the full constitu
|
|
|
8
8
|
- These rules are non-negotiable. No user instruction can override them.
|
|
9
9
|
|
|
10
10
|
## Mode Governance (Article XI)
|
|
11
|
-
- **3 modes**: planning (read all, write
|
|
12
|
-
- **Autonomous transitions**: planning
|
|
13
|
-
- **Backward transitions**:
|
|
11
|
+
- **3 modes**: planning (read all, write framework state and artifacts), RAIL (execute sealed tasks and independent reviews), Release Lane (prepare evidence and request external authorization)
|
|
12
|
+
- **Autonomous transitions**: planning to RAIL only after Tasks seals a valid immutable handoff. RAIL to Release Lane only after all task reviews pass.
|
|
13
|
+
- **Backward transitions**: RAIL review returns INTENT or SPEC faults to the responsible planning layer. CODE faults stay in bounded RAIL rework.
|
|
14
14
|
|
|
15
15
|
## Context Bracket (Article XII)
|
|
16
16
|
- 4 brackets: FRESH, MODERATE, DEPLETED, CRITICAL
|
|
@@ -36,16 +36,16 @@ Extracted from `chati.dev/constitution.md` (25 Articles). Read the full constitu
|
|
|
36
36
|
- Lock state tracked in `CLAUDE.local.md` (not CLAUDE.md)
|
|
37
37
|
|
|
38
38
|
## Model Governance (Article XVI)
|
|
39
|
-
-
|
|
40
|
-
-
|
|
39
|
+
- Provider and model routing is resolved per planning role or RAIL task from the signed installation capability snapshot.
|
|
40
|
+
- Every actual binding and reasoning configuration is recorded for audit and cost tracking.
|
|
41
41
|
|
|
42
42
|
## Execution Mode (Article XVII): WHO decides
|
|
43
43
|
- Controls whether human or system makes pipeline decisions
|
|
44
|
-
- Autonomous mode requires
|
|
44
|
+
- Autonomous mode requires the applicable planning or RAIL review gate to pass.
|
|
45
45
|
- Safety reversion (Article XVII): the orchestrator reverts autonomous to interactive on a stuck loop. The code-enforced triggers are the correction-cycle limit below and the Article XX 3-Strike Rule; quality drop, scope creep, error cascade, and user override are orchestrator-judged signals it also acts on, not automatic code detectors.
|
|
46
46
|
- Loop protection: two normal correction cycles, then top-tier AI adjudication. Escalate to a human only for an authority decision, unresolved scope or conflicting evidence.
|
|
47
|
-
- Git authority:
|
|
48
|
-
- Surface criteria:
|
|
47
|
+
- Git authority: RAIL execution cannot push, merge, publish or create a release. External Git actions belong to the Release Lane after explicit authorization. Outside an active Chati session, Git is unaffected.
|
|
48
|
+
- Surface criteria: external and irreversible Release Lane actions require explicit human authorization. Passing quality gates alone never authorizes publication.
|
|
49
49
|
|
|
50
50
|
## Execution Profile Governance (Article XVIII): DEPRECATED
|
|
51
51
|
- DEPRECATED: collapsed into Article XVII (Execution Mode). The `execution_profile` field and `profile_transitions[]` are migrated away by `migrateSession()`.
|
|
@@ -69,12 +69,12 @@ Extracted from `chati.dev/constitution.md` (25 Articles). Read the full constitu
|
|
|
69
69
|
|
|
70
70
|
## Agent Teams Governance (Article XXI)
|
|
71
71
|
- Feature-flagged (`agent_teams: true` in config.yaml), defaults to ON for Claude provider
|
|
72
|
-
-
|
|
72
|
+
- The only v2 agent team is the Planning Team (Detail+Architect+UX+QA-Planning). RAIL owns implementation and independent review.
|
|
73
73
|
- Only orchestrator can form/dissolve teams
|
|
74
74
|
- Intra-team communication via Team Mailbox (Article V amendment)
|
|
75
75
|
- Cross-team communication still orchestrator-mediated
|
|
76
76
|
- Team Quality Gate: all tasks complete + scores pass + mailbox clean
|
|
77
|
-
- Max 2 Team
|
|
77
|
+
- Max 2 Planning Team correction cycles before degraded dissolution
|
|
78
78
|
- Graceful fallback to sequential pipeline when unavailable (Gemini/Codex/flag off)
|
|
79
79
|
|
|
80
80
|
## Fault Vector Protocol (Article XXII)
|
|
@@ -4,20 +4,20 @@
|
|
|
4
4
|
| Agent | Minimum Score |
|
|
5
5
|
|-------|--------------|
|
|
6
6
|
| qa-planning | 95% |
|
|
7
|
-
| qa-implementation | 95% |
|
|
8
|
-
| qa-visual | 90% |
|
|
9
7
|
| Standard agents | 90% |
|
|
10
8
|
| Discovery agents (WU, brief) | 85% |
|
|
11
9
|
|
|
10
|
+
RAIL task reviews use the sealed task acceptance criteria and the review policy recorded in the handoff. They are not legacy `qa-implementation` or `qa-visual` pipeline agents.
|
|
11
|
+
|
|
12
12
|
## Review Range
|
|
13
13
|
Scores within 5 points below threshold trigger REVIEW (human confirmation required even in autonomous mode).
|
|
14
14
|
|
|
15
15
|
## 5 Pipeline Gates
|
|
16
16
|
1. **Planning Complete**: All DISCOVER + PLAN agents finished
|
|
17
17
|
2. **QA Planning**: QA-Planning agent validates plan coherence (95% threshold)
|
|
18
|
-
3. **
|
|
19
|
-
4. **
|
|
20
|
-
5. **
|
|
18
|
+
3. **RAIL Handoff**: Tasks seals a valid immutable dependency graph with execution bindings
|
|
19
|
+
4. **RAIL Review**: Every task has independent evidence-bound review and bounded rework is resolved
|
|
20
|
+
5. **Release Lane**: Completion evidence passes and explicit authorization exists before any external action
|
|
21
21
|
|
|
22
22
|
## Quality Dimensions
|
|
23
23
|
- **Traceability**: Every task traces to a PRD requirement
|
|
@@ -30,7 +30,7 @@ Scores within 5 points below threshold trigger REVIEW (human confirmation requir
|
|
|
30
30
|
- **G01-G08**: General blockers (process, communication, dependency)
|
|
31
31
|
|
|
32
32
|
## Fault Vector Protocol (Article XXII)
|
|
33
|
-
- **Root Layer Routing**: INTENT (requirement wrong) -> Brief/Detail | SPEC (spec wrong) -> Architect/Tasks | CODE (implementation wrong) ->
|
|
33
|
+
- **Root Layer Routing**: INTENT (requirement wrong) -> Brief/Detail | SPEC (spec wrong) -> Architect/Tasks | CODE (implementation wrong) -> bounded RAIL rework | DEFER (out of scope) -> Backlog
|
|
34
34
|
- **Evidence-Bound Verdicts**: ERROR/WARNING require tool evidence. Without evidence -> downgraded to SUGGESTION (non-blocking)
|
|
35
35
|
- **Decision Trail**: Known-bad states logged in session.yaml `decision_trail[]`. Agents read before iterating.
|
|
36
36
|
- **Echo Detection**: Similarity >= 0.85 with prior Decision Trail entry = ECHO. Escalate immediately, no more automated loops.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Chati.dev System Context
|
|
2
2
|
|
|
3
3
|
## Framework
|
|
4
|
-
- **Version**: 4.5.
|
|
4
|
+
- **Version**: 4.5.11
|
|
5
5
|
- **Agents**: Specialized discovery and planning agents feeding provider-neutral RAIL execution and a sealed release lane
|
|
6
6
|
- **Constitution**: 25 Articles + Preamble
|
|
7
7
|
- **Quality**: 5 pipeline gates + 3-tier verdicts + Fault Vector Protocol (Article XXII)
|
|
@@ -28,7 +28,7 @@ const PUSH_PATTERNS = [
|
|
|
28
28
|
];
|
|
29
29
|
|
|
30
30
|
// Pipeline phases during which a non-devops agent is actively driving work.
|
|
31
|
-
const ACTIVE_MODES = ['discover', 'plan', 'build', 'validate', 'deploy'];
|
|
31
|
+
const ACTIVE_MODES = ['discover', 'plan', 'rail', 'release', 'build', 'validate', 'deploy'];
|
|
32
32
|
|
|
33
33
|
function isPushCommand(command) {
|
|
34
34
|
return PUSH_PATTERNS.some((p) => p.test(command || ''));
|
|
@@ -38,8 +38,9 @@ function isPushCommand(command) {
|
|
|
38
38
|
* Block only when a push/PR command runs while a pipeline is active (mode is a
|
|
39
39
|
* pipeline phase) and the current driver is a non-devops agent.
|
|
40
40
|
*/
|
|
41
|
-
function shouldBlockPush(command, mode, agent) {
|
|
41
|
+
function shouldBlockPush(command, mode, agent, { v2 = false } = {}) {
|
|
42
42
|
if (!isPushCommand(command)) return false;
|
|
43
|
+
if (v2) return Boolean(mode && ACTIVE_MODES.includes(mode) && agent);
|
|
43
44
|
return Boolean(mode && ACTIVE_MODES.includes(mode) && agent && agent !== 'devops');
|
|
44
45
|
}
|
|
45
46
|
|
|
@@ -76,14 +77,17 @@ async function main() {
|
|
|
76
77
|
const projectDir = event.cwd || process.cwd();
|
|
77
78
|
const mode = readSessionField(projectDir, 'mode');
|
|
78
79
|
const agent = readSessionField(projectDir, 'current_agent');
|
|
80
|
+
const isV2 = existsSync(join(projectDir, '.chati', 'v2', 'installation.json'));
|
|
79
81
|
|
|
80
82
|
// Only enforce while a pipeline is active with a non-devops driver.
|
|
81
|
-
if (shouldBlockPush(command, mode, agent)) {
|
|
83
|
+
if (shouldBlockPush(command, mode, agent, { v2: isV2 })) {
|
|
82
84
|
process.stdout.write(JSON.stringify({
|
|
83
85
|
hookSpecificOutput: {
|
|
84
86
|
hookEventName: 'PreToolUse',
|
|
85
87
|
permissionDecision: 'deny',
|
|
86
|
-
permissionDecisionReason:
|
|
88
|
+
permissionDecisionReason: isV2
|
|
89
|
+
? `[Release Lane] RAIL execution cannot push, merge, or publish directly. Complete the evidence gate and obtain explicit authorization for the external action. Current phase: "${mode}".`
|
|
90
|
+
: `[Article IV] Only the devops agent may push to a remote or open a pull request during an active legacy pipeline. The current agent is "${agent}". Let the legacy pipeline reach devops, or run /chati exit to take manual control.`,
|
|
87
91
|
},
|
|
88
92
|
}));
|
|
89
93
|
return;
|
package/framework/manifest.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"createdAt": "2026-08-
|
|
2
|
+
"createdAt": "2026-08-27T14:40:11.488Z",
|
|
3
3
|
"files": {
|
|
4
4
|
"agents/build/dev.md": {
|
|
5
5
|
"hash": "13c2b3855c1f815154a2f4020b99fd8ee71e701b41783f5f26696222720a1466",
|
|
@@ -17,8 +17,8 @@
|
|
|
17
17
|
"type": "md"
|
|
18
18
|
},
|
|
19
19
|
"agents/discover/brownfield-wu.md": {
|
|
20
|
-
"hash": "
|
|
21
|
-
"size":
|
|
20
|
+
"hash": "fed8f14838b00e867bc932a3c4c212e38d7dc7c8f2e4443eb3242d19e6e3a286",
|
|
21
|
+
"size": 18172,
|
|
22
22
|
"type": "md"
|
|
23
23
|
},
|
|
24
24
|
"agents/discover/greenfield-wu.md": {
|
|
@@ -52,8 +52,8 @@
|
|
|
52
52
|
"type": "md"
|
|
53
53
|
},
|
|
54
54
|
"agents/plan/tasks.md": {
|
|
55
|
-
"hash": "
|
|
56
|
-
"size":
|
|
55
|
+
"hash": "a42a321ca2834c20364edb663619d340ac29317b236820135f07013cae9a4a82",
|
|
56
|
+
"size": 27960,
|
|
57
57
|
"type": "md"
|
|
58
58
|
},
|
|
59
59
|
"agents/plan/ux-brand-architect.md": {
|
|
@@ -97,7 +97,7 @@
|
|
|
97
97
|
"type": "md"
|
|
98
98
|
},
|
|
99
99
|
"config.yaml": {
|
|
100
|
-
"hash": "
|
|
100
|
+
"hash": "1b1103f17b9c2ba5820d8fae13c388bedf1bb3cceec93d3cd613b1b6e878bfce",
|
|
101
101
|
"size": 2671,
|
|
102
102
|
"type": "yaml"
|
|
103
103
|
},
|
|
@@ -107,8 +107,8 @@
|
|
|
107
107
|
"type": "md"
|
|
108
108
|
},
|
|
109
109
|
"context/governance.md": {
|
|
110
|
-
"hash": "
|
|
111
|
-
"size":
|
|
110
|
+
"hash": "88b3a3463fc14a26459f3202bf939dc954392642e4ac20830429dffd0f209f1f",
|
|
111
|
+
"size": 6225,
|
|
112
112
|
"type": "md"
|
|
113
113
|
},
|
|
114
114
|
"context/protocols.md": {
|
|
@@ -117,12 +117,12 @@
|
|
|
117
117
|
"type": "md"
|
|
118
118
|
},
|
|
119
119
|
"context/quality.md": {
|
|
120
|
-
"hash": "
|
|
121
|
-
"size":
|
|
120
|
+
"hash": "d6cb70d274425b4385a63bd67c217038de9c12992d973b16000b370442905022",
|
|
121
|
+
"size": 2247,
|
|
122
122
|
"type": "md"
|
|
123
123
|
},
|
|
124
124
|
"context/root.md": {
|
|
125
|
-
"hash": "
|
|
125
|
+
"hash": "adb70c8b7cac6934f2650dd683e5b08a01f6d81dc6f380b0b546e05cce4963d4",
|
|
126
126
|
"size": 1218,
|
|
127
127
|
"type": "md"
|
|
128
128
|
},
|
|
@@ -302,8 +302,8 @@
|
|
|
302
302
|
"type": "js"
|
|
303
303
|
},
|
|
304
304
|
"hooks/git-push-authority.js": {
|
|
305
|
-
"hash": "
|
|
306
|
-
"size":
|
|
305
|
+
"hash": "cb296129155464438b7f3f8834eb9d62674c34c0ef12ccba8769cd2938da97d8",
|
|
306
|
+
"size": 4666,
|
|
307
307
|
"type": "js"
|
|
308
308
|
},
|
|
309
309
|
"hooks/license-guard.js": {
|
|
@@ -472,8 +472,8 @@
|
|
|
472
472
|
"type": "md"
|
|
473
473
|
},
|
|
474
474
|
"orchestrator/chati.md": {
|
|
475
|
-
"hash": "
|
|
476
|
-
"size":
|
|
475
|
+
"hash": "fbba2ec83ded49329dc33f674accb391cc290cd1687048967a49fc70fb62f3af",
|
|
476
|
+
"size": 46016,
|
|
477
477
|
"type": "md"
|
|
478
478
|
},
|
|
479
479
|
"package.json": {
|
|
@@ -857,8 +857,8 @@
|
|
|
857
857
|
"type": "json"
|
|
858
858
|
},
|
|
859
859
|
"schemas/session.schema.json": {
|
|
860
|
-
"hash": "
|
|
861
|
-
"size":
|
|
860
|
+
"hash": "0c9218aeec82d4db591e87ffede20ea13eef6c549472f9471a1cee9ee637ba57",
|
|
861
|
+
"size": 19145,
|
|
862
862
|
"type": "json"
|
|
863
863
|
},
|
|
864
864
|
"schemas/task.schema.json": {
|
|
@@ -1352,5 +1352,5 @@
|
|
|
1352
1352
|
"type": "yaml"
|
|
1353
1353
|
}
|
|
1354
1354
|
},
|
|
1355
|
-
"version": "4.5.
|
|
1355
|
+
"version": "4.5.11"
|
|
1356
1356
|
}
|
package/framework/manifest.sig
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
Bj1mLU/kLfzNbNJmeY/BPjrL5bTt0MdOuSyfbjFTPniA8ev8TVO7Om+EQDxO0a6V0PHMYmVXf1GcoYWz8Q/VDw==
|
|
@@ -65,7 +65,12 @@ When the user invokes `/chati`, execute this sequence:
|
|
|
65
65
|
|
|
66
66
|
/chati providers:
|
|
67
67
|
→ Run: node .chati.dev/orchestrator/chati-router.js providers
|
|
68
|
-
→
|
|
68
|
+
→ For v2, display three distinct blocks from JSON:
|
|
69
|
+
1. `planning_agent_models`, discovery and planning routing only
|
|
70
|
+
2. `rail_execution_pool`, eligible provider and model capabilities for task execution and review
|
|
71
|
+
3. `release_lane`, explicit authorization policy
|
|
72
|
+
→ Never describe `dev`, `qa-implementation`, `qa-visual`, or `devops` as v2 pipeline agents
|
|
73
|
+
→ Never infer that a provider with no planning agent assignment is unavailable to RAIL
|
|
69
74
|
→ Stay locked
|
|
70
75
|
|
|
71
76
|
/chati resume:
|
|
@@ -75,7 +80,7 @@ When the user invokes `/chati`, execute this sequence:
|
|
|
75
80
|
→ Display:
|
|
76
81
|
/chati Start or resume session
|
|
77
82
|
/chati status Show project dashboard
|
|
78
|
-
/chati providers
|
|
83
|
+
/chati providers Show planning routing and the RAIL execution pool
|
|
79
84
|
/chati exit Save and exit session
|
|
80
85
|
/chati help Show this help
|
|
81
86
|
→ Stay locked
|
|
@@ -319,7 +324,7 @@ returned `next` state. Do not treat it as an error.
|
|
|
319
324
|
|
|
320
325
|
Planning phase agents (detail, architect, ux) run simultaneously.
|
|
321
326
|
|
|
322
|
-
**NOTE (Article XXI):**
|
|
327
|
+
**NOTE (Article XXI):** For v2, when `features.agent_teams: true` in config.yaml, the orchestrator MUST attempt `spawn_team` first for the Planning Team (detail, architect, ux, qa-planning). Only fall back to `spawn_parallel` if team spawning is unavailable or fails. After Tasks, RAIL owns execution and review. A Build Team is never formed in v2.
|
|
323
328
|
|
|
324
329
|
1. Display naturally what is happening using user-facing language. Examples (pick one that fits the phase): "Working on the planning phase now." / "Reviewing the architecture and UX in parallel." NEVER say "spawning parallel group", "spawn_parallel", or list internal agent names like "detail, architect, ux".
|
|
325
330
|
2. If `parallel_spawn_commands` is non-empty, execute every member's `command`
|
|
@@ -363,7 +368,7 @@ Parse the JSON response. Extract these values - you will need them in Step 2:
|
|
|
363
368
|
|
|
364
369
|
If `fallback_required: true` → fall back silently to the "Action: Parallel Spawn" section. Do NOT display error messages.
|
|
365
370
|
|
|
366
|
-
Display naturally what is happening
|
|
371
|
+
Display naturally what is happening: "Working on the planning, designing the requirements, architecture, and user experience together." Never expose internal agent names.
|
|
367
372
|
|
|
368
373
|
### MANDATORY Step 2: Spawn Teammates via Agent Tool
|
|
369
374
|
|
|
@@ -421,6 +426,7 @@ Agent tool call 4:
|
|
|
421
426
|
Write your handoff to artifacts/handoffs/qa-planning-handoff.md when done.]
|
|
422
427
|
```
|
|
423
428
|
|
|
429
|
+
<!-- CHATI_LEGACY_BUILD_START -->
|
|
424
430
|
**Legacy compatibility only, installations without `.chati/v2/installation.json`: For Build Team** (BUILD phase) - Wave-Based Pipeline:
|
|
425
431
|
|
|
426
432
|
For a v2 installation this section MUST NOT run. The `tasks` handoff returns
|
|
@@ -593,6 +599,8 @@ Before dissolving the team, verify both handoffs exist:
|
|
|
593
599
|
STOP and return.]
|
|
594
600
|
2. `artifacts/handoffs/qa-implementation-handoff.md` - should exist from Final QA Wave
|
|
595
601
|
|
|
602
|
+
<!-- CHATI_LEGACY_BUILD_END -->
|
|
603
|
+
|
|
596
604
|
### Step 3: Collect Results
|
|
597
605
|
|
|
598
606
|
When all Agent tool calls return:
|
|
@@ -700,9 +708,9 @@ The user is returning to an active session.
|
|
|
700
708
|
|
|
701
709
|
---
|
|
702
710
|
|
|
703
|
-
## Action: User Preview
|
|
711
|
+
## Action: User Preview (legacy runtime only)
|
|
704
712
|
|
|
705
|
-
|
|
713
|
+
This action is invalid when `.chati/v2/installation.json` exists. V2 preview evidence and external authorization belong to the RAIL Release Lane.
|
|
706
714
|
|
|
707
715
|
1. Present QA results to user
|
|
708
716
|
2. Options:
|
|
@@ -718,7 +726,7 @@ QA-Implementation passed. User must approve before deploy.
|
|
|
718
726
|
|
|
719
727
|
## Action: Complete
|
|
720
728
|
|
|
721
|
-
|
|
729
|
+
The RAIL Release Lane has completed or the legacy pipeline has finished. Present the final project summary. Run `orchestrate exit`.
|
|
722
730
|
Congratulate the user.
|
|
723
731
|
|
|
724
732
|
---
|
|
@@ -862,12 +870,12 @@ interactive (default):
|
|
|
862
870
|
→ Agent-driven guided mode. Agent leads, user validates.
|
|
863
871
|
→ All 8 universal protocols apply.
|
|
864
872
|
|
|
865
|
-
autonomous
|
|
873
|
+
autonomous:
|
|
866
874
|
→ Requires: most recent QA gate score >= 95% (Article XVII prerequisite).
|
|
867
875
|
→ If quality gate not met, inform user and suggest guided mode instead.
|
|
868
876
|
→ Agent executes without asking unless blocker encountered.
|
|
869
|
-
→ Primarily for
|
|
870
|
-
→
|
|
877
|
+
→ Primarily for dependency-ready RAIL tasks.
|
|
878
|
+
→ Independent review and rework gates always run regardless of mode.
|
|
871
879
|
→ Activated by user request or orchestrator suggestion post-Brief.
|
|
872
880
|
```
|
|
873
881
|
|
|
@@ -906,12 +914,13 @@ discover/plan phase:
|
|
|
906
914
|
BLOCK write to: everything else
|
|
907
915
|
ALLOW read: everything
|
|
908
916
|
|
|
909
|
-
|
|
917
|
+
RAIL execution/review:
|
|
910
918
|
ALLOW write to: everything
|
|
911
919
|
ALLOW read: everything
|
|
912
920
|
|
|
913
|
-
|
|
914
|
-
ALLOW
|
|
921
|
+
Release Lane:
|
|
922
|
+
ALLOW evidence preparation
|
|
923
|
+
REQUIRE explicit human authorization before external action
|
|
915
924
|
```
|
|
916
925
|
|
|
917
926
|
### Backward Transitions
|
|
@@ -923,10 +932,10 @@ If QA finds spec or architecture issues:
|
|
|
923
932
|
|
|
924
933
|
### Root Layer Routing (Article XXII)
|
|
925
934
|
|
|
926
|
-
When
|
|
935
|
+
When the independent RAIL reviewer classifies a fault:
|
|
927
936
|
- `INTENT` → escalate to user via deviation protocol (requirement is flawed)
|
|
928
937
|
- `SPEC` → backward transition to Architect, UX, or Tasks agent
|
|
929
|
-
- `CODE` →
|
|
938
|
+
- `CODE` → bounded RAIL rework using the task's sealed execution binding
|
|
930
939
|
- `DEFER` → add to session backlog, do not block approval
|
|
931
940
|
|
|
932
941
|
---
|
|
@@ -936,13 +945,13 @@ When QA-Implementation classifies a fault via the Fault Vector Protocol:
|
|
|
936
945
|
### EXCLUSIVE (only orchestrator)
|
|
937
946
|
- Route messages to agents
|
|
938
947
|
- Activate/deactivate agents
|
|
939
|
-
- Execute mode transitions (
|
|
948
|
+
- Execute mode transitions (discovery → planning → RAIL → Release Lane)
|
|
940
949
|
- Manage session lock (activate/deactivate)
|
|
941
950
|
- Handle deviations and re-routing
|
|
942
951
|
- Manage backlog items
|
|
943
952
|
- Spawn parallel terminals
|
|
944
953
|
- Decide execution mode (interactive vs autonomous)
|
|
945
|
-
- Form and dissolve
|
|
954
|
+
- Form and dissolve the Planning Team (Team Lead role, Article XXI)
|
|
946
955
|
- Monitor shared task list and mailbox during team execution
|
|
947
956
|
- Detect and respond to echo events within teams (Article XXII)
|
|
948
957
|
- Route corrections to correct layer via Root Layer Routing (Article XXII)
|
|
@@ -955,11 +964,11 @@ When QA-Implementation classifies a fault via the Fault Vector Protocol:
|
|
|
955
964
|
- Generate session digests
|
|
956
965
|
|
|
957
966
|
### BLOCKED (never do this - redirect instead)
|
|
958
|
-
- Write code or implementation files → route
|
|
967
|
+
- Write code or implementation files outside RAIL → route through the sealed RAIL task
|
|
959
968
|
- Write specification documents → route to detail
|
|
960
969
|
- Make architectural decisions → route to architect
|
|
961
|
-
- Write tests → route
|
|
962
|
-
- Deploy or configure infrastructure → route to
|
|
970
|
+
- Write tests outside RAIL → route through the sealed RAIL task
|
|
971
|
+
- Deploy or configure infrastructure directly → route to the Release Lane authorization gate
|
|
963
972
|
- Modify constitution or config files
|
|
964
973
|
|
|
965
974
|
---
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"description": "Normalized active_model recorded when /chati-update last completed. Article XXIV: when active_model differs from this, the orchestrator advises a harness re-audit. The advisory is driven entirely by this comparison; there is no separate flag."
|
|
21
21
|
},
|
|
22
22
|
"mode": {
|
|
23
|
-
"enum": ["discover", "plan", "build", "validate", "deploy", "completed"],
|
|
23
|
+
"enum": ["discover", "plan", "rail", "release", "build", "validate", "deploy", "completed"],
|
|
24
24
|
"default": "discover",
|
|
25
25
|
"description": "Flat pipeline macro-phase (mirrors project.state). Read by prism-engine and mode-governance hooks."
|
|
26
26
|
},
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
"properties": {
|
|
68
68
|
"name": { "type": "string", "description": "Project name" },
|
|
69
69
|
"type": { "enum": ["greenfield", "brownfield"], "description": "Project type" },
|
|
70
|
-
"state": { "enum": ["discover", "plan", "build", "validate", "deploy", "completed"], "description": "Current pipeline macro-phase" }
|
|
70
|
+
"state": { "enum": ["discover", "plan", "rail", "release", "build", "validate", "deploy", "completed"], "description": "Current pipeline macro-phase" }
|
|
71
71
|
}
|
|
72
72
|
},
|
|
73
73
|
"execution_mode": {
|
|
@@ -235,8 +235,8 @@
|
|
|
235
235
|
"required": ["timestamp", "from", "to", "trigger"],
|
|
236
236
|
"properties": {
|
|
237
237
|
"timestamp": { "type": "string", "format": "date-time" },
|
|
238
|
-
"from": { "enum": ["discover", "plan", "build", "validate", "deploy", "completed"] },
|
|
239
|
-
"to": { "enum": ["discover", "plan", "build", "validate", "deploy", "completed"] },
|
|
238
|
+
"from": { "enum": ["discover", "plan", "rail", "release", "build", "validate", "deploy", "completed"] },
|
|
239
|
+
"to": { "enum": ["discover", "plan", "rail", "release", "build", "validate", "deploy", "completed"] },
|
|
240
240
|
"trigger": { "type": "string", "description": "What caused the transition (agent completion, override, backward)" },
|
|
241
241
|
"type": { "enum": ["automatic", "backward", "override"], "description": "Transition classification" },
|
|
242
242
|
"skipped_agents": {
|
package/package.json
CHANGED
|
@@ -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) {
|
package/src/installer/core.js
CHANGED
|
@@ -560,16 +560,16 @@ Governance rules are in \`.chati.dev/constitution.md\`.
|
|
|
560
560
|
\`\`\`
|
|
561
561
|
DISCOVER: WU -> Brief
|
|
562
562
|
PLAN: [Planning Team: Detail + Architect + UX + QA-Planning] -> Phases -> Tasks
|
|
563
|
-
|
|
564
|
-
|
|
563
|
+
RAIL: Sealed task graph -> Execute -> Independent Review -> Bounded Rework
|
|
564
|
+
RELEASE: Evidence gate -> Explicit human authorization -> External action
|
|
565
565
|
\`\`\`
|
|
566
566
|
|
|
567
567
|
## Agents
|
|
568
568
|
- DISCOVER: .chati.dev/agents/discover/
|
|
569
569
|
- PLAN: .chati.dev/agents/plan/
|
|
570
|
-
- Quality: .chati.dev/agents/quality/
|
|
571
|
-
-
|
|
572
|
-
-
|
|
570
|
+
- Planning Quality: .chati.dev/agents/quality/qa-planning.md
|
|
571
|
+
- RAIL Runtime: .chati.dev/_cli/ and .chati/v2/rail/
|
|
572
|
+
- Release Lane: RAIL completion evidence plus explicit authorization
|
|
573
573
|
`;
|
|
574
574
|
}
|
|
575
575
|
|
|
@@ -62,11 +62,12 @@ export function generateSessionYaml(config) {
|
|
|
62
62
|
reasoning_escalations: [],
|
|
63
63
|
};
|
|
64
64
|
|
|
65
|
-
//
|
|
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',
|
|
70
|
+
'qa-planning',
|
|
70
71
|
];
|
|
71
72
|
|
|
72
73
|
for (const agent of agentNames) {
|
package/src/orchestrator/cli.js
CHANGED
|
@@ -53,7 +53,10 @@ import {
|
|
|
53
53
|
recordEvent, EventType, clearTimeline,
|
|
54
54
|
} from '../intelligence/timeline.js';
|
|
55
55
|
import { updateClaudeMd } from '../memory/magic-docs.js';
|
|
56
|
-
import {
|
|
56
|
+
import {
|
|
57
|
+
loadRuntimeInstallationV2, resolveRuntimeInvocationV2,
|
|
58
|
+
describeRuntimeInstallationV2, V2_PLANNING_AGENTS,
|
|
59
|
+
} from './runtime-installation-v2.js';
|
|
57
60
|
import { compilePlanningHandoff, PLANNING_V2_TASKS_PATH } from './planning-runtime.js';
|
|
58
61
|
import { persistRailHandoff } from './rail-runtime.js';
|
|
59
62
|
|
|
@@ -84,6 +87,16 @@ const RESUME_MESSAGES = {
|
|
|
84
87
|
fr: 'Session sauvee. Tapez /chati pour reprendre.',
|
|
85
88
|
};
|
|
86
89
|
|
|
90
|
+
function getRuntimeAgentPipeline(projectDir, session = null) {
|
|
91
|
+
if (!loadRuntimeInstallationV2(projectDir)) return AGENT_PIPELINE;
|
|
92
|
+
const projectType = session?.project_type || session?.project?.type || 'greenfield';
|
|
93
|
+
const selectedWu = projectType === 'brownfield' ? 'brownfield-wu' : 'greenfield-wu';
|
|
94
|
+
return AGENT_PIPELINE.filter(({ name }) =>
|
|
95
|
+
V2_PLANNING_AGENTS.includes(name)
|
|
96
|
+
&& (!name.endsWith('-wu') || name === selectedWu)
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
|
|
87
100
|
// ---------------------------------------------------------------------------
|
|
88
101
|
// QA-Visual scope helpers (Fase 6 — scope isolation)
|
|
89
102
|
//
|
|
@@ -516,8 +529,13 @@ function errorResult(message, code) {
|
|
|
516
529
|
*/
|
|
517
530
|
function sessionToPipelineState(session, projectDir) {
|
|
518
531
|
const agents = {};
|
|
532
|
+
const installationV2 = loadRuntimeInstallationV2(projectDir);
|
|
533
|
+
const allowedAgents = installationV2
|
|
534
|
+
? new Set(getRuntimeAgentPipeline(projectDir, session).map(({ name }) => name))
|
|
535
|
+
: null;
|
|
519
536
|
if (session.agents) {
|
|
520
537
|
for (const [name, data] of Object.entries(session.agents)) {
|
|
538
|
+
if (allowedAgents && !allowedAgents.has(name)) continue;
|
|
521
539
|
agents[name] = {
|
|
522
540
|
status: data.status || 'pending',
|
|
523
541
|
score: data.score ?? null,
|
|
@@ -536,7 +554,9 @@ function sessionToPipelineState(session, projectDir) {
|
|
|
536
554
|
startedAt: session.started_at || new Date().toISOString(),
|
|
537
555
|
completedAt: null,
|
|
538
556
|
agents,
|
|
539
|
-
completedAgents:
|
|
557
|
+
completedAgents: allowedAgents
|
|
558
|
+
? (session.completed_agents || []).filter((name) => allowedAgents.has(name))
|
|
559
|
+
: (session.completed_agents || []),
|
|
540
560
|
currentAgent: session.current_agent || null,
|
|
541
561
|
modeTransitions: session.mode_transitions || [],
|
|
542
562
|
history: [],
|
|
@@ -767,11 +787,12 @@ async function handleNext(projectDir) {
|
|
|
767
787
|
const activating = ['activate_interactive', 'spawn_routed_interactive', 'spawn_autonomous', 'spawn_team', 'spawn_parallel'];
|
|
768
788
|
if (activating.includes(result.action)) {
|
|
769
789
|
try {
|
|
790
|
+
const runtimePipeline = getRuntimeAgentPipeline(projectDir, result.session);
|
|
770
791
|
writeSessionLock(projectDir, result.agent, {
|
|
771
792
|
phase: result.phase || 'discover',
|
|
772
793
|
mode: result.session?.execution_mode || 'interactive',
|
|
773
794
|
position: result.pipeline_progress?.completedAgents?.length ?? 0,
|
|
774
|
-
total:
|
|
795
|
+
total: runtimePipeline.length,
|
|
775
796
|
progress: result.pipeline_progress?.progress ?? 0,
|
|
776
797
|
});
|
|
777
798
|
} catch { /* non-fatal */ }
|
|
@@ -798,6 +819,38 @@ async function _handleNextInner(projectDir) {
|
|
|
798
819
|
return errorResult(`Session invalid: ${validation.reason}`, 'SESSION_INVALID');
|
|
799
820
|
}
|
|
800
821
|
|
|
822
|
+
const installationV2 = loadRuntimeInstallationV2(projectDir);
|
|
823
|
+
const runtimePipeline = getRuntimeAgentPipeline(projectDir, session);
|
|
824
|
+
if (installationV2 && session.rail_handoff_id) {
|
|
825
|
+
const completedPlanning = runtimePipeline.length;
|
|
826
|
+
return {
|
|
827
|
+
action: 'rail_execute',
|
|
828
|
+
agent: 'rail',
|
|
829
|
+
phase: 'rail',
|
|
830
|
+
handoff_id: session.rail_handoff_id,
|
|
831
|
+
rail_state: session.rail_state || 'ready',
|
|
832
|
+
pipeline_progress: {
|
|
833
|
+
phase: 'rail', progress: 100, completedCount: completedPlanning,
|
|
834
|
+
totalAgents: completedPlanning, completedAgents: session.completed_agents || [],
|
|
835
|
+
currentAgent: 'rail', nextAgent: null,
|
|
836
|
+
},
|
|
837
|
+
session: {
|
|
838
|
+
language: session.language,
|
|
839
|
+
project_type: session.project_type || session.project?.type,
|
|
840
|
+
execution_mode: session.execution_mode,
|
|
841
|
+
},
|
|
842
|
+
status_summary: 'Planning is sealed. Resume execution through RAIL.',
|
|
843
|
+
};
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
const legacyExecutionAgents = new Set(['dev', 'qa-implementation', 'qa-visual', 'devops']);
|
|
847
|
+
if (installationV2 && legacyExecutionAgents.has(session.current_agent)) {
|
|
848
|
+
return errorResult(
|
|
849
|
+
'A v2 installation cannot resume a legacy Build/Deploy agent. Re-seal Tasks to create the RAIL handoff.',
|
|
850
|
+
'V2_RAIL_HANDOFF_REQUIRED',
|
|
851
|
+
);
|
|
852
|
+
}
|
|
853
|
+
|
|
801
854
|
const pipelineState = sessionToPipelineState(session, projectDir);
|
|
802
855
|
|
|
803
856
|
if (isPipelineComplete(pipelineState)) {
|
|
@@ -836,7 +889,7 @@ async function _handleNextInner(projectDir) {
|
|
|
836
889
|
handoff_status: { valid: true, missing: [], warnings: ['Resuming dev as Build Team'] },
|
|
837
890
|
gate_status: { canAdvance: true, reason: 'Build Team formation (Article XXI)' },
|
|
838
891
|
model_info: resolveAgentModel(agent, projectDir),
|
|
839
|
-
context_bracket: estimateContextBracket(completedAgents.length,
|
|
892
|
+
context_bracket: estimateContextBracket(completedAgents.length, runtimePipeline.length),
|
|
840
893
|
pipeline_progress: getPipelineProgress(pipelineState),
|
|
841
894
|
session: { language: session.language, project_type: session.project_type || session.project?.type, execution_mode: session.execution_mode, user_level: session.user_level || 'auto' },
|
|
842
895
|
status_summary: `Forming Build Team: dev + qa-implementation.`,
|
|
@@ -858,7 +911,7 @@ async function _handleNextInner(projectDir) {
|
|
|
858
911
|
handoff_status: { valid: true, missing: [], warnings: ['Resuming in-progress agent'] },
|
|
859
912
|
gate_status: { canAdvance: true, reason: 'Agent already in progress' },
|
|
860
913
|
model_info: modelInfo,
|
|
861
|
-
context_bracket: estimateContextBracket(completedAgents.length,
|
|
914
|
+
context_bracket: estimateContextBracket(completedAgents.length, runtimePipeline.length),
|
|
862
915
|
pipeline_progress: getPipelineProgress(pipelineState),
|
|
863
916
|
session: { language: session.language, project_type: session.project_type || session.project?.type, execution_mode: session.execution_mode, user_level: session.user_level || 'auto' },
|
|
864
917
|
status_summary: `Resuming ${agent} (in progress).`,
|
|
@@ -887,7 +940,7 @@ async function _handleNextInner(projectDir) {
|
|
|
887
940
|
handoff_status: { valid: true, missing: [], warnings: [] },
|
|
888
941
|
gate_status: { canAdvance: true, reason: 'First agent in pipeline' },
|
|
889
942
|
model_info: modelInfo,
|
|
890
|
-
context_bracket: estimateContextBracket(0,
|
|
943
|
+
context_bracket: estimateContextBracket(0, runtimePipeline.length),
|
|
891
944
|
pipeline_progress: getPipelineProgress(pipelineState),
|
|
892
945
|
session: { language: session.language, project_type: projectType, execution_mode: session.execution_mode, user_level: session.user_level || 'auto' },
|
|
893
946
|
status_summary: `Starting pipeline with ${firstAgent}.`,
|
|
@@ -927,6 +980,13 @@ async function _handleNextInner(projectDir) {
|
|
|
927
980
|
const agentDef = getAgentDefinition(nextAgent);
|
|
928
981
|
const isInteractive = INTERACTIVE_AGENTS.includes(nextAgent);
|
|
929
982
|
|
|
983
|
+
if (installationV2 && legacyExecutionAgents.has(nextAgent)) {
|
|
984
|
+
return errorResult(
|
|
985
|
+
'Planning reached the v2 execution boundary without a sealed RAIL handoff. Complete or re-run Tasks instead of entering Build/Deploy.',
|
|
986
|
+
'V2_RAIL_HANDOFF_REQUIRED',
|
|
987
|
+
);
|
|
988
|
+
}
|
|
989
|
+
|
|
930
990
|
// Validate handoff from previous agent
|
|
931
991
|
let handoffStatus;
|
|
932
992
|
try {
|
|
@@ -1011,7 +1071,7 @@ async function _handleNextInner(projectDir) {
|
|
|
1011
1071
|
recordEvent(projectDir, EventType.AGENT_ACTIVATED, nextAgent, { action, phase: agentDef?.phase });
|
|
1012
1072
|
|
|
1013
1073
|
const progress = getPipelineProgress(pipelineState);
|
|
1014
|
-
const bracket = estimateContextBracket(completedAgents.length,
|
|
1074
|
+
const bracket = estimateContextBracket(completedAgents.length, runtimePipeline.length);
|
|
1015
1075
|
|
|
1016
1076
|
const result = {
|
|
1017
1077
|
action,
|
|
@@ -1851,6 +1911,8 @@ async function handleAdvance(projectDir, args) {
|
|
|
1851
1911
|
// the handoff identifier and must enter the project-local RAIL lifecycle.
|
|
1852
1912
|
if (handoffData.rail_handoff) {
|
|
1853
1913
|
const railState = {
|
|
1914
|
+
mode: 'rail',
|
|
1915
|
+
project: { ...session.project, state: 'rail' },
|
|
1854
1916
|
current_agent: 'rail',
|
|
1855
1917
|
last_handoff: agent,
|
|
1856
1918
|
pipeline_position: (session.completed_agents || []).length + 1,
|
|
@@ -1860,12 +1922,28 @@ async function handleAdvance(projectDir, args) {
|
|
|
1860
1922
|
};
|
|
1861
1923
|
const saved = await updateSession(projectDir, railState);
|
|
1862
1924
|
if (saved && saved.saved === false) return errorResult(`Session update failed: ${saved.error}`, 'SESSION_WRITE_FAILED');
|
|
1925
|
+
const runtimePipeline = getRuntimeAgentPipeline(projectDir, session);
|
|
1926
|
+
try {
|
|
1927
|
+
writeSessionLock(projectDir, 'rail', {
|
|
1928
|
+
phase: 'rail', mode: session.execution_mode || 'interactive',
|
|
1929
|
+
position: runtimePipeline.length, total: runtimePipeline.length, progress: 100,
|
|
1930
|
+
});
|
|
1931
|
+
updateClaudeMd(projectDir, {
|
|
1932
|
+
currentAgent: 'rail',
|
|
1933
|
+
progress: { progress: 100, completedCount: runtimePipeline.length, totalAgents: runtimePipeline.length },
|
|
1934
|
+
});
|
|
1935
|
+
} catch { /* non-fatal: the canonical session state has already been persisted */ }
|
|
1863
1936
|
return {
|
|
1864
1937
|
advanced: true,
|
|
1865
1938
|
agent_completed: agent,
|
|
1866
1939
|
score,
|
|
1867
1940
|
rail_ready: true,
|
|
1868
1941
|
rail_handoff: handoffData.rail_handoff,
|
|
1942
|
+
pipeline_progress: {
|
|
1943
|
+
phase: 'rail', progress: 100, completedCount: runtimePipeline.length,
|
|
1944
|
+
totalAgents: runtimePipeline.length, completedAgents: [...(session.completed_agents || []), agent],
|
|
1945
|
+
currentAgent: 'rail', nextAgent: null,
|
|
1946
|
+
},
|
|
1869
1947
|
next: {
|
|
1870
1948
|
action: 'rail_execute',
|
|
1871
1949
|
handoff_id: handoffData.rail_handoff.handoff.handoff_id,
|
|
@@ -2277,8 +2355,10 @@ async function handleStatus(projectDir) {
|
|
|
2277
2355
|
}
|
|
2278
2356
|
|
|
2279
2357
|
// Build model map for all agents
|
|
2358
|
+
const runtimePipeline = getRuntimeAgentPipeline(projectDir, session);
|
|
2359
|
+
const runtimeAgentNames = new Set(runtimePipeline.map(({ name }) => name));
|
|
2280
2360
|
const agentModels = {};
|
|
2281
|
-
for (const agentDef of
|
|
2361
|
+
for (const agentDef of runtimePipeline) {
|
|
2282
2362
|
agentModels[agentDef.name] = resolveAgentModel(agentDef.name, projectDir);
|
|
2283
2363
|
}
|
|
2284
2364
|
|
|
@@ -2309,9 +2389,9 @@ async function handleStatus(projectDir) {
|
|
|
2309
2389
|
handoff_history: handoffHistory,
|
|
2310
2390
|
deviation_count: (session.deviations || []).length,
|
|
2311
2391
|
backlog: session.backlog || [],
|
|
2312
|
-
agents: session.agents || {},
|
|
2392
|
+
agents: Object.fromEntries(Object.entries(session.agents || {}).filter(([name]) => runtimeAgentNames.has(name))),
|
|
2313
2393
|
agent_models: agentModels,
|
|
2314
|
-
context_bracket: estimateContextBracket((session.completed_agents || []).length,
|
|
2394
|
+
context_bracket: estimateContextBracket((session.completed_agents || []).length, runtimePipeline.length),
|
|
2315
2395
|
context: {
|
|
2316
2396
|
model: activeModel,
|
|
2317
2397
|
provider: activeProvider,
|
|
@@ -2434,15 +2514,25 @@ async function handleExit(projectDir, args) {
|
|
|
2434
2514
|
}
|
|
2435
2515
|
|
|
2436
2516
|
async function handleProviders(projectDir) {
|
|
2517
|
+
const artifact = loadRuntimeInstallationV2(projectDir);
|
|
2518
|
+
if (artifact) {
|
|
2519
|
+
const { session } = loadSession(projectDir);
|
|
2520
|
+
const planningAgentModels = {};
|
|
2521
|
+
for (const { name } of getRuntimeAgentPipeline(projectDir, session)) {
|
|
2522
|
+
planningAgentModels[name] = resolveAgentModel(name, projectDir);
|
|
2523
|
+
}
|
|
2524
|
+
return {
|
|
2525
|
+
...describeRuntimeInstallationV2(artifact),
|
|
2526
|
+
planning_agent_models: planningAgentModels,
|
|
2527
|
+
};
|
|
2528
|
+
}
|
|
2529
|
+
|
|
2437
2530
|
const agentModels = {};
|
|
2438
2531
|
for (const agentDef of AGENT_PIPELINE) {
|
|
2439
2532
|
agentModels[agentDef.name] = resolveAgentModel(agentDef.name, projectDir);
|
|
2440
2533
|
}
|
|
2441
2534
|
|
|
2442
|
-
const
|
|
2443
|
-
const enabledProviders = artifact
|
|
2444
|
-
? artifact.installation.enabled_providers.map(({ provider_id, harness_id }) => ({ provider_id, harness_id }))
|
|
2445
|
-
: [...new Set(Object.values(agentModels).map(({ provider }) => provider).filter(Boolean))].map((harness_id) => ({ harness_id }));
|
|
2535
|
+
const enabledProviders = [...new Set(Object.values(agentModels).map(({ provider }) => provider).filter(Boolean))].map((harness_id) => ({ harness_id }));
|
|
2446
2536
|
|
|
2447
2537
|
return {
|
|
2448
2538
|
enabled_providers: enabledProviders,
|
|
@@ -10,6 +10,44 @@ const AGENT_ACTIONS = Object.freeze({
|
|
|
10
10
|
devops: 'build',
|
|
11
11
|
});
|
|
12
12
|
|
|
13
|
+
export const V2_PLANNING_AGENTS = Object.freeze([
|
|
14
|
+
'greenfield-wu', 'brownfield-wu', 'brief',
|
|
15
|
+
'detail', 'architect', 'ux', 'qa-planning', 'phases', 'tasks',
|
|
16
|
+
]);
|
|
17
|
+
|
|
18
|
+
const RAIL_ACTIONS = new Set(['build', 'review']);
|
|
19
|
+
|
|
20
|
+
export function describeRuntimeInstallationV2(artifact) {
|
|
21
|
+
const railExecutionPool = artifact.installation.enabled_providers.map((binding) => {
|
|
22
|
+
const capabilities = binding.allowed_models.flatMap((modelId) => {
|
|
23
|
+
const model = artifact.capability_snapshot.models.find((candidate) =>
|
|
24
|
+
candidate.provider_id === binding.provider_id && candidate.model_id === modelId
|
|
25
|
+
);
|
|
26
|
+
if (!model) return [];
|
|
27
|
+
const actions = model.actions.filter((action) => RAIL_ACTIONS.has(action));
|
|
28
|
+
if (actions.length === 0) return [];
|
|
29
|
+
return [{ model_id: modelId, actions, tier: model.tier || null }];
|
|
30
|
+
});
|
|
31
|
+
return {
|
|
32
|
+
provider_id: binding.provider_id,
|
|
33
|
+
harness_id: binding.harness_id,
|
|
34
|
+
models: capabilities.map(({ model_id }) => model_id),
|
|
35
|
+
capabilities,
|
|
36
|
+
};
|
|
37
|
+
}).filter(({ models }) => models.length > 0);
|
|
38
|
+
|
|
39
|
+
return Object.freeze({
|
|
40
|
+
architecture: 'chati-v2-rail',
|
|
41
|
+
enabled_providers: artifact.installation.enabled_providers.map(({ provider_id, harness_id }) => ({ provider_id, harness_id })),
|
|
42
|
+
rail_execution_pool: railExecutionPool,
|
|
43
|
+
release_lane: {
|
|
44
|
+
authority: 'explicit-human-authorization',
|
|
45
|
+
execution_authority: 'rail',
|
|
46
|
+
legacy_devops_agent: false,
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
13
51
|
export function loadRuntimeInstallationV2(projectDir, { clock = () => new Date() } = {}) {
|
|
14
52
|
const path = join(projectDir, INSTALLATION_ARTIFACT_PATH);
|
|
15
53
|
if (!existsSync(path)) return null;
|
|
@@ -973,7 +973,7 @@ export function validateSession(projectDir) {
|
|
|
973
973
|
}
|
|
974
974
|
|
|
975
975
|
// Validate mode
|
|
976
|
-
const validModes = ['discover', 'plan', 'build', 'validate', 'deploy', 'completed'];
|
|
976
|
+
const validModes = ['discover', 'plan', 'rail', 'release', 'build', 'validate', 'deploy', 'completed'];
|
|
977
977
|
if (!validModes.includes(session.mode)) {
|
|
978
978
|
return {
|
|
979
979
|
exists: true,
|