--- title: Claude Proxy description: Multi-account Claude proxy with automatic token management, rate-limit failover, and multi-provider fallback for Claude Code keywords: claude, proxy, multi-account, oauth, rate-limit, failover, fallback, claude-code, anthropic, pool --- # Claude Proxy NeuroLink includes a Claude-API-compatible proxy server that sits between Claude Code and Anthropic. It pools multiple Claude accounts, handles rate-limit failover automatically, refreshes OAuth tokens on demand before they expire, and falls back to other providers when all Claude accounts are exhausted. ## Overview ### Why use the proxy? Claude Code supports only one Anthropic account at a time. If you hit a rate limit, you wait. If your token expires mid-session, you re-authenticate manually. The NeuroLink proxy solves these problems: - **Multi-account pooling** -- Combine multiple Claude Pro/Max subscriptions for higher aggregate throughput. - **Automatic token refresh** -- OAuth tokens are refreshed before they expire (pre-request check + 401 retry). - **Rate-limit failover** -- When one account hits a 429, the proxy immediately tries the next account with exponential backoff. - **Multi-provider fallback** -- When all Claude accounts are exhausted, requests are routed to alternative providers (Gemini, OpenAI, etc.) through NeuroLink's provider layer. - **Transparent to Claude Code** -- Set `ANTHROPIC_BASE_URL` and Claude Code works normally. The proxy auto-configures this on start. ### How it works at a glance ``` Claude Code | | POST /v1/messages v NeuroLink Proxy (localhost:55669) | |-- Passthrough mode (Claude -> Claude): raw body forwarding |-- Translation mode (Claude -> Other): through neurolink.generate()/stream() v Anthropic API / Google AI / OpenAI / ... ``` ## Quick Start If you do not already have the CLI installed, install it first: ```bash pnpm add -g @juspay/neurolink # or npm install -g @juspay/neurolink ``` Then continue with the proxy setup steps below. ### One-command setup ```bash neurolink proxy setup ``` This command: 1. Checks for existing authenticated accounts 2. Runs OAuth login if no valid accounts exist 3. Installs the proxy as a **launchd service** (macOS) that auto-restarts on crash or reboot 4. Auto-configures Claude Code to use the proxy Use `--no-service` to skip service installation and start the proxy in the foreground instead: ```bash neurolink proxy setup --no-service ``` ### Manual setup ```bash # Step 1: Authenticate with Anthropic via OAuth neurolink auth login anthropic --method oauth # Step 2: (Optional) Add more accounts for pooling neurolink auth login anthropic --method oauth --add --label work neurolink auth login anthropic --method oauth --add --label personal # Step 3: (Optional) Start the local OpenObserve stack and import the dashboard # (auto-writes OTEL_EXPORTER_OTLP_ENDPOINT to ~/.neurolink/.env) neurolink proxy telemetry setup # Step 4: Start the proxy neurolink proxy start # Step 5: Restart Claude Code to pick up the new ANTHROPIC_BASE_URL ``` ### Restart the serving worker ```bash neurolink proxy restart --check neurolink proxy restart ``` `restart` starts a replacement worker while the existing worker continues serving. The supervisor switches new connections only after the replacement acknowledges readiness and activation, then lets requests on the previous worker finish. You do not need to run the check separately: `restart` includes it. The command verifies admission, worker identity/version, socket-transfer counters and preservation of request-log disk/OTel settings. It does not generate a model request. A failed candidate has a 120-second readiness limit; the serving worker is retained. Concurrent restarts, pending updates and additional restarts while an older worker is still draining are refused. A disconnected terminal does not cancel the supervisor-owned operation or close admission. Use `--format json` for scripts. Exit zero means the check or activation was verified. `activated_unverified` means the replacement activated but a subsequent check failed; inspect `neurolink proxy status` before another operation. A lost control connection leaves the outcome unknown, rather than triggering a forced service restart. The JSON contract is `CliProxyRestartOutput`: an authenticated supervisor result or `{ "ok": false, "phase": "unverified", "message": "..." }` when the CLI cannot receive or authenticate that result. The latter exits nonzero and deliberately omits supervisor/worker fields that could not be verified. It does not mean the replacement failed or was rolled back. Control-server errors after binding are reported through the supervisor logger without stopping the serving listener. This requires a running supervisor that advertises restart-control support. Older supervisors must first receive a separately planned service activation; installing a newer CLI alone does not add the capability to an existing process. The command refuses an unsupported supervisor without signalling it. The listener and supervisor remain running, so this command does not apply changed launchd stdout/stderr destinations or replace supervisor/updater code. Those need a service activation with its own interruption budget. `proxy install` is service setup, not a routine restart command. The restart command does not rewrite the launcher, environment, routing configuration or update history. Local OTel initialization is checked; collector/backend delivery still needs telemetry verification. ## How It Works ### Request Flow Every request from Claude Code flows through the proxy in one of two modes: **Passthrough mode** (Claude to Claude): The request body is forwarded directly to `api.anthropic.com` with only the authentication headers modified. This preserves multi-turn conversation history, thinking content, cache control, and tool definitions exactly as Claude Code sent them. No lossy conversion through an intermediate format. **Translation mode** (Claude to other provider): When model routing directs a request to a non-Anthropic provider, the proxy parses the Claude Messages API request into NeuroLink's internal format, calls `neurolink.generate()` or `neurolink.stream()`, and serializes the result back into Claude Messages API format (including SSE streaming events). For streaming, the proxy emits SSE keep-alive comments (`: keep-alive`) every 15 seconds during idle periods to prevent connection timeouts. ### Trace And Session Context If the caller sends W3C trace headers (`traceparent`, `tracestate`) or NeuroLink session headers (`x-neurolink-session-id`, `x-neurolink-user-id`, `x-neurolink-conversation-id`), the proxy links its spans to the caller trace and preserves that session/user/conversation context in proxy traces and logs. ### Token Management The proxy uses three coordinated token refresh paths: 1. **Background check** -- Every 30 seconds, one non-overlapping maintenance cycle checks allowed, enabled accounts. 2. **Pre-request check** -- A request refreshes an OAuth token when it is within 5 minutes of expiry. 3. **401 retry** -- An unexpected Anthropic 401 triggers refresh and bounded retry before account rotation. Refresh calls sharing the same rotating refresh token are serialized and reuse the winning result. Credential rejection responses (`400`, `401`, `403`, or `404`) disable the account until explicit login; network errors, refresh-endpoint `429`s, and `5xx` responses apply a bounded 30-second to 5-minute auth cooldown instead. Automatic token saves preserve an operator-disabled account's metadata. Refreshed TokenStore and legacy credentials are persisted with `0o600` permissions using serialized atomic snapshot writes. ### Multi-Account Routing When multiple accounts are available, the proxy uses **fill-first** routing: 1. Use the first non-cooling account for every request. 2. On a 429, classify the authoritative quota window, persist its cooldown, and try the next account. 3. Continue until a request succeeds or all accounts are exhausted. 4. If all accounts are exhausted, walk the fallback chain (alternative providers). 5. If all fallbacks fail, return a 429 with a `Retry-After` header indicating the earliest account recovery time. If every account has a known future cooldown, the proxy does not call any of them again. Cooldowns survive restarts in `~/.neurolink/account-cooldowns.json`. Account sources are checked in priority order: 1. **TokenStore** compound keys (e.g., `anthropic:work`, `anthropic:personal`) -- from `neurolink auth login --label` 2. **Legacy credentials file** (`~/.neurolink/anthropic-credentials.json`) -- only if no TokenStore accounts exist 3. **Environment variable** (`ANTHROPIC_API_KEY`) -- only if no other accounts exist #### Designating a primary (home) account By default the "first" account is the first key in token-store insertion order. To override this without re-OAuthing or editing the encrypted token store, set `routing.primary-account` in the proxy config. The proxy resolves the email to a stable token-store key per request, so the choice survives account additions/removals and only takes effect when that account is currently authenticated: ```bash neurolink auth set-primary alice@example.com neurolink proxy status # Config: generation N curl http://127.0.0.1:55669/status # stats.primaryAccount.label = alice@example.com ``` After a 429 cools off, traffic returns to the configured primary (not literal index 0). When the configured account is missing or disabled, the proxy logs a warning while loading the configuration and falls back to insertion-order index 0. See the [config reference](./claude-proxy-config-reference.md#neurolink-auth-set-primary) for the full CLI surface (`set-primary` / `get-primary` / `clear-primary`). #### Restricting eligible accounts `primary-account` controls ordering; it is not a security or isolation boundary. To ensure the proxy can use only an explicit set of Anthropic credentials, configure `routing.account-allowlist`: ```yaml routing: primary-account: primary@example.com account-allowlist: - primary@example.com ``` Entries accept an email/label or a full `anthropic:` key and are matched case-insensitively. When the field is present, unlisted TokenStore accounts are excluded before token loading or refresh. The legacy credential and `ANTHROPIC_API_KEY` fallback are also denied unless explicitly listed as `legacy-default` or `env`, and neither hidden fallback is considered while any Anthropic TokenStore entry exists. An empty list denies all Anthropic credentials; an absent field preserves unrestricted account discovery. ### Fallback Chain When all Claude accounts are rate-limited, the proxy walks the fallback chain defined in the config file. Each fallback entry specifies a provider and model: ```yaml routing: fallback-chain: - provider: google-ai model: gemini-3-flash-preview - provider: openai model: gpt-4o ``` Fallback requests go through NeuroLink's `stream()` pipeline (translation mode), which handles the format conversion to and from the target provider's API. Tools, thinking configuration, and conversation history from the original request are passed through to the fallback provider. ## Configuration ### Proxy config file The proxy loads configuration from `~/.neurolink/proxy-config.yaml` by default (override with `--config`). The file supports YAML or JSON format with environment variable interpolation. The running proxy watches this file and its resolved proxy env file. Valid routing edits are published atomically for new requests; in-flight requests keep their original generation. Invalid or deleted observed files are rejected and the last-known-good generation remains active. ```yaml # ~/.neurolink/proxy-config.yaml version: 1 # Account definitions (alternative to neurolink auth login) accounts: anthropic: - name: primary apiKey: ${ANTHROPIC_API_KEY_PRIMARY} - name: secondary apiKey: ${ANTHROPIC_API_KEY_SECONDARY} weight: 2 rateLimit: 100 # Routing configuration routing: strategy: fill-first # or round-robin quota-routing: true session-soft-limit: 0.97 session-reset-tolerance-ms: 900000 primary-account: primary@example.com account-allowlist: - primary@example.com # Model mappings: remap incoming model names to different providers model-mappings: - from: claude-sonnet-4-20250514 to: gemini-3-pro-preview provider: google-ai # Fallback chain: try these when all Claude accounts are exhausted fallback-chain: - provider: google-ai model: gemini-3-flash-preview - provider: openai model: gpt-4o # Models that always go to Anthropic (skip routing logic) passthrough-models: - claude-opus-4-20250514 - claude-sonnet-4-5-20250929 # Cloaking configuration (request transformation for OAuth) cloaking: mode: auto # "auto" | "always" | "never" plugins: {} ``` When routing is enabled, any requested model that starts with `gemini-` is treated as a Vertex target by default unless an explicit `model-mappings` rule overrides it. ### Environment variable interpolation String values in the config file support `${VAR_NAME}` and `${VAR_NAME:-default}` syntax: ```yaml accounts: anthropic: - name: primary apiKey: ${ANTHROPIC_KEY_1} - name: fallback apiKey: ${ANTHROPIC_KEY_2:-sk-ant-fallback-key} ``` ### Account configuration options | Field | Type | Default | Description | | ----------- | ------- | ------- | ------------------------------------------ | | `name` | string | unnamed | Human-readable label for the account | | `apiKey` | string | -- | API key or token (supports `${ENV_VAR}`) | | `baseUrl` | string | -- | Override the provider endpoint URL | | `orgId` | string | -- | Organization ID (e.g., for OpenAI orgs) | | `weight` | number | 1 | Weight for weighted round-robin selection | | `enabled` | boolean | true | Whether this account is active | | `rateLimit` | number | -- | Max requests per minute for this account | | `metadata` | object | -- | Arbitrary metadata attached to the account | ### Server options | Option | Default | Description | | -------- | -------------------------------- | ------------------- | | `port` | 55669 | Port to listen on | | `host` | 127.0.0.1 | Host to bind to | | `config` | `~/.neurolink/proxy-config.yaml` | Path to config file | ## CLI Commands ### `neurolink proxy setup` One-command onboarding: checks for existing accounts, runs OAuth login if needed, installs the proxy as a persistent service, and configures Claude Code. ```bash neurolink proxy setup # Full setup: login + install as launchd service (macOS) neurolink proxy setup --no-service # Login + start foreground (no auto-restart) neurolink proxy setup -p 9000 # Setup on custom port ``` ### `neurolink proxy install` Install the proxy as a persistent macOS launchd service. The service auto-restarts on crash (5-second throttle interval) and starts on login. ```bash neurolink proxy install # Install with defaults (port 55669) neurolink proxy install --port 9000 # Install on custom port neurolink proxy install --host 0.0.0.0 # Bind to all interfaces ``` **Options:** | Flag | Alias | Default | Description | | -------- | ----- | --------- | ----------------- | | `--port` | `-p` | 55669 | Port to listen on | | `--host` | `-H` | 127.0.0.1 | Host to bind to | ### `neurolink proxy uninstall` Remove the launchd service. Stops the proxy if it is running and deletes the launchd plist. ```bash neurolink proxy uninstall ``` ### `neurolink proxy start` Start the proxy server. ```bash neurolink proxy start # Default: port 55669, fill-first neurolink proxy start -p 8080 -s fill-first # Custom port and strategy neurolink proxy start --config ./my-proxy.yaml # Custom config file neurolink proxy start --debug # Enable debug logging neurolink proxy start --quiet # Suppress non-essential output neurolink proxy start --passthrough # Transparent forwarding (no retry/rotation) neurolink proxy start --env-file ./proxy.env # Load provider keys from dedicated file ``` **Options:** | Flag | Alias | Default | Description | | ------------------- | ----- | -------------------------------- | ---------------------------------------------------------- | | `--port` | `-p` | 55669 | Port to listen on | | `--host` | `-H` | 127.0.0.1 | Host to bind to | | `--strategy` | `-s` | fill-first | Account selection strategy (`fill-first` or `round-robin`) | | `--health-interval` | | 30 | Health check interval (seconds) | | `--config` | `-c` | `~/.neurolink/proxy-config.yaml` | Config file path | | `--quiet` | `-q` | false | Suppress output | | `--debug` | `-d` | false | Enable debug output | | `--passthrough` | | false | Transparent forwarding (no retry, rotation, or polyfill) | | `--env-file` | | | Path to .env file for provider API keys | **Strategy choices:** `round-robin`, `fill-first` ### `neurolink proxy status` Show proxy status, including PID, uptime, strategy, fallback chain, and per-account usage statistics fetched from the live `/status` endpoint. Status output now distinguishes total upstream attempts from completed requests, so retry-heavy incidents are easier to spot. ```bash neurolink proxy status # Human-readable text output neurolink proxy status --format json # Machine-readable JSON ``` ### `neurolink proxy telemetry ` Manage the local OpenObserve stack and the maintained proxy dashboard from the CLI. ```bash neurolink proxy telemetry setup # Start OpenObserve + OTEL collector and import dashboard neurolink proxy telemetry start # Start the local telemetry stack only neurolink proxy telemetry stop # Stop the local telemetry stack neurolink proxy telemetry status # Show local stack health neurolink proxy telemetry logs # Follow OpenObserve + collector logs neurolink proxy telemetry import-dashboard # Re-import the dashboard without restarting containers ``` These commands use the repo-owned assets under `scripts/observability/` and the dashboard JSON at `docs/assets/dashboards/neurolink-proxy-observability-dashboard.json`. ### `neurolink proxy analyze` Read the proxy's own request and attempt logs and report what actually happened: per-account success and failure counts, retry-recovered requests, terminal error categories, and routing decisions. ```bash neurolink proxy analyze # summarise the retained window neurolink proxy analyze --logs-dir # a specific log directory ``` Reported counts are bounded by log retention. When the request and attempt windows are not comparable, the command says so rather than printing a recovered-after-retry figure it cannot stand behind. ### `neurolink proxy replay ` Reconstruct a captured request for debugging, or send it directly upstream to compare proxied and direct behaviour. ```bash neurolink proxy replay export --request-id --output bundle.json neurolink proxy replay compare --bundle bundle.json --execute ``` `compare` reaches a provider, so it requires the explicit `--execute` flag. Captured bodies are redacted; supply `--body-file` when a full body is needed, and `--header-env` to inject a credential from an environment variable rather than a literal. ### `neurolink proxy share ` Lend spare pool capacity to a peer, with the terms enforced on every request. See [Proxy Peer Sharing](/docs/features/proxy-peer-sharing) for the full guide. ```bash neurolink proxy share url https://proxy.example.com # record this node's address neurolink proxy share url # show it neurolink proxy share url get # bare value, for scripts neurolink proxy share url --clear # forget it neurolink proxy share create --peer --preset spare neurolink proxy share list | status [--peer ] neurolink proxy share pause --peer # stops at their next request neurolink proxy share resume --peer neurolink proxy share set --peer --reserve 40 --max-slice 5h=15 neurolink proxy share topup --peer --coins 200 neurolink proxy share rotate --peer # new token, same controls neurolink proxy share revoke --peer neurolink proxy share delete --peer neurolink proxy share level --peer --to complete neurolink proxy share provision --peer --from-account neurolink proxy share provision --peer --code # finish it neurolink proxy share receipts --peer # what you charged them neurolink proxy share note --coins 200 --ttl 30d # mint a transferable note neurolink proxy share notes # notes minted, and spent ``` `share provision` is a **split-PKCE** flow: the borrower runs `neurolink proxy peer request` first and keeps the verifier, you authorize in your browser and relay a single-use code. You never hold a token for the credential you mint. See [Proxy peer sharing](/docs/features/proxy-peer-sharing). Controls, all applied together: | Flag | Meaning | | ---------------------------------------------- | ------------------------------------------------------------- | | `--reserve 30` | Keep 30% headroom on **each** account for yourself | | `--max-slice 20` | Borrower may take at most 20% of the **pool**, however spread | | `--max-slice-per-account 20` | Apply that ceiling to each account independently instead | | `--spillover 12h<60@25` | Lend only near a reset, when little of the window was used | | `--models sonnet haiku` | Restrict which model tiers the share covers | | `--accounts