peaks-cli 1.3.2 → 1.3.4

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 (115) hide show
  1. package/README.md +6 -2
  2. package/dist/src/cli/commands/core-artifact-commands.js +6 -3
  3. package/dist/src/cli/commands/gate-commands.js +28 -19
  4. package/dist/src/cli/commands/hook-handle.d.ts +17 -0
  5. package/dist/src/cli/commands/hook-handle.js +111 -0
  6. package/dist/src/cli/commands/hooks-commands.js +72 -21
  7. package/dist/src/cli/commands/progress-commands.js +9 -2
  8. package/dist/src/cli/commands/progress-start-spawn.js +30 -4
  9. package/dist/src/cli/commands/project-commands.js +8 -4
  10. package/dist/src/cli/commands/statusline-commands.js +75 -17
  11. package/dist/src/cli/commands/sub-agent-commands.d.ts +5 -0
  12. package/dist/src/cli/commands/sub-agent-commands.js +488 -0
  13. package/dist/src/cli/commands/sub-agent-dispatch-guard.d.ts +55 -0
  14. package/dist/src/cli/commands/sub-agent-dispatch-guard.js +57 -0
  15. package/dist/src/cli/commands/workflow-commands.js +2 -1
  16. package/dist/src/cli/commands/workspace-commands.js +3 -0
  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/config/config-types.d.ts +1 -1
  21. package/dist/src/services/context/artifact-meta.d.ts +72 -0
  22. package/dist/src/services/context/artifact-meta.js +105 -0
  23. package/dist/src/services/context/context-guard.d.ts +49 -0
  24. package/dist/src/services/context/context-guard.js +91 -0
  25. package/dist/src/services/context/dispatch-context-guard.d.ts +27 -0
  26. package/dist/src/services/context/dispatch-context-guard.js +192 -0
  27. package/dist/src/services/context/headroom-client.d.ts +34 -0
  28. package/dist/src/services/context/headroom-client.js +117 -0
  29. package/dist/src/services/context/shared-channel.d.ts +92 -0
  30. package/dist/src/services/context/shared-channel.js +285 -0
  31. package/dist/src/services/context/threshold.d.ts +35 -0
  32. package/dist/src/services/context/threshold.js +76 -0
  33. package/dist/src/services/dashboard/project-dashboard-service.d.ts +23 -0
  34. package/dist/src/services/dashboard/project-dashboard-service.js +21 -0
  35. package/dist/src/services/dispatch/batch-counter.d.ts +27 -0
  36. package/dist/src/services/dispatch/batch-counter.js +85 -0
  37. package/dist/src/services/dispatch/dispatch-record-writer.d.ts +93 -0
  38. package/dist/src/services/dispatch/dispatch-record-writer.js +261 -0
  39. package/dist/src/services/dispatch/heartbeat-truncator.d.ts +26 -0
  40. package/dist/src/services/dispatch/heartbeat-truncator.js +13 -0
  41. package/dist/src/services/dispatch/leak-detector.d.ts +11 -0
  42. package/dist/src/services/dispatch/leak-detector.js +72 -0
  43. package/dist/src/services/dispatch/sub-agent-dispatcher.d.ts +127 -0
  44. package/dist/src/services/dispatch/sub-agent-dispatcher.js +98 -0
  45. package/dist/src/services/ide/adapters/claude-code-adapter.d.ts +18 -0
  46. package/dist/src/services/ide/adapters/claude-code-adapter.js +80 -0
  47. package/dist/src/services/ide/adapters/trae-adapter.d.ts +42 -0
  48. package/dist/src/services/ide/adapters/trae-adapter.js +98 -0
  49. package/dist/src/services/ide/hook-protocol.d.ts +47 -0
  50. package/dist/src/services/ide/hook-protocol.js +74 -0
  51. package/dist/src/services/ide/hook-translator.d.ts +72 -0
  52. package/dist/src/services/ide/hook-translator.js +128 -0
  53. package/dist/src/services/ide/ide-detector.d.ts +10 -0
  54. package/dist/src/services/ide/ide-detector.js +19 -0
  55. package/dist/src/services/ide/ide-registry.d.ts +14 -0
  56. package/dist/src/services/ide/ide-registry.js +45 -0
  57. package/dist/src/services/ide/ide-types.d.ts +180 -0
  58. package/dist/src/services/ide/ide-types.js +2 -0
  59. package/dist/src/services/ide/resource-profile.d.ts +52 -0
  60. package/dist/src/services/ide/resource-profile.js +33 -0
  61. package/dist/src/services/ide/shared/atomic-json.d.ts +15 -0
  62. package/dist/src/services/ide/shared/atomic-json.js +58 -0
  63. package/dist/src/services/ide/shared/safe-path.d.ts +11 -0
  64. package/dist/src/services/ide/shared/safe-path.js +29 -0
  65. package/dist/src/services/memory/project-context-service.js +2 -1
  66. package/dist/src/services/memory/project-memory-service.js +4 -3
  67. package/dist/src/services/perf/perf-baseline-service.js +2 -1
  68. package/dist/src/services/progress/progress-service.d.ts +1 -1
  69. package/dist/src/services/progress/progress-service.js +18 -14
  70. package/dist/src/services/security/safe-settings-path.d.ts +12 -0
  71. package/dist/src/services/security/safe-settings-path.js +104 -0
  72. package/dist/src/services/session/getSessionDir.d.ts +1 -0
  73. package/dist/src/services/session/getSessionDir.js +27 -0
  74. package/dist/src/services/session/index.d.ts +1 -0
  75. package/dist/src/services/session/index.js +1 -0
  76. package/dist/src/services/signal/cancel-handler.d.ts +14 -0
  77. package/dist/src/services/signal/cancel-handler.js +76 -0
  78. package/dist/src/services/skill/resume-detector.d.ts +54 -0
  79. package/dist/src/services/skill/resume-detector.js +334 -0
  80. package/dist/src/services/skill/skill-scheduler.d.ts +40 -0
  81. package/dist/src/services/skill/skill-scheduler.js +53 -0
  82. package/dist/src/services/skills/hooks-settings-service.d.ts +47 -29
  83. package/dist/src/services/skills/hooks-settings-service.js +190 -144
  84. package/dist/src/services/skills/statusline-settings-service.d.ts +33 -6
  85. package/dist/src/services/skills/statusline-settings-service.js +31 -34
  86. package/dist/src/services/slice/slice-archive-service.d.ts +20 -0
  87. package/dist/src/services/slice/slice-archive-service.js +111 -0
  88. package/dist/src/services/solo/batch-heartbeat-poller.d.ts +51 -0
  89. package/dist/src/services/solo/batch-heartbeat-poller.js +88 -0
  90. package/dist/src/services/solo/status-line-renderer.d.ts +34 -0
  91. package/dist/src/services/solo/status-line-renderer.js +55 -0
  92. package/dist/src/services/standards/ide-aware-standards-service.d.ts +94 -0
  93. package/dist/src/services/standards/ide-aware-standards-service.js +89 -0
  94. package/dist/src/services/standards/project-standards-service.d.ts +1 -2
  95. package/dist/src/services/workspace/reconcile-service.d.ts +36 -0
  96. package/dist/src/services/workspace/reconcile-service.js +107 -6
  97. package/dist/src/services/workspace/reconcile-types.d.ts +12 -0
  98. package/dist/src/shared/version.d.ts +1 -1
  99. package/dist/src/shared/version.js +1 -1
  100. package/package.json +2 -1
  101. package/scripts/install-skills.mjs +112 -2
  102. package/skills/peaks-ide/SKILL.md +159 -0
  103. package/skills/peaks-ide/references/audit-log-helper.md +52 -0
  104. package/skills/peaks-qa/SKILL.md +153 -55
  105. package/skills/peaks-qa/references/qa-fanout-contract.md +150 -0
  106. package/skills/peaks-rd/SKILL.md +134 -62
  107. package/skills/peaks-solo/SKILL.md +124 -37
  108. package/skills/peaks-solo/references/browser-workflow.md +22 -20
  109. package/skills/peaks-solo/references/context-governance.md +144 -0
  110. package/skills/peaks-solo/references/headroom-integration.md +107 -0
  111. package/skills/peaks-solo/references/runbook.md +3 -3
  112. package/skills/peaks-solo/references/sub-agent-dispatch.md +261 -0
  113. package/skills/peaks-solo/references/swarm-dispatch-contract.md +3 -37
  114. package/skills/peaks-txt/SKILL.md +17 -0
  115. package/skills/peaks-ui/SKILL.md +45 -10
@@ -0,0 +1,107 @@
1
+ # Headroom Integration — G7.7 opt-in compression channel
2
+
3
+ > Slice #010 (G7.7 headroom-ai integration route).
4
+ > Source: https://github.com/chopratejas/headroom
5
+ > Package: `headroom-ai@0.22.4` (Apache-2.0, MIT-compatible).
6
+ > See: `THIRD_PARTY_LICENSES.md` for the license record.
7
+
8
+ ## Why headroom-ai is justified (R-14)
9
+
10
+ The dev-preference red line "非必要不添加新的 dep" is preserved:
11
+ headroom-ai is the only opt-in mechanism for G7.7 + G9 to compress
12
+ sub-agent prompts that exceed the 75% / 80% threshold. Without
13
+ headroom-ai, `--use-headroom` is a no-op and the only fallback is
14
+ `--force` override at CLI.
15
+
16
+ The user's explicit reference (https://github.com/chopratejas/headroom)
17
+ is the basis for the dev-preference override.
18
+
19
+ ## API shape (real SDK, not the PRD's spec)
20
+
21
+ ```ts
22
+ import { compress } from 'headroom-ai';
23
+
24
+ const result = await compress(messages, {
25
+ model: 'claude-sonnet-4-5-20250929',
26
+ baseUrl: 'http://localhost:8787', // local proxy; not used in slice #010
27
+ apiKey: 'hr_...', // Headroom Cloud; not used in slice #010
28
+ timeout: 30_000,
29
+ fallback: true, // CRITICAL: return original messages if proxy is dead
30
+ retries: 1,
31
+ tokenBudget: 4000, // compress to fit this limit
32
+ hooks: new MyHooks(), // pre/post compression hooks
33
+ });
34
+
35
+ result.messages // compressed messages
36
+ result.tokensBefore // original token count
37
+ result.tokensAfter // compressed token count
38
+ result.tokensSaved // tokens removed
39
+ result.compressionRatio // tokensAfter / tokensBefore
40
+ result.transformsApplied // e.g. ['router:smart_crusher:0.35']
41
+ result.compressed // false if fallback kicked in
42
+ ```
43
+
44
+ `fallback: true` is the key option: if the proxy is unavailable, the SDK
45
+ returns the original messages + `result.compressed: false` instead of
46
+ throwing. This makes the failure mode non-blocking (RL-22d / RL-32).
47
+
48
+ ## Mode table (peaks wrapper)
49
+
50
+ The peaks wrapper maps the user-facing `HeadroomMode` to the SDK's
51
+ `tokenBudget` option. Slice #010 does not consume the SDK's internal
52
+ "audit" / "optimize" / "simulate" modes (those are SDK-internal);
53
+
54
+ | Mode | tokenBudget | Use case |
55
+ |---|---|---|
56
+ | `balanced` (default) | promptSize * 0.40 / 4 | General sub-agent dispatch |
57
+ | `aggressive` | promptSize * 0.20 / 4 | Last-resort large prompt |
58
+ | `conservative` | promptSize * 0.70 / 4 | Sensitive code analysis, accuracy-critical |
59
+
60
+ The `0.40 / 4` factor approximates 60% byte reduction (1 token ≈ 4 bytes
61
+ for English text). The SDK does its own tokenization internally; the
62
+ `tokenBudget` is a hint, not a hard cap.
63
+
64
+ ## Failure semantics (RL-22d / RL-32)
65
+
66
+ - `result.compressed === false` → `code: "HEADROOM_UNAVAILABLE"` warning
67
+ - `compress()` throws (network error, JSON parse error) → caught and treated as `HEADROOM_UNAVAILABLE`
68
+ - Import failure (headroom-ai not installed) → caught and treated as `HEADROOM_UNAVAILABLE`
69
+ - **NOT blocking** — peak falls back to G7 metadata-only and continues dispatch
70
+
71
+ ## CCR reversible hydration (slice #011+ TODO)
72
+
73
+ The PRD mentions "CCR (Cross-Context Reversible)" as a benefit of
74
+ headroom. In the SDK, this is implemented via the `hooks` option on
75
+ `compress()`. A pre/post hook can persist the `ccrHashes` to disk,
76
+ and a later `rehydrate()` call can re-hydrate the compressed prompt
77
+ to the original. Slice #010 does NOT consume CCR — it only uses
78
+ compression. R-17 (CCR for aggressive / conservative modes) is
79
+ deferred to slice #011+.
80
+
81
+ ## Cross-platform behavior (R-19)
82
+
83
+ - In-process compression (the SDK's library mode) is platform-agnostic.
84
+ - The long-running `headroom proxy` daemon is platform-specific
85
+ (Unix socket on Linux/macOS, named pipe on Windows). Slice #010
86
+ does NOT consume the proxy daemon.
87
+ - All headroom-ai calls in slice #010 go through the in-process SDK
88
+ with `fallback: true`. The peak wrapper at
89
+ `src/services/context/headroom-client.ts` catches all errors and
90
+ treats them as fallback.
91
+
92
+ ## What slice #010 does NOT do
93
+
94
+ - Does NOT install the `headroom proxy` daemon (N-7).
95
+ - Does NOT consume headroom's `SharedContext` directly (G7.7.3 in the
96
+ PRD); the peak-internal `SharedChannel` (G8) is the cross-sub-agent
97
+ state store. `buildSharedContextBridge()` is a stub that returns
98
+ the peak-internal channel ID + a placeholder headroom context ID.
99
+ - Does NOT use the SDK's `audit` / `optimize` / `simulate` modes
100
+ (those are SDK-internal; the peak wrapper exposes
101
+ `balanced` / `aggressive` / `conservative` to the user).
102
+
103
+ ## Security + license
104
+
105
+ - License: Apache-2.0 (MIT-compatible) — see `THIRD_PARTY_LICENSES.md`.
106
+ - Pinned version: exact `0.22.4` (no `^` / `~` range) per dev-preference.
107
+ - `pnpm audit` ran on install; no new high-severity vulnerabilities.
@@ -53,10 +53,10 @@ peaks request lint <rid> --role prd --project <repo> --json
53
53
  peaks request transition <rid> --role prd --state confirmed-by-user --project <repo> --json
54
54
  peaks request transition <rid> --role prd --state handed-off --project <repo> --json
55
55
 
56
- # 3. Peaks-Cli Swarm parallel — sub-agent fan-out (Task tool, NOT Skill tool)
56
+ # 3. Peaks-Cli Swarm parallel — sub-agent fan-out (peaks sub-agent dispatch, NOT Skill tool)
57
57
  # Solo computes the swarm plan from --type + frontendOnly + frontend-keyword scan,
58
58
  # writes it to .peaks/<sid>/sc/swarm-plan.json, then launches one
59
- # Task(subagent_type="general-purpose", ...) call per sub-agent in the same message.
59
+ # `peaks sub-agent dispatch <role>` call per sub-agent in the same message.
60
60
  # See "Peaks-Cli Swarm parallel phase" above for the full decision table and the
61
61
  # prompt template; the role's required artefact paths are listed there.
62
62
  # Hard rule: do NOT call Skill(skill="peaks-rd" | "peaks-qa" | "peaks-ui") from
@@ -75,7 +75,7 @@ peaks skill presence:set peaks-solo --project <repo> --mode <mode> --gate swarm-
75
75
  # e.g. if plan = [ui, rd, qa]: run init for ui, rd, qa.
76
76
  # If plan = [rd, qa]: run for rd, qa only.
77
77
  # If plan = [] (config|docs|chore skip): no inits here, jump to step 4 directly.
78
- # 3b. Solo issues N Task(subagent_type="general-purpose", ...) calls in ONE message
78
+ # 3b. Solo issues N `peaks sub-agent dispatch <role>` calls in ONE message
79
79
  # (N = len(swarm-plan.subAgents)). Each prompt embeds the role's body minus
80
80
  # Step 0 / presence, plus the runtime args (rid / sid / mode / type / paths).
81
81
  # 3c. After fan-out, Solo restores presence once and runs Gate B (ls checks):
@@ -0,0 +1,261 @@
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 + MCP-decoupled)
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
+ **Slice #007-007-2026-06-07-mcp-decouple (G3 prompt template addition)**:
147
+ when the sub-agent is dispatched into a non-Claude IDE (Trae, Cursor,
148
+ Codex, Qoder, Tongyi, ...) or into a Claude Code environment where the
149
+ LLM cannot directly invoke the `mcp__<server>__*` tool prefix, the
150
+ sub-agent prompt must additionally include the MCP-decouple instruction
151
+ below. Without it, the sub-agent would either fall back to direct
152
+ `mcp__` invocations (which fail in non-Claude IDEs) or skip MCP
153
+ operations entirely (which breaks RD/QA/UI flows that depend on the
154
+ Playwright, Chrome DevTools, Figma, or Context7 servers).
155
+
156
+ ```
157
+ When you need to use an MCP server (playwright, chrome-devtools, figma, or
158
+ context7), do NOT invoke the `mcp__<server>__*` tool prefix directly. The
159
+ canonical path is `peaks mcp call`:
160
+
161
+ peaks mcp call --capability <capabilityId> --tool <toolName> --args-json '<argsObject>' --json
162
+
163
+ where `<capabilityId>` is one of:
164
+ - playwright-mcp.browser-validation (headed browser, primary E2E surface)
165
+ - chrome-devtools-mcp.browser-debug (CDP to running Chrome on :9222, secondary)
166
+ - figma-context-mcp.design-context (Figma design data, requires FIGMA_API_KEY)
167
+ - context7.docs-lookup (library docs, requires CONTEXT7_API_KEY)
168
+
169
+ For install / plan / detect, use:
170
+ peaks mcp list --json
171
+ peaks mcp plan --capability <capabilityId> --json
172
+ peaks mcp apply --capability <capabilityId> --yes --json
173
+
174
+ The `peaks mcp plan` envelope's `envCheck.missing` field is the source of
175
+ truth for required env vars. Do not bake the `mcp__<server>__*` prefix
176
+ into any artifact or message; the prefix is owned by the LLM runtime, not
177
+ by the skill. On Trae, `capabilities.mcpInstall` is `false`; do not
178
+ attempt `peaks mcp apply` on Trae — surface the manual install path
179
+ instead.
180
+ ```
181
+
182
+ The MCP-decouple paragraph is required for any sub-agent dispatched
183
+ into a non-Claude environment or any sub-agent that needs an MCP
184
+ capability. The CLI auto-generates it for `role in (rd, qa, ui, txt)`
185
+ when the active IDE is not `claude-code`; for `role = general-purpose`
186
+ or unknown roles, the caller (the SKILL.md heart of the Dispatcher) must
187
+ add it explicitly.
188
+
189
+ `heartbeatIntervalSec` is overridable per SKILL.md (5..600). Default 30.
190
+
191
+ ### Status line shape (G6.5)
192
+
193
+ Single line, 80-120 chars:
194
+
195
+ ```
196
+ [peaks-solo] swarm 3/3 running | rd-planning 45% (12s ago) | qa-test-cases 30% (5s ago) | ui-design 20% (2s ago)
197
+ [peaks-solo] swarm 3/3 running | rd-planning 70% (8s ago) | qa-test-cases 50% (3s ago) | ui-design 30% (6s ago)
198
+ ...
199
+ [peaks-solo] swarm 3/3 done
200
+ ```
201
+
202
+ If a sub-agent has not written a heartbeat in 5 minutes, the poller
203
+ appends `⚠ stale` to that sub-agent's segment and marks
204
+ `status: 'stale'` on the record. **It does not cancel, kill, or send
205
+ SIGTERM** (RL-15). Stale is a user-visible warning, not a failure.
206
+ The user decides.
207
+
208
+ ### Truncation (RL-16)
209
+
210
+ `heartbeats[]` is append-only for audit, but capped at 100 entries.
211
+ Past 100, the oldest are dropped and `truncated: true` is set. The
212
+ record JSON can otherwise balloon to MB on long-running sub-agents.
213
+ 100 is the LLM-friendly limit — stale heartbeats are not informative
214
+ once the poller has read them.
215
+
216
+ ### Acceptance criteria covered
217
+
218
+ - AC-33 `peaks sub-agent heartbeat` CLI primitive (implemented)
219
+ - AC-34 Dispatch record schema upgrade (`heartbeats[]` + `lastBeatAt` + `status` aggregate, backward-compat defaults)
220
+ - AC-35 peaks-solo main loop batch-sync poller (10 s cadence, 5 min stale)
221
+ - AC-36 SKILL.md fan-out sections include heartbeat instruction
222
+ - AC-37 G6 E2E dogfood (3 heartbeats, 101 → truncated, stale simulation)
223
+
224
+ ## Acceptance criteria (overall G1-G6)
225
+
226
+ - AC-1..AC-5: dispatcher interface + 3 adapter impls (`claudeCodeSubAgentDispatcher`, `traeSubAgentDispatcher`, `nullSubAgentDispatcher`)
227
+ - AC-6: dispatcher unit tests
228
+ - AC-7..AC-9: dispatch CLI signature + envelope + steps
229
+ - AC-10: dispatch CLI unit tests
230
+ - AC-11 / AC-11b / AC-11c: E2E dogfood on the live repo
231
+ - AC-12: `peaks --help` byte-level delta is `+1` line (`sub-agent <cmd>`)
232
+ - 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)
233
+ - AC-22..AC-24: R-2 path guard, prompt size limit, atomic write
234
+ - AC-25..AC-32: G5 resource lifecycle (RL-1 batch counter, dispatch record schema, reducer dispose, slice archive, cancel dispose)
235
+ - AC-33..AC-37: G6 heartbeat CLI, schema, poller, status line, E2E
236
+
237
+ ## How to apply
238
+
239
+ When writing a SKILL.md that fans out sub-agents:
240
+
241
+ 1. Use `peaks sub-agent dispatch <role>` (never `Task(...)`).
242
+ 2. Issue all dispatches in a single message; the LLM will fire all
243
+ returned toolCalls in parallel.
244
+ 3. Pass `--request-id` and `--session-id` (or omit and let the CLI
245
+ resolve the active session).
246
+ 4. The sub-agent prompt **must** include the heartbeat instruction
247
+ (30 s cadence; override via `heartbeatIntervalSec` if needed).
248
+ 5. After the fan-out returns, the Dispatcher reducer reads the
249
+ dispatch record + the artifacts the sub-agents wrote, marks
250
+ `disposed: true` on each record, and advances the state machine.
251
+ 6. The poller handles the 5-min stale case as a warning, never as a
252
+ failure. The user is the one who decides to cancel.
253
+
254
+ ## Cross-reference
255
+
256
+ - PRD #009 G1-G6 (this slice's source of truth)
257
+ - RD request #009 in-scope files (implementation contract)
258
+ - `.peaks/memory/sub-agent-resource-lifecycle-red-line.md` (G5 red line)
259
+ - `.peaks/memory/sub-agent-heartbeat-progress-red-line.md` (G6 red line)
260
+ - `skills/peaks-solo/references/swarm-dispatch-contract.md` (predecessor contract)
261
+ - `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
 
@@ -250,3 +250,20 @@ find .peaks/<id>/txt/ -type f | sort
250
250
  Do not choose the refactor plan or install runtime resources. Use artifacts produced by other skills and CLI reports.
251
251
 
252
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
+
@@ -13,7 +13,7 @@ UI's headed-browser work (visual inspection, regression seed capture, Figma / li
13
13
 
14
14
  ### Contract 1 — Inspection screenshots must land under .peaks/<sid>/qa/screenshots/
15
15
 
16
- Every `mcp__playwright__browser_take_screenshot` call **MUST** pass `filename` inside `.peaks/<session-id>/qa/screenshots/`, named after the inspection target (e.g. `home-after-cta.png`, `empty-state-v2.png`). Do not let Playwright fall back to the project root. After every batch, run:
16
+ Every Playwright screenshot tool call (via `peaks mcp call --capability playwright-mcp.browser-validation --tool browser_take_screenshot --args-json '<args>' --json`) **MUST** pass `filename` (in the args object) inside `.peaks/<session-id>/qa/screenshots/`, named after the inspection target (e.g. `home-after-cta.png`, `empty-state-v2.png`). Do not let Playwright fall back to the project root. After every batch, run:
17
17
 
18
18
  ```bash
19
19
  ls .peaks/<sid>/qa/screenshots/*.png 2>&1
@@ -28,7 +28,7 @@ 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
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.
34
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.
@@ -152,7 +152,8 @@ peaks mcp apply --capability playwright-mcp.browser-validation --yes --json
152
152
 
153
153
  # 5. drive the running page or prototype through Claude Code MCP tools
154
154
  # (these are not Peaks-Cli CLI commands; they are invoked by the host MCP runtime)
155
- # mcp__playwright__browser_navigate → URL (after allow-list check), launches headed browser
155
+ # peaks mcp call --capability playwright-mcp.browser-validation --tool browser_navigate --args-json '{"url":"<url>"}' --json
156
+ # → URL (after allow-list check), launches headed browser
156
157
  #
157
158
  # LOGIN GATE (MANDATORY checkpoint):
158
159
  # After browser_navigate, check for login/CAPTCHA/SSO/MFA redirect.
@@ -161,11 +162,19 @@ peaks mcp apply --capability playwright-mcp.browser-validation --yes --json
161
162
  # If user does not confirm within reasonable time → pause and ask.
162
163
  # Only after user confirmation, continue to:
163
164
  #
164
- # mcp__playwright__browser_take_screenshot → visible-browser confirmation
165
- # mcp__playwright__browser_snapshot accessibility tree for regression seeds
166
- # mcp__playwright__browser_console_messages console errors
167
- # mcp__playwright__browser_network_requests failed network
168
- # mcp__playwright__browser_close → end the session cleanly
165
+ # peaks mcp call --capability playwright-mcp.browser-validation --tool browser_take_screenshot --args-json '{"filename":"<abs-path>"}' --json
166
+ # → visible-browser confirmation
167
+ # peaks mcp call --capability playwright-mcp.browser-validation --tool browser_snapshot --args-json '{}' --json
168
+ # → accessibility tree for regression seeds
169
+ # peaks mcp call --capability playwright-mcp.browser-validation --tool browser_console_messages --args-json '{}' --json
170
+ # → console errors
171
+ # peaks mcp call --capability playwright-mcp.browser-validation --tool browser_network_requests --args-json '{}' --json
172
+ # → failed network
173
+ # peaks mcp call --capability playwright-mcp.browser-validation --tool browser_close --args-json '{}' --json
174
+ # → end the session cleanly
175
+ # The skill body NEVER bakes in the `mcp__playwright__` prefix; the LLM's runtime
176
+ # resolves the tool name from the registered server. The capability id
177
+ # `playwright-mcp.browser-validation` is the contract; the registry is the source of truth.
169
178
 
170
179
  # 5. write design-draft artifact to .peaks/<session-id>/ui/design-draft.md
171
180
 
@@ -229,7 +238,7 @@ Use gstack as a concrete design-review workflow reference for the `Plan → Revi
229
238
  - map browser walkthrough concepts to UI regression seeds when runtime validation is approved;
230
239
  - keep accessibility, performance, and product-specific visual direction as Peaks-Cli UI acceptance inputs.
231
240
 
232
- For frontend work, especially full-auto mode, use Playwright MCP (`mcp__playwright__browser_navigate` / `browser_snapshot` / `browser_take_screenshot` / `browser_console_messages` / `browser_network_requests` / `browser_close`) to inspect the running page or prototype before accepting the UI direction. Playwright MCP launches a headed browser on demand; if `peaks mcp list --json` does not include `playwright`, install it through `peaks mcp plan/apply --capability playwright-mcp.browser-validation --yes` before attempting to inspect. (Chrome DevTools MCP is a secondary surface that connects to an already-running Chrome via `--remote-debugging-port=9222`; it does NOT launch a browser on its own.) If login, CAPTCHA, SSO, or MFA appears, the visible browser is already open; wait for the user to complete login and explicitly confirm completion before continuing. Capture only sanitized visible regressions, weak hierarchy, generic template patterns, console errors, and interaction problems as UI feedback that should return to design/RD before handing off to QA; do not retain login URLs, cookies, headers, tokens, storage state, browser traces, or screenshots/logs containing PII or SSO/MFA material. Canonical browser workflow: `peaks-solo/references/browser-workflow.md`.
241
+ For frontend work, especially full-auto mode, use Playwright MCP to inspect the running page or prototype before accepting the UI direction. The skill body never bakes in the `mcp__playwright__` prefix; it uses `peaks mcp call --capability playwright-mcp.browser-validation --tool <name> --args-json '<args>' --json` for every browser operation (browser_navigate / browser_snapshot / browser_take_screenshot / browser_console_messages / browser_network_requests / browser_close). Playwright MCP launches a headed browser on demand; if `peaks mcp list --json` does not include `playwright`, install it through `peaks mcp plan --capability playwright-mcp.browser-validation --json` then `peaks mcp apply --capability playwright-mcp.browser-validation --yes --json` before attempting to inspect. (Chrome DevTools MCP is a secondary surface that connects to an already-running Chrome via `--remote-debugging-port=9222`; it does NOT launch a browser on its own.) If login, CAPTCHA, SSO, or MFA appears, the visible browser is already open; wait for the user to complete login and explicitly confirm completion before continuing. Capture only sanitized visible regressions, weak hierarchy, generic template patterns, console errors, and interaction problems as UI feedback that should return to design/RD before handing off to QA; do not retain login URLs, cookies, headers, tokens, storage state, browser traces, or screenshots/logs containing PII or SSO/MFA material. Canonical browser workflow: `peaks-solo/references/browser-workflow.md`.
233
242
 
234
243
  ## Prototype fidelity gate (MANDATORY — check BEFORE any design work)
235
244
 
@@ -239,7 +248,7 @@ For frontend work, especially full-auto mode, use Playwright MCP (`mcp__playwrig
239
248
 
240
249
  Check these sources in order:
241
250
 
242
- 1. **Figma design file** — If the PRD links to a Figma file, use `mcp__Figma_AI_Bridge__get_figma_data` to fetch the design. The Figma data IS the design. Replicate layout, spacing, colors, typography, and component choices exactly as specified.
251
+ 1. **Figma design file** — If the PRD links to a Figma file, use `peaks mcp call --capability figma-context-mcp.design-context --tool get_figma_data --args-json '{"fileKey":"<key>"}' --json` to fetch the design (the skill body never bakes in the `mcp__Figma_AI_Bridge__` prefix; the prefix is owned by the LLM runtime, and `FIGMA_API_KEY` must be set in the env before `peaks mcp apply` — the plan envelope's `envCheck.missing` field is the source of truth). The Figma data IS the design. Replicate layout, spacing, colors, typography, and component choices exactly as specified.
243
252
  2. **PRD document screenshots** — If the PRD source (Feishu/Lark doc) contains screenshots or mockups, those ARE the visual target. Check `.peaks/<id>/prd/source/` for saved screenshots.
244
253
  3. **PRD visual descriptions** — If the PRD explicitly describes layout, component placement, or visual behavior, those descriptions are constraints, not suggestions.
245
254
  4. **Existing application pages** — If modifying an existing app, the existing visual language (component library, spacing patterns, color usage) is the fidelity baseline. New pages must match existing conventions.
@@ -355,3 +364,29 @@ Use `peaks capabilities --source access-repo --json` and `peaks capabilities --s
355
364
  Do not own backend architecture, non-UI implementation, runtime hook installation, or final QA acceptance.
356
365
 
357
366
  Reference: `references/workflow.md`.
367
+
368
+ ## Sub-agent context governance (G7 + G7.7 + G8 + G9 — slice #010)
369
+
370
+ > 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`.
371
+
372
+ ### G7 — UI sub-agent protocol
373
+
374
+ 1. Write design draft / component scaffold to `.peaks/_sub_agents/<sid>/artifacts/<rid>-ui-001.md` (path convention mandatory; size ≤ 1MB).
375
+ 2. Call `peaks sub-agent dispatch --write-artifact <path>` to register ArtifactMeta.
376
+ 3. Main LLM sees metadata-only view (~200 chars/UI sub-agent).
377
+
378
+ ### G8.6 — UI sub-agent prompt template
379
+
380
+ ```
381
+ You are sub-agent role ui, batch <batchId>.
382
+
383
+ PROTOCOL (mandatory):
384
+ 1. On start: `peaks sub-agent shared-read --batch <batchId> --json`.
385
+ 2. While running: write share entry `peaks sub-agent share --key "ui.design-blocker" --value {"reason": "..."}`.
386
+ 3. On completion: `peaks sub-agent share --key "ui.completed" --value <artifact-meta>` BEFORE final heartbeat (RL-23).
387
+ ```
388
+
389
+ ### G9 — UI prompt size self-check
390
+
391
+ Same as RD/QA. UI design descriptions can grow large; use `--use-headroom` proactively.
392
+