{"id":"0404d9fd-6485-4c19-8f6e-bb7dcfc2822d","slug":"pi-ensemble","kind":"skill","name":"pi-ensemble","summary":"Safe multi-agent delegation and scripted orchestration for Pi","owner":"elBenz","repoUrl":"https://github.com/elBenz/pi-ensemble","license":"MIT","licenseTier":"permissive","trust":"community","stars":0,"match":null,"fewStars":true,"format":"skill","createdAt":"2026-08-16T11:14:10.000Z","addedAt":"2026-10-21T14:32:53.883Z","logoUrl":"https://avatars.githubusercontent.com/u/59069279?u=8365b099ac4c37d6fba3ed4654aca284139ed81c&v=4","linkOnly":false,"collection":null,"skillPath":null,"categories":["writing"],"tags":["multi-agent","orchestration","pi","pi-coding-agent","typescript"],"runtime":"node","local":true,"cloudCapable":false,"cloudCapability":"unknown","cloudReadyOnPlatform":false,"needsApiKey":false,"reviewed":false,"syncedAt":"2026-10-26T11:56:13.041Z","sample":false,"url":"https://conduits.dev/tools/pi-ensemble","language":"TypeScript","transports":["stdio"],"install":{"npm":"pi-ensemble"},"requirements":{"env":[],"upstreamMayCharge":false},"tools":null,"readme":"# pi-ensemble\n\nSafe multi-agent delegation and scripted orchestration for [Pi](https://github.com/earendil-works/pi).\n\n> [!IMPORTANT]\n> `pi-ensemble` is an independently maintained fork of [Nico Bailon's `pi-subagents`](https://github.com/nicobailon/pi-subagents), not an unrelated rewrite or an official successor. Most of the feature surface and codebase originated upstream.\n\n## Thank you, Nico\n\n`pi-ensemble` would not exist without Nico Bailon's work on `pi-subagents`: its agent model, foreground and background execution, scripted workflows, missions, observability, extension APIs, and extensive test suite provide the foundation for this fork.\n\nThe repository preserves upstream Git history, copyright, and MIT license. If the original project fits your needs, use it and support it. This fork exists to explore a narrower maintenance direction—not to erase or obscure its source.\n\n## Why this fork exists\n\n`pi-subagents` is a broad, capable multi-agent framework. `pi-ensemble` keeps that foundation while prioritizing four constraints:\n\n1. **Bounded parent context** — child work should not flood the orchestrator's model context.\n2. **Explicit execution boundaries** — fresh context, extension loading, replay, and mutation rules should be deliberate.\n3. **Parent-owned authority** — children provide work and evidence; the parent retains orchestration and final decisions.\n4. **Compatibility-first hardening** — improve safety without casually breaking existing tools, commands, storage, or integrations.\n\n## What differs from upstream\n\nCurrent fork-specific work is intentionally focused rather than a wholesale redesign.\n\n| Area | `pi-ensemble` change | Practical benefit |\n| --- | --- | --- |\n| Tool context | Default compact schema plus optional payload routing for rare controls | Smaller standing prompt cost; measured schema size fell from 12,127 to 1,266 bytes in the remediation benchmark (−89.6%) |\n| Child results | Bounded model-facing receipts backed by verified full-output artifacts | Parent sees status and artifact location without ingesting arbitrary child prose |\n| Child isolation | Fresh-context defaults and tighter ambient-extension loading for mutation-capable builtins | Less accidental inheritance of parent conversation and unrelated extension behavior |\n| Replay safety | Startup/model replay stops after any observed mutation-capable tool attempt | Avoids silently repeating work after a child may already have changed state |\n| Completion handling | Settled successful results survive unrelated late extension teardown failures | Valid child work is not discarded because another extension crashes afterward |\n| Supervisor channel | Private file modes, bounded payloads, file validation, and untrusted-data quoting | Reduces cross-session leakage and prompt-injection risk in child-to-parent messaging |\n| Parent context | Routine supervisor progress stays in TUI-only surfaces | Progress remains visible without becoming model-visible conversation history |\n| Missions | Cross-process locking around mission record updates | Concurrent children preserve sibling runs, decisions, receipts, artifacts, and usage |\n| Compatibility | Stable `subagent` tool, `/subagents-*` commands, storage paths, and registry identifiers retained | Existing workflows and persisted run state need fewer migration changes |\n\nSee [CHANGELOG.md](CHANGELOG.md) and commit [`76c6385`](https://github.com/elBenz/pi-ensemble/commit/76c6385) for the concrete remediation diff.\n\n## Install\n\nThe npm package is not published yet. Install from GitHub:\n\n```bash\npi install https://github.com/elBenz/pi-ensemble\n```\n\nFor local development:\n\n```bash\npi install /absolute/path/to/pi-ensemble\n```\n\n### Run a Route benchmark\n\nCreate a declarative JSON case, then run one isolated Agent role benchmark:\n\n```bash\nnpm run benchmark -- ./benchmarks/scout-case.json --output ./benchmark-results/scout-run-1\n# Installed package: pi-ensemble-benchmark ./benchmarks/scout-case.json --output ./benchmark-results/scout-run-1\n```\n\n```json\n{\n  \"id\": \"scout-synthetic\",\n  \"agentRole\": \"scout\",\n  \"route\": {\n    \"modelTier\": \"GPT-5.6 Luna\",\n    \"model\": \"openai-codex/gpt-5.6-luna\",\n    \"thinkingLevel\": \"medium\"\n  },\n  \"currentPricing\": {\n    \"currency\": \"USD\",\n    \"unit\": \"per-million-tokens\",\n    \"effectiveAt\": \"2026-08-27\",\n    \"source\": \"https://example.com/provider-pricing\",\n    \"input\": 0,\n    \"output\": 0,\n    \"cacheRead\": 0,\n    \"cacheWrite\": 0\n  },\n  \"prompt\": \"Find the relevant file and report its contents.\",\n  \"fixture\": \"./fixtures/scout-synthetic\",\n  \"evaluator\": { \"kind\": \"output-includes\", \"expected\": \"known result\" },\n  \"timeoutMs\": 120000,\n  \"mutationPolicy\": \"forbid\"\n}\n```\n\n`fixture` resolves relative to the case file. To replay history instead, replace it with `\"source\": { \"repository\": \"../..\", \"revision\": \"<full commit hash>\" }`; repository paths also resolve relative to the case. The runner exports only that commit's tracked tree, without Git metadata, into a unique temporary candidate directory. Candidate support files stay beside that tree; parent session/npm path variables and source-root `PATH` entries are removed. It evaluates there, records the resolved commit and file hashes, then removes the tree in `finally`, including failed runs. `fixture` and `source` are mutually exclusive.\n\nMutation policy accepts `forbid`, `allow`, or `require`. `currentPricing` records USD per-million-token rates and provenance. Derived Benchmark cost uses reported input, output, cache-read, and cache-write usage; reported historical provider cost remains separate. Reasoning usage is retained but not charged twice when included in output usage.\n\nRun result schema v4 requires raw provider usage provenance and preserves missing/invalid usage as `null`, not zero. Stock Pi 0.85.1 and unsupported API families cannot establish complete Benchmark cost; adapter-normalized numbers alone are no longer accepted. The [Responses adapter patch and offline verification](docs/benchmark-adapter.md) describe the required runtime integration, now built locally and validated through the real CLI with synthetic loopback fixtures, but not selected for ordinary sessions or campaigns. `benchmarkCostUnavailableReason` explains unavailable repricing; raw `receipt.json` keeps the original transcript. A missing historical-cost field in any turn makes the historical run total unavailable. Missing optional reasoning stays unknown and is omitted from repricing usage. Peak context uses the maximum per-turn reported total (or a sum of complete per-turn token categories if the total is absent), never cumulative output; incomplete context stays unknown and cannot establish Route eligibility. `metrics.observedTailBreach` retains any observed turn above 150k even if another turn is incomplete or unfinished. `contextPolicy.tailBreach` is true for that evidence, null for an unknown peak without a proven breach, and false for a complete peak at or below 150k; Markdown and plan breach counts consume this decision. Streaming usage updates are not counted again alongside terminal messages.\n\nEvaluators run only after candidate exit; expectations never enter candidate prompt or workspace. Each run creates a fresh session plus read-only `receipt.json`, derived `result.json`, and `report.md`. Fixture workspaces remain as artifacts; historical candidate trees are represented by receipt snapshots and removed. Set `PI_SUBAGENT_PI_BINARY` to substitute a Pi-compatible process shim.\n\nRun comparable repetitions and enforce cumulative spend with a plan:\n\n```json\n{\n  \"id\": \"worker-screening\",\n  \"stage\": \"screening\",\n  \"launches\": [{ \"case\": \"./worker-case.json\", \"repetitions\": 3 }]\n}\n```\n\nPass plan JSON to the same command. Keep the complete stage in one plan: exactly three completed runs per screening Route or nine per finalist Route. Plans require `currentPricing` on every case. Screening warns at $15 and blocks new launches at $25; finalist plans warn at $30 cumulative and block new launches at $50. Checks occur between sequential launches, so active mutation-capable runs always finish. Plan results report median Peak context load per Route, mark medians above 100k ineligible, count runs above 150k as Tail breaches, and reject a nine-run finalist Route with more than one breach. Completed run receipts remain available after hard stop. Unavailable repricing also blocks subsequent launches, without interrupting the current run. Plan result schema v2 reports `budget.cumulativeSpend: null`, `complete: false`, `knownSpend` (the sum of fully repriced runs), and `unavailableReason`; it never presents that subtotal as complete campaign spend. Case pricing missing or malformed before launch is still rejected at preflight.\n\n### Importing external DeepSWE evidence\n\nImport a preserved official artifact through the same top-level runner without launching Pi, then regenerate a report offline:\n\n```sh\nnpm run benchmark -- import-deepswe docs/research/deepswe-refresh/leaderboard-live.json \\\n  --output ./benchmark-results/evidence --retrieved-at 2026-09-07T11:37:08.124933+00:00\n# Add --current-pricing ./openai-prices.json only when it contains dated source/rates,\n# including explicit cacheWrite and computeUnit rates (zero is written as 0).\nnpm run benchmark -- report-deepswe ./benchmark-results/evidence/deepswe-v1.1-<sha-prefix>-unpriced \\\n  --output ./benchmark-results/deepswe-report\n```\n\nImport stores the source bytes read-only, content-addresses snapshots by SHA-256, and records source URL, source generation time, retrieval time, and benchmark version. Re-importing identical bytes rejects rather than overwriting; changed bytes create a new snapshot directory. Regeneration reads only that local immutable snapshot: it makes no network request, does not launch Pi, and does not change Pi settings. The normalized JSON retains every source row, all twenty GPT-6 Astra/GPT-5.6 Sol/Terra/Luna effort configurations when present, and non-GPT rows as comparison baselines only. Markdown compares GPT configurations; baseline evidence remains in JSON.\n\n`--current-pricing` JSON is keyed by source model and uses USD per million units. Every rate is explicit so missing data cannot become a zero charge. Example below reproduces the snapshot's Astra cost basis; replace its example URL/date and verify rates before treating them as current pricing:\n\n```json\n{\n  \"gpt-6-astra\": {\n    \"currency\": \"USD\",\n    \"unit\": \"per-million-tokens\",\n    \"effectiveAt\": \"2026-09-07\",\n    \"source\": \"https://example.com/pricing\",\n    \"input\": 12,\n    \"output\": 50,\n    \"cacheRead\": 1.2,\n    \"cacheWrite\": 15,\n    \"computeUnit\": 2\n  }\n}\n```\n\n`input`, `output`, `cacheRead`, and `cacheWrite` are USD per million tokens; `computeUnit` is USD per million compute units. Import requires a valid ISO effective date, HTTP(S) source URL, USD currency, finite non-negative rates, and all required usage fields. The pricing file is retained with a SHA-256 in provenance; regeneration verifies it before producing a report.\n\nRecorded historical cost, captured website-adjusted cost, and independently current Benchmark cost are distinct. Without complete dated current pricing and usage provenance, current Benchmark cost remains explicitly unavailable. Separate live Astra compute-unit charges are not established by current official schema/pricing evidence. The [approved acceptance reconciliation](docs/research/compute-acceptance-reconciliation.md) permits explicit unsupported compute handling, not fabricated capture; missing required token/cache data still blocks pricing. The local live runner intentionally rejects `computeUnit` pricing before launching Pi because it does not yet capture compute-unit telemetry; external DeepSWE import supports compute charges. Context absent from aggregate evidence is `unknown`, not eligible or failed. Live results explicitly report `metrics.computeUnits: null` and unsupported compute telemetry. Pi's adapter-normalized zeros cannot prove that original provider fields were present. Live repricing now reads the patched adapter's `message.usageProvenance.rawUsage` instead; absent/unsupported provenance makes cost unavailable and blocks queued launches. See [live telemetry readiness](docs/benchmark-telemetry.md) for inspected runtime versions, model/effort support, and remaining screening blockers.\n\nFor host-side validation, use `evaluator.kind: \"command\"` with `command`, optional `args`, `expectations`, and `timeoutMs`. `{input}`, `{workspace}`, and `{caseDir}` tokens resolve after candidate exit; the same input and workspace paths are exposed as `PI_BENCHMARK_EVALUATOR_INPUT` and `PI_BENCHMARK_WORKSPACE`. Evaluator input JSON contains `candidateOutput`, `workspace`, and `expectations`. Commands are trusted case configuration and run with operator permissions.\n\nThe [support Agent role corpus](benchmarks/support/README.md) provides nine source-checkout cases for scout, delegate, and researcher: one screening plus two additional finalist cases per role, with host-only evaluators and offline regression tests. Case Routes are intentionally unconfigured; this does not authorize paid screening.\n\nThe [decision and orchestration corpus](benchmarks/judgment/README.md) adds six oracle/parent cases. Parent workflows launch actual fixed-Route Pi children, retain fresh-session/per-turn evidence, and include child spend in pre-launch budget checks. Hidden rubrics verify grounded decisions and executable integration, not claimed success. All Routes remain unconfigured; no paid screening is authorized.\n\nA complete historical case lives at `benchmarks/historical-mission-lock/case.json`. It replays the source immediately before the later fix; its host-only evaluator preserves known lock-collision behavior and adds an unseen Windows edge case.\n\n### Replacing `pi-subagents`\n\nDo not load both packages simultaneously: both register the same `subagent` tools and `/subagents-*` commands.\n\n```bash\npi remove npm:pi-subagents\npi install https://github.com/elBenz/pi-ensemble\n```\n\nIf you installed `pi-subagents` from Git or a local path, remove that exact source shown by `pi list`, then install `pi-ensemble`. Restart Pi after switching packages.\n\n## Try it\n\nAsk Pi naturally:\n\n```text\nUse reviewer to review this diff.\n```\n\n```text\nAsk oracle to challenge this plan before we edit.\n```\n\n```text\nRun parallel reviewers for correctness, tests, and unnecessary complexity.\n```\n\nPi decides how to call the stable `subagent` tool and compose the work.\n\n## How it works\n\nPi remains the parent orchestrator. Each subagent is a focused child session with its own task, model, tools, context, and optional isolated worktree.\n\n- Fresh or explicitly forked child context\n- Foreground and asynchronous execution\n- Scripted sequential, parallel, branching, retry, and resume workflows\n- Bounded model-facing receipts backed by full output artifacts\n- Capability ceilings, replay barriers, mission locking, and supervisor messaging\n- Fleet status, live inspection, steering, stopping, and durable run records\n\nInstalling the extension does not start autonomous work. It adds capabilities the parent session may invoke.\n\n## Builtin agents\n\n| Agent | Purpose |\n| --- | --- |\n| `scout` | Fast codebase reconnaissance |\n| `researcher` | Web and documentation research |\n| `worker` | Scoped implementation and validation |\n| `reviewer` | Correctness, test, and simplicity review |\n| `oracle` | Read-only second opinion and assumption challenge |\n| `delegate` | Lightweight general delegation |\n\nRecommended implementation loop: `clarify → scout → worker → fresh reviewers → worker`.\n\n## Compatibility and migration notes\n\n- Model-facing tool name remains `subagent`.\n- Existing workflow payloads and `/subagents-*` commands remain compatible.\n- Internal `pi-subagents.*` registry keys and established storage paths remain where changing them would break interoperability or existing state.\n- TypeScript package imports use the new package name, for example `pi-ensemble/background-work`.\n- The bundled parent skill still uses compatibility-oriented subagent terminology internally. Further renaming will require explicit migration support.\n- Upstream changes are not merged automatically; every sync must be reviewed against fork-specific boundaries.\n\n## Caveats and security boundaries\n\n- **Not a sandbox.** Pi extensions execute with the user's OS permissions. A child can use every tool and extension its resolved launch contract allows.\n- **Capability controls are policy boundaries, not process isolation.** Use containers, restricted credentials, or separate OS accounts when stronger isolation is required.\n- **Artifacts may be sensitive.** Child transcripts, prompts, results, and receipts can contain source code or secrets. Protect session and artifact directories accordingly.\n- **Remote actions remain human authority.** A passing child, reviewer, CI receipt, or mission record is evidence—not permission to merge, publish, deploy, or release.\n- **Composite async workflows may be intentionally unbounded.** Configure child/runtime limits when finite completion time matters.\n- **Real-session E2E depends on Pi runtime fixtures.** That suite skips when required runtime packages are unavailable; unit, integration, and type checks remain the baseline.\n- **Young fork.** Version `0.1.x` signals that naming, release automation, and upstream-sync policy are still being established.\n\n## Known roadmap gaps\n\nThese areas are not claimed as solved:\n\n- true nonterminal review gates\n- finite top-level timeout semantics for composite async workflows\n- capability-token authentication for supervisor messaging\n- clearer model-scope naming and enforcement\n- deeper turn, tool, and usage-budget semantics\n- typed prompt-section filtering and stronger memory-integrity guarantees\n\nContributions and design discussion are welcome, but compatibility and execution safety take precedence over feature count.\n\n## Documentation\n\n- [Agents](docs/agents.md)\n- [Models](docs/models.md)\n- [Workflows](docs/workflows.md)\n- [Watchdog](docs/watchdog.md)\n- [Tool reference](docs/tool-reference.md)\n- [Observability](docs/observability.md)\n- [Missions and schedules](docs/missions.md)\n- [Configuration](docs/configuration.md)\n- [Extension API](docs/extension-api.md)\n\nUse `/subagents-doctor` to inspect installation health and `/subagents-guide [topic]` for installed-version help.\n\n## License\n\n[MIT](LICENSE). Original and fork copyright notices are preserved.\n"}