{"id":46405258,"url":"https://github.com/tintinweb/pi-subagents","last_synced_at":"2026-04-02T14:16:05.304Z","repository":{"id":342252082,"uuid":"1173389913","full_name":"tintinweb/pi-subagents","owner":"tintinweb","description":"Sub-agents for pi with Claude Code look and feel — parallel execution, live widget, custom agent types, mid-run steering and more ...","archived":false,"fork":false,"pushed_at":"2026-03-24T15:37:52.000Z","size":11016,"stargazers_count":87,"open_issues_count":5,"forks_count":14,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-03-25T20:13:36.018Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/@tintinweb/pi-subagents","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tintinweb.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-05T10:08:27.000Z","updated_at":"2026-03-25T05:57:16.000Z","dependencies_parsed_at":"2026-03-10T23:00:42.807Z","dependency_job_id":null,"html_url":"https://github.com/tintinweb/pi-subagents","commit_stats":null,"previous_names":["tintinweb/pi-subagents"],"tags_count":22,"template":false,"template_full_name":null,"purl":"pkg:github/tintinweb/pi-subagents","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tintinweb%2Fpi-subagents","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tintinweb%2Fpi-subagents/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tintinweb%2Fpi-subagents/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tintinweb%2Fpi-subagents/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tintinweb","download_url":"https://codeload.github.com/tintinweb/pi-subagents/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tintinweb%2Fpi-subagents/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31307679,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-02T12:59:32.332Z","status":"ssl_error","status_checked_at":"2026-04-02T12:54:48.875Z","response_time":89,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-03-05T12:03:41.549Z","updated_at":"2026-04-02T14:16:05.032Z","avatar_url":"https://github.com/tintinweb.png","language":"TypeScript","funding_links":[],"categories":["TypeScript","HarmonyOS"],"sub_categories":["Windows Manager"],"readme":"# @tintinweb/pi-subagents\n\nA [pi](https://pi.dev) extension that brings **Claude Code-style autonomous sub-agents** to pi. Spawn specialized agents that run in isolated sessions — each with its own tools, system prompt, model, and thinking level. Run them in foreground or background, steer them mid-run, resume completed sessions, and define your own custom agent types.\n\n\u003e **Status:** Early release.\n\n\u003cimg width=\"600\" alt=\"pi-subagents screenshot\" src=\"https://github.com/tintinweb/pi-subagents/raw/master/media/screenshot.png\" /\u003e\n\n\nhttps://github.com/user-attachments/assets/8685261b-9338-4fea-8dfe-1c590d5df543\n\n\n## Features\n\n- **Claude Code look \u0026 feel** — same tool names, calling conventions, and UI patterns (`Agent`, `get_subagent_result`, `steer_subagent`) — feels native\n- **Parallel background agents** — spawn multiple agents that run concurrently with automatic queuing (configurable concurrency limit, default 4) and smart group join (consolidated notifications)\n- **Live widget UI** — persistent above-editor widget with animated spinners, live tool activity, token counts, and colored status icons\n- **Conversation viewer** — select any agent in `/agents` to open a live-scrolling overlay of its full conversation (auto-follows new content, scroll up to pause)\n- **Custom agent types** — define agents in `.pi/agents/\u003cname\u003e.md` with YAML frontmatter: custom system prompts, model selection, thinking levels, tool restrictions\n- **Mid-run steering** — inject messages into running agents to redirect their work without restarting\n- **Session resume** — pick up where an agent left off, preserving full conversation context\n- **Graceful turn limits** — agents get a \"wrap up\" warning before hard abort, producing clean partial results instead of cut-off output\n- **Case-insensitive agent types** — `\"explore\"`, `\"Explore\"`, `\"EXPLORE\"` all work. Unknown types fall back to general-purpose with a note\n- **Fuzzy model selection** — specify models by name (`\"haiku\"`, `\"sonnet\"`) instead of full IDs, with automatic filtering to only available/configured models\n- **Context inheritance** — optionally fork the parent conversation into a sub-agent so it knows what's been discussed\n- **Persistent agent memory** — three scopes (project, local, user) with automatic read-only fallback for agents without write tools\n- **Git worktree isolation** — run agents in isolated repo copies; changes auto-committed to branches on completion\n- **Skill preloading** — inject named skill files from `.pi/skills/` into agent system prompts\n- **Tool denylist** — block specific tools via `disallowed_tools` frontmatter\n- **Styled completion notifications** — background agent results render as themed, compact notification boxes (icon, stats, result preview) instead of raw XML. Expandable to show full output. Group completions render each agent individually\n- **Event bus** — lifecycle events (`subagents:created`, `started`, `completed`, `failed`, `steered`) emitted via `pi.events`, enabling other extensions to react to sub-agent activity\n- **Cross-extension RPC** — other pi extensions can spawn subagents via the `pi.events` event bus (`subagents:rpc:ping`, `subagents:rpc:spawn`). Emits `subagents:ready` on load\n\n## Install\n\n```bash\npi install npm:@tintinweb/pi-subagents\n```\n\nOr load directly for development:\n\n```bash\npi -e ./src/index.ts\n```\n\n## Quick Start\n\nThe parent agent spawns sub-agents using the `Agent` tool:\n\n```\nAgent({\n  subagent_type: \"Explore\",\n  prompt: \"Find all files that handle authentication\",\n  description: \"Find auth files\",\n  run_in_background: true,\n})\n```\n\nForeground agents block until complete and return results inline. Background agents return an ID immediately and notify you on completion.\n\n## UI\n\nThe extension renders a persistent widget above the editor showing all active agents:\n\n```\n● Agents\n├─ ⠹ Agent  Refactor auth module · 5 tool uses · 33.8k token · 12.3s\n│    ⎿  editing 2 files…\n├─ ⠹ Explore  Find auth files · 3 tool uses · 12.4k token · 4.1s\n│    ⎿  searching…\n└─ 2 queued\n```\n\nIndividual agent results render Claude Code-style in the conversation:\n\n| State | Example |\n|-------|---------|\n| **Running** | `⠹ 3 tool uses · 12.4k token` / `⎿ searching, reading 3 files…` |\n| **Completed** | `✓ 5 tool uses · 33.8k token · 12.3s` / `⎿ Done` |\n| **Wrapped up** | `✓ 50 tool uses · 89.1k token · 45.2s` / `⎿ Wrapped up (turn limit)` |\n| **Stopped** | `■ 3 tool uses · 12.4k token` / `⎿ Stopped` |\n| **Error** | `✗ 3 tool uses · 12.4k token` / `⎿ Error: timeout` |\n| **Aborted** | `✗ 55 tool uses · 102.3k token` / `⎿ Aborted (max turns exceeded)` |\n\nCompleted results can be expanded (ctrl+o in pi) to show the full agent output inline.\n\nBackground agent completion notifications render as styled boxes:\n\n```\n✓ Find auth files completed\n  3 tool uses · 12.4k token · 4.1s\n  ⎿  Found 5 files related to authentication...\n  transcript: .pi/output/agent-abc123.jsonl\n```\n\nGroup completions render each agent as a separate block. The LLM receives structured `\u003ctask-notification\u003e` XML for parsing, while the user sees the themed visual.\n\n## Default Agent Types\n\n| Type | Tools | Model | Prompt Mode | Description |\n|------|-------|-------|-------------|-------------|\n| `general-purpose` | all 7 | inherit | `append` (parent twin) | Inherits the parent's full system prompt — same rules, CLAUDE.md, project conventions |\n| `Explore` | read, bash, grep, find, ls | haiku (falls back to inherit) | `replace` (standalone) | Fast codebase exploration (read-only) |\n| `Plan` | read, bash, grep, find, ls | inherit | `replace` (standalone) | Software architect for implementation planning (read-only) |\n\nThe `general-purpose` agent is a **parent twin** — it receives the parent's entire system prompt plus a sub-agent context bridge, so it follows the same rules the parent does. Explore and Plan use standalone prompts tailored to their read-only roles.\n\nDefault agents can be **ejected** (`/agents` → select agent → Eject) to export them as `.md` files for customization, **overridden** by creating a `.md` file with the same name (e.g. `.pi/agents/general-purpose.md`), or **disabled** per-project with `enabled: false` frontmatter.\n\n## Custom Agents\n\nDefine custom agent types by creating `.md` files. The filename becomes the agent type name. Any name is allowed — using a default agent's name overrides it.\n\nAgents are discovered from two locations (higher priority wins):\n\n| Priority | Location | Scope |\n|----------|----------|-------|\n| 1 (highest) | `.pi/agents/\u003cname\u003e.md` | Project — per-repo agents |\n| 2 | `~/.pi/agent/agents/\u003cname\u003e.md` | Global — available everywhere |\n\nProject-level agents override global ones with the same name, so you can customize a global agent for a specific project.\n\n### Example: `.pi/agents/auditor.md`\n\n```markdown\n---\ndescription: Security Code Reviewer\ntools: read, grep, find, bash\nmodel: anthropic/claude-opus-4-6\nthinking: high\nmax_turns: 30\n---\n\nYou are a security auditor. Review code for vulnerabilities including:\n- Injection flaws (SQL, command, XSS)\n- Authentication and authorization issues\n- Sensitive data exposure\n- Insecure configurations\n\nReport findings with file paths, line numbers, severity, and remediation advice.\n```\n\nThen spawn it like any built-in type:\n\n```\nAgent({ subagent_type: \"auditor\", prompt: \"Review the auth module\", description: \"Security audit\" })\n```\n\n### Frontmatter Fields\n\nAll fields are optional — sensible defaults for everything.\n\n| Field | Default | Description |\n|-------|---------|-------------|\n| `description` | filename | Agent description shown in tool listings |\n| `display_name` | — | Display name for UI (e.g. widget, agent list) |\n| `tools` | all 7 | Comma-separated built-in tools: read, bash, edit, write, grep, find, ls. `none` for no tools |\n| `extensions` | `true` | Inherit MCP/extension tools. `false` to disable |\n| `skills` | `true` | Inherit skills from parent. Can be a comma-separated list of skill names to preload from `.pi/skills/` |\n| `memory` | — | Persistent agent memory scope: `project`, `local`, or `user`. Auto-detects read-only agents |\n| `disallowed_tools` | — | Comma-separated tools to deny even if extensions provide them |\n| `isolation` | — | Set to `worktree` to run in an isolated git worktree |\n| `model` | inherit parent | Model — `provider/modelId` or fuzzy name (`\"haiku\"`, `\"sonnet\"`) |\n| `thinking` | inherit | off, minimal, low, medium, high, xhigh |\n| `max_turns` | 50 | Max agentic turns before graceful shutdown |\n| `prompt_mode` | `replace` | `replace`: body is the full system prompt. `append`: body appended to parent's prompt (agent acts as a \"parent twin\" with optional extra instructions) |\n| `inherit_context` | `false` | Fork parent conversation into agent |\n| `run_in_background` | `false` | Run in background by default |\n| `isolation` | — | `worktree`: run in a temporary git worktree for full repo isolation |\n| `isolated` | `false` | No extension/MCP tools, only built-in |\n| `enabled` | `true` | Set to `false` to disable an agent (useful for hiding a default agent per-project) |\n\nFrontmatter sets defaults. Explicit `Agent` parameters always override them.\n\n## Tools\n\n### `Agent`\n\nLaunch a sub-agent.\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `prompt` | string | yes | The task for the agent |\n| `description` | string | yes | Short 3-5 word summary (shown in UI) |\n| `subagent_type` | string | yes | Agent type (built-in or custom) |\n| `model` | string | no | Model — `provider/modelId` or fuzzy name (`\"haiku\"`, `\"sonnet\"`) |\n| `thinking` | string | no | Thinking level: off, minimal, low, medium, high, xhigh |\n| `max_turns` | number | no | Max agentic turns (default: 50) |\n| `run_in_background` | boolean | no | Run without blocking |\n| `resume` | string | no | Agent ID to resume a previous session |\n| `isolated` | boolean | no | No extension/MCP tools |\n| `isolation` | `\"worktree\"` | no | Run in an isolated git worktree |\n| `inherit_context` | boolean | no | Fork parent conversation into agent |\n| `join_mode` | `\"async\"` \\| `\"group\"` | no | Override join strategy for background completion notifications (default: smart) |\n\n### `get_subagent_result`\n\nCheck status and retrieve results from a background agent.\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `agent_id` | string | yes | Agent ID to check |\n| `wait` | boolean | no | Wait for completion |\n| `verbose` | boolean | no | Include full conversation log |\n\n### `steer_subagent`\n\nSend a steering message to a running agent. The message interrupts after the current tool execution.\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `agent_id` | string | yes | Agent ID to steer |\n| `message` | string | yes | Message to inject into agent conversation |\n\n## Commands\n\n| Command | Description |\n|---------|-------------|\n| `/agents` | Interactive agent management menu |\n\nThe `/agents` command opens an interactive menu:\n\n```\nRunning agents (2) — 1 running, 1 done     ← only shown when agents exist\nAgent types (6)                             ← unified list: defaults + custom\nCreate new agent                            ← manual wizard or AI-generated\nSettings                                    ← max concurrency, max turns, grace turns, join mode\n```\n\n- **Agent types** — unified list with source indicators: `•` (project), `◦` (global), `✕` (disabled). Select an agent to manage it:\n  - **Default agents** (no override): Eject (export as `.md`), Disable\n  - **Default agents** (ejected/overridden): Edit, Disable, Reset to default, Delete\n  - **Custom agents**: Edit, Disable, Delete\n  - **Disabled agents**: Enable, Edit, Delete\n- **Eject** — writes the embedded default config as a `.md` file to project or personal location, so you can customize it\n- **Disable/Enable** — toggle agent availability. Disabled agents stay visible in the list (marked `✕`) and can be re-enabled\n- **Create new agent** — choose project/personal location, then manual wizard (step-by-step prompts for name, tools, model, thinking, system prompt) or AI-generated (describe what the agent should do and a sub-agent writes the `.md` file). Any name is allowed, including default agent names (overrides them)\n- **Settings** — configure max concurrency, default max turns, grace turns, and join mode at runtime\n\n## Graceful Max Turns\n\nInstead of hard-aborting at the turn limit, agents get a graceful shutdown:\n\n1. At `max_turns` — steering message: *\"Wrap up immediately — provide your final answer now.\"*\n2. Up to 5 grace turns to finish cleanly\n3. Hard abort only after the grace period\n\n| Status | Meaning | Icon |\n|--------|---------|------|\n| `completed` | Finished naturally | `✓` green |\n| `steered` | Hit limit, wrapped up in time | `✓` yellow |\n| `aborted` | Grace period exceeded | `✗` red |\n| `stopped` | User-initiated abort | `■` dim |\n\n## Concurrency\n\nBackground agents are subject to a configurable concurrency limit (default: 4). Excess agents are automatically queued and start as running agents complete. The widget shows queued agents as a collapsed count.\n\nForeground agents bypass the queue — they block the parent anyway.\n\n## Join Strategies\n\nWhen background agents complete, they notify the main agent. The **join mode** controls how these notifications are delivered:\n\n| Mode | Behavior |\n|------|----------|\n| `smart` (default) | 2+ background agents spawned in the same turn are auto-grouped into a single consolidated notification. Solo agents notify individually. |\n| `async` | Each agent sends its own notification on completion (original behavior). Best when results need incremental processing. |\n| `group` | Force grouping even when spawning a single agent. Useful when you know more agents will follow. |\n\n**Timeout behavior:** When agents are grouped, a 30-second timeout starts after the first agent completes. If not all agents finish in time, a partial notification is sent with completed results and remaining agents continue with a shorter 15-second re-batch window for stragglers.\n\n**Configuration:**\n- Per-call: `Agent({ ..., join_mode: \"async\" })` overrides for that agent\n- Global default: `/agents` → Settings → Join mode\n\n## Events\n\nAgent lifecycle events are emitted via `pi.events.emit()` so other extensions can react:\n\n| Event | When | Key fields |\n|-------|------|------------|\n| `subagents:created` | Background agent registered | `id`, `type`, `description`, `isBackground` |\n| `subagents:started` | Agent transitions to running (including queued→running) | `id`, `type`, `description` |\n| `subagents:completed` | Agent finished successfully | `id`, `type`, `durationMs`, `tokens`, `toolUses`, `result` |\n| `subagents:failed` | Agent errored, stopped, or aborted | same as completed + `error`, `status` |\n| `subagents:steered` | Steering message sent | `id`, `message` |\n| `subagents:ready` | Extension loaded and RPC handlers registered | — |\n\n## Cross-Extension RPC\n\nOther pi extensions can spawn subagents programmatically via the `pi.events` event bus, without importing this package directly.\n\n### Discovery\n\nListen for `subagents:ready` to know when RPC handlers are available:\n\n```typescript\npi.events.on(\"subagents:ready\", () =\u003e {\n  // RPC handlers are registered — safe to call ping/spawn\n});\n```\n\n### Ping\n\nCheck if the subagents extension is loaded:\n\n```typescript\nconst requestId = crypto.randomUUID();\nconst unsub = pi.events.on(`subagents:rpc:ping:reply:${requestId}`, () =\u003e {\n  unsub();\n  // Extension is alive\n});\npi.events.emit(\"subagents:rpc:ping\", { requestId });\n```\n\n### Spawn\n\nSpawn a subagent and receive its ID:\n\n```typescript\nconst requestId = crypto.randomUUID();\nconst unsub = pi.events.on(`subagents:rpc:spawn:reply:${requestId}`, (reply) =\u003e {\n  unsub();\n  if (reply.error) {\n    console.error(\"Spawn failed:\", reply.error);\n  } else {\n    console.log(\"Agent ID:\", reply.id);\n  }\n});\npi.events.emit(\"subagents:rpc:spawn\", {\n  requestId,\n  type: \"general-purpose\",\n  prompt: \"Do something useful\",\n  options: { description: \"My task\", run_in_background: true },\n});\n```\n\nReply channels are scoped per `requestId`, so concurrent requests don't interfere.\n\n## Persistent Agent Memory\n\nAgents can have persistent memory across sessions. Set `memory` in frontmatter to enable:\n\n```yaml\n---\nmemory: project   # project | local | user\n---\n```\n\n| Scope | Location | Use case |\n|-------|----------|----------|\n| `project` | `.pi/agent-memory/\u003cname\u003e/` | Shared across the team (committed) |\n| `local` | `.pi/agent-memory-local/\u003cname\u003e/` | Machine-specific (gitignored) |\n| `user` | `~/.pi/agent-memory/\u003cname\u003e/` | Global personal memory |\n\nMemory uses a `MEMORY.md` index file and individual memory files with frontmatter. Agents with write tools get full read-write access. **Read-only agents** (no `write`/`edit` tools) automatically get read-only memory — they can consume memories written by other agents but cannot modify them. This prevents unintended tool escalation.\n\nThe `disallowed_tools` field is respected when determining write capability — an agent with `tools: write` + `disallowed_tools: write` correctly gets read-only memory.\n\n## Worktree Isolation\n\nSet `isolation: worktree` to run an agent in a temporary git worktree:\n\n```\nAgent({ subagent_type: \"refactor\", prompt: \"...\", isolation: \"worktree\" })\n```\n\nThe agent gets a full, isolated copy of the repository. On completion:\n- **No changes:** worktree is cleaned up automatically\n- **Changes made:** changes are committed to a new branch (`pi-agent-\u003cid\u003e`) and returned in the result\n\nIf the worktree cannot be created (not a git repo, no commits), the agent falls back to the main working directory with a warning.\n\n## Skill Preloading\n\nSkills can be preloaded as named files from `.pi/skills/` or `~/.pi/skills/`:\n\n```yaml\n---\nskills: api-conventions, error-handling\n---\n```\n\nSkill files (`.md`, `.txt`, or extensionless) are read and injected into the agent's system prompt. Project-level skills take priority over global ones. Symlinked skill files are rejected for security.\n\n## Tool Denylist\n\nBlock specific tools from an agent even if extensions provide them:\n\n```yaml\n---\ntools: read, bash, grep, write\ndisallowed_tools: write, edit\n---\n```\n\nThis is useful for creating agents that inherit extension tools but should not have write access.\n\n## Architecture\n\n```\nsrc/\n  index.ts            # Extension entry: tool/command registration, rendering\n  types.ts            # Type definitions (AgentConfig, AgentRecord, etc.)\n  default-agents.ts   # Embedded default agent configs (general-purpose, Explore, Plan)\n  agent-types.ts      # Unified agent registry (defaults + user), tool factories\n  agent-runner.ts     # Session creation, execution, graceful max_turns, steer/resume\n  agent-manager.ts    # Agent lifecycle, concurrency queue, completion notifications\n  cross-extension-rpc.ts # RPC handlers for cross-extension spawn/ping via pi.events\n  group-join.ts       # Group join manager: batched completion notifications with timeout\n  custom-agents.ts    # Load user-defined agents from .pi/agents/*.md\n  memory.ts           # Persistent agent memory (resolve, read, build prompt blocks)\n  skill-loader.ts     # Preload skill files from .pi/skills/\n  output-file.ts      # Streaming output file transcripts for agent sessions\n  worktree.ts         # Git worktree isolation (create, cleanup, prune)\n  prompts.ts          # Config-driven system prompt builder\n  context.ts          # Parent conversation context for inherit_context\n  env.ts              # Environment detection (git, platform)\n  ui/\n    agent-widget.ts       # Persistent widget: spinners, activity, status icons, theming\n    conversation-viewer.ts # Live conversation overlay for viewing agent sessions\n```\n\n## License\n\nMIT — [tintinweb](https://github.com/tintinweb)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftintinweb%2Fpi-subagents","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftintinweb%2Fpi-subagents","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftintinweb%2Fpi-subagents/lists"}