npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@harms-haus/pi-subagents

v0.1.0

Published

Pi extension for spawning parallel sub-agents with live TUI windows

Readme

pi-subagents

A pi extension that allows the main agent to spawn parallel sub-agents, with each sub-agent's latest output rendered in a rolling TUI window inline with the main agent's conversation history.

Sub-agents can optionally use named profiles that pre-configure provider/model, system prompts, thinking levels, and other model settings. Profiles are stored as individual .md files with YAML frontmatter.

Installation

Installed as a pi package (Recommended)

pi install git:github.com/harms-haus/pi-subagents

Or use https:// / ssh:// instead of git: if you prefer.

Local Development

Clone the repo and install the local path (use -l for project-local install):

cd pi-subagents
pi install . -l

Usage

Once installed, the LLM can use the tool:

{
  "delegate_to_subagents": {
    "tasks": [
      {
        "name": "linter-src",
        "prompt": "Review and fix all linting errors in the src/ directory."
      },
      {
        "name": "linter-tests",
        "prompt": "Review and fix all linting errors in the tests/ directory.",
        "profile": "fast-worker"
      }
    ]
  }
}

Providing File Context

Each task can include a files array to read file contents and prepend them to the sub-agent's prompt:

{
  "delegate_to_subagents": {
    "tasks": [
      {
        "name": "fix-lint",
        "prompt": "Fix all linting errors in this file.",
        "files": ["src/utils.ts"]
      }
    ]
  }
}

File specs support line ranges: { "path": "src/main.ts", "start": 10, "end": 50 }, { "path": "log.txt", "tail": 20 }, or { "path": "config.json", "head": 5 }.

See docs/tools-reference.md for complete parameter documentation.

After delegate_to_subagents completes, it returns session IDs for each task. Use get_subagent_output to retrieve the final text output:

Parameters

| Name | Type | Required | Description | | --------- | ------------------------------------------------------------------ | -------- | ---------------------------------------------------------------- | | tasks | Array<{name, prompt, cwd?, profile?, timeout?, resume?, files?}> | Yes | Array of tasks to delegate. Each gets its own sub-agent process. | | profile | string | No | Default profile for all tasks (overridden by per-task profile) |

Each task:

| Field | Type | Required | Description | | --------- | ----------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | name | string | Yes | Display label shown in the TUI window header | | prompt | string | Yes | Prompt sent to the sub-agent (same as typing into pi directly) | | cwd | string | No | Working directory for the sub-agent (default: current directory) | | profile | string | No | Named profile to use for this sub-agent (see below) | | timeout | number | No | Timeout in seconds for this sub-agent. Default: 600. Timeouts auto-extend when the sub-agent is actively producing output — after the initial timeout expires, the sub-agent is only killed after a configurable idle period (see extend_timeout_debounce setting). | | resume | string | No | Previous session ID to resume from. The resumed sub-agent receives the prior session's transcript as context. Only completed or errored sessions can be resumed. | | files | Array<FileSpec> | No | File paths to read and prepend to the sub-agent's prompt. See "Providing File Context" above. |

The maxLinesPerWindow setting is configured in settings.json under subagents.maxLinesPerWindow (default: 15).

Retrieving Sub-agent Output

After delegate_to_subagents completes, each task has a session ID. Use these tools to retrieve results:

  • get_subagent_output(sessionId) — Returns the last assistant text output from a sub-agent session. For resumed sessions, returns the latest run's output. This is the primary way to get results.
  • get_subagent_session(sessionId) — Returns the full session transcript including all messages, tool calls, and results. For resumed sessions, returns all runs' data concatenated. Use for debugging.
  • list_subagent_profiles() — Lists all available subagent profiles that can be used with delegate_to_subagents.
{
  "get_subagent_output": {
    "sessionId": "a1b2c3d4e5f6a7b8"
  }
}

Resuming Sessions

Use the resume parameter to continue work from a previously completed (or errored) sub-agent session. The resumed agent receives the full transcript of all prior runs prepended to its prompt:

{
  "delegate_to_subagents": {
    "tasks": [
      {
        "name": "continue-refactor",
        "prompt": "Continue the refactoring. Focus on the remaining utility modules.",
        "resume": "a1b2c3d4e5f6a7b8"
      }
    ]
  }
}

Key behaviors:

  • The resumed agent's prompt is prefixed with Previously:\n\n<transcript>\n\nInstructions:\n\n<your prompt>, giving it full context of prior work.
  • Only completed or errored sessions can be resumed. Running sessions will throw an error.
  • A session can be resumed multiple times — each resume creates a new "run" appended to the session record.
  • get_subagent_output returns output from the latest run only.
  • get_subagent_session returns all runs concatenated with run separators.

Subagent Profiles

Profiles let you pre-configure the provider, model, system prompt, thinking level, and other settings for sub-agents. Each profile is a .md file with YAML frontmatter.

Profile Locations

| Scope | Directory | | ------- | --------------------------------- | | Global | ~/.pi/agent/agent-profiles/*.md | | Project | .pi/agent-profiles/*.md |

Project-local profiles override global profiles with the same name.

Example Profiles

~/.pi/agent/agent-profiles/code-reviewer.md:

---
name: code-reviewer
provider: anthropic
model: claude-sonnet-4-5
thinkingLevel: high
tools: read,bash,grep,find
---

You are an expert code reviewer. Focus on bugs, security issues, and performance problems. Be thorough but concise.

~/.pi/agent/agent-profiles/fast-worker.md:

---
name: fast-worker
model: dashscope/qwen3.5-plus
appendSystemPrompt: Be concise. Skip explanations unless asked.
thinkingLevel: off
---

.pi/agent-profiles/researcher.md (project-local):

---
name: researcher
provider: openai
model: gpt-4o
appendSystemPrompt: Use web search to find information. Cite sources when possible.
---

You are a research assistant.

Profile Fields

| Field | Type | Description | | -------------------- | ---------------------- | ----------------------------------------------------------------------------------------------------------- | | name | string | Required. Profile identifier (from YAML frontmatter name field) | | provider | string | Provider name (e.g., "anthropic", "openai", "dashscope") | | model | string | Model pattern or ID. Supports "provider/id" format and ":thinking" shorthand (e.g., "sonnet:high") | | systemPrompt | N/A | Set via the body of the markdown file (text after ---). Replaces the default system prompt entirely. | | appendSystemPrompt | string | Append text to the default system prompt | | thinkingLevel | string | Thinking level: "off", "minimal", "low", "medium", "high", "xhigh" | | noTools | boolean | Disable all tools | | tools | string or string[] | Comma-separated string or YAML array of tool names to enable (allowlist) | | excludeTools | string or string[] | Comma-separated string or YAML array of tool names to exclude (blacklist; mutually exclusive with tools) | | noExtensions | boolean | Disable all extensions | | extensions | string or string[] | Comma-separated string or YAML array of extension paths to load | | noSkills | boolean | Disable skills. Mutually exclusive with suggestedSkills and loadSkills | | suggestedSkills | string or string[] | Skill names to suggest to the sub-agent via --skill CLI flags; the model chooses whether to load them | | loadSkills | string or string[] | Skill names to pre-load into the sub-agent's system prompt (content wrapped in <loaded_skill> XML tags) | | noContextFiles | boolean | Disable AGENTS.md/CLAUDE.md context files | | apiKey | string | Custom API key (stored as PI_API_KEY env var, not in CLI args) | | extraArgs | string or string[] | Comma-separated string or YAML array of additional CLI arguments |

Array fields (tools, extensions, extraArgs, suggestedSkills, loadSkills) support both YAML arrays and comma-separated strings:

tools:
  - read
  - bash
  - grep

or equivalently:

tools: read,bash,grep

Using Profiles

Per-task profile — each task specifies its own profile:

{
  "delegate_to_subagents": {
    "tasks": [
      { "name": "review", "prompt": "Review src/...", "profile": "code-reviewer" },
      { "name": "research", "prompt": "Find best practices for...", "profile": "researcher" }
    ]
  }
}

Default profile for all tasks — set at the top level, overridden by per-task profiles:

{
  "delegate_to_subagents": {
    "profile": "fast-worker",
    "tasks": [
      { "name": "task-a", "prompt": "..." },
      { "name": "task-b", "prompt": "...", "profile": "code-reviewer" }
    ]
  }
}

Profile Resolution Order

  1. Per-task profile field (highest priority)
  2. Top-level profile parameter
  3. If neither is specified, no profile is applied (uses pi defaults)

Profiles are loaded from .md files:

  1. Global: ~/.pi/agent/agent-profiles/*.md
  2. Project-local: .pi/agent-profiles/*.md (overrides global profiles with the same name)

The profile cache refreshes every 5 seconds.

Settings

Additional settings are configured in settings.json under the subagents key:

| Setting | Type | Default | Description | | ------------------------- | -------- | ------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | maxLinesPerWindow | number | 15 | Number of lines shown in each sub-agent's rolling TUI window | | commandPreviewWidth | number | Terminal width − 4 (TTY) or 160 (non-TTY) | Controls tool call preview truncation width in the rolling window. In TTY mode, terminal width − 4 is used as a hard override — settings files are never consulted. In non-TTY mode, falls back through settings files (global → project → default 160). Minimum: 20 | | extend_timeout_debounce | number | 30 | Seconds of idle time (no output activity) before a timed-out sub-agent is killed. The initial timeout starts this idle window; any output resets it. Range: 0–300. | | looping_tool_count | number | 5 | Number of consecutive tool calls checked for loop detection. Set to 0 to disable. Range: 0–50. | | looping_tool_similarity | number | 0.95 | Bigram similarity threshold for loop detection. When the last looping_tool_count tool calls are all pairwise similar above this threshold, the sub-agent is killed. Range: 0–1. |

Settings are loaded from ~/.pi/agent/settings.json (global) and .pi/settings.json (project-local, overrides global). Note: commandPreviewWidth settings are only consulted in non-TTY mode.

The /profile Command

Use /profile interactively to manage subagent profiles without editing files by hand:

| Command | Description | | ------------------------ | -------------------------------------- | | /profile list | List all profiles with summaries | | /profile show <name> | Display full details of a profile | | /profile <name> | Alias for show | | /profile create <name> | Interactively create a new profile | | /profile edit <name> | Interactively edit an existing profile | | /profile delete <name> | Delete a profile |

Interactive Editor

/profile create and /profile edit walk you through each setting:

  1. Scope — save to global (~/.pi/agent/agent-profiles/) or project-local (.pi/agent-profiles/) directory
  2. Provider — e.g. anthropic, openai, dashscope
  3. Model — supports provider/id and :thinking shorthand
  4. System prompt — the body text of the .md file (replaces default system prompt)
  5. Append system prompt — optionally append to the default
  6. Thinking level — off, minimal, low, medium, high, xhigh
  7. Tools — choose to disable all (noTools), enable a specific set (tools), or exclude specific tools (excludeTools)
  8. Extensions — restrict or disable
  9. Skills — if skills are already set, offers to remove them; otherwise asks whether to configure skills, then prompts for comma-separated suggested and/or pre-loaded skill names
  10. Review & save — shows full profile as markdown before confirming

You can skip any field by answering "No" — it will be omitted from the profile (using pi defaults).

Features

  • Parallel execution: Multiple sub-agents run concurrently (up to 4 at a time by default)
  • Rolling window: Each sub-agent shows its latest N lines in real-time
  • Live updates: The TUI re-renders as sub-agents stream output
  • Expandable (Ctrl+O): Collapse to rolling window, expand to see full sub-agent output
  • Error handling: Non-zero exit codes and errors are highlighted
  • Abort support: Hitting Escape cancels all running sub-agents
  • Session resume: Continue work from completed/errored sessions with full transcript context
  • Per-task timeouts: Configurable timeout per sub-agent (default 600s), with auto-extension while the agent remains active
  • Loop detection: Automatically kills sub-agents that repeat the same tool calls in a tight loop
  • Session persistence: Sessions are persisted to the main agent's session log immediately after each sub-agent completes. On agent restart, sessions are reconstructed from the log — no data is lost across restarts.

Architecture

Main Agent TUI
  │
  └── delegate_to_subagents
        │
        ├── Resolve profiles from .md files
        │   ├── Global: ~/.pi/agent/agent-profiles/*.md
        │   └── Project: .pi/agent-profiles/*.md
        │
        ├── Validate profile skills (suggestedSkills/loadSkills vs noSkills)
        │
        ├── Resolve skill names → file paths (suggestedSkills) or injected content (loadSkills)
        │
        ├── Validate resume targets (must be completed/errored)
        │
        ├── For each task (concurrency ≤ 4):
        │   │
        │   ├── [resume?] Inject prior session transcript into prompt
        │   │
        │   ├── Spawn: pi --mode json -p --no-session [profile args...] "prompt"
        │   │   │
        │   │   ├── Parse JSONL stdout events
        │   │   ├── Update rolling window (latest N lines)
        │   │   ├── Track tool calls & results
        │   │   └── [timeout?] Abort if task timeout exceeded
        │   │
        │   ├── Store session data (messages, status, exit code)
        │   └── persistSession → pi.appendEntry() (fault-tolerant)
        │
        ├── On session_start (restart/resume):
        │   └── Reconstruct sessionStore from persisted entries
        │       └── Stale "running" sessions → auto-converted to "error"
        │
        └── Return session IDs → get_subagent_output / get_subagent_session

Each sub-agent is a separate pi process in JSON mode. We parse JSONL events from stdout and maintain a rolling line buffer per agent. The tool's renderResult builds a Container of Text components, displayed inline with the conversation history.