peaks-cli 1.2.4 → 1.2.6

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 (29) hide show
  1. package/bin/peaks.js +0 -0
  2. package/dist/src/cli/commands/openspec-commands.js +31 -0
  3. package/dist/src/cli/commands/workspace-commands.js +50 -4
  4. package/dist/src/services/config/config-safety.d.ts +26 -0
  5. package/dist/src/services/config/config-safety.js +76 -0
  6. package/dist/src/services/config/config-service.d.ts +1 -1
  7. package/dist/src/services/config/config-service.js +2 -2
  8. package/dist/src/services/memory/project-memory-service.d.ts +18 -0
  9. package/dist/src/services/memory/project-memory-service.js +131 -13
  10. package/dist/src/services/openspec/openspec-init-service.d.ts +23 -0
  11. package/dist/src/services/openspec/openspec-init-service.js +122 -0
  12. package/dist/src/services/session/index.d.ts +1 -1
  13. package/dist/src/services/session/index.js +1 -1
  14. package/dist/src/services/session/session-manager.d.ts +11 -0
  15. package/dist/src/services/session/session-manager.js +19 -0
  16. package/dist/src/services/skills/skill-presence-service.js +11 -0
  17. package/dist/src/services/workspace/workspace-service.d.ts +15 -0
  18. package/dist/src/services/workspace/workspace-service.js +60 -1
  19. package/dist/src/shared/version.d.ts +1 -1
  20. package/dist/src/shared/version.js +1 -1
  21. package/package.json +1 -1
  22. package/skills/peaks-prd/SKILL.md +36 -0
  23. package/skills/peaks-qa/SKILL.md +91 -2
  24. package/skills/peaks-rd/SKILL.md +69 -2
  25. package/skills/peaks-solo/SKILL.md +249 -41
  26. package/skills/peaks-solo/references/a2a-artifact-mapping.md +115 -0
  27. package/skills/peaks-solo/references/swarm-dispatch-contract.md +186 -0
  28. package/skills/peaks-txt/SKILL.md +16 -0
  29. package/skills/peaks-ui/SKILL.md +61 -2
@@ -9,6 +9,16 @@ Peaks-Cli Solo is the orchestration facade for the Peaks-Cli short skill family.
9
9
 
10
10
  Use this skill to identify the user scenario, recommend an execution mode, coordinate role skills, and produce the final handoff report. Do not collapse role responsibilities into this skill.
11
11
 
12
+ ## Skill-first architecture note (read once, internalise)
13
+
14
+ This skill is the **primary surface**. The `peaks <cmd>` CLI is **auxiliary** — invoked by the skill prompt when a primitive is the right tool (atomic side effect, machine-enforced gate, structured JSON for a downstream decision, or backstop the LLM cannot skip). Concretely:
15
+
16
+ - Behaviour that only an LLM in a skill prompt would use (e.g. "scan a handoff for memory blocks", "decide if a stable fact deserves persistence") lives **here in the SKILL.md**, not as a new CLI command.
17
+ - The CLI earns its keep when it is (a) hook- / script- / CI-invokable, (b) the consumer needs a structured JSON envelope to gate a downstream decision, or (c) it is a destructive side effect that needs an explicit `--apply` opt-in.
18
+ - When you reach for `peaks <X> --project <repo> --json` in a runbook step, that command is the **contract** you are calling; the LLM work around it (deciding what to pass, interpreting the response, deciding the next step) is what this skill owns.
19
+
20
+ See `.claude/rules/common/dev-preference.md` for the full dev policy and the decision template. The user-facing consequence: every iteration on this skill and the rest of the peaks-* family is judged first by "is this skill work or CLI work?", and only the latter opens a new command.
21
+
12
22
  ## Code-Change Red Line (BLOCKING — read before ANY tool call)
13
23
 
14
24
  **Peaks-Cli Solo is an orchestrator, NOT an implementer. You MUST NOT write, edit, or modify any application source code directly.**
@@ -17,12 +27,12 @@ Every code change — bugfix, feature, refactor, or config — MUST go through t
17
27
 
18
28
  ```
19
29
  peaks-solo (orchestrate only)
20
- Skill(skill="peaks-rd") ← ALL code changes happen HERE
30
+ RD work ← ALL code changes happen HERE
21
31
  → Unit tests written + pass (Peaks-Cli Gate B2)
22
32
  → Karpathy standards enforced (file-size ≤800 lines, TypeScript rules)
23
33
  → Code review evidence (Peaks-Cli Gate B3)
24
34
  → Security review evidence (Peaks-Cli Gate B4)
25
- Skill(skill="peaks-qa") ← ALL validation happens HERE
35
+ QA work ← ALL validation happens HERE
26
36
  → Functional test execution (Peaks-Cli Gate A2)
27
37
  → Performance check (Peaks-Cli Gate A4)
28
38
  → Security test (Peaks-Cli Gate A3)
@@ -30,35 +40,83 @@ peaks-solo (orchestrate only)
30
40
  → Verdict: pass | return-to-rd | blocked
31
41
  ```
32
42
 
43
+ **Mechanism for "RD work" / "QA work" depends on the orchestration mode** (full details in "Peaks-Cli Swarm parallel phase" and "How Solo invokes another role"):
44
+
45
+ | Mode | Swarm side (after PRD) | Repair loop side (RD↔QA) |
46
+ |---|---|---|
47
+ | `full-auto` / `swarm` | `Task(subagent_type="general-purpose")` sub-agent running `peaks-rd`/`peaks-qa`/`peaks-ui` body | `Task(...)` sub-agent per cycle |
48
+ | `assisted` / `strict` / inline-fallback | Solo executes the role steps inline in the main loop (the `peaks-solo` skill IS the role's owner) | Solo executes inline |
49
+
50
+ In all modes, the work itself follows the same `peaks-rd` and `peaks-qa` contracts. The only difference is whether the role's body is being read by a sub-agent Task prompt or by Solo's own main loop. **Never bypass the role contracts regardless of which path runs.**
51
+
33
52
  **Violations (BLOCKING — Solo must refuse to proceed):**
34
53
 
35
- 1. Writing implementation code directly instead of calling `Skill(skill="peaks-rd")`
36
- 2. Declaring work "done" without invoking `Skill(skill="peaks-qa")` after RD
54
+ 1. Writing implementation code directly instead of routing through the RD contract (whether inline or via sub-agent)
55
+ 2. Declaring work "done" without producing QA evidence after RD
37
56
  3. Skipping unit tests ("it's a small change")
38
57
  4. Skipping code review or security review
39
58
  5. Skipping QA functional/performance/security validation
40
59
 
41
- **If you catch yourself about to write code in this skill, STOP. Call `Skill(skill="peaks-rd")` instead.**
60
+ **If you catch yourself about to write code in this skill, STOP. Hand off to the RD contract path immediately** (sub-agent Task in full-auto, inline execution in assisted/strict).
42
61
 
43
62
  **Before declaring workflow complete, run:** `peaks workflow verify-pipeline --rid <rid> --project <repo> --json`
44
63
 
45
64
  ## Peaks-Cli Startup sequence (MANDATORY — execute in order)
46
65
 
47
- ### Peaks-Cli Step 0: Anchor the workflow (MANDATORY FIRST ACTIONS — no bail-out)
66
+ ### Peaks-Cli Step 0.5: OpenSpec first-run opt-in (conditional)
48
67
 
49
- The instant Peaks-Cli Solo is invoked, **before** the mode-selection question, before any analysis, and before you decide whether the request "needs" the full pipeline, you MUST run these two commands and see their output:
68
+ After the workspace is anchored, before project scan, Solo checks whether
69
+ the project already has an `openspec/` directory. The lifecycle
70
+ (`render → validate → show → to-rd → validate → archive`) only applies
71
+ when `openspec/` exists; without it, RD/QA/SC silently skip the
72
+ openspec-aware paths and you lose change-proposal tracking, commit
73
+ boundaries from `tasks.md`, and the historical archive.
74
+
75
+ To make that opt-in visible instead of silent, Solo runs:
50
76
 
51
77
  ```bash
52
- # Session ID is auto-generated when omitted; the command returns it in the JSON output
53
- peaks workspace init --project <repo> --json
54
- peaks skill presence:set peaks-solo --project <repo> --gate startup
78
+ # 1. Detect whether the project already has openspec/.
79
+ ls <repo>/openspec/changes 2>&1
80
+ # 2. If absent, ask the user once — only on the first Solo run in this
81
+ # project. The decision is sticky: write it to .peaks/.peaks-openspec-opt-in.json
82
+ # so subsequent Solo invocations do not re-ask.
83
+ test -f <repo>/.peaks/.peaks-openspec-opt-in.json || \
84
+ echo "{\"enabled\": <bool>}" > <repo>/.peaks/.peaks-openspec-opt-in.json
55
85
  ```
56
86
 
57
- If `workspace init` fails with "required option '--session-id' not specified", the CLI version predates auto-generation. Generate a session ID manually and pass it:
87
+ **AskUserQuestion** (only when `openspec/` is absent and the opt-in
88
+ file is missing):
89
+
90
+ | Option | What it does |
91
+ |---|---|
92
+ | Enable OpenSpec for this project (Recommended) | Run `peaks openspec init --project <repo> --apply`. After that, every Solo run uses the change-proposal lifecycle for the same project. |
93
+ | Skip for now | Do nothing. Solo proceeds without openspec; the question is re-asked on the next first-run detection. |
94
+ | Never ask again for this project | Write `{enabled: false, sticky: true}`. Solo stops asking. The user can re-enable later by removing `.peaks/.peaks-openspec-opt-in.json` and re-running. |
95
+
96
+ The first option is the recommended default because it gives Solo the
97
+ full change-proposal lifecycle (proposal / tasks / design / specs
98
+ deltas, archive on ship, commit boundaries from `tasks.md`). It costs
99
+ only a single scaffolded directory and pays back the first time the
100
+ project needs a real review trail.
101
+
102
+ If the user picks "Enable", the only required follow-up is to make
103
+ sure `openspec/changes/` is added to git (it is part of the project
104
+ repo, not a tool-managed artefact). Solo does not run `git add` for
105
+ the user; that is the user's commit boundary.
106
+
107
+ ### Peaks-Cli Step 0: Anchor the workflow (MANDATORY FIRST ACTIONS — no bail-out)
108
+
109
+ The instant Peaks-Cli Solo is invoked, **before** the mode-selection question, before any analysis, and before you decide whether the request "needs" the full pipeline, you MUST run these two commands and see their output:
58
110
 
59
111
  ```bash
60
- SESSION_ID="$(date +%Y-%m-%d)-session-$(openssl rand -hex 3)"
61
- peaks workspace init --project <repo> --session-id "$SESSION_ID" --json
112
+ # Session ID is auto-generated when omitted; the command returns it in the JSON output.
113
+ # Do NOT pass --session-id manually — the CLI is the single source of truth for the
114
+ # project session binding. If you forge a session id with `openssl rand` and pass it
115
+ # via --session-id, peaks workspace init will write it to .peaks/.session.json but
116
+ # the binding only sticks if no prior session is open. To avoid the "two sessions
117
+ # in .peaks/" confusion that bites Solo, always omit --session-id here and let the
118
+ # CLI auto-generate.
119
+ peaks workspace init --project <repo> --json
62
120
  peaks skill presence:set peaks-solo --project <repo> --gate startup
63
121
  ```
64
122
 
@@ -68,6 +126,9 @@ peaks skill presence:set peaks-solo --project <repo> --gate startup
68
126
 
69
127
  **Anti-bail-out rule (BLOCKING):** You MUST NOT exit the peaks-solo workflow, hand control back, or produce a final answer before Step 0 has run. If you catch yourself thinking "this is just analysis, I don't need the workflow" — STOP. Run Step 0, set presence, then continue. A pure-analysis request runs the **lightweight analysis branch** (project scan + standards dry-run + handoff with a Standards-increment section), but it still anchors the workspace and keeps presence active. Declining to anchor is a workflow violation.
70
128
 
129
+ **Session conflict resolution (read once, internalise):** If `peaks workspace init` returns `code: "CONFLICTING_SESSION"` with a body like
130
+ `{"existingSessionId":"<Y>","requestedSessionId":"<X>"}`, the project is already bound to a different in-flight session `<Y>` (the one you or a prior run was working on). The fix is **NOT** to pass `--allow-session-rebind` to clobber `<Y>` — that destroys an active session's data. Instead: finish or abandon `<Y>` first (use `peaks session list --json` to see what it is, then `peaks session finish --id <Y>` or `peaks session abandon --id <Y>` — see your session command's help for the exact verbs). Only after `<Y>` is closed should you re-run `peaks workspace init`. The same rule applies to `peaks workspace init --session-id "<manually-forged>"` — do not pre-forge session ids; the CLI's auto-generated value is the binding.
131
+
71
132
  `presence:set` accepts no `--mode` here on purpose — mode is unknown until Step 1. It is re-run with the selected mode in Step 2. Setting presence early guarantees the status header/line shows `peaks-solo` from the very first turn even if the user never reaches mode selection.
72
133
 
73
134
  ### Peaks-Cli Step 1: Mode selection
@@ -595,19 +656,112 @@ ls <repo>/.claude/rules/common/coding-style.md \
595
656
  ```
596
657
 
597
658
 
598
- ## Peaks-Cli Swarm parallel phase
659
+ ## Peaks-Cli Swarm parallel phase (sub-agent fan-out, conditional)
660
+
661
+ The Swarm phase is **conditional**, not unconditional. It only runs when there is a real, user-confirmed requirement. Solo derives the fan-out set from the PRD type and the request content — never from a default of "always launch three".
599
662
 
600
- After PRD reaches `confirmed-by-user`, Solo launches peaks-ui, peaks-rd(planning), and peaks-qa(test-cases) simultaneously using parallel Agent calls. All three derive independently from the same PRD and write to separate artifact paths. Solo waits for all three, checks convergence (Peaks-Cli Gate B), then enters RD implementation.
663
+ ### Swarm gate (decide BEFORE fan-out)
601
664
 
602
- ### Degradation when swarm roles fail
665
+ Before launching any sub-agent, Solo must compute the **swarm plan** from three signals:
603
666
 
604
- 1. **UI missing**: RD continues with PRD visual descriptions; note "ui-design-missing" in TXT.
605
- 2. **RD planning missing**: RD continues; note "tech-doc-missing" in TXT.
606
- 3. **QA test-cases missing**: RD continues; QA must backfill test cases before issuing verdict.
607
- 4. **Two or more missing**: Fall back to sequential mode (PRD RD QA); note "swarm-degraded-to-sequential".
608
- 5. **All three missing**: Pause workflow; report to user; request confirmation to continue.
667
+ 1. **PRD state** `prd/requests/<rid>.md` must be in state `confirmed-by-user` or `handed-off`. If not, STOP. The Swarm is downstream of PRD, not a substitute for it.
668
+ 2. **Request type** (`--type` from `peaks request init`):
669
+ - `feature` / `refactor` / `bugfix` RD(planning) and QA(test-cases) are always in the swarm
670
+ - `config` / `docs` / `chore` → no swarm. RD/QA artefacts are not required by Gates B/C/D for these types. Skip the Swarm phase entirely and proceed to step 4 (RD implementation) with only the PRD in hand.
671
+ 3. **Frontend touch** does the request affect user-visible behavior? This is decided by:
672
+ - Reading `.peaks/<session-id>/rd/project-scan.md` `## Project mode` for `frontendOnly` (project-shape signal)
673
+ - **AND** scanning the PRD body for frontend keywords: 页面 / 组件 / 表单 / 弹窗 / 表格 / 样式 / 布局 / 交互 / UI / UX / page / component / form / modal / table / styling / layout / interaction
674
+ - UI joins the swarm when (a) is `true` OR (b) matches. Both signals required `false` to skip UI.
609
675
 
610
- **UI phase mandatory for frontend**: When the request affects user-visible behavior (pages, components, forms, modals, tables, styling, interaction, or layout), Peaks-Cli Solo MUST invoke `peaks-ui` in the swarm parallel phase alongside RD planning and QA test-case generation. UI produces design drafts that RD implementation later consumes. Skipping UI for frontend work is a blocking violation. The only valid reason to skip UI is when the request is purely backend (API, database, CLI, config, or build tooling).
676
+ Solo records the swarm plan in `.peaks/<session-id>/sc/swarm-plan.json` so SC and TXT can audit what was launched:
677
+
678
+ ```json
679
+ {
680
+ "rid": "<rid>",
681
+ "type": "feature",
682
+ "frontendOnly": true,
683
+ "frontendKeywordHit": true,
684
+ "subAgents": ["ui", "rd-planning", "qa-test-cases"]
685
+ }
686
+ ```
687
+
688
+ Sub-agent presence in this list = Solo launched a Task for it. Absence = the role was skipped with documented reason.
689
+
690
+ ### Mode-driven fan-out shape
691
+
692
+ | Mode | How the swarm plan is decided | What Solo does |
693
+ |---|---|---|
694
+ | `full-auto` | Compute plan from signals above, no question to user | Auto-launch all sub-agents in the plan in parallel |
695
+ | `swarm` | Same as `full-auto` | Same as `full-auto` (this profile name is historical — behavior is identical) |
696
+ | `assisted` | `AskUserQuestion` with three options: (a) Full — UI + RD(planning) + QA(test-cases); (b) Backend-only — RD(planning) + QA(test-cases); (c) Sequential — run RD first, then QA, skip UI | Use the user's choice as the plan |
697
+ | `strict` | Same as `assisted` (the question is informational; strict still enforces confirmation gates later) | Same as `assisted` |
698
+
699
+ In all modes, **the plan must be written to `sc/swarm-plan.json` before any Task call.** Solo updates `.peaks/.active-skill.json` to `gate=swarm-fan-out` at this point.
700
+
701
+ ### Sub-agent mechanism (Task tool, NOT Skill tool)
702
+
703
+ **Solo is itself a skill running in the current session. To invoke a role in the Swarm, Solo MUST use the `Task` tool with `subagent_type="general-purpose"` and a prompt that embeds the role's contract — NOT the `Skill` tool.** The `Skill` tool is single-stack and blocking; using it for "parallel" work was the v1.x illusion of concurrency. The Task tool is the only mechanism that gives real fan-out in Claude Code.
704
+
705
+ Each sub-agent Task call looks like:
706
+
707
+ ```
708
+ Task(
709
+ subagent_type="general-purpose",
710
+ description="<role> for rid=<rid>",
711
+ prompt="<paste peaks-<role>/SKILL.md body, minus the self-presence / Step 0 blocks, plus
712
+ the runtime arguments: project=<repo>, session-id=<sid>, request-id=<rid>, mode=<mode>>
713
+ plus the explicit output contract: 'Write your artefacts to the paths listed below and
714
+ return only the list of paths. Do not call Skill(...). Do not set presence. Do not
715
+ hand back prose.'"
716
+ )
717
+ ```
718
+
719
+ The role's required artefact paths (also see peaks-ui/rd/qa SKILL.md and `references/swarm-dispatch-contract.md`):
720
+
721
+ | Role | Writes | Reads (PRD-side) |
722
+ |---|---|---|
723
+ | `ui` | `.peaks/<sid>/ui/design-draft.md`, `.peaks/<sid>/ui/requests/<rid>.md` | PRD body, project-scan, archetype |
724
+ | `rd-planning` | `.peaks/<sid>/rd/tech-doc.md` (feature/refactor) or `.peaks/<sid>/rd/bug-analysis.md` (bugfix) | PRD body, project-scan, existing-system, codegraph |
725
+ | `qa-test-cases` | `.peaks/<sid>/qa/test-cases/<rid>.md` | PRD body, RD planning artefact, project-scan, codegraph |
726
+
727
+ **Solo launches all sub-agents in the swarm plan in a single message (multiple Task tool calls in parallel)** — this is what gives real concurrency. Do not sequentialize them. Solo then waits for all to return, runs `ls` checks against the paths above (Peaks-Cli Gate B), and only then advances to RD implementation.
728
+
729
+ **Hard prohibitions on sub-agents** (also passed in each Task prompt):
730
+
731
+ - Do NOT call `Skill(skill="...")` — sub-agents must not recursively activate skills, that defeats the fan-out.
732
+ - Do NOT call `peaks skill presence:set` — only the main Solo loop owns `.peaks/.active-skill.json`. Sub-agents write to a per-agent marker file `.peaks/<sid>/system/sub-agent-<role>.json` if they need to record state, but never the main presence file.
733
+ - Do NOT open interactive user prompts. If a sub-agent needs clarification, it must return a `blocked` verdict in its return string and let Solo handle the user message.
734
+ - Do NOT commit, push, install hooks, or apply settings.json mutations. Only Solo holds those permissions.
735
+
736
+ After every sub-agent Task returns, Solo **restores presence** once (not per-agent), then continues to Gate B verification:
737
+
738
+ ```bash
739
+ peaks skill presence:set peaks-solo --project <repo> --mode <mode> --gate swarm-converged
740
+ ```
741
+
742
+ ### Degradation when swarm roles fail or are absent
743
+
744
+ | Condition | Solo action | TXT handoff note |
745
+ |---|---|---|
746
+ | UI sub-agent returns blocked/error | RD continues with PRD visual descriptions | `ui-design-missing` |
747
+ | RD planning sub-agent returns blocked/error | RD continues with PRD-derived planning | `tech-doc-missing` |
748
+ | QA test-cases sub-agent returns blocked/error | RD continues; QA backfills test cases before verdict | `qa-test-cases-missing` |
749
+ | Two or more of the above | Fall back to sequential: `peaks request transition rd → spec-locked` then inline RD run, then QA | `swarm-degraded-to-sequential` |
750
+ | All three fail | Pause workflow; surface to user; request confirmation to continue | `swarm-aborted` |
751
+
752
+ Skipping the entire swarm (when `--type` is `config|docs|chore`) is not a degradation — record `swarm-skipped: type=<type>` and proceed.
753
+
754
+ ### Frontend-only trigger pre-flight
755
+
756
+ Before computing the swarm plan, Solo runs the keyword scan deterministically:
757
+
758
+ 1. Read `.peaks/<session-id>/prd/requests/<rid>.md` body.
759
+ 2. Lowercase + strip markdown; check regex `\b(页面|组件|表单|弹窗|表格|样式|布局|交互|UI|UX|page|component|form|modal|table|styling|layout|interaction|frontend|前端)\b`.
760
+ 3. If match count ≥ 1 → `frontendKeywordHit=true`.
761
+ 4. If `frontendOnly` (from project-scan) is `true` and no keyword hit → UI joins anyway (frontend-only project, even non-visual changes may need visual sanity for regressions).
762
+ 5. If `frontendOnly` is `false` and no keyword hit → UI skipped.
763
+
764
+ Solo records the pre-flight result in `sc/swarm-plan.json` so the audit trail shows why UI was or was not included.
611
765
 
612
766
  ## Peaks-Cli Mandatory RD QA repair loop (AUTO-PROCEED)
613
767
 
@@ -622,19 +776,24 @@ After PRD reaches `confirmed-by-user`, Solo launches peaks-ui, peaks-rd(planning
622
776
 
623
777
  After `peaks-rd` finishes any implementation, repair, or code-output slice, Peaks-Cli Solo MUST automatically route the result to `peaks-qa` without waiting for user confirmation. This is not optional in full-auto mode. Solo must not declare the workflow complete, emit a TXT handoff, or stop at RD completion.
624
778
 
625
- **How Solo invokes another role skill (mechanism, not metaphor):**
779
+ **How Solo invokes another role (mechanism, not metaphor):**
780
+
781
+ Solo is itself a skill running in the current session. There are **two distinct mechanisms** in this skill, and they MUST NOT be confused:
782
+
783
+ 1. **Swarm fan-out (planning side, after PRD confirmed)** — uses the `Task` tool with `subagent_type="general-purpose"` to launch real concurrent sub-agents. See "Peaks-Cli Swarm parallel phase" above for the full contract. Sub-agents do NOT call Skill(...) back into the role; they execute the role's instructions inline from the prompt.
784
+ 2. **Sequential handoff (execution side, RD↔QA repair loop)** — Solo is the only loop, and after RD or QA finishes (whether as a sub-agent or directly), Solo drives the next step from the orchestrator seat. Do NOT use the `Skill` tool to "reactivate" peaks-rd or peaks-qa in the main loop; doing so is the v1.x anti-pattern that masqueraded as "calling the role" but actually just re-prompted the same session. From v1.3 onward, the main loop drives roles via the CLI gate (`peaks request transition`) and reads back artefacts (`peaks request show ... --json`); the actual RD/QA work is either done inline by Solo (when Solo has just been re-invoked by the user) or by a Task sub-agent (in swarm mode).
626
785
 
627
- Solo is itself a skill running in the current session. To "invoke peaks-rd" or "peaks-qa", Solo MUST use the `Skill` tool with the role's name (e.g. `Skill(skill="peaks-rd")` or `Skill(skill="peaks-qa")`), passing the `<request-id>` and `<session-id>` as arguments so the role reads the same artifacts Solo wrote. Do NOT re-implement the role's logic inline in Solo. Do NOT use the `Agent` tool with a sub-agent — role skills are skills, not agents. After the role skill returns, Solo reads the artifacts the role wrote (via the request artifact path or `peaks request show <rid> --role <role>`) to decide the next step.
786
+ After RD completes (whether inline or sub-agent), Solo does not stop it must advance to QA. There is no "RD done, ask the user" state in full-auto mode. The only valid stops are: (a) QA verdict=pass, (b) repair cap hit, (c) explicit user cancel.
628
787
 
629
- **Presence restoration after role skill returns (MANDATORY):** Role skills (peaks-rd, peaks-qa, peaks-ui) call `peaks skill presence:set <role>` internally, which overwrites `.peaks/.active-skill.json`. After EVERY role skill returns whether success, repair-needed, or failure Solo MUST immediately restore the orchestrator presence by re-running the same presence command from Step 2:
788
+ **Presence restoration after RD/QA work returns (MANDATORY):** In v1.x, role skills called `peaks skill presence:set <role>` internally and stomped on `.peaks/.active-skill.json`. From v1.3 onward, sub-agents in the Swarm path are forbidden from calling `peaks skill presence:set` (see "Sub-agent dispatch" in each role's SKILL.md), so the main loop's presence file is preserved across the fan-out window by construction. The one place Solo still has to actively restore presence is **once after the fan-out returns** (gate=swarm-converged) and again **after each RD↔QA repair iteration** (gate=repair-cycle-<N>). Use the same command from Step 2 with the current mode and the gate that has just advanced:
630
789
 
631
790
  ```bash
632
791
  peaks skill presence:set peaks-solo --project <repo> --mode <mode> --gate <current-gate>
633
792
  ```
634
793
 
635
- This keeps the CLAUDE.md status header accurate (`Peaks-Cli Skill: peaks-solo`) instead of showing a stale role name. Use the current mode and gate values; the gate may have advanced since startup. Skipping this step causes the header to display the last role skill name permanently.
794
+ This keeps the CLAUDE.md status header accurate (`Peaks-Cli Skill: peaks-solo`) instead of showing a stale role name. Use the current mode and gate values; the gate may have advanced since startup. Skipping this step causes the header to display the last-known gate permanently.
636
795
 
637
- **Full-auto auto-proceed rule**: In the `full-auto` profile, when RD transitions to `qa-handoff`, Solo immediately invokes `peaks-qa` via the Skill tool with the same `<request-id>`. Do not pause, do not ask the user, do not summarize RD results as if they were final. The only valid reason to skip QA is when `--type` is `docs` or `chore` (no acceptance surface).
796
+ **Full-auto auto-proceed rule**: In the `full-auto` profile, when RD transitions to `qa-handoff`, Solo immediately drives QA — by launching a `Task(subagent_type="general-purpose", ...)` sub-agent carrying the `peaks-qa` body (swarm path), or by running QA inline in the main loop (assisted/strict path). Do not pause, do not ask the user, do not summarize RD results as if they were final. The only valid reason to skip QA is when `--type` is `docs` or `chore` (no acceptance surface).
638
797
 
639
798
  A QA report with any failing, blocked, missing, or unverified acceptance item is not a pass.
640
799
 
@@ -650,9 +809,12 @@ When `peaks-qa` returns `verdict=return-to-rd`, Solo does NOT manually rewrite R
650
809
  --project <repo> --json
651
810
  ```
652
811
  `spec-locked` is the canonical "needs more RD work" state. The reason is mandatory in repair cycles so the artifact history shows the loop.
653
- 3. Invoke `peaks-rd` via the Skill tool. Pass the request id and the path to the QA findings; peaks-rd reads `qa/test-reports/<rid>.md` and the QA `requests/<rid>.md` for the verdict.
812
+ 3. Re-launch `peaks-rd` work. Two paths, mode-driven:
813
+ - **Swarm / full-auto**: launch a fresh `Task(subagent_type="general-purpose", ...)` sub-agent with the same `peaks-rd` body used in the Swarm phase, plus the QA findings path so it can read the failure list. Solo restores presence after the sub-agent returns.
814
+ - **Assisted / strict / inline-fallback**: Solo executes the RD repair steps directly in the main loop, since there is no concurrent fan-out to coordinate.
815
+ In both paths, pass the QA findings path so the repair sees what failed.
654
816
  4. peaks-rd fixes the reported issues only (red-line scope: do not modify unrelated surfaces), regenerates code-review and security-review evidence if changes touched reviewed surfaces, then transitions `rd → implemented → qa-handoff` again.
655
- 5. Solo invokes `peaks-qa` again with the same `<request-id>` (the same Skill call as before). QA re-runs gates against the new diff.
817
+ 5. Solo re-runs QA (sub-agent Task in swarm/full-auto, inline in assisted/strict) with the same `<request-id>`. QA re-runs gates against the new diff.
656
818
  6. Repeat steps 1-5 until QA returns `verdict=pass`, or the cap below fires.
657
819
  **After each repair iteration** (after peaks-rd and peaks-qa both return), Solo MUST restore presence:
658
820
  ```bash
@@ -707,14 +869,40 @@ peaks request lint <rid> --role prd --project <repo> --json
707
869
  peaks request transition <rid> --role prd --state confirmed-by-user --project <repo> --json
708
870
  peaks request transition <rid> --role prd --state handed-off --project <repo> --json
709
871
 
710
- # 3. Peaks-Cli Swarm parallel — launch UI + RD(planning) + QA(test-cases) simultaneously
711
- # Pass the same --type chosen for PRD so RD/QA gate matrix lines up.
712
- peaks request init --role ui --id <rid> --project <repo> --apply --type <type> --json
713
- peaks request transition <rid> --role ui --state direction-locked --project <repo> --json
714
- peaks request transition <rid> --role ui --state handed-off --project <repo> --json
715
- peaks request init --role rd --id <rid> --project <repo> --apply --type <type> --json
716
- peaks request transition <rid> --role rd --state spec-locked --project <repo> --json
717
- peaks request init --role qa --id <rid> --project <repo> --apply --type <type> --json
872
+ # 3. Peaks-Cli Swarm parallel — sub-agent fan-out (Task tool, NOT Skill tool)
873
+ # Solo computes the swarm plan from --type + frontendOnly + frontend-keyword scan,
874
+ # writes it to .peaks/<sid>/sc/swarm-plan.json, then launches one
875
+ # Task(subagent_type="general-purpose", ...) call per sub-agent in the same message.
876
+ # See "Peaks-Cli Swarm parallel phase" above for the full decision table and the
877
+ # prompt template; the role's required artefact paths are listed there.
878
+ # Hard rule: do NOT call Skill(skill="peaks-rd" | "peaks-qa" | "peaks-ui") from
879
+ # the Swarm phase that's the v1.x anti-pattern.
880
+ #
881
+ # 3a. Pre-fan-out: Solo initialises every role's request artefact slot in the main
882
+ # loop so sub-agents find a stable rid <-> artefact binding. Each role's
883
+ # sub-agent may also call peaks request init itself (idempotent on the same rid);
884
+ # Solo's call here is the source of truth. Only init roles that are in the
885
+ # swarm plan — roles not in the plan do not get a slot yet.
886
+ peaks skill presence:set peaks-solo --project <repo> --mode <mode> --gate swarm-fan-out
887
+ # for each role in swarm-plan.subAgents:
888
+ # peaks request init --role ui --id <rid> --project <repo> --apply --type <type> --json
889
+ # peaks request init --role rd --id <rid> --project <repo> --apply --type <type> --json
890
+ # peaks request init --role qa --id <rid> --project <repo> --apply --type <type> --json
891
+ # e.g. if plan = [ui, rd, qa]: run init for ui, rd, qa.
892
+ # If plan = [rd, qa]: run for rd, qa only.
893
+ # If plan = [] (config|docs|chore skip): no inits here, jump to step 4 directly.
894
+ # 3b. Solo issues N Task(subagent_type="general-purpose", ...) calls in ONE message
895
+ # (N = len(swarm-plan.subAgents)). Each prompt embeds the role's body minus
896
+ # Step 0 / presence, plus the runtime args (rid / sid / mode / type / paths).
897
+ # 3c. After fan-out, Solo restores presence once and runs Gate B (ls checks):
898
+ peaks skill presence:set peaks-solo --project <repo> --mode <mode> --gate swarm-converged
899
+ ls .peaks/<sid>/prd/requests/<rid>.md # PRD artefact must exist (Gate B hard)
900
+ # feature / refactor → ls .peaks/<sid>/rd/tech-doc.md
901
+ # bugfix → ls .peaks/<sid>/rd/bug-analysis.md
902
+ ls .peaks/<sid>/qa/test-cases/<rid>.md # QA test-cases (skipped for docs|chore)
903
+ # ui (only when in plan):
904
+ ls .peaks/<sid>/ui/design-draft.md 2>&1 # non-blocking (Gate B info)
905
+ # Apply the degradation rules in the main SKILL.md if any artefact is missing.
718
906
  # → Peaks-Cli Gate B convergence check. Assisted/Strict: [CONFIRM]
719
907
 
720
908
  # 4. Peaks-Cli RD planning artifact (the file required by the prerequisite gate)
@@ -762,10 +950,30 @@ peaks openspec validate <cid> --project <repo> --json
762
950
  peaks openspec archive <cid> --project <repo> --apply --json
763
951
 
764
952
  # 10. Peaks-Cli TXT handoff — invoke peaks-txt which embeds memory markers and extracts
765
- # peaks-txt writes the handoff capsule to .peaks/<id>/txt/handoff.md with embedded
766
- # <!-- peaks-memory:start --> blocks, then runs memory extract on it.
767
- # --apply is REQUIRED to write .peaks/memory; without it the command only previews.
953
+ # peaks-txt writes the handoff capsule to .peaks/<id>/txt/handoff.md. Inside the
954
+ # capsule body, peaks-txt embeds <!-- peaks-memory:start --> blocks for every
955
+ # stable project fact surfaced this session.
956
+ #
957
+ # 10a. Skill-side scan (do this BEFORE the AskUserQuestion below):
958
+ # grep -n "peaks-memory:start" .peaks/<id>/txt/handoff.md
959
+ # Record the count. This is the skill doing the work, not a CLI command —
960
+ # we deliberately do not ship a `peaks memory scan` because the LLM is
961
+ # the only consumer and the LLM has grep.
962
+
963
+ # 10b. AskUserQuestion (only if 10a returned count >= 1):
964
+ # "The TXT handoff has N peaks-memory:start blocks. Persist to .peaks/memory/?
965
+ # (a) Apply all — `peaks memory extract --project <repo>
966
+ # --artifact .peaks/<id>/txt/handoff.md --apply --json`
967
+ # (b) Apply selectively — re-edit handoff.md first, then re-apply
968
+ # (c) Skip for now — blocks stay in the handoff only, no .peaks/memory/ write"
969
+ # If 10a returned 0 AND the session surfaced a stable project fact
970
+ # (decision / convention / approved refactor), STOP — peaks-txt must go
971
+ # back and embed at least one block before Solo can advance.
972
+
973
+ # 10c. After the user picks (a) or (b), run:
768
974
  peaks memory extract --project <repo> --artifact .peaks/<id>/txt/handoff.md --apply --json
975
+ # --apply is REQUIRED to write .peaks/memory/; without it the command only
976
+ # previews. The extract regenerates index.json in the same call.
769
977
 
770
978
  # 11. Peaks-Cli Final snapshot
771
979
  peaks project dashboard --project <repo> --json
@@ -857,4 +1065,4 @@ Do not run upstream installer flows, mutate agent settings, or commit `.codegrap
857
1065
 
858
1066
  **MCP lifecycle**: `list → plan → apply --yes → call → rollback`. `apply` backs up settings and refuses non-peaks entries unless `--claim` is passed.
859
1067
 
860
- Detailed rules: `references/external-skill-invocation.md`, `references/openspec-mcp-workflow.md`, `references/workflow.md`, `references/existing-system-extraction.md`.
1068
+ Detailed rules: `references/external-skill-invocation.md`, `references/openspec-mcp-workflow.md`, `references/workflow.md`, `references/existing-system-extraction.md`. For an informational mapping of peaks artefact paths to the A2A (Agent2Agent) protocol's Task / Artifact / Part / Message / AgentCard vocabulary (no A2A implementation, just a shared naming layer), see `references/a2a-artifact-mapping.md`.
@@ -0,0 +1,115 @@
1
+ # A2A artifact mapping (informational)
2
+
3
+ > Reference for `peaks-solo` and any other peaks skill that produces durable artefacts in `.peaks/<session-id>/`. Maps peaks's on-disk artefact vocabulary onto the A2A (Agent2Agent) protocol's vocabulary so a future peaks consumer (e.g. an external LLM agent or a downstream peaks-cli extension) can read peaks output without having to learn a brand-new schema. This is a **documentation mapping**, not a protocol implementation: peaks-cli does not speak A2A over HTTP, does not host an AgentCard endpoint, and does not advertise its capabilities via A2A's discovery mechanism. It only uses A2A's *concepts* as a shared naming layer.
4
+
5
+ ## 1. Why this reference exists
6
+
7
+ The A2A protocol (https://a2acn.com) defines five core concepts: **AgentCard**, **Task**, **Artifact**, **Message**, and **Part**. peaks-cli's session workspace is a parallel vocabulary that grew up independently: `prd/requests/<rid>.md`, `rd/tech-doc.md`, `qa/test-cases/<rid>.md`, etc. The two vocabularies are *not* identical (A2A is HTTP-shaped, peaks is filesystem-shaped), but the A2A concepts are close enough that aligning peaks artefact names with A2A terms in this reference:
8
+
9
+ - gives an external consumer a single translation table instead of two schemas to learn,
10
+ - lets a peaks operator talk about "the artifact" or "the task" in mixed conversations without losing precision,
11
+ - documents what peaks output is **not** (no SSE streaming, no remote AgentCard), so the limits are explicit.
12
+
13
+ This is the kind of borrowing that costs zero code and earns some interoperability. It is **not** an integration: peaks-cli does not implement A2A, does not run an A2A server, and does not depend on the a2a-protocol package. Adopting A2A concepts here is the same as adopting any other shared nomenclature (UML, OpenTelemetry, etc.): it improves the conversation, nothing more.
14
+
15
+ ## 2. Concept-to-path mapping
16
+
17
+ The mapping below uses peaks's own paths verbatim. Each row also notes where peaks **diverges** from A2A, so a reader does not assume parity.
18
+
19
+ | A2A concept | peaks artefact | Path (under `.peaks/<session-id>/`) | Notes |
20
+ |---|---|---|---|
21
+ | **AgentCard** (capability advertisement) | `peaks-skill-output-style` + `.peaks/.active-skill.json` | `.peaks/.active-skill.json`, `.peaks/.session.json` | peaks is a *local* tool, not a service. The "card" is the active-skill file plus a peek at `.peaks/PROJECT.md` for human-readable history. There is no `/.well-known/agent-card.json` endpoint. |
22
+ | **Task** (stateful unit of work) | `peaks request` state machine for a single `<rid>` | `.peaks/<sid>/{prd,rd,qa,ui,sc}/requests/<rid>.md` (the request artefact); `.peaks/<sid>/<role>/session.json` (per-session metadata) | peaks's task lifecycle is `prd:confirmed-by-user → handed-off`, then per role `draft → spec-locked → implemented → qa-handoff`, then `qa:running → verdict-issued`. The full state graph is enforced by `peaks request transition`. A2A's Task object is JSON; peaks's task is **a set of files with a `state` field per role**. |
23
+ | **Artifact** (immutable output) | `rd/tech-doc.md`, `rd/code-review.md`, `rd/security-review.md`, `qa/test-cases/<rid>.md`, `qa/test-reports/<rid>.md`, `qa/security-findings.md`, `qa/performance-findings.md`, `sc/handoff.md` | as listed | peaks's artefacts are *append-once*, not strictly immutable: a `qa/test-reports/<rid>.md` may be re-emitted on repair cycles. The convention is "newest write wins; the file at the end of the workflow is the truth", which is close enough to A2A's immutable-Artifact semantics for translation purposes. |
24
+ | **Message** (non-artifact communication) | `peaks skill presence` heartbeat + transition `--reason` notes | `.peaks/.active-skill.json` (`lastHeartbeat`), transition notes in `.peaks/<sid>/<role>/requests/<rid>.md` | peaks does **not** separate Messages from Artifacts at the storage layer; a "message" is anything that is not the artefact body (the `<!-- peaks-memory:start -->` markers, the `state` field, the `--reason` text on a transition). Treat these as inline metadata of the artefact, not as separate objects. |
25
+ | **Part** (atomic content unit) | Markdown sections within an artefact, frontmatter fields | inline within the artefact | peaks's Artifacts are single Markdown files, so the "Part" concept maps to a heading or a frontmatter field. A `Part`'s `kind` in A2A terms is `text` (the prose), `file` (a `<!-- peaks-memory:start -->` block as a structured chunk), or `data` (the frontmatter). A2A's `form` / `iframe` / video `Part` kinds are not produced by peaks. |
26
+
27
+ ## 3. Field-level mapping (A2A Part ↔ peaks frontmatter)
28
+
29
+ A2A `Part` has `kind` and `metadata` (free-form) plus `content` (typed by kind). peaks's per-artifact frontmatter carries a subset:
30
+
31
+ ```yaml
32
+ ---
33
+ name: <slug> # used in memory extraction; not a 1:1 A2A field
34
+ description: <title> # roughly the A2A Artifact.description
35
+ metadata:
36
+ type: <kind> # A2A Artifact.kind equivalent
37
+ sourceArtifact: <rel> # A2A Artifact.source / provenance equivalent
38
+ ---
39
+ ```
40
+
41
+ A consumer reading a peaks artefact and translating it to A2A can populate:
42
+
43
+ - `Artifact.name` ← peaks `name`
44
+ - `Artifact.description` ← peaks `description` (or the first H1)
45
+ - `Artifact.kind` ← peaks `metadata.type`
46
+ - `Artifact.parts[0]` ← the body text (A2A `Part{kind: "text"}`)
47
+ - `Artifact.metadata.sourcePath` ← peaks `metadata.sourceArtifact`
48
+ - `Artifact.metadata.sessionId` ← from `.peaks/.session.json`
49
+
50
+ The mapping is not 100% lossless: A2A's `Part` can carry structured forms or file references, peaks cannot. That is the explicit *non-goal* of this mapping; it would be over-claiming to assert parity where there is none.
51
+
52
+ ## 4. State-graph mapping (A2A Task ↔ peaks request)
53
+
54
+ A2A's Task object has a small set of states (typically: `submitted`, `working`, `input-required`, `completed`, `failed`, `canceled`). peaks's per-role request state machine is richer and per-role:
55
+
56
+ | Role | peaks states (in order) | Closest A2A Task state |
57
+ |---|---|---|
58
+ | `prd` | `draft` → `confirmed-by-user` → `handed-off` | `submitted` → `working` → `input-required` (for the confirm gate) |
59
+ | `rd` | `draft` → `spec-locked` → `implemented` → `qa-handoff` | `working` |
60
+ | `qa` | `draft` → `running` → `verdict-issued` (verdict is `pass` / `return-to-rd` / `blocked`) | `working` → `completed` (pass) / `input-required` (return-to-rd) / `failed` (blocked) |
61
+ | `ui` | `draft` → `direction-locked` → `handed-off` | `working` → `completed` |
62
+ | `sc` | `draft` → `recorded` | `working` → `completed` |
63
+
64
+ A consumer translating peaks states to A2A should:
65
+
66
+ - collapse peaks's multi-role state machine to a *single* A2A Task state by taking the most progressed of any role,
67
+ - use the A2A `input-required` state to model **any** gate where peaks is waiting for a human (`confirmed-by-user`, `--confirm`, AskUserQuestion for a login wall, etc.),
68
+ - emit `completed` only when QA verdict is `pass` and SC has recorded the change,
69
+ - emit `failed` on `blocked` QA verdict or `blocked` handoff.
70
+
71
+ ## 5. Worked example: a feature slice from start to finish
72
+
73
+ A user runs `peaks-solo` for a "add user authentication" feature. Mapping the resulting files to A2A concepts:
74
+
75
+ ```
76
+ .peaks/<sid>/prd/requests/001.md → A2A Artifact (kind=proposal)
77
+ .peaks/<sid>/ui/requests/001.md → A2A Artifact (kind=design-direction)
78
+ .peaks/<sid>/ui/design-draft.md → A2A Artifact (kind=visual-spec)
79
+ .peaks/<sid>/rd/tech-doc.md → A2A Artifact (kind=implementation-plan)
80
+ .peaks/<sid>/qa/test-cases/001.md → A2A Artifact (kind=test-cases)
81
+ .peaks/<sid>/rd/code-review.md → A2A Artifact (kind=review, status=fixed)
82
+ .peaks/<sid>/rd/security-review.md → A2A Artifact (kind=security-review)
83
+ .peaks/<sid>/qa/test-reports/001.md → A2A Artifact (kind=test-report, verdict=pass)
84
+ .peaks/<sid>/qa/security-findings.md → A2A Artifact (kind=security-findings)
85
+ .peaks/<sid>/qa/performance-findings.md → A2A Artifact (kind=performance-findings)
86
+ .peaks/<sid>/sc/handoff.md → A2A Artifact (kind=change-record)
87
+ .peaks/<sid>/txt/handoff.md → A2A Artifact (kind=handoff-capsule)
88
+ .peaks/<sid>/system/sub-agent-*.json → A2A Message (sub-agent presence markers)
89
+ .peaks/<sid>/sc/swarm-plan.json → A2A Message (the dispatch plan)
90
+ .peaks/memory/*.md → A2A Artifact (kind=project-memory, persists across sessions)
91
+ ```
92
+
93
+ A consumer wanting to render a single "feature" object in A2A terms picks the `test-reports/001.md` (verdict=pass) as the terminal Artifact and the rest as supporting Parts or sibling Artifacts. The mapping is intentionally loose: peaks's value is that *all of these files exist*, not that they fit A2A's object model exactly.
94
+
95
+ ## 6. What peaks does NOT provide
96
+
97
+ To keep the mapping honest, peaks-cli **does not** currently provide the following A2A primitives, and consumers should not expect them:
98
+
99
+ - A2A **AgentCard** served over HTTP at `/.well-known/agent-card.json`. peaks-cli is a local CLI; its "card" is the on-disk `.peaks/.active-skill.json` plus `peaks skill doctor --json`.
100
+ - A2A **streaming** responses (SSE / WebSocket). peaks commands are synchronous and return a single JSON envelope.
101
+ - A2A **identity / auth** (OAuth, OIDC, mTLS). peaks assumes local-machine trust.
102
+ - A2A **cross-vendor discovery**. peaks has no A2A registry entry; it has `peaks mcp list --json` for MCP-compatible capabilities.
103
+ - A2A **Task delegation across the network**. peaks's "sub-agent" is a Claude Code `Task` tool call in the same process, not a remote A2A server.
104
+
105
+ These are *deliberate* omissions. peaks-cli solves a different problem (a local workflow-gating CLI for Claude Code), and adopting A2A's networking surface would add weight without addressing peaks's actual failure modes (which are around LLM bypassing gates, not around inter-agent discovery).
106
+
107
+ ## 7. When to re-evaluate
108
+
109
+ Re-open this mapping in any of the following cases:
110
+
111
+ - a peaks user reports a real need to share workflow state with a non-peaks agent (e.g. an Autogen / LangChain agent that wants to read a peaks handoff capsule);
112
+ - peaks-cli ships a hosted / multi-user mode where AgentCard-style discovery becomes useful;
113
+ - the A2A protocol stabilises on a thin `Artifact` JSON schema that matches peaks's on-disk shape close enough to make translation a one-liner rather than a reference doc.
114
+
115
+ Until one of those fires, this reference doc is the entire A2A surface area of peaks-cli. Adding more is over-engineering.