pi-cc-shim

🛂 Use Claude models in pi through relays that only accept Claude Code traffic (e.g. anyrouter). In-process request shim, no proxy.

Packages

Package details

extension

Install pi-cc-shim from npm and Pi will load the resources declared by the package manifest.

$ pi install npm:pi-cc-shim
Package
pi-cc-shim
Version
0.2.0
Published
Oct 14, 2026
Downloads
210/mo · 32/wk
Author
wylu
License
MIT
Types
extension
Size
66.8 KB
Dependencies
0 dependencies · 1 peer
Pi manifest JSON
{
  "extensions": [
    "./extensions"
  ]
}

Security note

Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.

README

pi-cc-shim

🛂 Use Claude models in pi through relays that only accept Claude Code traffic, such as anyrouter.

[!IMPORTANT] 2026-10-14 — anyrouter added a new check, and this package now adapts to it. Requests must carry the x-claude-code-session-id header (Claude Code sends the same UUID it puts in metadata.user_id.session_id); without it the relay answers 429 / 520. The fix is in the source since 2026-10-14, so if your installed copy is older (npm 0.1.0), update from git, or add the header yourself in ~/.pi/agent/pi-cc-shim.json:

{
  "headers": {
    "User-Agent": "claude-cli/2.1.287 (external, sdk-cli)",
    "x-app": "cli",
    "x-claude-code-session-id": "00000000-0000-0000-0000-000000000000"
  }
}

headers replaces the default object, so keep the two defaults above. A fixed UUID is enough: the relay only checks that the header is present. Background and the exact measurements are in the Troubleshooting section below.

Some relays fingerprint the Anthropic Messages payload and answer 503 / 520 to anything that does not look like Claude Code, regardless of load. pi-cc-shim reshapes each request in-process via pi's before_provider_headers / before_provider_request hooks. No proxy, no extra process, and it only fires for the providers you point it at.

Third-party community package, not affiliated with Anthropic or anyrouter. It only changes the shape of requests and does not bypass authentication or billing. Use it with relay accounts you are entitled to.

✨ What it does

  • 🪪 Claude Code identity — prepends the Claude Code opener to system[] and sets metadata.user_id in Claude Code's format (device_id stable per machine, session_id per session)
  • 🧰 Placeholder tools — adds any missing Agent Bash Edit Read Write Glob Grep entries to tools[] as inert stubs whose descriptions point at pi's real tools
  • 🏷️ Model & betas — strips the [1m] suffix from model and declares 1M context through the context-1m-2025-08-07 beta instead
  • 📡 Headers — sends User-Agent: claude-cli/…, x-app: cli and x-claude-code-session-id (the session UUID Claude Code also puts in metadata.user_id.session_id); auth headers are never touched
  • 🎯 Scoped — only anthropic-messages providers that match your config are rewritten; an openai-responses provider on the same host is left alone
  • 🧠 Self-healing tool calls — if the model calls a stub tool, the "not found" error is rewritten into "use read instead" so it recovers on the next step
  • 🧊 Cache-friendly — never adds cache_control; pi's own prompt-cache breakpoints stay intact

📦 Install

Requires pi ≥ 0.85.0 and Node ≥ 22.19.

pi install npm:pi-cc-shim

# or from GitHub
pi install git:github.com/wylu1037/pi-cc-shim

# or try it for a single run without installing
pi -e npm:pi-cc-shim

If other extensions also rewrite payloads, list pi-cc-shim last in packages in settings.json: before_provider_request hooks run in load order and the last one wins.

⚙️ Configure the provider

Add an anthropic-messages provider to ~/.pi/agent/models.json. baseUrl must not end with /v1:

{
  "providers": {
    "anyrouter": {
      "baseUrl": "https://anyrouter.top",
      "api": "anthropic-messages",
      "apiKey": "sk-...",
      "models": [
        {
          "id": "claude-fable-5-1",
          "name": "claude-fable-5-1 (anyrouter)",
          "reasoning": true,
          "input": ["text", "image"],
          "contextWindow": 1000000,
          "maxTokens": 32000,
          "cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
        }
      ]
    }
  }
}

Any baseUrl containing anyrouter.top is matched out of the box; the provider key can be anything. Pick the model with /model. The footer shows cc-shim 🟢 while the shim is active and cc-shim ⚪ after /cc-shim off.

🔧 Options

Optional ~/.pi/agent/pi-cc-shim.json. Each relay check maps to one field, so you can follow rule changes without waiting for a release. Defaults:

{
  "enabled": true,
  "providers": [],
  "baseUrlPatterns": ["anyrouter.top"],
  "systemPrompt": "You are Claude Code, Anthropic's official CLI for Claude.",
  "sessionIdHeader": "x-claude-code-session-id",
  "toolNames": ["Agent", "Bash", "Edit", "Read", "Write", "Glob", "Grep"],
  "headers": {
    "User-Agent": "claude-cli/2.1.274 (external, cli)",
    "x-app": "cli"
  },
  "betas": ["context-1m-2025-08-07"],
  "stripModelSuffix": true,
  "decoyToolHints": true
}
Field Description
enabled Master switch
providers Exact provider keys frommodels.json to target; use it to narrow the scope
baseUrlPatterns Fallback match:baseUrl contains any of these substrings
systemPrompt Sentence inserted atsystem[0]; empty string disables it
sessionIdHeader Header set to the session UUID on every request; empty string disables it
toolNames Tool names that must be present intools[]; missing ones are stubbed
headers Request headers to set; replaces the default object. Putanthropic-beta in betas, not here
betas Appended topayload.betas
stripModelSuffix Remove a trailing[1m] from model
decoyToolHints Rewrite the error when the model calls a stub tool

Fields of the wrong type fall back to their defaults and are reported at startup and in /cc-shim status.

🕹️ Commands

Command What it does
/cc-shim or /cc-shim status Whether the current model matches and why, last response status, what was injected last
/cc-shim on / /cc-shim off Toggle for this session only; the config file is not written
/cc-shim dump Write the next request's final payload and headers (auth redacted) to~/.pi/agent/logs/cc-shim-last.json

A warning pops up whenever the relay answers 503 / 520.

🩺 Troubleshooting

  1. /cc-shim status: confirm the model matches and the API is anthropic-messages.
  2. Still rejected? /cc-shim dump, resend, then check system[0], tools, metadata.user_id, betas and the headers in cc-shim-last.json.
  3. Bisect the relay's rules with RELAY_API_KEY=sk-... scripts/probe-relay.sh. It sends a baseline request and then drops one rule at a time; fix the matching option.
  4. If the extra "You are Claude Code" sentence makes the model drift, append something like Ignore the previous sentence; you are running inside pi. to systemPrompt.

The status code tells you which check failed (observed on anyrouter, 2026-09-18; relays change their rules without notice):

Relay answers What it checks Option
503 Claude Code opener insystem[], or the shape of metadata.user_id systemPrompt (user_id is automatic)
520 At least 4 Claude Code tool names intools[] toolNames
429 model still carries a [1M] suffix stripModelSuffix
429 / 520 x-claude-code-session-id header missing (relay added this check around 2026-10-14) sessionIdHeader
400 anthropic-beta header lacks context-1m-2025-08-07 betas

🛠️ Development

pnpm install
pnpm check   # tsc --noEmit + node --test
pnpm e2e     # fake relay + real pi process, fully offline

scripts/fake-relay.mjs mirrors the relay's checks. scripts/e2e.sh verifies rejection without the shim, success with it, stub-tool hint rewriting, and the RPC-mode commands and dump.

License

MIT