HOMELAB-1345: feat(pi-swarm-suite): merge pi-subagents, pi-swarm, and pi-swarm-view #4

Merged
aaron merged 48 commits from plane/HOMELAB-1345-swarm-suite into main 2026-07-06 04:26:02 +00:00
Owner

HOMELAB-1345 — pi-swarm-suite merge

Consolidates three extensions (pi-subagents, pi-swarm, pi-swarm-view) into a single unified pi-swarm-suite extension. The legacy pi-swarm/ and pi-swarm-view/ directories were moved out to ~/.pi/agent/.disabled-extensions/ and show as deletions here; git detected the relocated files as renames into pi-swarm-suite/.

Verification

  • npm run typecheck — clean (tsc --noEmit, no errors)
  • npm run test — 28 test files, 198 tests passed, 0 failed

Branch

  • plane/HOMELAB-1345-swarm-suite → main
  • Commit: 952f9b1
## HOMELAB-1345 — pi-swarm-suite merge Consolidates three extensions (`pi-subagents`, `pi-swarm`, `pi-swarm-view`) into a single unified `pi-swarm-suite` extension. The legacy `pi-swarm/` and `pi-swarm-view/` directories were moved out to `~/.pi/agent/.disabled-extensions/` and show as deletions here; git detected the relocated files as renames into `pi-swarm-suite/`. ### Verification - `npm run typecheck` — clean (tsc --noEmit, no errors) - `npm run test` — 28 test files, 198 tests passed, 0 failed ### Branch - `plane/HOMELAB-1345-swarm-suite` → `main` - Commit: `952f9b1`
The Paperclip listIssues endpoint now returns a raw array [{...}]
instead of the legacy shape { issues: [...], nextCursor?, totalCount? }.

This broke paperclip_get_issue, paperclip_list_issues, and any tool
calling getIssueByIdentifier(), which all assumed the old wrapper shape.

- listIssues: normalize raw array to { issues: res } before returning
- getIssueByIdentifier: defensively read from both array and .issues
- listApprovalIssues, listAgents: apply same guard pattern for safety
- paperclip_list_issues tool: handle both shapes in execute() body

Tested: getIssueByIdentifier('HOM-71') resolves correctly against
live API returning raw array.
Adds 6 tools for orchestrating Kimi multi-agent swarms as first-class Pi tools:
- kimi_swarm_list — list templates/agents
- kimi_swarm_run — execute swarm with objective (CLI or HTTP fallback)
- kimi_swarm_status — check run progress by ID
- kimi_swarm_result — retrieve final answer and artifacts
- kimi_swarm_agent_list — filter agents by role/capability
- kimi_config_get — show masked Kimi config

Includes built-in swarm templates (research, code_review, plan_execute,
full_team, writer_workshop), 5 agent roles, lazy config loading, progress
streaming via onUpdate, and a SKILL.md for Pi usage guidance.
New extension pi-swarm layering Kimi AgentSwarm ergonomics + Swarm Mode
over @tintinweb/pi-subagents via its subagents:rpc:* event bus. Includes
tiered models (deepseek/kimi/glm), free per-child OTel telemetry, and a
required parity benchmark (same queries vs Kimi Code, hybrid scoring).
Retires pi-kimi-agent-swarm. Phase-0 feasibility resolved.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NzWBhYm2S4Tv1fLXGjPeMi
Decisions from review: wide fan-outs (>confirmThreshold, default 32)
require explicit confirmation (UI confirm, or acknowledge_large in
headless). Parity bar set to >=90% of Kimi Code aggregate rubric with no
category categorically worse.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NzWBhYm2S4Tv1fLXGjPeMi
13 TDD tasks: scaffolding, validation, tiers, subagent-type mapping, XML
renderer, RPC client, completion collector, runSwarm orchestration, Swarm
Mode, settings, extension wiring, and live in-pi smoke + retire old ext.
Benchmark harness (spec §11) scoped to a separate Plan 2.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NzWBhYm2S4Tv1fLXGjPeMi
typebox ^1.1.24 and @mariozechner/pi-coding-agent ^0.73.1 (the ^0.1.0 pins
did not exist on npm). Note that unit-tested modules don't import either.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NzWBhYm2S4Tv1fLXGjPeMi
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NzWBhYm2S4Tv1fLXGjPeMi
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NzWBhYm2S4Tv1fLXGjPeMi
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NzWBhYm2S4Tv1fLXGjPeMi
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NzWBhYm2S4Tv1fLXGjPeMi
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NzWBhYm2S4Tv1fLXGjPeMi
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NzWBhYm2S4Tv1fLXGjPeMi
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NzWBhYm2S4Tv1fLXGjPeMi
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NzWBhYm2S4Tv1fLXGjPeMi
Prevents a pending signal-less allTerminal() from hanging after dispose().

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NzWBhYm2S4Tv1fLXGjPeMi
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NzWBhYm2S4Tv1fLXGjPeMi
A spawn RPC rejection now marks that child failed and the swarm continues,
instead of rejecting the whole run and abandoning already-spawned children.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NzWBhYm2S4Tv1fLXGjPeMi
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NzWBhYm2S4Tv1fLXGjPeMi
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NzWBhYm2S4Tv1fLXGjPeMi
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NzWBhYm2S4Tv1fLXGjPeMi
C1: before_agent_start now appends the Swarm Mode reminder to the base
system prompt instead of replacing it (pi's systemPrompt return replaces).
I1: CompletionCollector treats 'steered' status as completed (pi-subagents
emits steered on the success channel).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NzWBhYm2S4Tv1fLXGjPeMi
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NzWBhYm2S4Tv1fLXGjPeMi
The old sequential role-based swarm is superseded by pi-swarm's Kimi-style
agent_swarm + Swarm Mode. Removed from the extensions dir so pi no longer
discovers it. Recoverable from git history if needed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NzWBhYm2S4Tv1fLXGjPeMi
HOMELAB-1335. New pi extension giving live in-session visibility into
running subagents/swarms: passive always-on indicator (working line +
footer chip) plus an interactive Agents TUI (navigable status grid +
per-agent live output tailed from JSONL). Roster from subagents:* events;
activity from per-agent output files. Cancel-guard deferred to Phase 2.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XGmvuV5GMX3zScTQzva8tu
HOMELAB-1335. Bite-sized, test-first plan: scaffold+types, roster store,
event wiring, output-file path+JSONL parse, incremental tailer, formatters,
navigation controller, passive indicator, settings, interactive overlay,
factory wiring, README + live verification.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XGmvuV5GMX3zScTQzva8tu
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XGmvuV5GMX3zScTQzva8tu
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XGmvuV5GMX3zScTQzva8tu
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XGmvuV5GMX3zScTQzva8tu
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XGmvuV5GMX3zScTQzva8tu
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XGmvuV5GMX3zScTQzva8tu
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XGmvuV5GMX3zScTQzva8tu
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XGmvuV5GMX3zScTQzva8tu
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XGmvuV5GMX3zScTQzva8tu
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XGmvuV5GMX3zScTQzva8tu
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XGmvuV5GMX3zScTQzva8tu
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XGmvuV5GMX3zScTQzva8tu
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XGmvuV5GMX3zScTQzva8tu
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XGmvuV5GMX3zScTQzva8tu
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XGmvuV5GMX3zScTQzva8tu
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XGmvuV5GMX3zScTQzva8tu
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XGmvuV5GMX3zScTQzva8tu
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XGmvuV5GMX3zScTQzva8tu
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XGmvuV5GMX3zScTQzva8tu
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XGmvuV5GMX3zScTQzva8tu
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XGmvuV5GMX3zScTQzva8tu
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XGmvuV5GMX3zScTQzva8tu
Author
Owner

Review (Claude, against docs/plans/2026-07-01-pi-swarm-suite-migration.md)

Verdict: solid — good to merge. Structure, vendoring fidelity, and the compatibility contract all match the plan. Verified locally: tsc --noEmit clean, 198/198 tests pass, and a live pi -p smoke test spawned a subagent through the suite end-to-end (queued → ran → streamed a universal .output file → result returned).

What's right

  • 24 of 28 vendored core files differ from upstream v0.10.3 by only the header comment; real patches (agent-manager.ts, index.ts, settings.ts) are exactly the plan's §5 list, all marked SUITE:.
  • Compat surface intact: Agent/get_subagent_result/steer_subagent tools, /agents, /swarm, /swarm-view, subagents:* events, RPC channels, subagents.json, agent-md dirs, output-file layout.
  • The cross-extension pain is genuinely gone: roster fed by manager.onAnyChange(), swarm collector in-process, transcripts prefer in-memory record.session with file fallback, output files on all spawn paths.

Findings

  1. Latent maxConcurrent clobber — suite-settings.ts seeds core knobs from loadProjectSettings() (project file only), but the comment claims "current effective values". Global ~/.pi/agent/subagents.json has maxConcurrent: 20; the page would show 4. If a settings host ever emits full values on change, syncCore writes 4 into <cwd>/.pi/subagents.json, silently downgrading 20 → 4 (the exact bug we fought in HOMELAB-1335). One-line fix: seed from loadSettings() (merged).
  2. The registry settings surface is dormant — nothing on this machine hosts pi-extension-settings:register / answers extension:settings:get (checked pi core, all npm packages, all extensions). All swarm/view knobs run on hardcoded defaults; README's claim that the page "appears in pi's extension-settings UI" doesn't hold today. Not a regression (legacy pages were equally dead), just know that ~335 lines + tests serve an uninstalled host.
  3. pi -p never exits after spawning a subagent — confirmed NOT a regression: reproduced identically with the unmodified upstream npm package (pi -ne -e …/pi-subagents/dist/index.js). Agent completes in seconds; process hangs indefinitely (event loop held by the retained child session). Matters for headless runs (Paperclip pi-over-SSH). Now that we own the core, a follow-up could dispose terminal sessions when !hasUI.

Minor

  • b47a87a (paperclip listIssues array fix) is scope creep in this PR — fine since it's its own commit.
  • swarm/index.ts:60 re-wires the no-op registerSettings on pi-extension-settings:ready — dead code.
## Review (Claude, against docs/plans/2026-07-01-pi-swarm-suite-migration.md) **Verdict: solid — good to merge.** Structure, vendoring fidelity, and the compatibility contract all match the plan. Verified locally: `tsc --noEmit` clean, 198/198 tests pass, and a live `pi -p` smoke test spawned a subagent through the suite end-to-end (queued → ran → streamed a universal `.output` file → result returned). ### What's right - 24 of 28 vendored core files differ from upstream v0.10.3 by only the header comment; real patches (`agent-manager.ts`, `index.ts`, `settings.ts`) are exactly the plan's §5 list, all marked `SUITE:`. - Compat surface intact: `Agent`/`get_subagent_result`/`steer_subagent` tools, `/agents`, `/swarm`, `/swarm-view`, `subagents:*` events, RPC channels, `subagents.json`, agent-md dirs, output-file layout. - The cross-extension pain is genuinely gone: roster fed by `manager.onAnyChange()`, swarm collector in-process, transcripts prefer in-memory `record.session` with file fallback, output files on **all** spawn paths. ### Findings 1. **Latent `maxConcurrent` clobber** — `suite-settings.ts` seeds core knobs from `loadProjectSettings()` (project file only), but the comment claims "current effective values". Global `~/.pi/agent/subagents.json` has `maxConcurrent: 20`; the page would show 4. If a settings host ever emits full values on change, `syncCore` writes 4 into `<cwd>/.pi/subagents.json`, silently downgrading 20 → 4 (the exact bug we fought in HOMELAB-1335). One-line fix: seed from `loadSettings()` (merged). 2. **The registry settings surface is dormant** — nothing on this machine hosts `pi-extension-settings:register` / answers `extension:settings:get` (checked pi core, all npm packages, all extensions). All swarm/view knobs run on hardcoded defaults; README's claim that the page "appears in pi's extension-settings UI" doesn't hold today. Not a regression (legacy pages were equally dead), just know that ~335 lines + tests serve an uninstalled host. 3. **`pi -p` never exits after spawning a subagent** — confirmed NOT a regression: reproduced identically with the unmodified upstream npm package (`pi -ne -e …/pi-subagents/dist/index.js`). Agent completes in seconds; process hangs indefinitely (event loop held by the retained child session). Matters for headless runs (Paperclip pi-over-SSH). Now that we own the core, a follow-up could dispose terminal sessions when `!hasUI`. ### Minor - `b47a87a` (paperclip listIssues array fix) is scope creep in this PR — fine since it's its own commit. - `swarm/index.ts:60` re-wires the no-op `registerSettings` on `pi-extension-settings:ready` — dead code.
aaron merged commit 277074106e into main 2026-07-06 04:26:02 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Homelab/pi-extensions!4
No description provided.