{"_id":"@blackbelt-technology/pi-dashboard-subagents","_rev":"6-99d6909a4c55094d69d57daa6fe6cd19","name":"@blackbelt-technology/pi-dashboard-subagents","dist-tags":{"latest":"0.2.5"},"versions":{"0.2.0":{"name":"@blackbelt-technology/pi-dashboard-subagents","version":"0.2.0","keywords":["pi-package","pi-coding-agent","subagent","agent"],"license":"MIT","_id":"@blackbelt-technology/pi-dashboard-subagents@0.2.0","maintainers":[{"name":"mbotond","email":"botond.molnar@blackbelt.hu"},{"name":"mrbence","email":"dbence10@gmail.com"},{"name":"robertcsakany","email":"robert.csakany@blackbelt.hu"},{"name":"norbert.herczeg","email":"norbert.herczeg@blackbelt.hu"}],"homepage":"https://github.com/BlackBeltTechnology/pi-dashboard-subagents#readme","bugs":{"url":"https://github.com/BlackBeltTechnology/pi-dashboard-subagents/issues"},"pi":{"extensions":["./extensions"]},"dist":{"shasum":"e16664d8f7e05dbb83cd0f6a46e00f907fe703ca","tarball":"https://registry.npmjs.org/@blackbelt-technology/pi-dashboard-subagents/-/pi-dashboard-subagents-0.2.0.tgz","fileCount":12,"integrity":"sha512-VLAHKk1Sx9uochdhPhPkFO8vhEJ5xowNlUhlgm02J94AkfywWxb1/Gtw4bg4XKYUBt+p4MFWibxylU0FJZWPsw==","signatures":[{"sig":"MEUCIQCSiE17ih7hdn3E384DOPyq13w6iMAhvu8iXstnJWX76AIgZNWjlfOdW5Lm2Gc03vQ1AzIRGOYAHEyX2UC47oVDcSY=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":143175},"main":"./extensions/index.ts","type":"module","exports":{".":"./extensions/index.ts"},"gitHead":"4853e59d514a3fa8eb85a0bd0bbe2ba7c18b7e2e","scripts":{"test":"vitest run","test:watch":"vitest"},"_npmUser":{"name":"mbotond","email":"botond.molnar@blackbelt.hu"},"repository":{"url":"git+https://github.com/BlackBeltTechnology/pi-dashboard-subagents.git","type":"git"},"_npmVersion":"11.12.1","description":"A lightweight subagent spawning and managing system for pi.","directories":{},"_nodeVersion":"24.15.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^4.0.0","@sinclair/typebox":"^0.34.49","@earendil-works/pi-ai":"^0.75.5","@earendil-works/pi-tui":"^0.75.5","@earendil-works/pi-coding-agent":"^0.75.5"},"peerDependencies":{"@sinclair/typebox":"^0.34.49","@earendil-works/pi-ai":"^0.75.5","@earendil-works/pi-tui":"^0.75.5","@earendil-works/pi-coding-agent":"^0.75.5"},"_npmOperationalInternal":{"tmp":"tmp/pi-dashboard-subagents_0.2.0_1779975875411_0.8964588677827843","host":"s3://npm-registry-packages-npm-production"}},"0.2.1":{"name":"@blackbelt-technology/pi-dashboard-subagents","version":"0.2.1","keywords":["pi-package","pi-coding-agent","subagent","agent"],"license":"MIT","_id":"@blackbelt-technology/pi-dashboard-subagents@0.2.1","maintainers":[{"name":"mbotond","email":"botond.molnar@blackbelt.hu"},{"name":"mrbence","email":"dbence10@gmail.com"},{"name":"robertcsakany","email":"robert.csakany@blackbelt.hu"},{"name":"norbert.herczeg","email":"norbert.herczeg@blackbelt.hu"}],"homepage":"https://github.com/BlackBeltTechnology/pi-dashboard-subagents#readme","bugs":{"url":"https://github.com/BlackBeltTechnology/pi-dashboard-subagents/issues"},"pi":{"extensions":["./extensions"]},"dist":{"shasum":"8d1d031b9d513d7e3e826f3837b7090b619fafa5","tarball":"https://registry.npmjs.org/@blackbelt-technology/pi-dashboard-subagents/-/pi-dashboard-subagents-0.2.1.tgz","fileCount":13,"integrity":"sha512-uhI4mA4+inzhenJsIfmsvWeMRbodaaFvDu76E/cygZKLbCTHLNCg5POZ/HaqU6HLV57BFH1AttefCkJibfLarA==","signatures":[{"sig":"MEYCIQD7fBECGpbDngTcoTBgAWZMCIxirDw8GR/CpOxfb1MjmgIhAO8LqQZksdOMDrhL56F441uQJLGsiOguNUvfU+M2a/y+","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@blackbelt-technology%2fpi-dashboard-subagents@0.2.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":161610},"main":"./extensions/index.ts","type":"module","exports":{".":"./extensions/index.ts"},"gitHead":"21bb945b15aa673c7ab11fcdf595537ea06077c5","scripts":{"lint":"eslint extensions","test":"vitest run","typecheck":"tsc --noEmit","test:watch":"vitest"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:b33fdd1a-ca73-4bed-a70b-a778ecd1b7d5"}},"repository":{"url":"git+https://github.com/BlackBeltTechnology/pi-dashboard-subagents.git","type":"git"},"_npmVersion":"11.16.0","description":"A lightweight subagent spawning and managing system for pi.","directories":{},"_nodeVersion":"24.16.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"eslint":"^10.4.0","vitest":"^4.0.0","@eslint/js":"^10.0.1","typescript":"^6.0.3","@types/node":"^25.8.0","@sinclair/typebox":"^0.34.49","typescript-eslint":"^8.59.3","@earendil-works/pi-ai":"^0.75.5","@earendil-works/pi-tui":"^0.75.5","@earendil-works/pi-coding-agent":"^0.75.5"},"peerDependencies":{"@sinclair/typebox":"^0.34.49","@earendil-works/pi-ai":"^0.75.5","@earendil-works/pi-tui":"^0.75.5","@earendil-works/pi-coding-agent":"^0.75.5"},"_npmOperationalInternal":{"tmp":"tmp/pi-dashboard-subagents_0.2.1_1780649770580_0.8043943595437713","host":"s3://npm-registry-packages-npm-production"}},"0.2.2":{"name":"@blackbelt-technology/pi-dashboard-subagents","version":"0.2.2","keywords":["pi-package","pi-coding-agent","subagent","agent"],"license":"MIT","_id":"@blackbelt-technology/pi-dashboard-subagents@0.2.2","maintainers":[{"name":"mbotond","email":"botond.molnar@blackbelt.hu"},{"name":"mrbence","email":"dbence10@gmail.com"},{"name":"robertcsakany","email":"robert.csakany@blackbelt.hu"},{"name":"norbert.herczeg","email":"norbert.herczeg@blackbelt.hu"}],"homepage":"https://github.com/BlackBeltTechnology/pi-dashboard-subagents#readme","bugs":{"url":"https://github.com/BlackBeltTechnology/pi-dashboard-subagents/issues"},"pi":{"extensions":["./extensions"]},"dist":{"shasum":"ec2ec50a894e021e3dc351d97d126958d7aa36df","tarball":"https://registry.npmjs.org/@blackbelt-technology/pi-dashboard-subagents/-/pi-dashboard-subagents-0.2.2.tgz","fileCount":13,"integrity":"sha512-D6a6T8pZGWUK1sUu8zKTrXlhsJsycMnBRH4MT9KvgSOFgBxmOqTLQe8zkt05wSy3Sfu99Cm1xkaFlFkLKFkmPw==","signatures":[{"sig":"MEQCIDAJKgU2g/uwYjWQ1FL/PPr0I9XOMCqrL6D+7nMVDfAjAiBYry5lQMeasediRIWcKBQLG7h/jtrmQpkcju7q52TsPQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@blackbelt-technology%2fpi-dashboard-subagents@0.2.2","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":162006},"main":"./extensions/index.ts","type":"module","exports":{".":"./extensions/index.ts"},"gitHead":"dde9ccc28fe220b78549c5aa828d35656c181664","scripts":{"lint":"eslint extensions","test":"vitest run","typecheck":"tsc --noEmit","test:watch":"vitest"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:b33fdd1a-ca73-4bed-a70b-a778ecd1b7d5"}},"repository":{"url":"git+https://github.com/BlackBeltTechnology/pi-dashboard-subagents.git","type":"git"},"_npmVersion":"11.16.0","description":"A lightweight subagent spawning and managing system for pi.","directories":{},"_nodeVersion":"24.16.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"eslint":"^10.4.0","vitest":"^4.0.0","@eslint/js":"^10.0.1","typescript":"^6.0.3","@types/node":"^25.8.0","@sinclair/typebox":"^0.34.49","typescript-eslint":"^8.59.3","@earendil-works/pi-ai":"^0.75.5","@earendil-works/pi-tui":"^0.75.5","@earendil-works/pi-coding-agent":"^0.75.5"},"peerDependencies":{"@sinclair/typebox":"^0.34.49","@earendil-works/pi-ai":"^0.75.5","@earendil-works/pi-tui":"^0.75.5","@earendil-works/pi-coding-agent":"^0.75.5"},"_npmOperationalInternal":{"tmp":"tmp/pi-dashboard-subagents_0.2.2_1780652047063_0.3398561059007339","host":"s3://npm-registry-packages-npm-production"}},"0.2.3":{"name":"@blackbelt-technology/pi-dashboard-subagents","version":"0.2.3","keywords":["pi-package","pi-coding-agent","subagent","agent"],"license":"MIT","_id":"@blackbelt-technology/pi-dashboard-subagents@0.2.3","maintainers":[{"name":"mbotond","email":"botond.molnar@blackbelt.hu"},{"name":"mrbence","email":"dbence10@gmail.com"},{"name":"robertcsakany","email":"robert.csakany@blackbelt.hu"},{"name":"norbert.herczeg","email":"norbert.herczeg@blackbelt.hu"}],"homepage":"https://github.com/BlackBeltTechnology/pi-dashboard-subagents#readme","bugs":{"url":"https://github.com/BlackBeltTechnology/pi-dashboard-subagents/issues"},"pi":{"extensions":["./extensions"]},"dist":{"shasum":"936133069f4fd5f96c2cb8cb958626b77317f32c","tarball":"https://registry.npmjs.org/@blackbelt-technology/pi-dashboard-subagents/-/pi-dashboard-subagents-0.2.3.tgz","fileCount":15,"integrity":"sha512-118mZCTtdAEhgy6keATJOIZ7Qkc/ZcQC+iViI9J5paJ2vZ6wg8CEFQ/RMGRGVvJco6nuQPC5gy16I3cyMlG+Ag==","signatures":[{"sig":"MEQCIAjlxuJFv/szQugo1sQqzV4teQV37BpkQeElQyFVIHGuAiAw4wucwlvCtxQyr34F6BanXcAXFyNMBj2xfibQ8gqI7w==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":199928},"main":"./extensions/index.ts","type":"module","exports":{".":"./extensions/index.ts"},"gitHead":"dc5b4fb7f749510d5af9b68d75e13877af5c43d6","scripts":{"lint":"eslint extensions","test":"vitest run","typecheck":"tsc --noEmit","test:watch":"vitest"},"_npmUser":{"name":"robertcsakany","email":"robert.csakany@blackbelt.hu"},"repository":{"url":"git+https://github.com/BlackBeltTechnology/pi-dashboard-subagents.git","type":"git"},"_npmVersion":"10.9.3","description":"A lightweight subagent spawning and managing system for pi.","directories":{},"_nodeVersion":"24.15.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"eslint":"^10.4.0","vitest":"^4.0.0","@eslint/js":"^10.0.1","typescript":"^6.0.3","@types/node":"^25.8.0","@sinclair/typebox":"^0.34.49","typescript-eslint":"^8.59.3","@earendil-works/pi-ai":"^0.75.5","@earendil-works/pi-tui":"^0.75.5","@earendil-works/pi-coding-agent":"^0.75.5"},"peerDependencies":{"@sinclair/typebox":"^0.34.49","@earendil-works/pi-ai":"^0.75.5","@earendil-works/pi-tui":"^0.75.5","@earendil-works/pi-coding-agent":"^0.75.5"},"_npmOperationalInternal":{"tmp":"tmp/pi-dashboard-subagents_0.2.3_1784372271685_0.45701316558076766","host":"s3://npm-registry-packages-npm-production"}},"0.2.4":{"name":"@blackbelt-technology/pi-dashboard-subagents","version":"0.2.4","keywords":["pi-package","pi-coding-agent","subagent","agent"],"license":"MIT","_id":"@blackbelt-technology/pi-dashboard-subagents@0.2.4","maintainers":[{"name":"mbotond","email":"botond.molnar@blackbelt.hu"},{"name":"mrbence","email":"dbence10@gmail.com"},{"name":"robertcsakany","email":"robert.csakany@blackbelt.hu"},{"name":"norbert.herczeg","email":"norbert.herczeg@blackbelt.hu"}],"homepage":"https://github.com/BlackBeltTechnology/pi-dashboard-subagents#readme","bugs":{"url":"https://github.com/BlackBeltTechnology/pi-dashboard-subagents/issues"},"pi":{"extensions":["./extensions"]},"dist":{"shasum":"63b5972776b92a775ad061e4302bfa23e2cc6da2","tarball":"https://registry.npmjs.org/@blackbelt-technology/pi-dashboard-subagents/-/pi-dashboard-subagents-0.2.4.tgz","fileCount":15,"integrity":"sha512-AJEI+UUjCsg6YIpTJQ7lXgsGJGkMu7m+z+jGUDtPWtjZitBwr+T+tVTk6+lJ/t3FyeeAwE5puVdSVjdIYBDB7g==","signatures":[{"sig":"MEYCIQDymNUvTX/gPXqUZcIZuqteUkA8sIJVjZVKuiwKtEipawIhANMnRW4NjvezXewscDr90cQmP3YNhAPTamHVWkBVQ6Mi","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@blackbelt-technology%2fpi-dashboard-subagents@0.2.4","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":200526},"main":"./extensions/index.ts","type":"module","exports":{".":"./extensions/index.ts"},"gitHead":"7f38345bd00ded7c89f6f6274389d01f95526930","scripts":{"lint":"eslint extensions","test":"vitest run","typecheck":"tsc --noEmit","test:watch":"vitest"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:b33fdd1a-ca73-4bed-a70b-a778ecd1b7d5"}},"repository":{"url":"git+https://github.com/BlackBeltTechnology/pi-dashboard-subagents.git","type":"git"},"_npmVersion":"12.0.2","description":"A lightweight subagent spawning and managing system for pi.","directories":{},"_nodeVersion":"24.18.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"eslint":"^10.4.0","vitest":"^4.0.0","@eslint/js":"^10.0.1","typescript":"^6.0.3","@types/node":"^25.8.0","@sinclair/typebox":"^0.34.49","typescript-eslint":"^8.59.3","@earendil-works/pi-ai":"^0.75.5","@earendil-works/pi-tui":"^0.75.5","@earendil-works/pi-coding-agent":"^0.75.5"},"peerDependencies":{"@sinclair/typebox":"^0.34.49","@earendil-works/pi-ai":"^0.75.5","@earendil-works/pi-tui":"^0.75.5","@earendil-works/pi-coding-agent":"^0.75.5"},"_npmOperationalInternal":{"tmp":"tmp/pi-dashboard-subagents_0.2.4_1786380358496_0.7822582355470864","host":"s3://npm-registry-packages-npm-production"}},"0.2.5":{"name":"@blackbelt-technology/pi-dashboard-subagents","version":"0.2.5","description":"A lightweight subagent spawning and managing system for pi.","repository":{"type":"git","url":"git+https://github.com/BlackBeltTechnology/pi-dashboard-subagents.git"},"license":"MIT","publishConfig":{"access":"public"},"keywords":["pi-package","pi-coding-agent","subagent","agent"],"type":"module","main":"./extensions/index.ts","exports":{".":"./extensions/index.ts"},"pi":{"extensions":["./extensions"]},"scripts":{"lint":"eslint extensions","typecheck":"tsc --noEmit","test":"vitest run","test:fanout-memory":"vitest run --execArgv=--expose-gc --disableConsoleIntercept extensions/__tests__/fanout-memory.test.ts","test:watch":"vitest"},"peerDependencies":{"@earendil-works/pi-ai":"^0.75.5","@earendil-works/pi-coding-agent":"^0.75.5","@earendil-works/pi-tui":"^0.75.5","@sinclair/typebox":"^0.34.49"},"devDependencies":{"@earendil-works/pi-ai":"^0.75.5","@earendil-works/pi-coding-agent":"^0.75.5","@earendil-works/pi-tui":"^0.75.5","@eslint/js":"^10.0.1","@sinclair/typebox":"^0.34.49","@types/node":"^25.8.0","eslint":"^10.4.0","typescript":"^6.0.3","typescript-eslint":"^8.59.3","vitest":"^4.0.0"},"gitHead":"4dc911fa81f8d5370a102642eb004c31626d0df8","_id":"@blackbelt-technology/pi-dashboard-subagents@0.2.5","bugs":{"url":"https://github.com/BlackBeltTechnology/pi-dashboard-subagents/issues"},"homepage":"https://github.com/BlackBeltTechnology/pi-dashboard-subagents#readme","_nodeVersion":"24.20.0","_npmVersion":"12.0.2","dist":{"integrity":"sha512-aGW02McyLcXIX7EgwMkhNKgDRXBMdE0rbKXWIqCvwoviU+dyHEuJ48Y765Zpui6hRx2nArxR71JbTTbSOpirFw==","shasum":"3430b90866594cd12f2b831ae2520b8267e62b86","tarball":"https://registry.npmjs.org/@blackbelt-technology/pi-dashboard-subagents/-/pi-dashboard-subagents-0.2.5.tgz","fileCount":16,"unpackedSize":234725,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@blackbelt-technology%2fpi-dashboard-subagents@0.2.5","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIBM/RAYmm3ftN4sAlI19tga2fVxqv4K4XS7DpluC6i0eAiEA/I37ULlIOgWxHPhOgFJ6LMBKo8SpxoldrQhSOq1z6aY="}]},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:b33fdd1a-ca73-4bed-a70b-a778ecd1b7d5"}},"directories":{},"maintainers":[{"name":"mbotond","email":"botond.molnar@blackbelt.hu"},{"name":"mrbence","email":"dbence10@gmail.com"},{"name":"robertcsakany","email":"robert.csakany@blackbelt.hu"},{"name":"norbert.herczeg","email":"norbert.herczeg@blackbelt.hu"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/pi-dashboard-subagents_0.2.5_1789558112877_0.5538879894723054"},"_hasShrinkwrap":false}},"time":{"created":"2026-05-28T13:44:35.268Z","modified":"2026-09-16T11:28:33.340Z","0.2.0":"2026-05-28T13:44:35.551Z","0.2.1":"2026-06-05T08:56:10.747Z","0.2.2":"2026-06-05T09:34:07.195Z","0.2.3":"2026-07-18T10:57:51.818Z","0.2.4":"2026-08-10T16:45:58.663Z","0.2.5":"2026-09-16T11:28:33.054Z"},"bugs":{"url":"https://github.com/BlackBeltTechnology/pi-dashboard-subagents/issues"},"license":"MIT","homepage":"https://github.com/BlackBeltTechnology/pi-dashboard-subagents#readme","keywords":["pi-package","pi-coding-agent","subagent","agent"],"repository":{"type":"git","url":"git+https://github.com/BlackBeltTechnology/pi-dashboard-subagents.git"},"description":"A lightweight subagent spawning and managing system for pi.","maintainers":[{"name":"mbotond","email":"botond.molnar@blackbelt.hu"},{"name":"mrbence","email":"dbence10@gmail.com"},{"name":"robertcsakany","email":"robert.csakany@blackbelt.hu"},{"name":"norbert.herczeg","email":"norbert.herczeg@blackbelt.hu"}],"readme":"# pi-dashboard-subagents\n\nA lightweight **foreground** subagent extension for [pi](https://github.com/mariozechner/pi).\n\nSpawns subagents **in-memory** (no new sessions appear in `~/.pi/agent/sessions/`, no\nclutter in the dashboard's session list) and emits **every event, tool call, and\nreasoning step** as a structured timeline the pi-agent-dashboard can render in its\nsubagent inspector and pop out into a new tab.\n\n## Scope\n\n- **Foreground only.** Subagents block the caller until completion.\n- **No background spawning.** No `get_subagent_result`. No `steer_subagent`.\n- **No new sessions on disk.** Sessions live entirely in memory.\n- **Full observability.** Every `tool_execution_end`, `text_end`, `thinking_end`,\n  and error from the subagent's session is mirrored to the dashboard as a\n  `SubagentTimelineEntry`.\n- **Inherits parent context by default.** Opt-out with `isolated: true`.\n\n## Context inheritance\n\nBy default, every subagent inherits a **compressed copy** of the parent's\nrecent conversation. The compression strategy is verbatim-compaction (zero\nhallucination risk, no extra LLM calls):\n\n```\nKeep last N turn pairs (default N=6) verbatim.\nFor turns beyond the tool-output window (default last 2 turns):\n  - tool_result blocks   → \"[…tool output omitted, see earlier message]\"\n  - tool_use blocks      → \"[tool_use: <name>]\"\n  - thinking blocks      → \"[…thinking omitted…]\"\n  - large text (>2KB)    → first 1.5KB + \"[…truncated…]\"\nHard cap at 24K characters (~6K tokens) with mid-truncation.\n```\n\n### Settings\n\nTwo persistent settings live at:\n\n```\n~/.pi/agent/extensions/pi-dashboard-subagents/config.json\n```\n\n```json\n{\n  \"inheritContext\": true,\n  \"exposeInheritanceInTool\": false,\n  \"maxConcurrent\": 4,\n  \"inheritance\": {\n    \"recentTurns\": 6,\n    \"toolOutputWindow\": 2,\n    \"maxChars\": 24000\n  }\n}\n```\n\n| Setting                    | Meaning                                                                                          |\n| -------------------------- | ------------------------------------------------------------------------------------------------ |\n| `inheritContext`           | When `true`, every subagent inherits a compressed copy of parent context.                        |\n| `exposeInheritanceInTool`  | When `true`, the `Agent` tool's JSON schema exposes an `isolated` parameter the LLM can flip. When `false` (default), the schema is fixed and the global `inheritContext` setting always applies. |\n| `inheritance.recentTurns`  | Verbatim turn pairs kept (default 6).                                                            |\n| `inheritance.toolOutputWindow` | Recent turns where tool outputs stay verbatim (default 2).                                   |\n| `inheritance.maxChars`     | Hard cap on the compressed context (default 24000 chars ≈ 6K tokens).                            |\n| `maxConcurrent`            | Maximum subagents running at once in this process (default 4). Extra spawns wait FIFO and their dashboard card shows `queued` until a slot frees. `0` = unlimited (the pre-0.2.5 behaviour). Re-read from disk per spawn — no `/reload` needed. |\n\n#### Why a concurrency cap\n\nSubagents run **in the parent process** (one V8 heap, one event loop). An\nunbounded fan-out of parallel `Agent` calls stacks every child's per-turn\nextension work onto the parent's loop, which can stall the parent long enough\nfor the dashboard bridge watchdog to force-close the session. The cap bounds\nthat worst case; set `maxConcurrent: 0` to opt out.\n\n#### Child resource loading\n\nEach child session gets its **own** lean resource loader: extensions are loaded\n(so the child keeps the full tool surface, minus `Agent`), but **skills, prompt\ntemplates and themes are not** — a headless child never reads them, and\nskipping them cuts memory noticeably on wide fan-outs. Skills remain reachable\nby path if the parent passes them in the prompt.\n\nFour usage modes:\n\n```\ninheritContext=true,  exposeInheritanceInTool=false  (default)\n  → every subagent inherits. LLM cannot opt out. Lean tool schema.\n\ninheritContext=false, exposeInheritanceInTool=false\n  → every subagent is isolated. LLM cannot opt in. Lean tool schema.\n\ninheritContext=true,  exposeInheritanceInTool=true\n  → inherits by default. LLM can set `isolated: true` per call to opt out.\n\ninheritContext=false, exposeInheritanceInTool=true\n  → isolated by default. LLM can set `isolated: false` per call to opt in.\n```\n\nMissing file or fields fall back to baked-in defaults. Settings are cached\nafter first read; edit the file and restart pi, or call `invalidateSettingsCache()`\nprogrammatically to pick up changes.\n\n### Compression is operator-controlled only\n\n`recentTurns`, `toolOutputWindow`, and `maxChars` are never exposed to the\nLLM under any setting. They're operator concerns — fine-tune them globally\nby editing the config file, then restart pi.\n\n## Upstream prompt caching — future work\n\nThe ideal architecture for context inheritance is what Claude Code calls\n[Fork Agents](https://claude-code-from-source.com/ch09-fork-agents/):\nthe subagent's first provider call hits the **parent's cache** by sending\na byte-identical prefix marked with `cache_control: { type: \"ephemeral\" }`.\nResult: 90% input cost reduction, 80% latency reduction on the inherited\ncontext.\n\nThis extension does NOT yet implement true cache-fork behavior because\n`pi-coding-agent`'s public `session.prompt(text)` API takes a string —\nthere's no path to inject pre-built message arrays with cache markers.\nFor now we accept token-savings-only from compression and leave upstream\ncaching as a follow-up.\n\nFollow-up paths (when pi-coding-agent SDK supports them):\n\n- Inject parent messages as initial session state via the lower-level\n  `createAgentSessionFromServices` / `AgentSessionRuntime` API.\n- Add `cache_control` markers at the inherited-prefix boundary.\n- Anthropic: 90/80% reduction. OpenAI: automatic (just needs identical\n  prefix). Gemini: explicit cache via `createCachedContent`.\n\n## Why another subagent extension?\n\nThe two existing subagent extensions for pi each have a tradeoff:\n\n| Extension                          | Spawn model        | Session list  | Rich timeline | Background |\n| ---------------------------------- | ------------------ | ------------- | ------------- | ---------- |\n| `@tintinweb/pi-subagents`          | In-memory          | Clean ✓       | Summary only  | Yes        |\n| `pi-subagents` (Nico Bailon)       | Separate process   | Cluttered ✗   | Full ✓        | Yes        |\n| **`pi-dashboard-subagents` (this)**| **In-memory ✓**    | **Clean ✓**   | **Full ✓**    | No (by design) |\n\nThis extension drops background/async complexity entirely and focuses on one\nthing: foreground subagent runs with first-class observability for the\npi-agent-dashboard inspector.\n\n## Install\n\n```bash\nnpm install -g @blackbelt-technology/pi-dashboard-subagents\n```\n\nThen add to `~/.pi/agent/settings.json`:\n\n```json\n{\n  \"packages\": [\n    \"npm:@blackbelt-technology/pi-dashboard-subagents\"\n  ]\n}\n```\n\nOr for local development:\n\n```json\n{\n  \"packages\": [\n    \"/absolute/path/to/pi-dashboard-subagents\"\n  ]\n}\n```\n\n## Usage\n\nIn any pi session, invoke the tool:\n\n```\nAgent(\n  subagent_type: \"Explore\",\n  description: \"Find auth flows\",\n  prompt: \"Look through src/auth and summarize OAuth providers\"\n)\n```\n\nThe subagent runs in-memory under the parent pi process. Live progress is\nstreamed back to the caller via the standard `AgentDetails` payload plus the\n`entries[]` timeline field. The subagent never appears as a separate session.\n\n## Agent `.md` files\n\nv0.2.0 added YAML frontmatter parsing for agent `.md` definition files plus a\n3-tier resolver and a bundled default Explore agent.\n\n### Frontmatter schema\n\nEvery field is optional. Missing fields fall through to current pre-frontmatter\nbehaviour, so an `.md` with no frontmatter still works.\n\n```yaml\n---\ndescription: Fast read-only codebase & docs exploration\nmodel: anthropic/claude-haiku-4-5      # OR \"@role\" — see below\nthinking: high                          # (alt: \"model: id:high\" suffix)\ntools: [read, grep, find, ls, bash]    # allowlist (built-in + extension tools)\ninherit_context: false                  # per-agent override of the global setting\nprompt: |                              # OPTIONAL — body fallback below\n  You are an Explore subagent. Be fast and read-only.\n---\n\nThe markdown body becomes the agent prompt when no `prompt:` field is set.\nThis matches the convention used by Claude Code and pi-coding-agent's own\nprompt-template / skill files.\n```\n\n| Field             | Effect                                                                                              |\n| ----------------- | --------------------------------------------------------------------------------------------------- |\n| `description`     | Overrides `displayName` on the dashboard card.                                                      |\n| `model`           | `\"@role\"`, `\"provider/model-id\"`, `\"provider/model-id:thinking\"`, or bare `\"model-id\"`. See [Model resolution](#model-resolution-model). |\n| `tools`           | Allowlist intersected with the parent's active tool set (minus `Agent`). Unknown names dropped silently. |\n| `inherit_context` | `true` → inherit parent context. `false` → isolated. Per-agent; overrides the global `inheritContext`.|\n| `prompt`          | Prepended as `<agent-prompt>...</agent-prompt>` before the task. Body of the `.md` is used if the field is absent. |\n\nAll fields are read once at spawn time. Editing the `.md` while a subagent is\nrunning has no effect on that subagent; the next spawn picks up changes.\n\n### Four-tier resolution\n\nWhen the LLM calls `Agent({ subagent_type: \"Explore\", ... })`, the extension\nlooks up `Explore.md` in four tiers, most-specific first:\n\n```\n1. <cwd>/.pi/agents/Explore.md          → source: \"project\"   (per-project override)\n2. ~/.pi/agent/agents/Explore.md        → source: \"user\"      (per-user override)\n3. <EXTENSION_ROOT>/agents/Explore.md   → source: \"bundled\"   (ships with this package)\n4. <installedPath>/agents/Explore.md    → source: \"package\"   (any other installed pi package)\n```\n\nThe first match wins. The tier is surfaced as `AgentDetails.agentMdSource` so\nthe dashboard card can render \"Explore (bundled)\" / \"Explore (user)\" badges;\nfor tier 4 the originating package is also carried in `AgentDetails.agentMdPkg`\n(\"reviewer (package: @acme/pi-reviewers)\").\n\n### Shipping agents from a package\n\nAny installed pi package can ship spawnable agents — no manual copying into\n`.pi/agents/` required. Drop `agents/<name>.md` into the package, make sure\n`agents/` is included in the package's `files[]` (so it ends up in the\npublished tarball), install the package, and `Agent({ subagent_type: \"<name>\" })`\ncan spawn it. The `.md` uses the exact same [frontmatter schema](#frontmatter-schema)\nas project/user/bundled agents.\n\n```jsonc\n// the providing package's package.json\n{\n  \"files\": [\"agents/\", \"...\"]\n}\n```\n\nResolution rules for the package tier:\n\n- **Ranks last (tier 4).** Package agents fill a name only when the project,\n  user, and bundled tiers all miss — no name that resolves today can be\n  shadowed by a newly installed package. Place a `.pi/agents/<name>.md` in your\n  project (or `~/.pi/agent/agents/<name>.md`) to override a package agent.\n- **User-scope only.** Only packages installed into `~/.pi/agent` (user scope)\n  are scanned. Project-scoped packages (declared in a repo's `.pi/settings.json`)\n  are **never** indexed for agents — an untrusted checkout cannot register\n  spawnable agents. This is a deliberate conservative default, not an SDK\n  limitation: skipping project scope closes the untrusted-checkout injection\n  surface without having to reason about trust. (The SDK *does* expose a\n  project-trust signal — `ExtensionContext.isProjectTrusted()` /\n  `SettingsManagerCreateOptions.projectTrusted` — so a future opt-in could gate\n  project scope on trust; deferred by choice.)\n- **Deterministic collisions.** If two packages ship the same basename, the\n  package whose `source` string sorts first wins; the loser is dropped and a\n  warning naming both is written to stderr.\n- **`filtered` packages skipped.** A package configured with a resource\n  allowlist (`{ source, skills: [...] }` form) contributes no agents — there is\n  no `agents` filter key, so it is treated as not opted in.\n- **Discovery is lazy + cached.** The index is built on `resources_discover`\n  (startup / `/reload`) and, as a fallback, on the first spawn; it rebuilds on\n  `/reload` or a working-directory change. A newly installed package becomes\n  spawnable after `/reload` (no full restart needed).\n\n### Bundled `Explore` agent\n\nThe package ships `agents/Explore.md` — a fast, read-only codebase / docs\nexplorer informed by Claude Code's Explore agent and the production guidance\nin Ranjan Kumar's *Subagents: How to Run Parallelism Inside a Single Agent\nSession* (April 2026):\n\n- **Model**: `\"@fast\"` — role alias resolved at spawn time by the dashboard's\n  roles plugin. Operators pick the underlying model behind `@fast` via\n  Settings → Roles. This makes model choice operator-controlled at runtime\n  rather than baked into the shipped file.\n- **Tools**: `[read, grep, find, ls, bash]` — no write/edit/Agent.\n- **Inherit context**: `false` — fresh window, parent's context not imported.\n- **Output contract**: structured `## Answer / ## Evidence / ## Notes` with\n  hard limits (≤2000 tokens, no raw file dumps).\n\nThe bundled Explore **requires** a `model:resolve` handler to be loaded (so\n`@fast` can be looked up in `~/.pi/agent/providers.json`). The handler ships\nwith **pi-agent-dashboard** and (optionally) **pi-flows**. Without one of\nthem, `@role` references HARD-FAIL the spawn; literal model ids still resolve\nvia the in-process registry fallback. See [Model resolution](#model-resolution-model)\nbelow.\n\nTo customise (e.g. to run without the dashboard, or to pin a specific model):\n\n```bash\nmkdir -p ~/.pi/agent/agents\ncp \"$(node -e 'console.log(require.resolve(\"@blackbelt-technology/pi-dashboard-subagents/agents/Explore.md\"))')\" \\\n   ~/.pi/agent/agents/Explore.md\n# Edit ~/.pi/agent/agents/Explore.md — e.g. change `model:` to a literal\n# \"provider/model-id\" so it works without the roles-plugin bridge.\n```\n\nThe user-global override automatically wins over the bundled file (tier 2 > 3).\n\n### Model resolution (`model:`)\n\nThe `model:` field accepts four input forms, in priority order:\n\n| Form                              | Example                            | How it resolves                                                    |\n| --------------------------------- | ---------------------------------- | ------------------------------------------------------------------ |\n| `@role` (role alias)              | `@fast`                            | Handler reads `~/.pi/agent/providers.json#roles` — needs handler.   |\n| `provider/model-id`               | `anthropic/claude-opus-4`          | `pi.modelRegistry.find(provider, id)`.                              |\n| `provider/model-id:thinking`      | `anthropic/claude-haiku-4-5:high`  | Same as above; `:thinking` parsed off and surfaced separately.      |\n| Bare `model-id` (\"like\" query)    | `claude-haiku-4-5`                 | `pi.modelRegistry.getAll().find(m => m.id === ref)` — first wins.   |\n\nThe extension resolves the field in two phases:\n\n**1. Primary — `model:resolve` event.** The extension emits a probe on\n`pi.events`:\n\n```ts\nconst probe = { ref: \"@fast\" };       // or \"anthropic/opus\", or \"opus-4-5\"\npi.events.emit(\"model:resolve\", probe);\nif (probe.model)   { /* success */ }\nif (probe.error)   { /* handler reported a miss */ }\n// else: silent emit (no handler) — fall through to the fallback below\n```\n\nA handler is provided by **pi-agent-dashboard** (always) and (optionally)\n**pi-flows**. The handler is responsible for all four input forms above.\n\n**2. Fallback — in-process registry.** When the emit returns with both\n`probe.model` and `probe.error` unset (no handler reacted), the extension\nresolves literal forms locally via `pi.modelRegistry`:\n\n- `provider/model-id[:thinking]` → `registry.find(provider, id)`\n- Bare `model-id[:thinking]` → `registry.getAll().find(m => m.id === ref)`\n- `@role` → **NOT** supported by the fallback (no `providers.json` access);\n  fails with a clear \"install pi-agent-dashboard or pi-flows\" message.\n\nThis means: **subagents using literal or bare-id models always work**, with\nor without the dashboard. Only `@role` requires a handler.\n\n#### Failure surface\n\nWhen resolution fails (handler error, fallback miss, no handler for `@role`),\nthe tool call returns `isError: true` with a structured message that:\n\n- names the unresolved ref,\n- includes the agent `.md` path that specified it,\n- distinguishes \"role unknown\" vs \"model unknown\" vs \"no resolver available\",\n- suggests the right fix (install plugin, use literal form, add to\n  `providers.json`, etc.),\n- on bare-id misses includes a hint of registered model ids (capped at 20).\n\n#### Implementing a `model:resolve` handler\n\nAny pi extension can register a handler. Use the cooperative early-return\nidiom so multiple handlers (e.g. pi-flows + pi-agent-dashboard) coexist\nwithout fighting:\n\n```ts\npi.events.on(\"model:resolve\", (probe) => {\n  if (probe.model) return;                  // someone else already handled it\n\n  // 1. @role indirection (if you own roles)\n  // 2. provider/model split + registry.find()\n  // 3. bare-id “like” query against registry.getAll()\n\n  if (resolvedSuccessfully) {\n    probe.resolved      = \"provider/id\";    // canonical literal\n    probe.model         = m;                // Model object\n    probe.thinkingLevel = thk;              // parsed from \":high\" suffix, optional\n    probe.auth          = a;                // optional, registry-defined shape\n  } else {\n    probe.error    ??= reason;              // first error sticks\n    probe.available ??= { roles, models };  // optional diagnostics\n  }\n});\n```\n\nProbe shape (TypeScript):\n\n```ts\ninterface ModelResolveProbe {\n  ref: string;                                          // input\n  resolved?: string;                                    // \"provider/model-id\"\n  model?: Model<any>;\n  thinkingLevel?: \"minimal\" | \"low\" | \"medium\" | \"high\" | \"xhigh\" | \"off\";\n  auth?: { ok?: boolean; error?: string; [k: string]: unknown };\n  error?: string;\n  available?: {\n    roles?: Record<string, string>;\n    models?: string[];\n  };\n}\n```\n\n#### Standalone behaviour matrix\n\n|                                 | `@role`      | `provider/id` | bare `id`  |\n| ------------------------------- | ------------ | ------------- | ---------- |\n| With pi-agent-dashboard         | event ✅      | event ✅       | event ✅    |\n| With pi-flows (optional handler)| event ✅      | event ✅       | event ✅    |\n| Neither — standalone pi         | ❌ (install)  | fallback ✅    | fallback ✅ |\n\nWhen neither handler is loaded, only `@role` fails. Literal `provider/model`\nand bare `model-id` continue to work via the in-process registry fallback.\n\n#### Per-call model override (`model` tool-call param)\n\nThe `Agent` tool's parameter schema accepts an optional `model` field that\nshort-circuits any frontmatter `model:` value:\n\n```js\nAgent({\n  subagent_type: \"research-spike\",   // any label — no `.md` required\n  description:   \"audit auth flow\",\n  prompt:        \"Review extensions/agent.ts for auth issues.\",\n  model:         \"@fast\",            // OR \"anthropic/claude-haiku-4-5\"\n                                     // OR bare \"claude-haiku-4-5\"\n})\n```\n\nThe `model` arg accepts the **same three forms** as the frontmatter field\n(`@role`, `provider/model[:thinking]`, bare `model-id`) and resolves via the\n**same `model:resolve` event-bus + in-process fallback** pipeline. No\nduplication, no second resolver — it's the identical machinery.\n\n**Precedence (highest wins):**\n\n```\n  args.model      (tool-call argument)\n   > agentConfig.model    (`.md` frontmatter)\n    > pi default (settings.json)\n```\n\nWhen `args.model` is non-empty it WINS and the `.md`'s `model:` is ignored.\nWhen `args.model` is omitted (or empty/whitespace) the `.md` value applies.\nWhen both are absent, the parent's default model is inherited.\n\nFailure modes are identical to the frontmatter path. Error messages cite\nthe source of the unresolvable ref — either the `.md` file path or the\nliteral label `(tool-call argument)` — so operators can trace bad refs.\n\n## Wire-protocol contract\n\nThis section locks the producer-side contract consumed by the dashboard inspector.\n\n### Emission channels\n\nEvery run emits on four `pi.events.emit(channel, data)` channels. The dashboard\nbridge's emit intercept renames them to its protocol event types:\n\n| Producer channel        | Dashboard protocol event | When                                          |\n| ----------------------- | ------------------------ | --------------------------------------------- |\n| `subagents:created`     | `subagent_created`       | Tool invocation begins (before any session work) |\n| `subagents:started`     | `subagent_started`       | Initial \"running\" emission, AND all progress ticks (re-uses channel; dashboard reducer merges) |\n| `subagents:completed`   | `subagent_completed`     | `await session.prompt(...)` resolves successfully |\n| `subagents:failed`      | `subagent_failed`        | Any throw, abort, or session error path       |\n\nProgress emissions are throttled to **≤4 per second per subagent** (`PROGRESS_THROTTLE_MS = 250`). The final progress snapshot is always flushed before `completed`/`failed`.\n\nEmissions are no-ops when `pi.events` is undefined — the run continues; the parent just doesn't get the rich UI.\n\n### Payload shape\n\nAll four channels send `{ id: string, ..., details: AgentDetails }`. The `id` equals `details.agentId`.\n\nPer-channel extras:\n\n```ts\nsubagents:created   → { id, type, description, details }\nsubagents:started   → { id, type?, description?, details }    // type/description on first emission only\nsubagents:completed → { id, result, durationMs, tokens, toolUses, details }\nsubagents:failed    → { id, error, durationMs, toolUses?, details }\n```\n\n### `AgentDetails` field reference\n\nThe `details` payload (defined in `extensions/events.ts`) carries everything the inspector renders.\n\n| Field          | Type                            | Purpose                                                                  |\n| -------------- | ------------------------------- | ------------------------------------------------------------------------ |\n| `agentId`      | `string`                        | Stable id; drives the popout URL `/session/<sid>/subagent/<agentId>`     |\n| `displayName`  | `string`                        | Human-readable name (defaults to `subagent_type`)                        |\n| `description`  | `string`                        | The 5–10-word task description passed in by the LLM                      |\n| `subagentType` | `string`                        | The `.md` agent type identifier (e.g. `\"Explore\"`)                       |\n| `status`       | `AgentStatus`                   | One of `queued \\| running \\| completed \\| aborted \\| stopped \\| error`     |\n| `activity?`    | `string`                        | Live current-activity line (\"running bash\", \"thinking\", …)               |\n| `entries?`     | `SubagentTimelineEntry[]`       | Full timeline (cumulative; dashboard REPLACES on each emission)          |\n| `toolUses`    | `number`                        | Cumulative count of completed tool calls                                 |\n| `tokens`       | `string`                        | Display-formatted total (`\"12.3k\"`)                                      |\n| `tokensUsage?` | `{ input, output, total }`      | Raw integer counts (populated on `completed`/`failed`)                    |\n| `turnCount?`   | `number`                        | Assistant turns so far                                                   |\n| `maxTurns?`    | `number`                        | Reserved — not enforced in v0.1.x                                        |\n| `durationMs`   | `number`                        | Elapsed milliseconds since `subagents:created`                            |\n| `modelName?`   | `string`                        | Resolved model id (e.g. `\"claude-sonnet-4-6\"`)                          |\n| `tags?`        | `string[]`                      | Notable config flags (e.g. `[\"thinking: high\"]`)                         |\n| `agentMdPath?` | `string`                        | Absolute path to the `.md` definition (project > user > bundled > package) |\n| `agentMdSource?` | `\"project\" \\| \"user\" \\| \"bundled\" \\| \"package\"` | Tier that supplied `agentMdPath`. v0.2.0+ (`\"package\"` added in the package-discovery tier). Undefined when path is undefined or producer is older. |\n| `agentMdPkg?`  | `string`                        | Originating package `source` string when `agentMdSource === \"package\"` (e.g. `\"@acme/pi-reviewers\"`); undefined otherwise |\n| `error?`       | `string`                        | Set on `failed` emissions                                                |\n\n### `SubagentTimelineEntry` kinds\n\n```ts\n| { kind: \"tool\";     toolName, input, output?, isError?, ts }\n| { kind: \"text\";     text, ts }              // assistant text (text_end)\n| { kind: \"thinking\"; text, ts }              // assistant thinking (thinking_end)\n| { kind: \"error\";    text, ts }              // assistant error\n```\n\nOnly `_end`-flavored session events become entries — each entry is final / idempotent. Live activity is conveyed via `details.activity` instead.\n\n### Persistence model\n\n- **Subagent's conversation** — in-memory only, dies with the parent turn (uses `SessionManager.inMemory(cwd)`).\n- **Subagent's final result + timeline** — embedded in the `AgentToolResult<AgentDetails>` returned to the parent. Pi persists it inside the parent's `ToolResultMessage.details` in the parent session's JSONL. Survives `/resume`.\n- **Live progress** — streamed only; not buffered server-side. A dashboard refresh while a subagent is still running loses the live card until the parent's tool result lands in JSONL (then state-replay re-hydrates from `details`). See the dashboard's `add-subagent-inspector` change for the consumer-side replay seam.\n\n## License\n\nMIT\n","readmeFilename":"README.md"}