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

restitch

v0.1.0

Published

See your agent runs as runs, not as forty disconnected HTTP requests.

Readme

Restitch

A local-first reverse proxy that reconstructs LLM agent runs from raw HTTP traffic.

See your agent runs as runs, not as forty disconnected HTTP requests. No SDK, no headers, no code changes.

npx restitch start --daemon
eval "$(restitch env)"
claude "explain this repo"

Then open http://localhost:7357.


The problem

When you give a coding agent a single instruction, it doesn't make one API call. It makes forty. It thinks, runs a command, reads the result, thinks again, edits a file, checks its work. Each of those is a separate, independent HTTP request, and none of them knows about the others.

Every proxy-based tool in this space forwards those bytes correctly. None of them group the requests into runs unless the client volunteers a session id, and coding agents — Claude Code, Cursor, Aider, opencode — do not volunteer one. So on the proxy path they all degrade to a flat list of disconnected requests.

Restitch works it out from the traffic itself.

How the grouping works

Turn N+1 of an agent loop resends turn N's entire message list. That prefix relationship is the signal.

After each response, Restitch indexes a fingerprint of the conversation state the next request should open with. On each new request it walks backwards from the full message list, trimming up to six trailing messages, and looks for a match. That is six hashes per request rather than the O(n²) of hashing every prefix.

The fingerprint deliberately ignores everything a client legitimately changes between turns — cache_control markers move as the client slides its cache breakpoints, block ids differ, image bytes are never hashed, thinking blocks aren't resent verbatim. Each of those breaks the chain if you leave it in.

If you own the client, skip the heuristic entirely:

x-restitch-session: my-run-id

Restitch strips the header before forwarding, so the provider never sees it.

What you get

▚ session aSA5vHC_qNBl  new conversation
│
├─ turn 1  claude-opus-5
│  ├─ ⚙ Bash  toolu_grep
│  └─ tool_use  4in/640out  cache=68.0kr/2.8kw
│
├─ turn 2  claude-opus-5
│  ├─ ✓ Bash returned  64ms round trip
│  ├─ ⚙ Read  toolu_read
│  └─ tool_use  4in/640out  cache=68.0kr/2.8kw
│
├─ turn 3  claude-opus-5
│  ├─ ✓ Read returned  63ms round trip
│  └─ end_turn  4in/640out  cache=68.0kr/2.8kw

Plus a dashboard at http://localhost:7357 with a session list, a span timeline, a latency waterfall, a token breakdown, and a context chain view that renders the conversation exactly as it was sent — which is how you answer "why is this call costing 50k tokens" in about two seconds.

Install

Needs Node 22.13 or newer (node:sqlite is built in from there).

npm install -g restitch     # or just use npx

Providers

| Client | Set this | |---|---| | Anthropic | ANTHROPIC_BASE_URL=http://localhost:7357/anthropic | | OpenAI | OPENAI_BASE_URL=http://localhost:7357/openai/v1 | | Anything OpenAI-compatible | restitch provider add <name> <base-url> |

restitch env prints the export lines for whatever you have configured, which is what eval "$(restitch env)" above is doing.

Groq, Together, Fireworks, OpenRouter, Azure, Ollama and vLLM all speak the OpenAI wire format, so they work through provider add with no new code:

restitch provider add groq https://api.groq.com/openai/v1
# base URL: http://localhost:7357/custom/groq

Commands

restitch start [--daemon]        run the proxy and dashboard
restitch stop                    stop a backgrounded proxy
restitch status                  running? seen traffic?
restitch env [--provider name]   print export lines

restitch session list            list recorded sessions
restitch session show <id>       one session, tools nested under turns
restitch session analyze <id>    explain what went wrong
restitch session export <id>     --format json | har
restitch session close <id>
restitch session delete <id> --yes

restitch provider add|list|remove
restitch config list|get|set|path
restitch pricing                 which models have a price
restitch stats

Session ids accept a unique prefix, so restitch session show aSA5 works.

Cost

restitch pricing shows which of your models are priced. Anthropic and OpenAI ship with the table; custom providers deliberately do not, because each sets its own rates and a guessed price is worse than none. Add yours to ~/.restitch/config.json:

{
  "pricingOverrides": {
    "llama-3.1-8b-instant": { "inputPerMToken": 0.05, "outputPerMToken": 0.08 }
  }
}

Existing runs are re-priced on the next start. An unpriced model reports cost as unknown, never $0.00.

Root cause analysis

restitch session analyze <id>

Names the specific turn or tool call that broke the chain. Needs ANTHROPIC_API_KEY or OPENAI_API_KEY, plus the matching SDK:

npm install @anthropic-ai/sdk    # or: npm install openai

Restitch does not install either for you — together they are about 19 MB, and only this one command needs them.

Your prompts are never sent. Only a structural summary goes to the analysis model: turns, stop reasons, latencies, token counts, and tool names with truncated inputs and results. Check for yourself before spending anything:

restitch session analyze <id> --summary   # prints exactly what would be sent, calls nothing

The call goes direct to the provider, not through the proxy, so analysis never shows up in its own trace.

Privacy

  • Credentials are forwarded and never stored. authorization and x-api-key are redacted at the boundary, before anything reaches storage.
  • Nothing leaves your machine except your own API traffic, which was going to the provider anyway, and root cause analysis if you explicitly run it.
  • The proxy binds 127.0.0.1. A process holding in-flight API credentials should not be reachable from the network. --host overrides it and prints a warning.
  • Host and Origin are validated on every path, including the WebSocket upgrade. Binding loopback alone does not stop a web page you visit from reaching a local service — an attacker can re-resolve their own domain to 127.0.0.1, at which point the browser treats it as same-origin and CORS protects nothing. Requests arriving for any host other than localhost are refused, so that does not work here.
  • restitch config set storePayloads false keeps metadata — model, tokens, latency, tool names, stop reasons — and drops message bodies.

Known limitations

Real, and documented rather than hidden. This category has enough overclaiming in it already.

| Scenario | What happens | What to do | |---|---|---| | Your client compacts or truncates history | A new session starts mid-run | Use the x-restitch-session header | | Two identical conversations run in parallel | They may chain into one session | Use the header | | More than 6 messages appended per turn | The chain breaks | restitch config set maxTrim 10 | | Tools routed through a vendor backend (Copilot subscription, Cursor Pro, ChatGPT web) | Not capturable at all | Nothing. These never talk to the API directly. | | OpenAI streaming without stream_options | Token counts unknown | Nothing — Restitch will not inject the parameter, and reports unknown rather than zero | | A model with no price | Cost reports as unknown | Add it to pricingOverrides |

The vendor-backend row is the important one. Restitch is a reverse proxy, not a MITM forward proxy — no certificate to install, no pinning to break — and the cost of that choice is that tools routing through a vendor's own backend cannot be seen at all.

What it will not do

  • Modify your request. Not even to add stream_options for OpenAI token counts, which would be genuinely useful. Tokens are reported as unknown instead.
  • Delay or corrupt your response. Bytes are forwarded first and parsed second, on a detached path. The test suite sabotages the parser deliberately to prove a broken one cannot reach your stream.
  • Report a number it isn't sure about. Unknown cost is null, unknown tokens say unknown, a truncated stream says TRUNCATED, and a tool that never returned says so.

Configuration

~/.restitch/config.json. Precedence is flag, then environment variable, then file, then default.

| Key | Default | |---|---| | port | 7357 | | host | 127.0.0.1 | | dbPath | ~/.restitch/restitch.db | | storePayloads | true | | storeSystemPrompts | true | | retentionDays | 30 | | sessionIdleMinutes | 15 | | maxTrim | 6 | | analysisProvider | auto | | analysisModel | provider default |

Development

npm install
npm run build       # server + dashboard
npm test
npm run typecheck   # strict, with noUncheckedIndexedAccess

Tests run offline with no API key. Fixtures under tests/fixtures/ include both real captures from api.anthropic.com (credentials scrubbed) and hand-authored ones that are deliberately adversarial about chunk boundaries.

Prior art

The category is occupied and this README will not pretend otherwise.

| Project | Capture | Session grouping | Tool calls on proxy path | Cost | |---|---|---|---|---| | agenttap | Proxy + OTLP | Needs x-session-id | No | No | | llm-visuals | Proxy | None | Partial | Yes | | agentlens | SDK / OTel / MCP | Free, from instrumentation | Yes | Yes | | Langfuse, LangSmith, Helicone, Braintrust | SDK / OTel / proxy | Free, from instrumentation | Yes | Yes |

If you can add an SDK to your code, several of those are more mature and you should probably use one. Restitch is for the case where you cannot: a closed-source agent, a tool you didn't write, a binary you can only point at a different base URL.

License

MIT