peaks-cli 1.3.1 → 1.3.3

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 (111) hide show
  1. package/README.md +6 -2
  2. package/bin/peaks.js +0 -0
  3. package/dist/src/cli/commands/core-artifact-commands.js +49 -11
  4. package/dist/src/cli/commands/gate-commands.js +28 -19
  5. package/dist/src/cli/commands/hook-handle.d.ts +17 -0
  6. package/dist/src/cli/commands/hook-handle.js +111 -0
  7. package/dist/src/cli/commands/hooks-commands.js +72 -21
  8. package/dist/src/cli/commands/progress-commands.js +9 -2
  9. package/dist/src/cli/commands/progress-start-spawn.js +30 -4
  10. package/dist/src/cli/commands/slice-commands.js +4 -2
  11. package/dist/src/cli/commands/statusline-commands.js +75 -17
  12. package/dist/src/cli/commands/sub-agent-commands.d.ts +5 -0
  13. package/dist/src/cli/commands/sub-agent-commands.js +488 -0
  14. package/dist/src/cli/commands/sub-agent-dispatch-guard.d.ts +55 -0
  15. package/dist/src/cli/commands/sub-agent-dispatch-guard.js +57 -0
  16. package/dist/src/cli/commands/workspace-commands.js +70 -14
  17. package/dist/src/cli/program.js +9 -0
  18. package/dist/src/hooks/pre-tool-use-sub-agent.d.ts +28 -0
  19. package/dist/src/hooks/pre-tool-use-sub-agent.js +105 -0
  20. package/dist/src/services/artifacts/artifact-prerequisites.d.ts +12 -0
  21. package/dist/src/services/artifacts/artifact-prerequisites.js +39 -8
  22. package/dist/src/services/artifacts/request-artifact-service.js +116 -76
  23. package/dist/src/services/config/config-types.d.ts +1 -1
  24. package/dist/src/services/context/artifact-meta.d.ts +72 -0
  25. package/dist/src/services/context/artifact-meta.js +105 -0
  26. package/dist/src/services/context/context-guard.d.ts +49 -0
  27. package/dist/src/services/context/context-guard.js +91 -0
  28. package/dist/src/services/context/dispatch-context-guard.d.ts +27 -0
  29. package/dist/src/services/context/dispatch-context-guard.js +192 -0
  30. package/dist/src/services/context/headroom-client.d.ts +34 -0
  31. package/dist/src/services/context/headroom-client.js +117 -0
  32. package/dist/src/services/context/shared-channel.d.ts +92 -0
  33. package/dist/src/services/context/shared-channel.js +285 -0
  34. package/dist/src/services/context/threshold.d.ts +35 -0
  35. package/dist/src/services/context/threshold.js +76 -0
  36. package/dist/src/services/dispatch/batch-counter.d.ts +27 -0
  37. package/dist/src/services/dispatch/batch-counter.js +85 -0
  38. package/dist/src/services/dispatch/dispatch-record-writer.d.ts +93 -0
  39. package/dist/src/services/dispatch/dispatch-record-writer.js +261 -0
  40. package/dist/src/services/dispatch/heartbeat-truncator.d.ts +26 -0
  41. package/dist/src/services/dispatch/heartbeat-truncator.js +13 -0
  42. package/dist/src/services/dispatch/leak-detector.d.ts +11 -0
  43. package/dist/src/services/dispatch/leak-detector.js +72 -0
  44. package/dist/src/services/dispatch/sub-agent-dispatcher.d.ts +127 -0
  45. package/dist/src/services/dispatch/sub-agent-dispatcher.js +98 -0
  46. package/dist/src/services/doctor/doctor-service.d.ts +62 -0
  47. package/dist/src/services/doctor/doctor-service.js +276 -1
  48. package/dist/src/services/ide/adapters/claude-code-adapter.d.ts +18 -0
  49. package/dist/src/services/ide/adapters/claude-code-adapter.js +53 -0
  50. package/dist/src/services/ide/adapters/trae-adapter.d.ts +34 -0
  51. package/dist/src/services/ide/adapters/trae-adapter.js +70 -0
  52. package/dist/src/services/ide/hook-protocol.d.ts +44 -0
  53. package/dist/src/services/ide/hook-protocol.js +71 -0
  54. package/dist/src/services/ide/hook-translator.d.ts +72 -0
  55. package/dist/src/services/ide/hook-translator.js +128 -0
  56. package/dist/src/services/ide/ide-detector.d.ts +10 -0
  57. package/dist/src/services/ide/ide-detector.js +19 -0
  58. package/dist/src/services/ide/ide-registry.d.ts +14 -0
  59. package/dist/src/services/ide/ide-registry.js +45 -0
  60. package/dist/src/services/ide/ide-types.d.ts +120 -0
  61. package/dist/src/services/ide/ide-types.js +2 -0
  62. package/dist/src/services/ide/shared/atomic-json.d.ts +15 -0
  63. package/dist/src/services/ide/shared/atomic-json.js +58 -0
  64. package/dist/src/services/ide/shared/safe-path.d.ts +11 -0
  65. package/dist/src/services/ide/shared/safe-path.js +29 -0
  66. package/dist/src/services/progress/progress-service.d.ts +1 -1
  67. package/dist/src/services/progress/progress-service.js +18 -14
  68. package/dist/src/services/security/safe-settings-path.d.ts +12 -0
  69. package/dist/src/services/security/safe-settings-path.js +104 -0
  70. package/dist/src/services/session/session-manager.d.ts +22 -1
  71. package/dist/src/services/session/session-manager.js +137 -28
  72. package/dist/src/services/signal/cancel-handler.d.ts +14 -0
  73. package/dist/src/services/signal/cancel-handler.js +76 -0
  74. package/dist/src/services/skill/resume-detector.d.ts +54 -0
  75. package/dist/src/services/skill/resume-detector.js +334 -0
  76. package/dist/src/services/skill/skill-scheduler.d.ts +40 -0
  77. package/dist/src/services/skill/skill-scheduler.js +53 -0
  78. package/dist/src/services/skills/hooks-settings-service.d.ts +47 -29
  79. package/dist/src/services/skills/hooks-settings-service.js +190 -144
  80. package/dist/src/services/skills/statusline-settings-service.d.ts +33 -6
  81. package/dist/src/services/skills/statusline-settings-service.js +31 -34
  82. package/dist/src/services/slice/slice-archive-service.d.ts +20 -0
  83. package/dist/src/services/slice/slice-archive-service.js +111 -0
  84. package/dist/src/services/slice/slice-check-service.js +20 -1
  85. package/dist/src/services/slice/slice-check-types.d.ts +9 -0
  86. package/dist/src/services/solo/batch-heartbeat-poller.d.ts +51 -0
  87. package/dist/src/services/solo/batch-heartbeat-poller.js +88 -0
  88. package/dist/src/services/solo/status-line-renderer.d.ts +34 -0
  89. package/dist/src/services/solo/status-line-renderer.js +55 -0
  90. package/dist/src/services/workspace/migrate-service.js +124 -2
  91. package/dist/src/services/workspace/migrate-types.d.ts +50 -7
  92. package/dist/src/services/workspace/reconcile-service.d.ts +69 -0
  93. package/dist/src/services/workspace/reconcile-service.js +267 -48
  94. package/dist/src/services/workspace/reconcile-types.d.ts +37 -0
  95. package/dist/src/services/workspace/workspace-service.js +29 -62
  96. package/dist/src/shared/version.d.ts +1 -1
  97. package/dist/src/shared/version.js +1 -1
  98. package/package.json +2 -1
  99. package/schemas/doctor-report.schema.json +2 -2
  100. package/skills/peaks-ide/SKILL.md +159 -0
  101. package/skills/peaks-qa/SKILL.md +58 -1
  102. package/skills/peaks-qa/references/qa-fanout-contract.md +150 -0
  103. package/skills/peaks-rd/SKILL.md +52 -9
  104. package/skills/peaks-solo/SKILL.md +83 -20
  105. package/skills/peaks-solo/references/context-governance.md +144 -0
  106. package/skills/peaks-solo/references/headroom-integration.md +107 -0
  107. package/skills/peaks-solo/references/runbook.md +3 -3
  108. package/skills/peaks-solo/references/sub-agent-dispatch.md +218 -0
  109. package/skills/peaks-solo/references/swarm-dispatch-contract.md +3 -37
  110. package/skills/peaks-txt/SKILL.md +19 -0
  111. package/skills/peaks-ui/SKILL.md +28 -1
@@ -0,0 +1,218 @@
1
+ # sub-agent-dispatch.md — peaks sub-agent dispatch orchestrator contract
2
+
3
+ > **Slice**: 2026-06-07-sub-agent-dispatch-decouple (G3 + G6)
4
+ > **Audience**: SKILL.md authors and LLM readers of peaks-solo / peaks-rd / peaks-qa
5
+ > **Status**: stable
6
+
7
+ This reference is the orchestrator-side contract for sub-agent dispatch.
8
+ It explains why the peaks family uses `peaks sub-agent dispatch <role>` as
9
+ the canonical primitive, how the dispatch envelope flows back to the LLM,
10
+ and how the new G6 heartbeat channel keeps the user informed during the
11
+ batch-sync wait. Read this before writing or extending any peaks-*
12
+ SKILL.md that dispatches sub-agents.
13
+
14
+ ## Why a CLI primitive (skill-first / CLI-auxiliary)
15
+
16
+ The peaks skill family is the **product**. The CLI is a thin atomic
17
+ the skills compose. For sub-agent dispatch the relationship is:
18
+
19
+ | Surface | Who owns | What it does | Who calls it |
20
+ |---|---|---|---|
21
+ | SKILL.md (主面) | peaks-solo, peaks-rd, peaks-qa | Tells the LLM when and why to dispatch a sub-agent; what prompt to pass; what artifacts to expect back | LLM (during normal Solo / RD / QA flow) |
22
+ | CLI (副 / 原子) | `peaks sub-agent dispatch` | Validates the role, looks up the current IDE's `subAgentDispatcher`, returns a per-IDE tool-call descriptor + writes a dispatch record | LLM (read from the SKILL.md) |
23
+ | Dispatcher 抽象 (per-IDE) | `src/services/dispatch/sub-agent-dispatcher.ts` | Encapsulates the IDE-private tool name (claude-code: `Task`, trae: UNVERIFIED placeholder) and arg shape | CLI (called by the CLI) |
24
+
25
+ This is the **inverse** of the prior shape: SKILL.md used to hardcode
26
+ `Task(subagent_type="general-purpose", ...)`, which made peaks-cli
27
+ depend on Claude Code's specific tool name. Adding a new IDE meant
28
+ editing every SKILL.md that mentioned sub-agents. With the new shape,
29
+ the only per-IDE thing in the dispatch chain is the dispatcher — SKILL.md
30
+ stays IDE-agnostic.
31
+
32
+ > **Red line**: do not invoke `peaks sub-agent dispatch` from your own
33
+ > shell. The CLI is a primitive the LLM composes. Users do not need it.
34
+
35
+ ## Dispatch contract
36
+
37
+ **Command**:
38
+
39
+ ```
40
+ peaks sub-agent dispatch <role> --prompt <text> [--request-id <rid>] [--session-id <sid>] [--project <repo>] [--batch-id <uuid>] --json
41
+ ```
42
+
43
+ **Envelope** (AC-8):
44
+
45
+ ```json
46
+ {
47
+ "ok": true,
48
+ "command": "sub-agent.dispatch",
49
+ "data": {
50
+ "role": "rd",
51
+ "ide": "claude-code",
52
+ "prompt": "<complete prompt the LLM should pass through>",
53
+ "toolCall": {
54
+ "name": "Task",
55
+ "args": {
56
+ "subagent_type": "general-purpose",
57
+ "description": "rd for rid=002-2026-06-07-...",
58
+ "prompt": "..."
59
+ }
60
+ },
61
+ "dispatchRecordPath": ".peaks/_sub_agents/2026-06-06-session-5b1095/dispatch-002-2026-06-07-...-...json",
62
+ "batchId": "<uuid>",
63
+ "dispatchedInBatch": 3
64
+ },
65
+ "warnings": [],
66
+ "nextActions": [
67
+ "Tool call is dry-run; LLM must execute the tool to actually dispatch the sub-agent.",
68
+ "After dispatching, the sub-agent should call `peaks sub-agent heartbeat --record <dispatchRecordPath>` periodically."
69
+ ]
70
+ }
71
+ ```
72
+
73
+ **LLM side**: read `data.toolCall` (the `{name, args}` descriptor), look
74
+ up the tool by `name` in the current environment, and invoke it with
75
+ `args`. The CLI does not spawn anything. The IDE (Claude Code, Trae,
76
+ etc.) is the one that actually runs the sub-agent.
77
+
78
+ **Side effect**: the CLI writes a dispatch record to
79
+ `.peaks/_sub_agents/<sid>/dispatch-<rid>-<ts>.json` (R-2 path-guarded).
80
+ The record starts with `heartbeats: []`, `lastBeatAt: null`, `status: 'queued'`
81
+ and is updated by the heartbeat flow (§G6 below).
82
+
83
+ ## Role model
84
+
85
+ `SubAgentRole` is a free-form string. The CLI **does not** enforce a
86
+ hard whitelist. Recommended roles:
87
+
88
+ - Top-level: `rd` | `qa` | `ui` | `txt` | `general-purpose`
89
+ - QA sub-roles: `qa-business` | `qa-perf` | `qa-security`
90
+ - Business sub-divisions: `qa-business-api` | `qa-business-frontend` |
91
+ `qa-business-regression` | ... (≤ 2 levels deep per RL-4)
92
+ - Promotable Worker (architecture预留, slice #009 不实际提升): `prd-business` |
93
+ `prd-technical` | `prd-ux` | `ui-visual` | `ui-flow` | `ui-component`
94
+
95
+ The only hard validation is: non-empty, ≤ 256 chars, no control
96
+ characters. Any other string is a convention, not a contract.
97
+
98
+ ## Per-IDE dispatchers (G1)
99
+
100
+ | IDE | Tool name | Args shape | Status |
101
+ |---|---|---|---|
102
+ | `claude-code` | `Task` | `{subagent_type: "general-purpose", description, prompt}` | verified |
103
+ | `trae` | `Task` | byte-identical to claude-code by design | UNVERIFIED — pending real Trae dogfood |
104
+ | `null` (no IDE detected) | — | throws `IDE_NOT_SUPPORTED` | fallback |
105
+
106
+ Adding a new IDE means:
107
+
108
+ 1. Add a new adapter to `src/services/ide/adapters/<id>-adapter.ts`.
109
+ 2. Fill in `subAgentDispatcher: <yourDispatcher>` (implements
110
+ `SubAgentDispatcher`).
111
+ 3. Register the adapter in `ide-registry.ts`.
112
+
113
+ SKILL.md and existing dispatcher implementations are untouched.
114
+
115
+ ## G6 — heartbeat + dynamic progress (RL-13..RL-16)
116
+
117
+ Sub-agents run for 30 s to 2 min. During that wait, the LLM platform
118
+ provides no progress signal to the Dispatcher. Without a heartbeat
119
+ channel, the user sees a frozen terminal and reasonably assumes the
120
+ system is dead. G6 is the rule that says: **no**.
121
+
122
+ ### The three-layer contract
123
+
124
+ | Layer | Who | What | Cadence |
125
+ |---|---|---|---|
126
+ | **Sub-agent writes** | The sub-agent itself | Calls `peaks sub-agent heartbeat --record <dispatchRecordPath> --status <state> --progress <pct> --note "<text>"` to append a heartbeat | 30 s default; SKILL.md can override via `heartbeatIntervalSec: 15` |
127
+ | **Dispatcher reads** | peaks-solo main loop, during the batch-sync wait | In-process async poller (`BatchHeartbeatPoller`) reads `heartbeats[]` + `lastBeatAt` from each record, emits a single-line status per G6.5 | 10 s (offset from 30 s to avoid jitter) |
128
+ | **User / CLI reads** | Anyone, anytime | `peaks sub-agent list --session-id <sid> --json` (G5 RL-10, future slice) | manual |
129
+
130
+ ### Sub-agent prompt template (heartbeat-aware)
131
+
132
+ Every sub-agent prompt dispatched via `peaks sub-agent dispatch` should
133
+ include the heartbeat instruction so the LLM knows when and how to
134
+ report progress. The recommended paragraph (auto-generated by the CLI
135
+ and the SKILL.md heart of each Dispatcher) is:
136
+
137
+ ```
138
+ While running, call `peaks sub-agent heartbeat --record <dispatchRecordPath>
139
+ --status <state> --progress <pct> --note "<text>"` at least every 30 seconds
140
+ (the Dispatcher expects 30s cadence). On completion call
141
+ `--status done --progress 100 --note "completed"`. On failure,
142
+ `--status failed`. Do not skip heartbeats; the parent Dispatcher uses them
143
+ to keep the user informed during the wait.
144
+ ```
145
+
146
+ `heartbeatIntervalSec` is overridable per SKILL.md (5..600). Default 30.
147
+
148
+ ### Status line shape (G6.5)
149
+
150
+ Single line, 80-120 chars:
151
+
152
+ ```
153
+ [peaks-solo] swarm 3/3 running | rd-planning 45% (12s ago) | qa-test-cases 30% (5s ago) | ui-design 20% (2s ago)
154
+ [peaks-solo] swarm 3/3 running | rd-planning 70% (8s ago) | qa-test-cases 50% (3s ago) | ui-design 30% (6s ago)
155
+ ...
156
+ [peaks-solo] swarm 3/3 done
157
+ ```
158
+
159
+ If a sub-agent has not written a heartbeat in 5 minutes, the poller
160
+ appends `⚠ stale` to that sub-agent's segment and marks
161
+ `status: 'stale'` on the record. **It does not cancel, kill, or send
162
+ SIGTERM** (RL-15). Stale is a user-visible warning, not a failure.
163
+ The user decides.
164
+
165
+ ### Truncation (RL-16)
166
+
167
+ `heartbeats[]` is append-only for audit, but capped at 100 entries.
168
+ Past 100, the oldest are dropped and `truncated: true` is set. The
169
+ record JSON can otherwise balloon to MB on long-running sub-agents.
170
+ 100 is the LLM-friendly limit — stale heartbeats are not informative
171
+ once the poller has read them.
172
+
173
+ ### Acceptance criteria covered
174
+
175
+ - AC-33 `peaks sub-agent heartbeat` CLI primitive (implemented)
176
+ - AC-34 Dispatch record schema upgrade (`heartbeats[]` + `lastBeatAt` + `status` aggregate, backward-compat defaults)
177
+ - AC-35 peaks-solo main loop batch-sync poller (10 s cadence, 5 min stale)
178
+ - AC-36 SKILL.md fan-out sections include heartbeat instruction
179
+ - AC-37 G6 E2E dogfood (3 heartbeats, 101 → truncated, stale simulation)
180
+
181
+ ## Acceptance criteria (overall G1-G6)
182
+
183
+ - AC-1..AC-5: dispatcher interface + 3 adapter impls (`claudeCodeSubAgentDispatcher`, `traeSubAgentDispatcher`, `nullSubAgentDispatcher`)
184
+ - AC-6: dispatcher unit tests
185
+ - AC-7..AC-9: dispatch CLI signature + envelope + steps
186
+ - AC-10: dispatch CLI unit tests
187
+ - AC-11 / AC-11b / AC-11c: E2E dogfood on the live repo
188
+ - AC-12: `peaks --help` byte-level delta is `+1` line (`sub-agent <cmd>`)
189
+ - AC-13..AC-19: SKILL.md fan-out rewrites (peaks-solo 5 spots, peaks-rd 2, peaks-qa 3-way, peaks-ui 1; this reference is the canonical contract)
190
+ - AC-22..AC-24: R-2 path guard, prompt size limit, atomic write
191
+ - AC-25..AC-32: G5 resource lifecycle (RL-1 batch counter, dispatch record schema, reducer dispose, slice archive, cancel dispose)
192
+ - AC-33..AC-37: G6 heartbeat CLI, schema, poller, status line, E2E
193
+
194
+ ## How to apply
195
+
196
+ When writing a SKILL.md that fans out sub-agents:
197
+
198
+ 1. Use `peaks sub-agent dispatch <role>` (never `Task(...)`).
199
+ 2. Issue all dispatches in a single message; the LLM will fire all
200
+ returned toolCalls in parallel.
201
+ 3. Pass `--request-id` and `--session-id` (or omit and let the CLI
202
+ resolve the active session).
203
+ 4. The sub-agent prompt **must** include the heartbeat instruction
204
+ (30 s cadence; override via `heartbeatIntervalSec` if needed).
205
+ 5. After the fan-out returns, the Dispatcher reducer reads the
206
+ dispatch record + the artifacts the sub-agents wrote, marks
207
+ `disposed: true` on each record, and advances the state machine.
208
+ 6. The poller handles the 5-min stale case as a warning, never as a
209
+ failure. The user is the one who decides to cancel.
210
+
211
+ ## Cross-reference
212
+
213
+ - PRD #009 G1-G6 (this slice's source of truth)
214
+ - RD request #009 in-scope files (implementation contract)
215
+ - `.peaks/memory/sub-agent-resource-lifecycle-red-line.md` (G5 red line)
216
+ - `.peaks/memory/sub-agent-heartbeat-progress-red-line.md` (G6 red line)
217
+ - `skills/peaks-solo/references/swarm-dispatch-contract.md` (predecessor contract)
218
+ - `skills/peaks-qa/references/qa-fanout-contract.md` (QA-specific fan-out)
@@ -6,41 +6,7 @@
6
6
 
7
7
  The previous "Swarm" used `Skill(skill="peaks-rd")` calls. That is **single-stack and blocking** — there is no concurrency. Three sequential `Skill` calls run in order on the same main loop, not in parallel. The "parallel Agent calls" wording in the old SKILL.md was a v1.x illusion.
8
8
 
9
- This contract moves the Swarm to the `Task` tool with `subagent_type="general-purpose"`, which is the only Claude Code mechanism that gives real concurrent fan-out. Solo launches all sub-agents in a single message; the platform schedules them concurrently.
10
-
11
- ## 2. When to swarm (decision)
12
-
13
- Solo runs the swarm only after `peaks request show <rid> --role prd` is in state `confirmed-by-user` or `handed-off`. Before that, there is nothing for the sub-agents to derive from.
14
-
15
- Solo computes the **swarm plan** from three signals (see "Swarm gate" in the main SKILL.md):
16
-
17
- 1. `--type` from `peaks request init` (already on the PRD artefact).
18
- 2. `frontendOnly` from `.peaks/<session-id>/rd/project-scan.md` `## Project mode`.
19
- 3. Frontend keyword scan over the PRD body.
20
-
21
- The plan is written to `.peaks/<session-id>/sc/swarm-plan.json` before any Task call, so SC and TXT can audit what was launched. Solo updates `.peaks/.active-skill.json` to `gate=swarm-fan-out` at this point.
22
-
23
- | `--type` | Frontend signal | Plan |
24
- |---|---|---|
25
- | `feature` / `refactor` / `bugfix` | keyword hit OR `frontendOnly=true` | `[ui, rd-planning, qa-test-cases]` |
26
- | `feature` / `refactor` / `bugfix` | no keyword hit AND `frontendOnly=false` | `[rd-planning, qa-test-cases]` |
27
- | `config` / `docs` / `chore` | (any) | `[]` (swarm skipped, recorded in plan) |
28
-
29
- In `assisted` and `strict` modes, Solo replaces signal (3) with a three-option `AskUserQuestion` (see "Mode-driven fan-out shape" in the main SKILL.md) and uses the user's choice as the plan.
30
-
31
- ## 3. Sub-agent invocation template
32
-
33
- Solo emits one Task call per sub-agent in the plan, all in the same message:
34
-
35
- ```js
36
- Task({
37
- subagent_type: "general-purpose",
38
- description: "<role> for rid=<rid>",
39
- prompt: <see role-specific sections below>
40
- })
41
- ```
42
-
43
- ### 3.1 Common prompt header (all sub-agents)
9
+ This contract (slice #009) replaces the IDE-private sub-agent literal with the IDE-agnostic primitive `peaks sub-agent dispatch <role>`. The CLI returns a JSON `data.toolCall` descriptor; the LLM executes that tool in its own environment. SKILL.md is now free of IDE-private tool names and the same prompt works on every registered IDE. Real concurrent fan-out is achieved by Solo launching N dispatch calls in a single message and the platform scheduling the returned toolCalls concurrently.
44
10
 
45
11
  ```
46
12
  You are a sub-agent invoked by peaks-solo. You are NOT the main Claude session.
@@ -158,7 +124,7 @@ no acceptance surface to plan tests for.
158
124
 
159
125
  ## 4. Reducer (Solo side)
160
126
 
161
- After all sub-agent Tasks return, Solo:
127
+ After all sub-agent dispatch calls return and the LLM has invoked the toolCalls, Solo:
162
128
 
163
129
  1. Restores presence ONCE (not per-agent):
164
130
  ```
@@ -176,7 +142,7 @@ If a sub-agent is misbehaving and writes to `.peaks/.active-skill.json` anyway,
176
142
 
177
143
  ## 6. Why not a `peaks-swarm` skill?
178
144
 
179
- A skill cannot itself trigger sub-agents — the Skill tool runs in the main loop. The orchestrator (peaks-solo) has to be in the main loop and has to use the Task tool directly. Putting swarm logic into a separate skill would either re-introduce the "single-stack blocking" anti-pattern or require a custom slash command that bypasses the Skill tool. The current design keeps swarm control in peaks-solo where it belongs.
145
+ A skill cannot itself trigger sub-agents — the Skill tool runs in the main loop. The orchestrator (peaks-solo) has to be in the main loop and has to call `peaks sub-agent dispatch` directly. Putting swarm logic into a separate skill would either re-introduce the "single-stack blocking" anti-pattern or require a custom slash command that bypasses the Skill tool. The current design keeps swarm control in peaks-solo where it belongs.
180
146
 
181
147
  ## 7. Tests / dogfood
182
148
 
@@ -15,6 +15,8 @@ Before any analysis or tool call, immediately run:
15
15
  peaks skill presence:set peaks-txt --project <repo> --mode <mode> --gate startup
16
16
  ```
17
17
 
18
+ **When invoked as a sub-agent (peaks-solo swarm):** do NOT call `peaks skill presence:set` (Solo owns the active-skill marker) and do NOT spawn your own session. Use the parent's sid — read `.peaks/_runtime/session.json` or pass `--session-id <parent-sid>` to any session-creating CLI. The new `peaks session info --active` reads the canonical binding for you.
19
+
18
20
  On the first presence:set in a project, ensure the out-of-band status bar is installed so the user can see at a glance that Peaks is orchestrating — it renders the active skill in Claude Code's terminal status line, independent of model output:
19
21
 
20
22
  ```bash
@@ -248,3 +250,20 @@ find .peaks/<id>/txt/ -type f | sort
248
250
  Do not choose the refactor plan or install runtime resources. Use artifacts produced by other skills and CLI reports.
249
251
 
250
252
  Reference: `references/context-capsule.md`.
253
+
254
+ ## Sub-agent context governance (G8 + G9 — slice #010, TXT reducer view)
255
+
256
+ > peaks-txt is the TXT reducer; it sees the metadata-only view from G7 + the share entries from G8. The TXT handoff summarizes the slice at the slice-close gate. Detailed: `skills/peaks-solo/references/context-governance.md`.
257
+
258
+ ### G8 — TXT reducer sees share entries on completion
259
+
260
+ When TXT reduces a batch, it consumes:
261
+ - The dispatch record's `artifactMetas[]` (G7.4.d) — paths + sizes + sha256s + summaries.
262
+ - The shared channel's entries (G8) — sibling sub-agent status (`<role>.completed`, `<role>.found-blocker`).
263
+
264
+ The TXT handoff summarizes the slice by listing the artifact metas + the share entries that arrived during the batch. Both are dispatcher-mediated (NOT inlined from the sub-agent prompt).
265
+
266
+ ### G9 — TXT prompt size self-check
267
+
268
+ Same G9 threshold table. TXT handoff messages can grow large when the slice has many batches; use `--use-headroom` proactively for handoff prompts > 50%.
269
+
@@ -28,8 +28,9 @@ UI's headed-browser inspection hits the same auth walls. The flow is identical t
28
28
 
29
29
  ## Sub-agent dispatch (when launched by peaks-solo swarm)
30
30
 
31
- When this skill is launched as a sub-agent via `Task(subagent_type="general-purpose", ...)` from `peaks-solo`, the following sections of THIS skill are **suspended** for the sub-agent run:
31
+ When this skill is launched as a sub-agent via `peaks sub-agent dispatch <role>` (then the LLM executes the returned toolCall) from `peaks-solo`, the following sections of THIS skill are **suspended** for the sub-agent run:
32
32
 
33
+ - **Session id** — use the parent's sid (read `.peaks/_runtime/session.json` or pass `--session-id <parent-sid>` to any session-creating CLI). Do NOT spawn your own session. The new `peaks session info --active` reads the canonical binding for you.
33
34
  - **Skill presence (MANDATORY first action)** — do NOT call `peaks skill presence:set peaks-ui`. The sub-agent must not overwrite `.peaks/.active-skill.json`; the main Solo loop owns that file. If you need to mark your own state, write a marker file at `.peaks/<session-id>/system/sub-agent-ui.json` and only that.
34
35
  - **Workspace initialization** — Solo has already run `peaks workspace init` before fan-out. Do not re-run it.
35
36
  - **Mode selection** — Solo has already chosen the mode.
@@ -354,3 +355,29 @@ Use `peaks capabilities --source access-repo --json` and `peaks capabilities --s
354
355
  Do not own backend architecture, non-UI implementation, runtime hook installation, or final QA acceptance.
355
356
 
356
357
  Reference: `references/workflow.md`.
358
+
359
+ ## Sub-agent context governance (G7 + G7.7 + G8 + G9 — slice #010)
360
+
361
+ > UI sub-agents follow the same G7 metadata-only + G8.6 share protocol. UI artifacts (design drafts, component scaffolds) can be large binary-ish files; the 1MB artifact size limit (G7.3) applies. Detailed: `skills/peaks-solo/references/context-governance.md`.
362
+
363
+ ### G7 — UI sub-agent protocol
364
+
365
+ 1. Write design draft / component scaffold to `.peaks/_sub_agents/<sid>/artifacts/<rid>-ui-001.md` (path convention mandatory; size ≤ 1MB).
366
+ 2. Call `peaks sub-agent dispatch --write-artifact <path>` to register ArtifactMeta.
367
+ 3. Main LLM sees metadata-only view (~200 chars/UI sub-agent).
368
+
369
+ ### G8.6 — UI sub-agent prompt template
370
+
371
+ ```
372
+ You are sub-agent role ui, batch <batchId>.
373
+
374
+ PROTOCOL (mandatory):
375
+ 1. On start: `peaks sub-agent shared-read --batch <batchId> --json`.
376
+ 2. While running: write share entry `peaks sub-agent share --key "ui.design-blocker" --value {"reason": "..."}`.
377
+ 3. On completion: `peaks sub-agent share --key "ui.completed" --value <artifact-meta>` BEFORE final heartbeat (RL-23).
378
+ ```
379
+
380
+ ### G9 — UI prompt size self-check
381
+
382
+ Same as RD/QA. UI design descriptions can grow large; use `--use-headroom` proactively.
383
+