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

@automatalabs/pi-acp

v0.9.4

Published

An in-process Agent Client Protocol server for the [pi coding agent](https://github.com/earendil-works/pi). It embeds pi through its published SDK and speaks ACP protocol version 1 over stdio. Standard output is reserved exclusively for ACP NDJSON.

Readme

@automatalabs/pi-acp

An in-process Agent Client Protocol server for the pi coding agent. It embeds pi through its published SDK and speaks ACP protocol version 1 over stdio. Standard output is reserved exclusively for ACP NDJSON.

Command line

Run the server with npx @automatalabs/pi-acp or an installed pi-acp binary. pi-acp --version prints the package version without starting a server.

Side-effect-free library API

The package entry exports the value APIs runAcp(options?), PiAcpAgent, and resolveDeps, plus the TypeScript-only PiAcpDeps type. Importing it starts no server, opens no stdio connection, and does not mutate console or stdio. Call and await runAcp() explicitly to connect; pass a partial PiAcpDeps and/or an ACP stream for embedding and tests.

Pi configuration and teardown

Sessions load the operator's real pi configuration — settings, extensions, and pi's own MCP servers — from PiAcpDeps.agentDir, which defaults to pi's getAgentDir() ($PI_CODING_AGENT_DIR, else ~/.pi/agent). Override it to point pi at an isolated directory; embedders and tests that stub createAgentSession should, because the resource loader reads this path and starts the extensions it finds before the session factory is called.

Closing a session emits pi's session_shutdown event to those extensions before disposing the session, matching AgentSessionRuntime.dispose(). That event is pi's only extension-cleanup contract, so an extension that spawned a process releases it there. This matters more here than for out-of-process ACP backends: pi runs in-process, so anything it leaves behind is a live handle on the host's event loop rather than something the OS reaps with a child process tree.

AgentPrism built-in backend

@automatalabs/acp-agents ships pi-acp as the built-in pi backend. Route a call with the backend-only id to keep pi's configured default model, or include pi's exact provider/model-id after the routing prefix:

await runner.run("Review this change", { model: "pi" });
await runner.run("Review this change", { model: "pi/openrouter/vendor/model-id" });

The runner strips exactly the first pi/ segment and sends the remaining provider/model-id verbatim through ACP's reserved model config channel. Pi-acp advertises a configured model select populated from the completed credential- and provider-filter-aware Pi catalog; set requests refresh and require membership in that same catalog. An unknown model rejects with JSON-RPC -32602 and data.errorKind = "invalid_model".

Thinking levels

Pi-acp's thinkingLevel select is model-aware. Its visible choices are Pi's getSupportedThinkingLevels() result for the selected model, in Pi's order: a model capped at high does not advertise xhigh or max, and a non-reasoning model advertises only off. Before a model is selected, the option uses Pi's complete recognized domain as an unknown-model best-effort fallback. That domain is derived once from Pi's helper with a synthetic model that supports every level; pi-acp does not maintain a parallel hardcoded vocabulary.

The option carries the additive ACP metadata _meta["@automatalabs/agentprism"].recognizedValues. The visible choices remain the supported subset, while this metadata contains Pi's complete ordered domain so clients can distinguish an unsupported recognized value from garbage. A supported set request is applied unchanged. A recognized but unsupported request is clamped with Pi's clampThinkingLevel() and the response echoes the effective level. An unrecognized value fails loudly with JSON-RPC -32602 and data.errorKind = "invalid_config_value"; it is never handed to Pi's lowest-level fallback.

MCP and structured output

Pi-acp serves stdio, Streamable HTTP, and legacy SSE MCP servers and consumes stable tools, resources, prompts, completion, logging, pagination, progress, and dynamic tool registration. It also provides MCP client sampling, the workspace root, and form/URL elicitation. Client-hosted acp transport remains runner-owned. For agent({ schema }), Pi receives the runner's client-hosted HTTP StructuredOutput tool through this standard MCP path and retains the common prompt-embedded schema plus validated last-text fallback.

Authentication

Credentials are ambient. The server advertises exactly one method unconditionally:

| id | name | source | | --- | --- | --- | | pi-stored-credentials | pi stored credentials | pi's ~/.pi/agent/auth.json, or a provider API key in the server's environment (ANTHROPIC_API_KEY, OPENAI_API_KEY, GEMINI_API_KEY, XAI_API_KEY, OPENROUTER_API_KEY) |

The per-provider API-key methods that used to sit alongside it were env_var-typed; ACP schema 1.21.0 (@agentclientprotocol/sdk 1.4.0) removed that variant from the protocol, so they are no longer advertised — the environment variables themselves are still honored. Authentication requests are no-op acknowledgements because the environment or pi's credential store supplies the secret. A selected or otherwise resolvable model whose credential is missing rejects with -32000 so clients can pause for authentication. Having no model at all is distinct: it rejects with -32602 / invalid_model.

Reserved tool namespaces

pi-acp owns the mcp__ prefix for injected MCP tools. Pi extensions must not register names in that namespace.

Version 1 limitations

Load replay is the active linear branch and excludes branch topology and compaction summaries. additionalDirectories is accepted but ignored because pi is not root-confined. ACP prompt audio is degraded to a text note. Terminal-login authentication is not exposed.

Native session steering

Pi advertises the _session/steering extension at top-level initialize metadata as _meta: { steering: { supported: true } }, with strict active-turn-only semantics. While a Pi prompt turn is live, the server converts the supplied ACP content with the same text/image conversion as session/prompt and calls native AgentSession.steer(text, images), returning { outcome: "injected" }; the original session/prompt still owns all output, usage, and settlement. When the session is idle — or a steer arrives just as the turn settles, before pi could consume it — the server removes any unconsumed native queue entry and returns { outcome: "promptRequired", reason: "noRunningTurn" }. It never calls prompt(), followUp(), or another turn-start helper from steering, so steering cannot create hidden work or prepend input to a later prompt. Cancellation races use the same promptRequired/noRunningTurn response when no active turn accepted the instruction. Unexpected internal failures reject the JSON-RPC request through the normal structured error path.

Loaded-session turn-terminal state (_session/loaded_turn)

Pi also advertises the _session/loaded_turn extension at top-level initialize metadata as _meta: { loadedTurn: { supported: true } } — the re-attach arm's AUTHORITATIVE completion evidence for a session re-opened with session/load (a restarted host's restore path). _session/loaded_turn/query { sessionId } answers whether the loaded session's founding turn is still running right now: running while a turn executes in this process (the client then waits for the _session/loaded_turn/ended push — sent with the turn's stop reason, or its error, when the turn finishes, arming and clearing a one-shot watch), completed when the session journal's last message entry is an assistant message (pi persists every complete LLM message atomically at message_end, so a completed turn always leaves an assistant leaf and the replay's trailing assistant message is the turn's FINAL message — authoritative, never a quiet-gap guess), and interrupted otherwise (the journal shows an interrupted/abandoned turn — nothing is running, so re-issue is safe). A query for an unknown session is the standard unknown_session error.

Session system prompt (_meta.systemPrompt)

Pi advertises a session system-prompt channel at top-level initialize metadata as _meta: { systemPrompt: { replace: true, append: true } }. A client sets _meta.systemPrompt on session/new, session/resume, session/load, or session/fork — the same bare key claude-agent-acp reads, so a client can keep one wire shape across the two servers — as either a string or an object:

  • a string, or { replace }, replaces pi's built-in system prompt: it takes pi's custom-prompt slot (the SYSTEM.md / --system-prompt slot) through the resource loader's systemPromptOverride, exactly as for an operator-configured prompt. With a custom prompt pi's buildSystemPrompt drops its default instruction text — the "Available tools" list with its snippets, its guidelines, and the pi docs/examples paths — and still appends, in this order, the append-system-prompt entries, the project context files (AGENTS.md and friends inside <project_context>), the skills block (when a read or bash tool is available), and the Current working directory line;
  • { append } is added as one more append-system-prompt entry after the operator's own configured entries (appendSystemPromptOverride), so it never displaces them;
  • { replace, append } does both.

The instructions are per session: they shape only the session the request opens and are read again on every reattach, so a session/resume without the key runs on pi's own configuration. A malformed value — a non-string/non-object, a blank string, a non-string field, or any field other than replace / append — is rejected with JSON-RPC -32602 and data.errorKind = "invalid_system_prompt" (data.field names the offender) before any journal or session state exists; an unusable instruction never runs under the default prompt. The @automatalabs/acp-agents pi backend drives this channel from the backend-neutral systemPrompt: { replace?, append? } option.

Development

The pnpm test script intentionally runs tsc -p tsconfig.type-tests.json before the runtime test suite. This is a small deviation from the test-script example in the frozen specification and ensures the T2b public type-contract check is enforced in local and CI test runs.

Run node scripts/smoke-pi-package.mjs from the repository root after changing Pi dependencies. It packs this adapter and checks its public SDK import in fresh npm and pnpm installations. Pi 0.87.0 keeps its experimental remote harness out of the published local SDK, so this adapter no longer needs to supply @earendil-works/pi-server.

Built on pi — THIRD-PARTY notice

This package depends on and embeds @earendil-works/pi-coding-agent, @earendil-works/pi-agent-core, and @earendil-works/pi-ai version 0.87.1. pi is Copyright Earendil Inc., Mario Zechner, and Armin Ronacher and is distributed under the MIT License. The dependency packages retain the full MIT copyright and license text. pi-acp itself is Apache-2.0.

Model discovery preferences

The ACP model catalog continues to expose every authenticated available model. Native merged Pi enabledModels settings add presentation metadata to the model config option at _meta["@automatalabs/agentprism.modelDiscovery"]: { source:"enabledModels", preferred:string[], unmatched:string[] }. Native pattern order and matching semantics are preserved, then preferences intersect the authenticated catalog. Unmatched patterns remain visible. Preferences do not restrict execution; without a configured preference list, the MCP summary shows available provider groups. The current model is distinct from preferred models, and thinkingLevel options must be discovered for the exact selected model.