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-subagents-extension

v1.0.0

Published

Standalone subagent delegation for Pi — six-part contracts, path-scoped gates, model-class routing with honest fallback, live action feed, hash-only ledger. Zero runtime dependencies. Published as pi-subagents-extension on npm (the plain pi-subagents name

Readme

pi-subagents

Standalone, modular extraction of the ZOB harness subagents system (delegate_agent / delegate_task) — a mirror of the pi-mesh pattern.

  • Pure core — the core (core/gates/registry/models/lanes/engine/shared) imports nothing from @earendil-works/*. Pi only appears in the thin extension adapter (src/extension, with local pi-types.ts).
  • Hot session pool (lanes) — a bounded pool of warm child sessions.
  • Model routing with fallback — explicit A→B→parent chain, no silent fallback; fallback carries an explicit model_fallback status.
  • Ported gates — the ZOB delegation gates carried over.

Install / use on another machine

As a Pi package (recommended — the extension auto-loads):

pi install npm:pi-subagents-extension
# or from git, pinned to a release tag
pi install git:github.com/cgarrot/[email protected]

From source (clone and run):

git clone [email protected]:cgarrot/pi-subagents.git
cd pi-subagents
npm install
npm run build          # tsc → dist/ (build needed for CLI + tests; the Pi
                       # extension itself loads from src/ directly)

This gives the project the delegate_task / delegate_agent tools, the subagents CLI, the default agent cards (agents/) and the subagents-routing skill (skills/). Run npm run smoke for a headless E2E demo with the fake-pi fixture (no real pi needed).

Releases & publishing

  • Versioning follows semver from package.json (v1.0.0 = tag + npm version).
  • The Release GitHub Action publishes to npm automatically on v* tags (requires the NPM_TOKEN repository secret): npm version patch|minor|major && git push && git push --tags. prepublishOnly runs the full build + test suite before every publish.
  • The package is published as pi-subagents-extension on npmjs.org (publishConfig.access is public; the plain pi-subagents name is already taken on npm by another project) and is a Pi package (pi manifest + pi-package keyword), so pi install npm:pi-subagents-extension works on any machine and the package appears in the pi.dev gallery automatically.

Target layout

packages/pi-subagents/
├── package.json               # pi-subagents-extension 0.1.0, zero runtime deps
├── tsconfig.json              # strict, ESM, NodeNext, outDir dist
├── .gitignore                 # node_modules, dist
├── index.ts                   # re-export default from src/extension/index.js
├── LICENSE                    # MIT
├── README.md                  # this file
├── src/
│   ├── core/index.ts          # pure core (no Pi import)
│   ├── gates/index.ts         # ported gates
│   ├── registry/index.ts      # registry
│   ├── models/index.ts        # model routing types
│   ├── lanes/index.ts         # LanePool — single mutable state
│   ├── engine/index.ts        # execution engine
│   ├── extension/
│   │   ├── index.ts           # thin Pi adapter (default export)
│   │   └── pi-types.ts        # local Pi type shims
│   └── cli/index.ts           # CLI entry
├── child/README.md            # child adapter notes
├── agents/                    # default subagent cards (see agents/README.md)
│   ├── explore.md planner.md implementer.md oracle.md qa.md
│   └── README.md              # override guide
├── skills/
│   └── subagents-routing/
│       └── SKILL.md           # routing skill for pi-subagents users
├── scripts/
│   ├── subagents-smoke.mjs    # headless E2E smoke (fake-pi, no real pi)
│   └── run-tests.mjs          # portable recursive test runner
└── test/                      # unit + engine + lanes + gates + models suites

Single mutable state: the LanePool

The only mutable state in the system is the LanePool (src/lanes). Every hot child session lives in exactly one lane; every operation flows through the pool. Everything else is derived or stateless, which keeps the system testable and auditable.

v1 verdict (delivered): spawn-per-task + stable session

Per the stdin spike verdict, pi exits after a task (stdin is one-shot — there is no built-in multi-task loop). Therefore v1 dispatches each task as a fresh one-shot spawn (pi --mode json -p --no-extensions), but reuses a STABLE --session path per lane. A chain of tasks on the same lane keeps context continuity through the same session file: one boot per lane for N tasks (demonstrated headless by the smoke: two chain steps share one sessionPath).

The v2 warm-loop (one long-lived pi serving N tasks via a child extension) is a separate future spike, out of scope here.

F8 (fresh-per-run sessions): single/parallel dispatches default to a FRESH per-run session file <agent>-<runId>.jsonl under .pi/agent-sessions/ (one unified session dir — same as the LanePool default, the CLI doctor, and this README) — successive runs to the same agent never stack onto one shared session. Continuity is preserved where it matters: a chain shares one lane/session across its steps, and continue_run resumes the original run's session file (byte-offset). Passing fresh: false to delegate_task restores the legacy stable agent-named lane session (<agent>.jsonl).

Model routing

Resolution priority: explicitModel → agentModel → class model → parentModel.

  • Explicit model is verified against an injected verified model catalog; it blocks with model_unavailable (no child spawned) unless it is present with resolutionStatus === 'verified'. No silent fallback.
  • Class routing (cheap | balanced | capable) builds the honest fallback chain A → B → parent; the parent is the last-resort sentinel and is never probed. The chosen model + direct/fallback status are always exposed.
  • The model probe is an optional injected hook fired off the critical path (fire-and-forget, never awaited before spawn) with a shared long-TTL cache.

Parent-model inheritance (F3)

A child dispatched without an explicit model inherits the parent/session model (spawned with --model <parentModel>), resolved as:

  1. the live session model when the host exposes it on the session context (ctx.model, optional);
  2. otherwise the pi settings defaultModel — project <repoRoot>/.pi/settings.json over the global ~/.pi/agent/settings.json.

Default class models are quota-safe: every class (cheap, balanced, capable) maps to the resolved parent model — the one model guaranteed available for this session — so a class-routed child never silently switches provider. Hosts wanting per-class routing pass an explicit classModels map (which replaces the default entirely).

Verified model catalog: .pi/model-catalog.json (F2)

Explicit model: overrides are verified against the catalog file read at every preflight from <repoRoot>/.pi/model-catalog.json (schema zob.model-catalog.v1; a catalog created or updated mid-session is honored without restarting). Only entries with resolutionStatus === "verified" pass; anything else blocks with model_unavailable and remediation naming this path. Example catalog:

{
  "schema": "zob.model-catalog.v1",
  "models": {
    "ollama-cloud/deepseek-v4-flash:preview": { "resolutionStatus": "verified" },
    "openai/gpt-4o": { "resolutionStatus": "verified" },
    "anthropic/claude-opus-4": { "resolutionStatus": "resolved" }
  }
}

(anthropic/claude-opus-4 above is intentionally NOT verified: it would be blocked — verify a model's current provider availability before flipping its resolutionStatus to verified.)

Invariants (I1–I15)

  • I1 — ledger hash-only, bodyStored: false; never store raw bodies.
  • I2 — six-part contract validated before any spawn.
  • I3allowed_paths repo-relative only, forbidden deny-only, broad roots refused.
  • I4 — one child = one isolated pi process (--no-extensions + child adapter), never a shell.
  • I5 — honest statuses queued → running → complete | failed | aborted | preflight_failed.
  • I6 — output validated against the output contract (*.v1 + final marker) before acceptance.
  • I7 — zero loop: anti-duplicate, abort SIGTERM → 5s → SIGKILL, named timeouts.
  • I8 — every bound is a named constant.
  • I9 — core (core/gates/registry/models/lanes/engine/shared) imports nothing from @earendil-works/*; extension = thin adapter with local pi-types.ts.
  • I10 — model probe: no silent fallback (fallback = explicit routing with model_fallback status).
  • I11 — injectable runner (spawner/stdio) → deterministic tests without Pi.
  • I12 — optional hooks (goal, mesh, models) never required by the core.
  • I13 — model probe off the critical path + shared long-TTL cache.
  • I14 — honest fallback chain A→B→parent with model_fallback status.
  • I15 — bounded hot lane pool (idle TTL, SIGTERM→SIGKILL, max size).

Tools

The package ports the ZOB delegation tool family onto the pure core (extension adapter src/extension, CLI src/cli).

| Tool / command | Surface | Notes | | --- | --- | --- | | delegate_task | extension tool | strict single child with preflight + write gates | | delegate_agent | extension tool | single / parallel / chain child agents | | get_delegation_run | engine (BackgroundRunRegistry) | read current background run state | | await_delegation_run | engine | bounded wait for background settlement | | subagents (CLI) | src/cli/subagents.ts | admin surface over the pure core |

subagents CLI commands:

subagents agents   [--scope project|user|both]
subagents catalog
subagents contract "<six-part task>"
subagents runs     [--sort active|latest|duration|agent]
subagents doctor   [--timing]
subagents --help

Configuration: .subagents

Runtime behaviour is configured via an optional .subagents file at the repo root (project-local defaults) plus injected options at the engine boundary:

  • model.classescheap | balanced | capable preferred model ids and the per-class fallback chain.
  • model.verifiedCatalog — explicit-model allowlist (only resolutionStatus: verified models may be requested explicitly).
  • lanes.maxParallel — concurrency cap (default 4).
  • lanes.killGraceMs — abort grace between SIGTERM and SIGKILL (default 5000).
  • lanes.sessionDir — session-file dir (default <cwd>/.pi/agent-sessions).
  • ledger.dir — hash-only ledger dir (default <repoRoot>/.pi/logs/runs).
  • spawn — injectable spawner; tests inject the fake-pi fixture (I11).

The exact .subagents schema is resolved by the extension adapter layer; the core only consumes injected options (never reads config itself), preserving the pure-core invariant.

Default agents

Five generic default cards ship under agents/: explore, planner, implementer, oracle, qa — each with model_class cheap|balanced|capable. They are the fallback when a project defines none. See agents/README.md for frontmatter fields and how to override them with project-local .pi/agents.

Note: agent discovery reads *.md under an agent dir. The package's agents/README.md is documentation only; a project agent dir should hold only agent cards (or exclude docs) so no spurious readme agent is found.

Scripts

npm run build            # tsc -p tsconfig.json
npm test                 # build + node --test dist/test
npm run smoke            # scripts/subagents-smoke.mjs (headless E2E, fake-pi)
npm run ci               # build + test + smoke

Smoke (headless, no real pi)

node scripts/subagents-smoke.mjs drives the full delegation pipeline with the fake-pi fixture (test/fixtures/bin/fake-pi.mjs) injected as the spawner:

  1. builds a body-free catalog (registry) over the default agents;
  2. validates a six-part contract and proves preflight blocks before any spawn (no child launched on gate failure);
  3. runs a single task through the engine + LanePool;
  4. runs a chain (2 steps) proving {previous} substitution + the same sessionPath (one boot for N tasks);
  5. runs parallel dispatch under a concurrency cap;
  6. verifies hash-only / body-free ledger entries (bodyStored: false, raw bodies stripped to sha-256);
  7. runs a background delegation and inspects it via get_delegation_run.

It exits 0 only when every check passes, otherwise prints the failure and exits non-zero. Requires a prior npm run build.

Limitations

  • v2 warm-loop (one long-lived pi serving N tasks via a child extension) is a future spike; v1 is spawn-per-task with a stable per-lane session.
  • Session files grow: each lane appends NDJSON to a stable *.jsonl session file, so long-running chains accumulate session content. v2 will add rollover / compaction.
  • Agent discovery reads *.md: a documentation file inside an agent dir is parsed as an (empty) agent; keep agent dirs to cards only.
  • Extension adapter (src/extension) and CLI are the thin Pi-facing layer and are the only modules allowed to touch pi-types.ts.