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
@@ -13,8 +13,8 @@
13
13
  "properties": {
14
14
  "id": {
15
15
  "type": "string",
16
- "pattern": "^(skill|skill-name|skill-parse|skill-runbook|skill-apply-note|skill-presence|statusline|schema|config|doctor-self|capability):[A-Za-z0-9][A-Za-z0-9._-]*$",
17
- "description": "Stable check id. Known prefixes: skill:<name> (required skill present), skill-name:<dir> (directory matches declared name), skill-parse:<dir> (skill metadata parsed), skill-runbook:<name> (Default runbook section exists), skill-apply-note:<name> (destructive --apply lines carry an authorization/--dry-run note), skill-presence:<topic> (status of .peaks/.active-skill.json — current/freshness/workspace), statusline:<topic> (out-of-band Claude Code statusLine — install/runtime), schema:<file> (schema file exists and is valid JSON), config:<scope> (optional config locations), doctor-self:<topic> (doctor validates its own output against this schema), capability:<name> (third-party capability is resolvable at the pinned version)."
16
+ "pattern": "^(skill|skill-name|skill-parse|skill-runbook|skill-apply-note|skill-presence|statusline|schema|config|doctor-self|capability|build):[A-Za-z0-9][A-Za-z0-9._-]*$",
17
+ "description": "Stable check id. Known prefixes: skill:<name> (required skill present), skill-name:<dir> (directory matches declared name), skill-parse:<dir> (skill metadata parsed), skill-runbook:<name> (Default runbook section exists), skill-apply-note:<name> (destructive --apply lines carry an authorization/--dry-run note), skill-presence:<topic> (status of .peaks/.active-skill.json — current/freshness/workspace), statusline:<topic> (out-of-band Claude Code statusLine — install/runtime), schema:<file> (schema file exists and is valid JSON), config:<scope> (optional config locations), doctor-self:<topic> (doctor validates its own output against this schema), capability:<name> (third-party capability is resolvable at the pinned version), build:<topic> (build-hygiene checks — dist/source version consistency)."
18
18
  },
19
19
  "ok": { "type": "boolean" },
20
20
  "message": { "type": "string", "minLength": 1 }
@@ -0,0 +1,159 @@
1
+ ---
2
+ name: peaks-ide
3
+ description: Orchestrate peaks-cli's IDE-aware behavior (hooks + statusline + handle) for a user's specific IDE. Detects the current state (which IDE the user is on, what peaks has already installed), plans the install / switch / status / uninstall actions, and invokes the existing peaks CLI primitives. Triggers on `/peaks-ide`, "set up peaks for my IDE", "switch peaks to Trae", "what did peaks install", "uninstall peaks hooks". Sits between the user and `peaks hooks install` / `peaks statusline install` / `peaks hook handle` — those are the CLI primitives; this skill is the user-facing surface.
4
+ ---
5
+
6
+ # Peaks-Cli IDE Setup (peaks-ide)
7
+
8
+ `peaks-ide` is the **user-facing surface** for everything peaks-cli does that's IDE-aware. It does NOT introduce new CLI commands. It orchestrates the existing CLI primitives — `peaks hooks install`, `peaks statusline install`, `peaks hook handle` — based on the user's intent and the IDE the user is on.
9
+
10
+ **Why this exists (dev-preference red line):** "skill is primary, CLI is auxiliary." The behavior that only an LLM in a skill prompt would use ("detect which IDE the user is on", "plan the migration steps", "ask the user before destructive actions") lives in this SKILL.md, not in a new `peaks <cmd>`. The CLI commands stay as atomic primitives the skill composes.
11
+
12
+ **Slice #2 scope:** the first version supports Trae (alongside Claude Code, the only other adapter in slice #2's registry). Cursor / Codex / Qoder / Tongyi Lingma will land in slice #3+ — the skill will pick them up automatically because the underlying auto-detect (the `peaks project dashboard --json` flow internally calls `listAdapterIds()` via the `IdeRegistry`) registers them as the registry grows.
13
+
14
+ ## Skill presence (MANDATORY first action)
15
+
16
+ ```bash
17
+ peaks skill presence:set peaks-ide --project <repo> --mode <mode> --gate startup
18
+ peaks project memories --project <repo> --json # load durable memory
19
+ ```
20
+
21
+ The presence marker tells the global peaks status line that peaks-ide is orchestrating. The memory read pulls forward the slice #1 contract: `peaks <cmd> --project <path>` is the canonical project-root source; `process.env[adapter.envVar]` (e.g. `CLAUDE_PROJECT_DIR`, `TRAE_PROJECT_DIR`) is the env-var override for auto-detect.
22
+
23
+ ## Step 1: detect current state
24
+
25
+ The skill's first move is to **read**, not to ask. Build a complete picture of the user's IDE environment before any AskUserQuestion.
26
+
27
+ ```bash
28
+ # 1. What adapters are registered? (slice #2 ships with claude-code + trae)
29
+ peaks project dashboard --project <repo> --json
30
+
31
+ # 2. Is the user on Claude Code, Trae, or something else?
32
+ # Check the cwd for adapter-specific directories:
33
+ ls -la <repo>/.claude 2>/dev/null && echo "claude-code detected"
34
+ ls -la <repo>/.trae 2>/dev/null && echo "trae detected"
35
+
36
+ # 3. Are peaks hooks already installed? For each candidate, read settings.json:
37
+ # claude: <root>/.claude/settings.json
38
+ # trae: <root>/.trae/settings.json
39
+ peaks hooks status --project <repo> --json 2>/dev/null
40
+ peaks statusline status --project <repo> --json 2>/dev/null
41
+ ```
42
+
43
+ The skill composes a 1-2 sentence **state summary** before asking anything:
44
+
45
+ > "I see you're on **Trae** (`.trae/` exists in the project root). peaks hooks are **not installed** yet. peaks statusline is **not installed** either. The `peaks hook handle` runtime is available as a CLI primitive — you don't need to install it separately; what needs installing is the settings.json entries that point to it."
46
+
47
+ The user gets a complete picture without having to answer any question. The next step only fires AskUserQuestion if intent is genuinely ambiguous.
48
+
49
+ ## Step 2: AskUserQuestion (only if intent is ambiguous)
50
+
51
+ If the user typed `/peaks-ide` without context, the skill's intent is genuinely ambiguous. The four canonical intents are:
52
+
53
+ | Option | What it does |
54
+ |---|---|
55
+ | First-time install | Run `peaks hooks install` + `peaks statusline install` for the detected IDE |
56
+ | Switch to a different IDE | Detect current install, uninstall from old IDE, install on new IDE (e.g. Claude → Trae) |
57
+ | Show current status | Just print the state summary from Step 1; no side effects |
58
+ | Uninstall peaks hooks | Run `peaks hooks uninstall` + `peaks statusline uninstall` for the detected IDE |
59
+
60
+ **Default option is "Show current status"** — the cheapest action, and the user gets useful output even if they didn't know what they wanted. AskUserQuestion is the ONLY place this skill asks anything. All destructive paths (Switch, Uninstall) gate on user confirmation here.
61
+
62
+ ## Step 3: plan & preview (dry-run)
63
+
64
+ Before any side effect, the skill prints the exact CLI invocations it will run. This is the "see before you leap" step.
65
+
66
+ ```
67
+ Plan: First-time install for Trae (.trae/ detected in project root)
68
+
69
+ 1. peaks hooks install --project <repo>
70
+ → writes a beforeToolCall hook entry to <root>/.trae/settings.json
71
+ that points to `peaks hook handle --project "${TRAE_PROJECT_DIR}"`
72
+
73
+ 2. peaks statusline install --project <repo>
74
+ → writes a statusLine field with command `peaks statusline`
75
+
76
+ 3. (no third command — `peaks hook handle` is the runtime; once the
77
+ settings.json entries point to it, the user's Trae will invoke it
78
+ on every PreToolUse event)
79
+
80
+ Verification: after install, re-run `peaks hooks status --project <repo>`
81
+ to confirm the entries are present.
82
+
83
+ Proceed? (Y/n)
84
+ ```
85
+
86
+ The plan MUST be human-readable. Don't run a side effect until the user confirms.
87
+
88
+ ## Step 4: execute
89
+
90
+ For each step in the plan, invoke the CLI primitive. The skill does NOT call out to a hidden script — it runs the actual peaks CLI commands, so the user sees the same output they'd see typing the command themselves.
91
+
92
+ ```bash
93
+ # Example: first-time Trae install
94
+ peaks hooks install --project <repo>
95
+ peaks statusline install --project <repo>
96
+
97
+ # After each command, check the exit code. If non-zero, STOP and report
98
+ # the failure to the user. The skill does NOT auto-rollback; the user
99
+ # decides what to do next.
100
+ ```
101
+
102
+ For destructive paths (Switch, Uninstall), the skill uses a **transactional pattern**: it captures the current state, runs the destructive CLI, then runs the install CLI; if any step fails, it reports the partial state and lets the user decide.
103
+
104
+ ## Step 5: audit log
105
+
106
+ Every successful execution writes one JSON line to `.peaks/_runtime/<sid>/ide-onboard.log`:
107
+
108
+ ```json
109
+ {"timestamp":"2026-06-06T19:55:00Z","intent":"first-time-install","detected_ide":"trae","cli_invocations":["peaks hooks install --project <repo>","peaks statusline install --project <repo>"],"outcome":"success","session_id":"2026-06-06-session-22f08c"}
110
+ ```
111
+
112
+ The audit log is **machine-readable** (so `peaks project dashboard` can read it and surface "you installed peaks for Trae on 2026-06-06") and **human-readable** (so the user can `cat` it to see the install history). The skill does NOT write the log file itself — it delegates to `peaks project dashboard` (the canonical log writer, per the dev-preference red line "skill-first for workflow, CLI-backed for gates / side effects"). The audit log writer is a CLI primitive, not a per-skill helper; the skill body MUST NOT introduce a new `peaks <cmd>` for the log writer.
113
+
114
+ ## Boundaries
115
+
116
+ `peaks-ide` may:
117
+
118
+ - detect the current IDE (cwd + env var + settings.json)
119
+ - ask the user via AskUserQuestion (Step 2 only)
120
+ - preview the CLI invocations (Step 3)
121
+ - execute existing peaks CLI commands (Step 4)
122
+ - write a single line to the audit log (Step 5)
123
+
124
+ `peaks-ide` must NOT:
125
+
126
+ - introduce new `peaks <cmd>` CLI commands (dev-preference red line: "Default-no on new CLI commands")
127
+ - bypass the user's confirmation on destructive paths (Switch / Uninstall)
128
+ - write the settings.json directly (the CLI primitives own that)
129
+ - run other peaks skills (peaks-solo, peaks-qa, etc.) — those are separate skills with their own scopes
130
+ - handle multi-IDE scenarios in slice #2 (e.g. "I use Claude at work and Trae at home" — the registry is single-IDE per session; a future slice could add multi-IDE)
131
+
132
+ ## Reference: the CLI primitives the skill composes
133
+
134
+ - `peaks hooks install` / `peaks hooks uninstall` / `peaks hooks status` — adapter-driven; auto-detects IDE from env / stdin / cwd
135
+ - `peaks statusline install` / `peaks statusline uninstall` / `peaks statusline status` — same
136
+ - `peaks hook handle` — the runtime handler; not installed, just invoked
137
+ - `peaks project dashboard --json` — surfaces the current state summary
138
+ - `peaks skill runbook` — surfaces the peaks-ide skill body for inspection
139
+
140
+ ## Next-step references
141
+
142
+ - The slice #1 RD artifact at `.peaks/_runtime/<sid>/rd/requests/002-2026-06-06-peaks-ide-skeleton.md` documents the slim `IdeAdapter` shape that the skill is built on.
143
+ - The slice #2 PRD at `.peaks/_runtime/<sid>/prd/requests/002-2026-06-06-trae-adapter-and-peaks-ide-skill.md` documents the 13 ACs this skill is part of.
144
+ - The slice #2 RD artifact (in flight) documents the implementation contract.
145
+
146
+ ## Default runbook
147
+
148
+ The skill is invoked as `/peaks-ide` or via the natural-language triggers listed in the frontmatter. The runbook is the body of this SKILL.md (steps 1-5 plus the boundaries and reference sections above); the runbook-service extracts the section between this `## Default runbook` heading and the next `##` heading.
149
+
150
+ When the user types `/peaks-ide` (or "set up peaks for my IDE" / "switch peaks to Trae" / "what did peaks install" / "uninstall peaks hooks"), execute Steps 1 → 5 in order:
151
+
152
+ 1. **Skill presence (MANDATORY first action)**: `peaks skill presence:set peaks-ide --project <repo> --gate startup` and `peaks project memories --project <repo> --json` (load durable memory).
153
+ 2. **Detect current state** (Step 1 above): `peaks project dashboard --project <repo> --json` + `peaks hooks status --project <repo> --json` + `peaks statusline status --project <repo> --json` + `ls -la <repo>/.claude 2>/dev/null` + `ls -la <repo>/.trae 2>/dev/null`. Build a 1-2 sentence state summary.
154
+ 3. **AskUserQuestion** (Step 2 above, only if intent is ambiguous). Default option: "Show current status". Destructive paths (Switch, Uninstall) gate on user confirmation here.
155
+ 4. **Plan & preview** (Step 3 above): print the exact `peaks hooks install` / `peaks statusline install` invocations before running them. Wait for "Proceed? (Y/n)".
156
+ 5. **Execute** (Step 4 above): run the `peaks hooks install` / `peaks statusline install` (or uninstall / status) commands. Stop on non-zero exit. Do not auto-rollback.
157
+ 6. **Audit log** (Step 5 above): delegate the JSONL write to `peaks project dashboard` (the canonical log writer; per the dev-preference red line, the skill MUST NOT introduce a new CLI primitive for the log writer).
158
+
159
+ CLI primitives the skill composes (per the "Reference" section above): `peaks skill presence:set`, `peaks project memories`, `peaks project dashboard`, `peaks hooks install` / `uninstall` / `status`, `peaks statusline install` / `uninstall` / `status`, `peaks hook handle`, `peaks skill runbook`. The skill does NOT introduce any new `peaks <cmd>` command.
@@ -60,8 +60,39 @@ This is the hard-block replacement for the previous "wait for the user" prose. W
60
60
 
61
61
  ## Sub-agent dispatch (when launched by peaks-solo swarm)
62
62
 
63
- 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:
63
+ 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:
64
64
 
65
+ ## QA fan-out (业务 + 性能 + 安全 并发, 业务可再分)
66
+
67
+ When peaks-qa is the **main loop** (i.e. it is the active skill and is about to run its own sub-agent dispatch, rather than being a sub-agent itself), it fans out the 3 QA review activities concurrently using the same `peaks sub-agent dispatch` primitive:
68
+
69
+ ```
70
+ peaks sub-agent dispatch qa-business \
71
+ --prompt "<qa-business contract, plus runtime args project=<repo>, session-id=<sid>, request-id=<rid>>" \
72
+ --request-id <rid> --session-id <sid> --project <repo> --json
73
+
74
+ peaks sub-agent dispatch qa-perf \
75
+ --prompt "<qa-perf contract, plus runtime args>" \
76
+ --request-id <rid> --session-id <sid> --project <repo> --json
77
+
78
+ peaks sub-agent dispatch qa-security \
79
+ --prompt "<qa-security contract, plus runtime args>" \
80
+ --request-id <rid> --session-id <sid> --project <repo> --json
81
+ ```
82
+
83
+ All three are issued in a single message; the LLM fires all 3 returned toolCalls in parallel; the IDE runs them concurrently; peaks-qa then collects the three envelopes and merges their outputs into:
84
+
85
+ - `.peaks/<sid>/qa/test-reports/<rid>.md` (business findings)
86
+ - `.peaks/<sid>/qa/performance-findings.md` (perf findings)
87
+ - `.peaks/<sid>/qa/security-findings.md` (security findings)
88
+
89
+ ## 业务测试细分 (optional)
90
+
91
+ If the PRD or project warrants it, subdivide `qa-business` further into roles like `qa-business-api` / `qa-business-frontend` / `qa-business-regression`; each gets its own `peaks sub-agent dispatch` call. Names are convention not contract — the dispatcher accepts any non-empty string. **Subdivision must stay ≤ 2 levels deep** (RL-4): `qa-business-api` is fine, `qa-business-api-user` is not. Two levels of depth is the empirical sweet spot — past that, the reducer cannot audit the boundaries between sub-agents, and prompts start overlapping.
92
+
93
+ For the full contract (heartbeat instructions for each sub-agent, batch-id discipline, 30s cadence, 100-truncation, 5min stale) see `skills/peaks-qa/references/qa-fanout-contract.md` and `skills/peaks-solo/references/sub-agent-dispatch.md` §G6.
94
+
95
+ - **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.
65
96
  - **Skill presence (MANDATORY first action)** — do NOT call `peaks skill presence:set peaks-qa`. 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-qa.json` and only that.
66
97
  - **Workspace initialization** — Solo has already run `peaks workspace init` before fan-out. Do not re-run it.
67
98
  - **Mode selection** — Solo has already chosen the mode.
@@ -525,3 +556,29 @@ Concrete rules and lint reference: `references/openspec-validation-gate.md`.
525
556
  Do not own product scope or implementation. Do not modify runtime configuration.
526
557
 
527
558
  Reference: `references/regression-gates.md`.
559
+
560
+ ## Sub-agent context governance (G7 + G7.7 + G8 + G9 — slice #010)
561
+
562
+ > QA sub-agents (qa / qa-business / qa-perf / qa-security) follow the same G7 metadata-only + G8.6 share protocol as RD. Detailed: `skills/peaks-solo/references/context-governance.md`.
563
+
564
+ ### G7 — QA sub-agent protocol
565
+
566
+ 1. Write test cases / perf baseline / security review to `.peaks/_sub_agents/<sid>/artifacts/<rid>-<role>-001.md` (path convention mandatory).
567
+ 2. Call `peaks sub-agent dispatch --write-artifact <path>` to register ArtifactMeta.
568
+ 3. Main LLM sees metadata-only view (~200 chars/QA sub-agent).
569
+
570
+ ### G8.6 — QA sub-agent prompt template
571
+
572
+ ```
573
+ You are sub-agent role qa-<subrole>, batch <batchId>.
574
+
575
+ PROTOCOL (mandatory):
576
+ 1. On start: `peaks sub-agent shared-read --batch <batchId> --json` to see sibling entries.
577
+ 2. While running: write share entry `peaks sub-agent share --key "qa-<subrole>.found-blocker" --value {"reason": "..."}` if a blocker is found.
578
+ 3. On completion: `peaks sub-agent share --key "qa-<subrole>.completed" --value <artifact-meta>` BEFORE final heartbeat (RL-23).
579
+ ```
580
+
581
+ ### G9 — QA prompt size self-check
582
+
583
+ Same as RD: 50% soft warn, 75% `CONTEXT_NEAR_LIMIT`, 80% hard reject unless `--force`. QA test plans can grow large; prefer `--use-headroom balanced` for plans > 75%.
584
+
@@ -0,0 +1,150 @@
1
+ # qa-fanout-contract.md — peaks-qa 3-way fan-out + business sub-division
2
+
3
+ > **Slice**: 2026-06-07-sub-agent-dispatch-decouple (G3 + G5 + G6)
4
+ > **Audience**: peaks-qa main loop and any future sub-role of peaks-qa
5
+ > **Status**: stable
6
+
7
+ This reference is the peaks-qa-specific contract for the 3-way fan-out
8
+ (business / perf / security) and the optional business sub-division
9
+ (`qa-business-api` / `qa-business-frontend` / `qa-business-regression` /
10
+ ...). peaks-qa is **itself a Dispatcher** (slice 2026-06-07 G1): when it
11
+ is the main loop, it fans out 3 sub-agents in one message via the
12
+ `peaks sub-agent dispatch <role>` primitive.
13
+
14
+ ## Why peaks-qa is a Dispatcher (not a Worker)
15
+
16
+ The user has been explicit: "peaks-qa 是需要的,因为可以同时进行
17
+ 业务测试,性能测试,安全测试。而且业务测试还是可以再分的". Three concerns
18
+ (business / perf / security) are **information-independent**:
19
+ - business validation exercises the user's expected behavior,
20
+ - perf baseline measures throughput / latency / memory,
21
+ - security review audits the trust boundary.
22
+
23
+ They have independent inputs (PRD / RD planning / codegraph for
24
+ business; perf-signals for perf; trust model for security), independent
25
+ outputs (different artifact paths), and can run concurrently without
26
+ sharing mutable state. peaks-qa fans them out so QA wall-clock drops
27
+ from "sum of all three" to "max of the three". Sub-dividing business
28
+ (`qa-business-api` etc.) further drops wall-clock when the business
29
+ slice is large.
30
+
31
+ The 2-level cap (RL-4) is empirical: past 2 levels, the reducer cannot
32
+ audit the boundaries between sub-agents and prompts start overlapping.
33
+
34
+ ## The 3-way fan-out
35
+
36
+ When peaks-qa is the main loop and the QA phase is about to run, it
37
+ issues 3 dispatch calls in a **single message**:
38
+
39
+ ```
40
+ peaks sub-agent dispatch qa-business \
41
+ --prompt "<qa-business contract below, plus runtime args: project=<repo>,
42
+ session-id=<sid>, request-id=<rid>.
43
+ Write your evidence at .peaks/<sid>/qa/test-reports/<rid>.md
44
+ and return ONLY the path. While running, call
45
+ peaks sub-agent heartbeat --record <dispatchRecordPath>
46
+ --status running --progress <pct> --note '<text>' at least every 30s;
47
+ on completion call --status done --progress 100 --note 'completed'." \
48
+ --request-id <rid> --session-id <sid> --project <repo> --json
49
+
50
+ peaks sub-agent dispatch qa-perf \
51
+ --prompt "<qa-perf contract below, plus runtime args; output .peaks/<sid>/qa/performance-findings.md>" \
52
+ --request-id <rid> --session-id <sid> --project <repo> --json
53
+
54
+ peaks sub-agent dispatch qa-security \
55
+ --prompt "<qa-security contract below, plus runtime args; output .peaks/<sid>/qa/security-findings.md>" \
56
+ --request-id <rid> --session-id <sid> --project <repo> --json
57
+ ```
58
+
59
+ The LLM reads the 3 `data.toolCall` descriptors from the envelopes and
60
+ fires all 3 in the same message (real concurrency). peaks-qa then
61
+ waits for all 3 to return, runs Gate B (`ls` checks on the 3 artifact
62
+ paths), and merges their findings into the QA verdict.
63
+
64
+ ## Business sub-division (optional)
65
+
66
+ If the project warrants it, `qa-business` can be split into:
67
+
68
+ - `qa-business-api` — REST / RPC / message-bus contracts
69
+ - `qa-business-frontend` — UI flows, component behavior, state machines
70
+ - `qa-business-regression` — re-run a curated test plan against the slice diff
71
+
72
+ Each gets its own `peaks sub-agent dispatch` call. The names are
73
+ **convention not contract** — the dispatcher accepts any non-empty
74
+ string. The recommended names above are hints, not a hard list.
75
+
76
+ **Cap (RL-4)**: ≤ 2 levels deep. `qa-business-api` is fine;
77
+ `qa-business-api-user` is not.
78
+
79
+ ## Independent inputs + independent artifacts
80
+
81
+ | Sub-agent | Reads | Writes | Must not depend on |
82
+ |---|---|---|---|
83
+ | `qa-business` (or subdivisions) | PRD body, RD planning, codegraph, project scan, existing system | `qa/test-reports/<rid>.md` | perf / security output (run in parallel) |
84
+ | `qa-perf` | RD planning, codegraph, perf baselines from prior slices | `qa/performance-findings.md` | business / security output |
85
+ | `qa-security` | PRD body (trust model), codegraph, RD planning, existing security notes | `qa/security-findings.md` | business / perf output |
86
+
87
+ The reducer merges all 3 outputs into the final QA verdict. None of
88
+ the 3 sub-agents reads another sub-agent's output (no peer-to-peer
89
+ messages — peaks is a pseudo-swarm, not a true bee colony).
90
+
91
+ ## Heartbeat instructions (G6)
92
+
93
+ Each sub-agent prompt must include the heartbeat instruction so the
94
+ parent peaks-qa can render a live status line during the wait. The
95
+ recommended paragraph (also auto-generated by peaks CLI):
96
+
97
+ ```
98
+ While running, call `peaks sub-agent heartbeat --record <dispatchRecordPath>
99
+ --status running --progress <pct> --note '<text>'` at least every 30 seconds.
100
+ On completion call `--status done --progress 100 --note 'completed'`. On
101
+ failure call `--status failed --note '<reason>'`. Do not skip heartbeats;
102
+ the parent peaks-qa uses them to render the live status line.
103
+ ```
104
+
105
+ The `heartbeatIntervalSec` value can be overridden in the peaks-qa
106
+ SKILL.md frontmatter (e.g. `heartbeatIntervalSec: 15` for fast QA
107
+ sub-agents that finish in <2 min).
108
+
109
+ ## Batch counter (RL-1)
110
+
111
+ peaks-qa is allowed up to 3 sub-agents in this fan-out by default. If
112
+ business is sub-divided, the total batch size is `1 (business) + 1 (perf)
113
+ + 1 (security) + N (business subdivisions) = 3 + N`. The peaks CLI
114
+ emits a `BATCH_OVER_LIMIT` warning if the dispatch count exceeds the
115
+ RL-1 empirical upper bound of 6, but does NOT block the dispatch (the
116
+ user has been explicit: "RL-1 is empirical; if you have a real reason
117
+ to go to 7, that's your call"). The warning goes into the dispatch
118
+ envelope and into the slice's `reducerReport`.
119
+
120
+ ## Resource lifecycle (G5)
121
+
122
+ - Each sub-agent dispatch writes a record to
123
+ `.peaks/_sub_agents/<sid>/dispatch-<rid>-<ts>.json` (RL-5).
124
+ - After the 3 sub-agents return, peaks-qa reducer marks each record
125
+ `disposed: true` + `disposedAt: <now>` (RL-7).
126
+ - A reducer-report is emitted with
127
+ `{ batchId, total: 3 + N, disposed, leaked: 0 }`. `leaked > 0` is a
128
+ user-visible warning (RL-11).
129
+ - Slice close archives the records to
130
+ `.peaks/_runtime/<sid>/_archive/_sub_agents/<slice-id>/` (RL-8).
131
+
132
+ ## Acceptance criteria covered
133
+
134
+ - AC-17 (peaks-qa 3-way fan-out + 业务可再分)
135
+ - AC-17b (peaks-ui说明行)
136
+ - AC-26 / AC-34 (dispatch record schema)
137
+ - AC-27 (RL-1 batch counter)
138
+ - AC-28 (reducer dispose)
139
+ - AC-29 (fan-out 原则)
140
+ - AC-33..AC-36 (G6 heartbeat + SKILL.md)
141
+ - AC-37 (E2E dogfood)
142
+
143
+ ## Cross-reference
144
+
145
+ - `skills/peaks-solo/references/sub-agent-dispatch.md` — orchestrator
146
+ contract for all Dispatchers
147
+ - `skills/peaks-solo/SKILL.md` "Peaks-Cli Swarm parallel phase" — sibling
148
+ fan-out pattern
149
+ - `.peaks/memory/sub-agent-resource-lifecycle-red-line.md` — G5 red line
150
+ - `.peaks/memory/sub-agent-heartbeat-progress-red-line.md` — G6 red line
@@ -37,8 +37,9 @@ The full hard-block contract is defined in `peaks-qa` (see "Hard contracts for b
37
37
 
38
38
  ## Sub-agent dispatch (when launched by peaks-solo swarm)
39
39
 
40
- 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:
40
+ 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:
41
41
 
42
+ - **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.
42
43
  - **Skill presence (MANDATORY first action)** — do NOT call `peaks skill presence:set peaks-rd`. 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-rd.json` and only that.
43
44
  - **Workspace initialization** — Solo has already run `peaks workspace init` before fan-out. Do not re-run it.
44
45
  - **Mode selection** — Solo has already chosen the mode. Read it from the prompt arguments (or from `.peaks/.active-skill.json` if you can, but do not write it).
@@ -46,7 +47,7 @@ When this skill is launched as a sub-agent via `Task(subagent_type="general-purp
46
47
 
47
48
  What the sub-agent **MUST** still do, from this skill's contract:
48
49
 
49
- 0. **Do NOT call `peaks request init`** — Solo has already initialised the request artefact slot in the main loop before fan-out (the runbook has the exact `peaks request init --role rd --id <rid> --project <repo> --apply --type <type> --json` call). The sub-agent reads the slot via `peaks request show <rid> --role rd --project <repo> --json` if it needs to.
50
+ 0. **Do NOT call `peaks request init`** — Solo has already initialised the request artefact slot in the main loop before fan-out (the runbook has the exact `peaks request init --role rd --id <rid> --project <repo> --apply --type <type> --json` call). The sub-agent reads the slot via `peaks request show <rid> --role rd --project <repo> --json` if it needs to. Note: `peaks request init` is **dry-run by default**. Pass `--apply` to actually create the artifact.
50
51
  2. `peaks request show <rid> --role prd --project <repo> --json` (and `--role ui` if UI is in the swarm plan).
51
52
  3. Standards preflight (dry-run only; Solo owns the apply step).
52
53
  4. Project-scan read; create `rd/project-scan.md` only if Solo flagged it missing in the dispatch prompt.
@@ -565,7 +566,7 @@ If any gate fails, return to development for fixes or hand off as blocked. Do no
565
566
 
566
567
  ## Parallel review fan-out (code-review + security-review + perf-baseline + qa-test-cases)
567
568
 
568
- **When RD reaches the end of implementation, the four review activities (code review, security review, perf baseline, AND QA test-cases draft) run in parallel via Task() sub-agents, not sequentially.** This is the same fan-out pattern peaks-solo uses for the post-PRD swarm (see `peaks-solo/SKILL.md` "Peaks-Cli Swarm parallel phase" L659-764). RD itself, when it is the main loop, behaves as a sub-agent orchestrator: it issues 4 Task() calls in a single message and waits for all to return before aggregating findings and transitioning to `qa-handoff`.
569
+ **When RD reaches the end of implementation, the four review activities (code review, security review, perf baseline, AND QA test-cases draft) run in parallel via `peaks sub-agent dispatch <role>` (then executing the returned toolCall), not sequentially.** This is the same fan-out pattern peaks-solo uses for the post-PRD swarm (see `peaks-solo/SKILL.md` "Peaks-Cli Swarm parallel phase" L659-764). RD itself, when it is the main loop, behaves as a sub-agent orchestrator: it issues 4 `peaks sub-agent dispatch` calls in a single message and waits for all to return before aggregating findings and transitioning to `qa-handoff`.
569
570
 
570
571
  **Why 4 sub-agents (added in slice 004):** the original 3-way fan-out (code-review + security-review + perf-baseline) cut the RD→QA wall-clock by running 3 LLM writes in parallel, but `qa/test-cases/<rid>.md` was still written sequentially by QA's main loop AFTER the RD handoff landed. Drafting QA test-cases in the same fan-out means the QA main loop's first action is "execute the pre-drafted test plan + write test-report" instead of "draft a test plan from scratch + execute + write report". Wall-clock drop: ~30-40% on the RD→QA-verdict segment for `feature` / `refactor` / `bugfix` slices.
571
572
 
@@ -574,14 +575,18 @@ If any gate fails, return to development for fixes or hand off as blocked. Do no
574
575
  - Bugfix slices: code-review + security-review + qa-test-cases always run; perf-baseline runs only when the bug is performance-shaped (matches the "When this applies" criteria in the perf-baseline section above).
575
576
  - Config / docs / chore slices: no fan-out (no review surface). Document N/A in the request artifact. (qa-test-cases also skipped — config / docs / chore have no acceptance surface to validate.)
576
577
 
577
- **The Task() template (mirror of peaks-solo L705-717):**
578
+ **The dispatch template (mirror of peaks-solo L705-717):**
578
579
 
579
580
  ```
580
- Task(
581
- subagent_type="general-purpose",
582
- description="<role> review for rid=<rid>",
583
- prompt="<role contract below>, plus runtime args: project=<repo>, session-id=<sid>, request-id=<rid>. Write your evidence file at .peaks/<sid>/<evidence-path> and return ONLY the path. Do not call Skill(...). Do not set presence. Do not prompt the user. Do not commit, push, install hooks, or mutate settings.json. Do not edit any source file — review only."
584
- )
581
+ peaks sub-agent dispatch <role> \
582
+ --prompt "<role contract below>, plus runtime args: project=<repo>, session-id=<sid>, request-id=<rid>.
583
+ Write your evidence file at .peaks/<sid>/<evidence-path> and return ONLY the path.
584
+ Do not call Skill(...). Do not set presence. Do not prompt the user. Do not commit, push,
585
+ install hooks, or mutate settings.json. Do not edit any source file — review only.
586
+ While running, call peaks sub-agent heartbeat --record <dispatchRecordPath>
587
+ --status running --progress <pct> --note \"<text>\" at least every 30 seconds;
588
+ on completion call --status done --progress 100 --note 'completed'." \
589
+ --request-id <rid> --session-id <sid> --project <repo> --json
585
590
  ```
586
591
 
587
592
  Note: sub-agents 1-3 write to `rd/<evidence-path>`, sub-agent 4 writes to `qa/test-cases/<rid>.md` (QA's dir). The role name in the description differentiates them.
@@ -790,3 +795,41 @@ Do not bypass PRD/QA artifacts. Do not install hooks, agents, MCP, or settings.
790
795
  Do not bypass the parallel review fan-out when the slice has a code-review / security-review / perf-baseline surface — see `## Parallel review fan-out` above for the contract. The three review activities are fan-out, not sequential; sequential re-implementation of the same logic by the main RD loop defeats the wall-clock benefit and is treated as a red-line violation.
791
796
 
792
797
  Reference: `references/refactor-workflow.md`.
798
+
799
+ ## Sub-agent context governance (G7 + G7.7 + G8 + G9 — slice #010)
800
+
801
+ > Slice #010 implements the G7 + G7.7 + G8 + G9 red lines from slice #009 closeout. RD sub-agent prompt template MUST include the G7 path convention + G8.6 share protocol. Detailed protocol: `skills/peaks-solo/references/context-governance.md` + `skills/peaks-solo/references/headroom-integration.md`.
802
+
803
+ ### G7 — RD sub-agent protocol
804
+
805
+ 1. Write artifact to `.peaks/_sub_agents/<sid>/artifacts/<rid>-rd-001.md` (path convention mandatory).
806
+ 2. Call `peaks sub-agent dispatch --write-artifact <path>` (or via the dispatch CLI flag) to register ArtifactMeta.
807
+ 3. The dispatch record stores only `path + size + sha256 + status + contentInlined:false + summary` — main LLM sees ~200 chars/sub-agent.
808
+
809
+ ### G8.6 — RD sub-agent prompt template (mandatory)
810
+
811
+ Sub-agent prompts dispatched by peaks-rd must include:
812
+
813
+ ```
814
+ You are sub-agent role rd, batch <batchId>.
815
+
816
+ PROTOCOL (mandatory):
817
+ 1. On start: peek at shared channel: `peaks sub-agent shared-read --batch <batchId> --json`
818
+ to see what other sub-agents in this batch have shared so far.
819
+ 2. While running: if you find a blocker or partial work, write share entry
820
+ `peaks sub-agent share --key "rd.found-blocker" --value {"reason": "..."}`.
821
+ 3. On completion: write share entry
822
+ `peaks sub-agent share --key "rd.completed" --value <artifact-meta>` BEFORE the
823
+ final `peaks sub-agent heartbeat --status done` heartbeat (RL-23 strong constraint).
824
+ 4. The shared channel is your only visibility into sibling sub-agents.
825
+ Do NOT attempt to read other sub-agents' dispatch records directly.
826
+ ```
827
+
828
+ ### G9 — RD prompt size self-check
829
+
830
+ Before dispatching a sub-agent, RD self-checks prompt size:
831
+ - < 50%: pass through.
832
+ - 50-75%: soft warn (consider `--use-headroom`).
833
+ - 75-80%: soft warn + `warnings: ["CONTEXT_NEAR_LIMIT"]` (mandatory suggest `--use-headroom`).
834
+ - 80%+: reject (CLI 兜底 returns `code: "PROMPT_TOO_LARGE"`). Use `--force` at CLI only when overriding; hook layer will still reject (RL-30).
835
+