@elizaos/plugin-anthropic-proxy
Routes Anthropic API traffic from your eliza agent through a Claude Max / Pro subscription instead of paying per-token Extra Usage rates.
The plugin applies a 7-layer bidirectional transformation pipeline so requests look like they originate from the official Claude Code CLI:
- Billing header injection (
x-anthropic-billing-headertext block carrying the CC version plus a 3-character SHA256 fingerprint computed per request) - String trigger sanitization
- Tool name fingerprint bypass (PascalCase CC convention rename)
- System prompt template bypass (strip + paraphrase)
- Tool description stripping (reduce schema fingerprint)
- Schema property name renaming
- Full bidirectional reverse mapping on SSE + JSON responses
Plus assistant-prefill stripping and thinking-block stripping for replay/session bugs.
The default fingerprint dictionaries target the elizaOS tool surface (@elizaos/native-reasoning). For non-eliza agents, supply your own dictionaries via config.json (see config.json.example).
Custom fingerprint dictionaries
The defaults make this plugin a one-line drop-in for any eliza agent. If you're running a non-eliza agent (LangChain, LlamaIndex, your own runtime, etc.) the eliza tool-name dictionary won't match your tool surface and you'll want to supply your own.
Drop a config.json next to your eliza root with the shape shown in config.json.example. The plugin merges it over the defaults at startup. Any of the four dictionaries (replacements, toolRenames, propRenames, reverseMap) can be overridden independently — the rest fall back to the eliza defaults.
You own the subscription
This plugin does not route your traffic through any service operated by anyone but you. It needs your Claude Code OAuth token (from your own subscription on your own machine). You are responsible for whether your usage complies with Anthropic's terms.
Setup
# 1. Install Claude Code CLI and log in once on this machine.
claude auth login
# 2. Add the plugin to your agent's plugin list (your character file or
# plugin loader). It will:
# - Start an in-process proxy on http://127.0.0.1:18801
# - Set ANTHROPIC_BASE_URL to that proxy URL (unless you've set it
# explicitly to something else)
Modes
Pick via CLAUDE_MAX_PROXY_MODE:
| Mode | What it does |
|---|---|
inline |
(default) Plugin starts an http proxy in this agent's process |
shared |
Plugin connects to an existing upstream proxy URL (one host, many agents) |
off |
Plugin loads but doesn't start anything (passthrough; you set ANTHROPIC_BASE_URL yourself) |
In inline mode each agent gets its own proxy server. In shared mode you run the proxy once on the host (or via this same plugin in a different agent) and point all your agents at the same CLAUDE_MAX_PROXY_UPSTREAM. Useful when you have many agents on one box and only one Claude subscription.
Environment variables
| Variable | Default | Notes |
|---|---|---|
CLAUDE_MAX_PROXY_MODE |
inline |
inline / shared / off |
CLAUDE_MAX_PROXY_PORT |
18801 |
inline mode listen port |
CLAUDE_MAX_PROXY_UPSTREAM |
(none) | shared mode upstream base URL, e.g. http://172.18.0.1:18801 |
CLAUDE_MAX_PROXY_BIND_HOST |
127.0.0.1 |
inline mode bind address |
CLAUDE_MAX_PROXY_AUTH_TOKEN |
(none) | required when CLAUDE_MAX_PROXY_BIND_HOST is not a loopback address; checked via Authorization: Bearer <token> or x-claude-max-proxy-token header |
CLAUDE_MAX_PROXY_VERBOSE |
false |
extra request logging |
CLAUDE_MAX_PROXY_CONFIG_PATH |
(none) | explicit path to a config.json fingerprint override file; takes precedence over a config.json found next to the agent root |
CLAUDE_MAX_CREDENTIALS_PATH |
(auto) | path to .credentials.json; defaults to ~/.claude/.credentials.json |
CLAUDE_CODE_OAUTH_TOKEN |
(none) | direct OAuth bearer token; takes precedence over the file |
ANTHROPIC_BASE_URL |
(auto-set by plugin) | leave unset and the plugin picks. Set to auto to opt back in if you ever set it. Set to anything else and the plugin will leave it alone. |
Diagnostics
- HTTP route:
GET /api/anthropic-proxy/statusreturns the current mode, URL, listening state, request count, token expiry, and (in shared mode) upstream reachability. - Action:
PROXY_STATUSreturns the same info to a chat surface. - Local proxy health:
GET http://127.0.0.1:18801/health(replace port to match config).
Token refresh
If you hit a 401 (token expired) run:
claude auth login
The plugin re-reads the credentials file on every request, so a fresh login is picked up immediately — no need to restart the agent.
Failure modes (intentional)
- Missing credentials. Plugin logs a warning, degrades to
offmode, agent keeps running. It does not crash. - Inline port collision. Plugin logs the bind error, degrades to
offmode. - Shared upstream unreachable at startup. Plugin still boots in
sharedmode; the unreachable upstream is reported via/api/anthropic-proxy/status.
Plugin shape
services: [AnthropicProxyService]— Service that owns the http server lifecycle (start/stop)actions: [proxyStatusAction]—PROXY_STATUSaction for in-chat diagnosticsroutes: anthropicProxyRoutes—GET /api/anthropic-proxy/statusfor external toolsinit()— setsANTHROPIC_BASE_URLif you haven't already
Files
plugins/plugin-anthropic-proxy/
├── index.ts # Plugin export + init
├── index.node.ts # Node entry
├── index.browser.ts # Browser-unavailable entry
├── auto-enable.ts # shouldEnable() opt-in check
├── config.json.example # Custom fingerprint dictionary shape
├── build.ts # Bun build script
├── package.json
├── tsconfig.json / tsconfig.build.json
├── vitest.config.ts
├── bunfig.toml
├── src/
│ ├── proxy/
│ │ ├── constants.ts # Algorithm constants + DEFAULT_* dict re-exports
│ │ ├── eliza-fingerprint.ts # ELIZA_* default fingerprint dictionaries
│ │ ├── billing-fingerprint.ts # Layer 1: SHA256 fingerprint
│ │ ├── sanitize.ts # Layer 2: string sanitize
│ │ ├── tool-rename.ts # Layer 3/6: quoted name renames
│ │ ├── system-prompt.ts # Layer 4: system strip + paraphrase
│ │ ├── cc-tool-injection.ts # Layer 5: description strip + synthetic CC tools
│ │ ├── sse-rewrite.ts # Tail-buffer SSE reverse map
│ │ ├── stainless-headers.ts # CC-emulating SDK headers
│ │ ├── process-body.ts # Forward request pipeline
│ │ ├── reverse-map.ts # Response/SSE reverse pipeline
│ │ └── server.ts # http.createServer lifecycle
│ ├── services/
│ │ └── proxy-service.ts # AnthropicProxyService extends Service
│ ├── actions/
│ │ └── proxy-status.action.ts # PROXY_STATUS action
│ ├── routes/
│ │ └── status-route.ts # /api/anthropic-proxy/status
│ └── utils/
│ └── credentials-loader.ts # ~/.claude/.credentials.json + JWT exp
└── __tests__/
├── proxy.test.ts
├── auto-enable.test.ts
├── eliza-fingerprint.test.ts
├── manifest-engine.integration.test.ts
├── process-body.edge.test.ts
├── proxy-server.routing.test.ts
└── sse-rewrite.test.ts