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

pi-herdr-subagents

v0.1.5

Published

Interactive subagents for pi running in herdr

Downloads

557

Readme

pi-herdr-subagents

Async subagents for pi running exclusively in herdr. Spawn, orchestrate, and manage sub-agent sessions in dedicated herdr tabs or panes. Fully non-blocking — the main agent keeps working while subagents run in the background.

How It Works

Call subagent() and it returns immediately. The sub-agent runs in its own terminal pane. A live widget above the input shows all tracked agents with their projected state — for example starting, active, waiting, interrupted, stalled, running, or finalizing. The header summarizes active (processing) vs open (not processing). When every tracked subagent is open, the border switches to amber. When a sub-agent finishes, its result is steered back into the main session as an async notification — triggering a new turn so the agent can process it.

╭─ Subagents ──────────────────── 1 active · 1 open ─╮
│ 00:23  Scout: Auth (scout)        active · bash 7m │
│ 00:45  Scout: DB (scout)                waiting 2m │
╰────────────────────────────────────────────────────╯

For parallel execution, just call subagent multiple times — they all run concurrently:

subagent({ name: "Scout: Auth", agent: "scout", task: "Analyze auth module" });
subagent({ name: "Scout: DB", agent: "scout", task: "Map database schema" });
// Both return immediately, results steer back independently

Development

Run unit tests and lint locally:

npm test
npm run lint

Run the real end-to-end suite from inside herdr with an explicit test model:

PI_TEST_MODEL="deepseek/deepseek-v4-flash" PI_TEST_TIMEOUT=180000 npm run test:integration

The full suite launches real Pi sessions and can take several minutes. PI_TEST_TIMEOUT is the per-test timeout in milliseconds; use at least 180000 for the lifecycle suite.

PI_TEST_MODEL is applied to both the parent Pi sessions and the project-local test subagents created by the harness.

Install

Install the package from npm:

pi install npm:pi-herdr-subagents

This project does not install or load HazAT/pi-interactive-subagents automatically.

Changing the package.json version on main automatically creates a matching Git tag and GitHub Release, generates release notes, and publishes the package to npm. For authentication, versioning, verification, and troubleshooting, see RELEASING.md.

Start herdr, then run pi inside it:

herdr
pi

herdr is the only supported terminal environment. The extension requires HERDR_ENV=1 and the herdr CLI to be available.

If your shell startup is slow and subagent commands sometimes get dropped before the prompt is ready, set PI_SUBAGENT_SHELL_READY_DELAY_MS to a higher value (defaults to 500):

export PI_SUBAGENT_SHELL_READY_DELAY_MS=2500

Subagent tabs and panes are created without stealing keyboard focus. Launch commands target child panes by explicit ID, so focus and command delivery are independent. Note: the interactive option controls parent status notifications, not terminal focus.

What's Included

Extensions

Subagents — 4 main-session tools + 3 commands, plus 1 subagent-only tool:

| Tool | Description | | -------------------- | ------------------------------------------------------------------------------------------- | | subagent | Spawn a sub-agent in a dedicated herdr pane (async — returns immediately) | | subagent_interrupt | Interrupt a running Pi-backed subagent's current turn | | subagents_list | List available agent definitions | | subagent_resume | Resume a previous sub-agent session (async) |

| Command | Description | | -------------------------- | ------------------------------------ | | /plan | Start a full planning workflow | | /iterate | Fork into a subagent for quick fixes | | /subagent <agent> <task> | Spawn a named agent directly |

Bundled Agents

| Agent | Default runtime | Role | | ----------------- | --------------------- | ---------------------------------------------------------------------------------------- | | planner | Config, then parent | Brainstorming — clarifies requirements, explores approaches, writes plans, creates todos | | scout | Config, then parent | Fast codebase reconnaissance — maps files, patterns, conventions | | worker | Config, then parent | Implements tasks from todos — writes code, runs tests, makes polished commits | | reviewer | Config, then parent | Reviews code for bugs, security issues, correctness | | visual-tester | Config, then parent | Visual QA via Chrome CDP — screenshots, responsive testing, interaction testing |

Bundled agents use model defaults from config.json when configured; otherwise they inherit the parent model. Thinking defaults still come from agent frontmatter or the parent level. The orchestrating agent can override either field for a specific task using an exact authenticated model ID and a supported Pi thinking level. Prefer changing thinking before changing models.

Agent discovery follows priority: project-local (.pi/agents/) > global (~/.pi/agent/agents/) > package-bundled. Override any bundled agent by placing your own version in the higher-priority location.


Async Subagent Flow

1. Agent calls subagent()          → returns immediately ("started")
2. Sub-agent runs in herdr pane    → widget shows live status
3. User keeps chatting             → main session fully interactive
4. Sub-agent finishes              → result steered back as a normal completion/failure
5. Main agent processes result     → continues with new context

Multiple subagents run concurrently — each steers its result back independently as it finishes. The live widget above the input tracks every agent still in flight:

╭─ Subagents ──────────────────── 1 active · 2 open ─╮
│ 01:23  Scout: Auth (scout)            active · write 7m │
│ 00:45  Researcher (researcher)               stalled 4m │
│ 00:12  Scout: DB (scout)                      starting… │
╰─────────────────────────────────────────────────────────╯

Completion messages render with a colored background and are expandable with Ctrl+O to show the full summary and session file path. Completed rows are removed from the widget as soon as their result is delivered or suppressed.

In-progress status updates

The widget projects each sub-agent from a process + turn lifecycle:

  • Herdr pane inspection is the coarse authority for whether the child process is present and whether Herdr reports it as idle, working, blocked, or done.
  • Child activity snapshots enrich the label with Pi-only detail (tool name, streaming, etc.) when available.
  • Session JSONL is still used for transcript, resume, lineage, and result extraction — not for liveness.

Projected labels include:

  • starting — launched; pane/activity confirmation is still settling
  • active — processing work (agent turn, provider request, streaming, or tool execution)
  • blocked — Herdr reports the child as blocked
  • waiting — turn finished; the process is intentionally open for more input or another stage
  • interrupted — the current turn was cancelled (Escape / subagent_interrupt); the process stays open and is not treated as active processing
  • stalled — pane inspection is unhealthy long enough that the parent can no longer trust the run
  • running — fallback when only coarse process presence is known (e.g. non-Pi backends)
  • finalizing — completion was observed and delivery is in progress; the process elapsed timer freezes here

The widget header counts active vs open:

  • activeactive, starting, running, or blocked
  • open — everything else still tracked (waiting, interrupted, stalled, finalizing, …)

When activeCount === 0 (every tracked row is open), the border uses an amber accent. Process elapsed time (MM:SS on the left) freezes when the process reaches finalizing/completed/failed. Interrupt does not freeze that process clock; the interrupted state shows its own duration on the right while the process remains open.

A fixed internal watchdog marks a run as stalled when pane inspection fails or the pane disappears without a completion sidecar; valid long-running active or waiting states do not become stalled just because time passes. When a run enters stalled or recovers from it, the parent agent receives a steer message so it can react. All other status transitions stay in the widget only.

Interactive subagents stay silent. Long-running user-driven subagents (e.g. planner, or any /iterate fork) do not wake the parent session on stalled/recovered transitions — the user is working directly in the subagent's pane, and a steer message there would just burn an orchestrator turn on a no-op "still waiting" ping. The widget still updates normally, and activity snapshots are still recorded/classified regardless of the interactive setting. By default, agents with auto-exit: true are treated as autonomous and get stall pings; agents without it are treated as interactive and stay quiet. Override per-agent with interactive: true|false in frontmatter, or per-spawn with interactive: true|false on the tool call.

Configuration

Status display is controlled by config.json in the extension directory. Copy config.json.example to get started:

cp config.json.example config.json
{
  "status": {
    "enabled": true
  },
  "models": {
    "agents": {}
  }
}

The copyable example is model-neutral, so it works without requiring credentials for a specific provider. To configure models, replace the empty section with exact IDs from your authenticated model catalog:

{
  "models": {
    "default": "your-provider/your-default-model",
    "agents": {
      "scout": "your-provider/your-fast-model",
      "reviewer": "your-provider/your-review-model"
    }
  }
}

models.default sets the model for subagents that do not specify a model. models.agents sets per-agent defaults, keyed by the agent name passed to subagent({ agent: ... }). Explicit model tool arguments take precedence, followed by agent frontmatter, per-agent config, the global default, and finally the parent model. Model values must be exact authenticated provider/model-id references.

config.json is gitignored so local overrides don't get committed.


Spawning Subagents

// Named agent with defaults from agent definition or config.json
subagent({ name: "Scout", agent: "scout", task: "Analyze the codebase..." });

// Force a full-context fork for this spawn
subagent({ name: "Iterate", fork: true, task: "Fix the bug where..." });

// Agent defaults can choose a different session-mode via frontmatter
subagent({ name: "Planner", agent: "planner", task: "Work through the design with me" });

// Custom working directory
subagent({ name: "Designer", agent: "game-designer", cwd: "agents/game-designer", task: "..." });

Parameters

| Parameter | Type | Default | Description | | ---------------------- | ------- | -------------- | ------------------------------------------------------------------------------------------------- | | name | string | required | Display name (shown in widget and pane title) | | task | string | required | Task prompt for the sub-agent | | agent | string | — | Load defaults from agent definition | | fork | boolean | false | Force the full-context fork mode for this spawn, overriding any agent session-mode frontmatter | | interactive | boolean | derived | Mark this spawn as interactive (don't wake the parent on stall/recovery). Defaults to the agent's interactive frontmatter, otherwise the inverse of auto-exit. | | model | string | configured or parent | Exact authenticated provider/model-id; resolution is tool argument → agent frontmatter → per-agent config → global config → parent | | thinking | string | parent level | Pi thinking level (off through max); omit to inherit the parent | | systemPrompt | string | — | Append to system prompt | | skills | string | — | Comma-separated skill names | | tools | string | — | Comma-separated tool names | | cwd | string | — | Working directory for the sub-agent (see Role Folders) |


Interrupting a running subagent

Use subagent_interrupt to cancel the active turn of a running Pi-backed subagent:

subagent_interrupt({ id: "abcd1234" });
// or
subagent_interrupt({ name: "Scout" });

This sends Escape to the child pane, cancelling the in-progress model turn. The subagent session stays alive — the pane, session file, and background polling all remain intact. After the interrupt, the widget immediately labels the child as interrupted (counted as open, not active processing). Stale pre-interrupt activity snapshots are ignored so a lagging Herdr/active reading cannot overwrite the interrupt. The process elapsed timer keeps running because the pane is still open; only the interrupted-state duration freezes relative to the interrupt request. If the child starts work later, newer observations return it to active; completion, failure, and caller_ping still flow through normally.

This is a turn-level interrupt, not a method for forcibly terminating a subagent session.

Note: Only Pi-backed subagents are supported. Claude-backed runs will return an error.


caller_ping — Child-to-Parent Help Request

The caller_ping tool lets a subagent request help from its parent agent. When called, the child session exits and the parent receives a notification with the help message. The parent can then resume the child session with a response using subagent_resume.

caller_ping parameters:

  • message (required): What you need help with

subagent_resume parameters:

  • sessionPath (required): Path to the child session .jsonl file
  • name (optional): Display name for the resumed pane (defaults to Resume)
  • message (optional): Follow-up prompt to send after resuming
  • autoExit (optional): Whether the resumed session should auto-exit after its next response. Defaults to true for autonomous follow-up work; set false when resuming for an interactive handoff.

Interaction flow:

  1. Child calls caller_ping({ message: "Not sure which schema to use" })
  2. Child session exits (like subagent_done)
  3. Parent receives a steer notification: "Sub-agent Worker needs help: Not sure which schema to use"
  4. Parent resumes the child session via subagent_resume with the response
  5. Child picks up where it left off with the parent's guidance

Example:

// Inside a worker subagent
await caller_ping({
  message: "Found two conflicting migration files — should I use v1 or v2?"
});
// Session exits here. Parent receives the ping, then resumes this session
// with guidance like "Use v2, v1 is deprecated"

Note: caller_ping is only available inside subagent contexts. Calling it from a standalone pi session returns an error.


The /plan Workflow

The /plan command orchestrates a full planning-to-implementation pipeline.

/plan Add a dark mode toggle to the settings page
Phase 1: Investigation    → Quick codebase scan
Phase 2: Planning         → Interactive planner subagent (user collaborates)
Phase 3: Review Plan      → Confirm todos, adjust if needed
Phase 4: Execute          → Scout + sequential workers implement todos
Phase 5: Review           → Reviewer subagent checks all changes

The parent workspace and tab names stay unchanged. Subagents are created in newly named tabs or panes for each phase.


The /iterate Workflow

For quick, focused work without polluting the main session's context.

/iterate Fix the off-by-one error in the pagination logic

This always forks the current session into a subagent with full conversation context. It does not inherit an agent default session-mode. Make the fix, verify it, and exit to return. The main session gets a summary of what was done.


Custom Agents

Place a .md file in .pi/agents/ (project) or ~/.pi/agent/agents/ (global):

---
name: my-agent
description: Does something specific
model: anthropic/claude-sonnet-4-6
thinking: minimal
tools: read, bash, edit, write
session-mode: lineage-only
spawning: false
---

# My Agent

You are a specialized agent that does X...

Frontmatter Reference

| Field | Type | Description | | ------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | name | string | Agent name (used in agent: "my-agent") | | description | string | Shown in subagents_list output | | model | string | Optional exact authenticated model default; omit to inherit the parent | | thinking | string | Optional Pi thinking default (off through max); omit to inherit the parent | | tools | string | Comma-separated native pi tools only: read, bash, edit, write, grep, find, ls | | skills | string | Comma-separated skill names to auto-load | | session-mode | string | Default child-session mode: standalone, lineage-only, or fork | | spawning | boolean | Set false to deny all subagent-spawning tools | | deny-tools | string | Comma-separated extension tool names to deny | | auto-exit | boolean | Auto-shutdown when the agent finishes its turn — no subagent_done call needed. If the user sends any input, auto-exit is permanently disabled and the user takes over the session. Recommended for autonomous agents (scout, worker); not for interactive ones (planner). Also determines the default value of interactive (see below). | | interactive | boolean | derived | Override whether stall/recovery transitions wake the parent session. Defaults to the inverse of auto-exit: autonomous agents (auto-exit: true) are non-interactive and get stall pings; agents without auto-exit are interactive and stay quiet. Explicit values take precedence. | | cwd | string | Default working directory (absolute or relative to project root) | | disable-model-invocation | boolean | Hide this agent from discovery surfaces like subagents_list. The agent still remains directly invokable by explicit name via subagent({ agent: "name", ... }). |


Discovery still resolves precedence before visibility filtering. If a project-local hidden agent has the same name as a visible global or bundled agent, the hidden project agent wins and the lower-precedence agent does not appear in subagents_list.

session-mode

Choose how a subagent session starts:

  • standalone — default fresh session with no lineage link to the caller
  • lineage-only — fresh blank child session with parentSession linkage, but no copied turns from the caller
  • fork — linked child session seeded with the caller's prior conversation context

lineage-only is useful when you want session discovery and fork lineage UX to show the relationship later, but you do not want the child to inherit the parent's turns.

fork: true on the tool call always forces the fork mode for that specific spawn. /iterate uses this explicit override on purpose.

---
name: planner
session-mode: lineage-only
---

auto-exit

When set to true, the agent session shuts down automatically as soon as the agent finishes its turn — no explicit subagent_done call is needed.

Behavior:

  • The session closes after the agent's final message (on the agent_end event)
  • If the user sends any input before the agent finishes, auto-exit is permanently disabled for that session — the user takes over interactively
  • The modeHint injected into the agent's task is adjusted accordingly: autonomous agents see "Complete your task autonomously." rather than instructions to call subagent_done

When to use:

  • ✅ Autonomous agents (scout, worker, reviewer) that run to completion
  • ❌ Interactive agents (planner, iterate) where the user drives the session
---
name: scout
auto-exit: true
---

interactive

Controls whether status transitions (stalled, recovered) wake the parent session with a steer message.

Default: the inverse of auto-exit. Autonomous agents (auto-exit: true) are non-interactive and ping the parent on stall/recovery; agents without auto-exit are interactive and stay quiet. Bare spawns with no agent defs (e.g. /iterate with fork: true) are treated as interactive.

Why it exists: Interactive agents can run for minutes or hours while the user thinks, types, and reads in the subagent's pane. Child snapshots still update the widget, but stalled/recovered supervision messages rarely need to wake the parent for user-driven sessions. Skipping the steer keeps the parent quiet until the child actually finishes.

When to override:

  • Set interactive: false on an agent that doesn't auto-exit but you still want stall pings for
  • Set interactive: true on an autonomous agent you'd rather check on yourself
---
name: planner
# interactive defaults to true because auto-exit is not set
---

Or per spawn:

subagent({ name: "Scout", agent: "scout", interactive: true, task: "..." });

Tool Access Control

By default, every sub-agent can spawn further sub-agents. Control this with frontmatter:

spawning: false

Denies all subagent lifecycle tools (subagent, subagent_interrupt, subagents_list, subagent_resume):

---
name: worker
spawning: false
---

deny-tools

Fine-grained control over individual extension tools:

---
name: focused-agent
deny-tools: subagent
---

Recommended Configuration

| Agent | spawning | Rationale | | ---------- | ----------- | -------------------------------------------- | | planner | (default) | Legitimately spawns scouts for investigation | | worker | false | Should implement tasks, not delegate | | researcher | false | Should research, not spawn | | reviewer | false | Should review, not spawn | | scout | false | Should gather context, not spawn |


Role Folders

The cwd parameter lets sub-agents start in a specific directory with its own configuration:

project/
├── agents/
│   ├── game-designer/
│   │   └── CLAUDE.md          ← "You are a game designer..."
│   ├── sre/
│   │   ├── CLAUDE.md          ← "You are an SRE specialist..."
│   │   └── .pi/skills/        ← SRE-specific skills
│   └── narrative/
│       └── CLAUDE.md          ← "You are a narrative designer..."
subagent({ name: "Game Designer", cwd: "agents/game-designer", task: "Design the combat system" });
subagent({ name: "SRE", cwd: "agents/sre", task: "Review deployment pipeline" });

Set a default cwd in agent frontmatter:

---
name: game-designer
cwd: ./agents/game-designer
spawning: false
---

Tools Widget

Every sub-agent session displays a compact tools widget showing available and denied tools. Toggle with Ctrl+J:

[scout] — 12 tools · 4 denied  (Ctrl+J)              ← collapsed
[scout] — 12 available  (Ctrl+J to collapse)          ← expanded
  read, bash, edit, write, todo, ...
  denied: subagent, subagents_list, ...

Requirements

  • pi — the coding agent
  • herdr — the required terminal workspace
herdr
pi

Other multiplexers and terminal backends are not supported.


Acknowledgements

The sub-agent status supervision and turn-only interruption features were inspired by RepoPrompt's sub-agent snapshot polling and run cancellation features.


License

MIT