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

acp2api

v1.11.1

Published

OpenAI-compatible HTTP server over ACP agents. Use Claude Code, Codex, opencode or any ACP CLI from anything that speaks the OpenAI API but does not speak ACP yet.

Readme

acp2api

ci npm node license built with HINT

Use Claude Code, Codex or any ACP agent from anything that speaks the OpenAI API. Each agent you configure becomes a model id — that is the whole interface.

   OpenAI client                acp2api                  ACP agent
  (Hermes, LangChain,   ──▶  /v1/chat/completions  ──▶  claude-agent-acp
   OpenWebUI, a router,       OpenAI  ⇄  ACP            codex-acp
   your own script)                                     opencode acp, …

It spawns the CLI you are already logged into and spends that subscription — no API key is read, replayed or forwarded. That is the point, and the reason this goes through ACP instead of borrowing a vendor's OAuth token for its private HTTP API: the CLI uses the login it already has, and nothing else.

Quick start

npm install -g acp2api
# acp2api.yaml
server:
  cwd: ./work                # the agents' workspace, and their fs boundary
agents:
  - name: claude-opus        # <- the model id clients ask for
    type: claude
    model: opus
  - name: codex
    type: codex
acp2api --config acp2api.yaml
curl localhost:10021/v1/chat/completions -H 'content-type: application/json' \
  -d '{"model":"claude-opus","messages":[{"role":"user","content":"what is in this repo?"}]}'

That is a working install. There is no authentication: acp2api listens on loopback and authorization belongs to whatever router sits in front.

What it gives you

A coding-agent turn runs for minutes, holds state you paid for, narrates itself, runs commands — and an OpenAI client knows none of that. Everything below makes one behave sensibly anyway; each link has the request that exercises it, in the guide.

| | what it solves | | --- | --- | | Conversations, not cold starts | replaying a transcript per message throws away everything the agent had learned; incoming histories match live sessions by prefix | | Naming a conversation | one x-conversation-id header keeps one agent session per chat thread, for callers with no growing prefix to match | | Steering a running turn | deliver a correction INTO a turn that has nineteen minutes left | | Parking, not forgetting | an idle thread gives back its process and keeps its memory (session/resume) | | Warm starts | one warm-up forked per conversation instead of a re-orientation per thread | | Watching the work | tool calls, diffs and plans on reasoning_content, so a long turn stops looking like a hang | | Running commands yourself | ACP terminal: execution in your process, with your bounds | | Your tools, in the agent's hands | OpenAI tools in, tool_calls back — served to the agent as an MCP server, the turn held open for your result | | The agent's own tools | mcpServers per agent; it acts instead of asking | | Honest parameters | split by what breaks if we proceed: emulated, ignored-and-reported, or a clean 400 | | /v1/responses | the stateful API maps onto ACP directly: previous_response_id, per-request reasoning.effort |

Which agents work

Measured, not inferred: all 38 registry agents were installed and driven on 2026-08-14 — full results in docs/agents.md. Verified end to end (real turn, own file tools, MCP, streaming, continuity):

| agent | run as | | --- | --- | | Claude Code | type: claude (steerable) | | Codex | type: codex (steerable) | | OpenCode | command: opencode, args: [acp] | | Qwen Code | npx @qwen-code/qwen-code --acp + OPENAI_BASE_URL/KEY/MODEL | | goose | goose acp --with-builtin developer |

Most of the rest are account-gated (sign the CLI in once and they work) or need a model configured; a handful cannot finish a turn — each with the reason recorded.

Configure

One YAML file, ${VAR} expanded from the environment; every option documented in acp2api.example.yaml. The essentials:

| key | meaning | | --- | --- | | type | claude / codex bundle an adapter; general needs command | | model, reasoning | set by semantic category (model, thought_level) — ids differ per agent | | mcpServers | the agent's tools (url+headers or command+args+env) | | env, cwd, args | per-agent spawn overrides | | server.* | continuity, conversation header, steering (busy: queue), session bounds, progress, terminal |

acp2api --config acp2api.yaml --check   # validate and exit

Routes: GET /health, GET /v1/models, POST /v1/chat/completions (SSE with stream: true), POST/GET/DELETE /v1/responses.

Status codes — the failover contract

This is built to sit in a failover chain; the difference between "out of quota" and "broken" is the contract:

| status | when | | --- | --- | | 429 | the agent reported a usage limit — try the next one (matched via server.limitPatterns; ACP has no quota code) | | 502 | any other agent failure — a fault, not exhaustion | | 503 | the CLI could not be spawned | | 504 | the turn outlived requestTimeoutMs | | 401 | the CLI is not logged in |

Streaming headers are held back until the agent actually starts, so a 429 stays a 429 instead of a stream that merely stops.

Develop

make test      # 183 tests, offline, against a real stdio fake agent
make check     # validate the example config
make spec      # the code still carries every surface its .hint declares
make verify    # clean install + test + check + spec + pack

Built with HINT, mostly by the coding agents it exists to serve: every source file has a companion .hint with its contracts, invariants and the expensive lessons (hint <path> to read them, make spec fails on drift).

Reference

License

Apache-2.0