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

oira666_pi-subagent

v0.1.14

Published

Subagent extension for Pi coding agent. Delegate tasks to specialized agents.

Downloads

1,519

Readme

Pi Subagent

Delegate tasks to specialized subagents with configurable context modes (spawn / fork).

Install

pi install npm:oira666_pi-subagent

Or via git:

pi install git:github.com/gee666/pi-subagent.git

Remove

pi remove npm:oira666_pi-subagent

How It Works

The extension supports two execution modes, selectable via PI_SUBAGENTS_MODE.

Execution mode: subprocess (default)

Each subagent runs as a separate pi process — fully isolated memory, its own model/tool loop. Processes are spawned via the operating system and communicate through JSON-line stdout.

  • Full OS-level isolation — a crashed subagent cannot affect the parent
  • True parallel execution across all CPU cores
  • Each subprocess boots a fresh Node.js runtime (adds ~200–500 ms per subagent)
  • Requires the pi binary on PATH

Execution mode: sdk

Each subagent runs as an in-process AgentSession created via the pi SDK — no new process is spawned.

  • No spawn overhead — sessions start in milliseconds
  • No temp files for system prompts or fork snapshots
  • Concurrency through the Node.js event loop (fine for I/O-bound LLM work)
  • All sessions share the same memory and event loop

Context modes

spawn (default) — Child receives only the task string. Best for isolated work, lower cost.
fork — Child receives a snapshot of the current session context + task. Best for follow-up work.

The main agent receives only the final text output from subagents (no tool calls, no reasoning).

Tool Call Shape

{ "tasks": [{ "agent": "code-writer", "task": "Implement the API" }], "mode": "spawn" }

Multiple tasks run in parallel:

{
  "tasks": [
    { "agent": "code-writer", "task": "Draft the implementation" },
    { "agent": "code-reviwer", "task": "Review the plan" }
  ],
  "mode": "fork"
}

Each task supports agent, task, and optional cwd.

Bundled Agents

Three fallback agents ship with the extension (used when no user/project agents are configured):

  • code-writer — implementation and refactoring
  • code-reviwer — code review and risk finding
  • code-architect — technical design and approach selection

Defining Agents

Create Markdown files with YAML frontmatter:

  • User agents: ~/.pi/agent/agents/*.md
  • Env agents: $PI_CODING_AGENT_DIR/agents/*.md (when PI_CODING_AGENT_DIR is set)
  • Project agents: .pi/agents/*.md (may prompt for confirmation — see PI_SUBAGENT_CONFIRM_PROJECT_AGENTS)

Agent discovery priority (highest wins on name collision): project > env > user. Built-in agents are only used as a fallback when all three locations are empty.

---
name: writer
description: Expert technical writer
model: anthropic/claude-3-5-sonnet
thinking: low
tools: read,write
---

You are an expert technical writer focused on clarity and conciseness.

Frontmatter Fields

| Field | Required | Default | Description | | ------------- | -------- | -------------------- | -------------------------------------------------------- | | name | Yes | — | Agent identifier used in tool calls | | description | Yes | — | What the agent does (shown to the main agent) | | model | No | Pi default | Override model, e.g. anthropic/claude-3-5-sonnet | | thinking | No | Pi default | off, minimal, low, medium, high, xhigh | | tools | No | read,bash,edit,write | Comma-separated built-in tools |

Available tools: read, bash, edit, write.

The Markdown body becomes the agent's system prompt (appended to Pi's default, not replacing it).

Execution Mode

| Env Var | Default | Values | Description | | --------------------- | ------------ | -------------------- | -------------------------------------- | | PI_SUBAGENTS_MODE | subprocess | subprocess / sdk | How subagent sessions are created |

# Run subagents as in-process SDK sessions (faster startup, no spawn overhead)
PI_SUBAGENTS_MODE=sdk pi

# Run subagents as isolated subprocess pi instances (default, full isolation)
PI_SUBAGENTS_MODE=subprocess pi

Comparison

| | subprocess | sdk | |---|---|---| | Session isolation | Full OS-level | Shared memory/event loop | | Startup overhead | ~200–500 ms per agent | ~10–50 ms per agent | | Parallelism | True OS parallelism | Event-loop concurrency | | Fork mode context | Temp JSONL file | Temp JSONL file (same format) | | Depth tracking | Env vars in child process | Closure parameters | | pi binary required | Yes | No | | Crash isolation | Yes — subprocess crash is contained | No — exception bubbles up |

Delegation Guards

Depth and cycle guards prevent runaway recursive delegation.

| Config | Default | Description | | ------------------------------ | ------- | ------------------------------------------------ | | --subagent-max-depth / PI_SUBAGENT_MAX_DEPTH | 3 | Max delegation depth (0 disables delegation) | | --subagent-prevent-cycles / PI_SUBAGENT_PREVENT_CYCLES | true | Block same agent in delegation chain |

pi --subagent-max-depth 2         # one nested level
pi --subagent-max-depth 0         # disable delegation entirely
pi --no-subagent-prevent-cycles   # allow cycles (not recommended)

Parallel Limits

| Env Var | Default | Description | | -------------------------------- | ------- | ---------------------------------------- | | PI_SUBAGENT_MAX_PARALLEL_TASKS | 16 | Max tasks per single call | | PI_SUBAGENT_MAX_CONCURRENCY | 8 | Max subagents running simultaneously |

Agent Discovery

| Env Var | Description | | ----------------------- | ------------------------------------------------------------ | | PI_CODING_AGENT_DIR | Base path for an additional agents directory ($PI_CODING_AGENT_DIR/agents/*.md). Agents here override user agents but are overridden by project agents. Built-in agents are only used when user, env, and project locations all yield zero agents. |

CLI Argument Proxying

Note: CLI argument proxying only applies to subprocess mode. In sdk mode, subagents inherit provider and model configuration directly from the calling session's model registry and API keys from environment variables, so no forwarding is needed.

In subprocess mode, all flags passed to the parent pi process are forwarded to subagent child processes, so they inherit the same provider, API key, model, and other runtime settings. Flags the extension manages itself are blocked from being forwarded.

Always forwarded verbatim:

| Flag(s) | Purpose | | --- | --- | | --provider | AI provider | | --api-key | API key | | --system-prompt | Base system prompt override | | --session-dir | Session storage directory | | --models | Model cycling list | | --skill, --no-skills/-ns | Skill loading | | --prompt-template, --no-prompt-templates/-np | Prompt templates | | --theme, --no-themes | Themes | | --verbose | Verbose startup output | | Unknown/custom flags | Forwarded with heuristic value detection |

Forwarded as fallback (agent frontmatter overrides if set):

| Flag | Overridden by | | --- | --- | | --model | model: in agent frontmatter | | --thinking | thinking: in agent frontmatter | | --tools / --no-tools | tools: in agent frontmatter |

Never forwarded (managed by the extension itself): --mode, -p/--print, --session/--no-session, --continue, --resume, --append-system-prompt, --offline, --extension/-e, --no-extensions/-ne, --subagent-max-depth, --subagent-prevent-cycles, --export, --list-models, --help, --version.


Programmatic Usage (JSON RPC)

When running pi programmatically with --mode rpc (or --mode json), the stream contains tool_result_end events whenever the agent completes a subagent tool call. The details field of these events carries the full stats for that delegation — including recursive usage and tool call counts from all subagents in the tree.

Stream event shape

tool_result_end
└── message
    ├── role:        "toolResult"
    ├── toolName:    "subagent"
    ├── toolCallId:  string
    ├── isError:     boolean
    ├── content:     [{ type: "text", text: "<final output>" }]
    └── details:     SubagentDetails

SubagentDetails object

interface SubagentDetails {
  // Execution metadata
  mode: "single" | "parallel";          // one task vs multiple parallel tasks
  delegationMode: "spawn" | "fork";     // context mode used
  projectAgentsDir: string | null;      // path to .pi/agents/ dir if used

  // Individual agent results (one per task)
  results: SingleResult[];

  // ── Stats summary (own + all descendants, recursively) ──────────────────
  aggregatedUsage: UsageStats;          // token counts and cost, full tree
  aggregatedToolCalls: ToolCallCounts;  // { toolName: callCount }, full tree

  // ── Per-agent breakdown ──────────────────────────────────────────────────
  usageTree: UsageTreeNode[];           // one root node per result
}

interface SingleResult {
  agent: string;                        // agent name
  agentSource: "user" | "project" | "builtin" | "unknown";
  task: string;                         // task string passed to this agent
  exitCode: number;                     // 0 = success, >0 = error, -1 = still running
  messages: Message[];                  // full conversation history of the subagent
  stderr: string;
  usage: UsageStats;                    // this agent's OWN token usage only
  toolCalls: ToolCallCounts;            // this agent's OWN tool calls only
  model?: string;
  stopReason?: string;                  // "end_turn" | "error" | "aborted" | ...
  errorMessage?: string;
}

interface UsageStats {
  input: number;                        // input tokens
  output: number;                       // output tokens
  cacheRead: number;                    // cache read tokens
  cacheWrite: number;                   // cache write tokens
  cost: number;                         // total cost in USD
  contextTokens: number;                // snapshot: last context window size (not summed in aggregates)
  turns: number;                        // number of assistant turns
}

// toolName → call count, e.g. { "bash": 5, "read": 3, "subagent": 1 }
type ToolCallCounts = Record<string, number>;

interface UsageTreeNode {
  agent: string;
  task: string;
  ownUsage: UsageStats;                 // only this agent's turns
  ownToolCalls: ToolCallCounts;         // only this agent's tool calls
  aggregatedUsage: UsageStats;          // ownUsage + all children recursively
  aggregatedToolCalls: ToolCallCounts;  // ownToolCalls + all children recursively
  children: UsageTreeNode[];            // one node per nested subagent invocation
}

Important notes on stats

  • SingleResult.usage and SingleResult.toolCalls cover only that one agent's own work — not its children. Children run in separate processes; their tokens never appear in the parent's usage.
  • aggregatedUsage / aggregatedToolCalls on SubagentDetails (and on each UsageTreeNode) are the correct totals to use when you want the cost or tool call count for an entire delegation subtree.
  • contextTokens is a point-in-time snapshot of the context window size at the last turn of that agent. It is not summed in aggregated stats (it would be meaningless as a cross-process sum).
  • toolCalls includes all tool calls an agent made, including the "subagent" call itself. You can use the "subagent" count to see how many nested delegations an agent spawned.

Annotated example JSON

The scenario below: main agent delegates to code-writer, which does some file work and then delegates to code-reviwer before finishing.

{
  "type": "tool_result_end",
  "message": {
    "role": "toolResult",
    "toolName": "subagent",
    "toolCallId": "toolu_01XYZ",
    "isError": false,
    "content": [
      {
        "type": "text",
        "text": "Feature implemented and reviewed. Added validation logic in auth.ts and updated the test suite."
      }
    ],
    "details": {
      "mode": "single",
      "delegationMode": "spawn",
      "projectAgentsDir": null,

      "aggregatedUsage": {
        "input": 2180,
        "output": 615,
        "cacheRead": 940,
        "cacheWrite": 120,
        "cost": 0.0079,
        "contextTokens": 0,
        "turns": 3
      },
      "aggregatedToolCalls": {
        "read":     3,
        "bash":     2,
        "edit":     1,
        "subagent": 1
      },

      "usageTree": [
        {
          "agent": "code-writer",
          "task": "Implement the auth feature and have it reviewed",
          "ownUsage": {
            "input": 1380,
            "output": 365,
            "cacheRead": 540,
            "cacheWrite": 120,
            "cost": 0.0058,
            "contextTokens": 2840,
            "turns": 2
          },
          "ownToolCalls": {
            "read":     1,
            "bash":     1,
            "edit":     1,
            "subagent": 1
          },
          "aggregatedUsage": {
            "input": 2180,
            "output": 615,
            "cacheRead": 940,
            "cacheWrite": 120,
            "cost": 0.0079,
            "contextTokens": 0,
            "turns": 3
          },
          "aggregatedToolCalls": {
            "read":     3,
            "bash":     2,
            "edit":     1,
            "subagent": 1
          },
          "children": [
            {
              "agent": "code-reviwer",
              "task": "Review the auth implementation in auth.ts",
              "ownUsage": {
                "input": 800,
                "output": 250,
                "cacheRead": 400,
                "cacheWrite": 0,
                "cost": 0.0021,
                "contextTokens": 1450,
                "turns": 1
              },
              "ownToolCalls": {
                "read": 2,
                "bash": 1
              },
              "aggregatedUsage": {
                "input": 800,
                "output": 250,
                "cacheRead": 400,
                "cacheWrite": 0,
                "cost": 0.0021,
                "contextTokens": 0,
                "turns": 1
              },
              "aggregatedToolCalls": {
                "read": 2,
                "bash": 1
              },
              "children": []
            }
          ]
        }
      ],

      "results": [
        {
          "agent": "code-writer",
          "agentSource": "builtin",
          "task": "Implement the auth feature and have it reviewed",
          "exitCode": 0,
          "stopReason": "end_turn",
          "model": "claude-opus-4-5",
          "stderr": "",
          "usage": {
            "input": 1380,
            "output": 365,
            "cacheRead": 540,
            "cacheWrite": 120,
            "cost": 0.0058,
            "contextTokens": 2840,
            "turns": 2
          },
          "toolCalls": {
            "read":     1,
            "bash":     1,
            "edit":     1,
            "subagent": 1
          },
          "messages": [
            "... full conversation history of code-writer (includes the nested subagent tool_result) ..."
          ]
        }
      ]
    }
  }
}

Collecting stats across an entire session

If you are consuming the JSON stream programmatically and want to track the total cost and tool usage across all subagent work in a session, listen for every tool_result_end event where message.toolName === "subagent" and sum message.details.aggregatedUsage across them.

let totalCost = 0;
const totalToolCalls = {};

for await (const line of jsonLines) {
  const event = JSON.parse(line);
  if (
    event.type === "tool_result_end" &&
    event.message?.toolName === "subagent" &&
    event.message?.details
  ) {
    const { aggregatedUsage, aggregatedToolCalls } = event.message.details;
    totalCost += aggregatedUsage.cost;
    for (const [tool, count] of Object.entries(aggregatedToolCalls)) {
      totalToolCalls[tool] = (totalToolCalls[tool] ?? 0) + count;
    }
  }
}

Note: if you also track the main agent's own usage from message_end events, make sure not to double-count the subagent costs there — the main agent's own token usage (from its own message_end events) does not include subagent work (whether subprocess or SDK-mode).


create-subagent Skill

If you want the agent to create new subagent definition files for itself, install the create-subagent skill. Once installed, the agent will know how to scaffold new .md agent files in the right location with correct frontmatter.

Attribution

Inspired by vaayne/agent-kit and mariozechner/pi-mono.

License

MIT