{"id":51013782,"url":"https://github.com/unsafe9/claude-pool","last_synced_at":"2026-06-21T07:03:55.243Z","repository":{"id":363804589,"uuid":"1224596564","full_name":"unsafe9/claude-pool","owner":"unsafe9","description":"Claude Code plugin for subscription account pooling with automatic API-key fallback on rate limits","archived":false,"fork":false,"pushed_at":"2026-06-10T13:01:03.000Z","size":63,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-10T13:09:45.997Z","etag":null,"topics":["anthropic","claude","claude-code","go","llm","oauth","proxy"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/unsafe9.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-29T12:44:22.000Z","updated_at":"2026-06-10T13:02:10.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/unsafe9/claude-pool","commit_stats":null,"previous_names":["unsafe9/claude-pool"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/unsafe9/claude-pool","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/unsafe9%2Fclaude-pool","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/unsafe9%2Fclaude-pool/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/unsafe9%2Fclaude-pool/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/unsafe9%2Fclaude-pool/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/unsafe9","download_url":"https://codeload.github.com/unsafe9/claude-pool/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/unsafe9%2Fclaude-pool/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34597337,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-21T02:00:05.568Z","response_time":54,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["anthropic","claude","claude-code","go","llm","oauth","proxy"],"created_at":"2026-06-21T07:03:54.507Z","updated_at":"2026-06-21T07:03:55.238Z","avatar_url":"https://github.com/unsafe9.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# claude-pool\n\nCredential pooler for [Claude Code](https://github.com/anthropics/claude-code). Pools multiple Claude subscription accounts — plus Anthropic API keys as a last resort — and automatically keeps Claude Code on whichever credential has the most rate-limit headroom. Works on macOS, Linux, WSL, and Windows (Git Bash, or plain PowerShell with a one-time manual binary install — see Caveats).\n\nNo proxy, no man-in-the-middle: Claude Code talks to `api.anthropic.com` directly. claude-pool only manages which credential it holds.\n\n## Quick start\n\nclaude-pool ships as a Claude Code plugin — installing it is all the setup there is. In Claude Code:\n\n```\n/plugin marketplace add unsafe9/claude-pool\n/plugin install claude-pool@claude-pool\n```\n\nFrom the next session start the plugin takes care of the rest:\n\n- installs the `claude-pool` binary into `~/.local/bin` on first run (in the background, active the session after; on Windows this requires Git for Windows and puts the directory on your user `PATH` — restart the terminal once if hooks still report it missing), and keeps it in step with the plugin's version by self-updating whenever a plugin update outpaces it (locally built `dev` binaries are left alone);\n- imports the account you are currently logged into as the pool's first account;\n- from then on, hooks keep the pool balanced and swap credentials — no manual commands needed.\n\nThree hooks do the work:\n\n- **StopFailure / rate_limit** — reactive: the turn just died on a rate limit; swap immediately so the next attempt uses a fresh credential.\n- **SessionStart** — proactive: start each session on the account with the most headroom.\n- **UserPromptSubmit** — proactive, fire-and-forget: keeps the pool balanced mid-session without delaying the prompt.\n\n`auto` is a silent no-op while the pool is empty, so the install order never matters.\n\nTo install the binary immediately instead of waiting a session (or to use the CLI without the plugin), run the installer one-liner — it targets `~/.local/bin`. On macOS/Linux that is normally already on your `PATH` (Claude Code lives there too); on Windows the installer adds it to your user `PATH` if missing (open a new terminal — and restart Claude Code — to pick it up):\n\n```sh\n# macOS / Linux / WSL\ncurl -fsSL https://raw.githubusercontent.com/unsafe9/claude-pool/main/install.sh | sh\n```\n```powershell\n# Windows (PowerShell)\nirm https://raw.githubusercontent.com/unsafe9/claude-pool/main/install.ps1 | iex\n```\n\n### Pool more accounts\n\nOne account is not much of a pool. `/login` with each additional account, then import it:\n\n```bash\nclaude-pool import                 # auto-named after the account email (or a timestamp)\n# /login with the next account, then:\nclaude-pool import --id work       # or name it yourself\n```\n\nIf `claude-pool` is not on your `PATH`, it is at `~/.local/bin/claude-pool`.\n\nImporting also makes that account the active one. Re-importing the same account (same `--id`, or auto-named by the same email) refreshes the stored credential without creating a duplicate.\n\n### Register fallback API keys (optional)\n\n```bash\nclaude-pool key add                            # auto-named key-YYYYMMDD-HHMMSS, key via stdin\nclaude-pool key add --id console2              # paste at the prompt (input hidden)\n# or non-interactively:  pbpaste | claude-pool key add --id console2\n```\n\n## How it works\n\n- **Account mode** (the default, preferred state): the chosen account's OAuth credential is written into Claude Code's own credential store — the macOS Keychain item `Claude Code-credentials`, or `~/.claude/.credentials.json` on Linux/WSL/Windows (the same plaintext file Claude Code itself uses there). Expiring tokens are refreshed before use.\n- **Selection**: each account is scored by its *binding utilization* — `max(5-hour %, 7-day %)` from the subscription usage API (`/api/oauth/usage`). `auto` polls all accounts concurrently and activates the one with the lowest score.\n- **API-key fallback**: accounts always win. Only when *every* successfully polled account sits at 100% does `auto` flip to API keys, by setting `apiKeyHelper` in `~/.claude/settings.json` — `apiKeyHelper` outranks the stored OAuth credential in Claude Code's documented [authentication precedence](https://code.claude.com/docs/en/authentication.md#authentication-precedence), and settings changes hot-reload into running sessions. The helper round-robins across registered keys on each invocation.\n- **Recovery**: API-key time is billed time, so leaving it is aggressive. Three triggers race to get you back on subscription auth the moment any account resets below 100%:\n  1. every `auto` run (hooks) re-polls all accounts while in API-key mode;\n  2. the helper itself probes the accounts each time Claude Code asks it for a key — i.e. exactly when money is about to be spent — and switches back on the spot (the key it prints bridges only the in-flight request);\n  3. on entering API-key mode, a detached one-shot is scheduled for the earliest known window reset (from the usage API's `resets_at`) and re-runs `auto` right after it.\n\n```\naccount mode ──(every account at 100%)──▶ API-key mode\naccount mode ◀──(any account resets)───── API-key mode\n```\n\n- **Errors are not exhaustion**: an account whose usage poll fails is skipped, not treated as exhausted — and if every poll fails, `auto` stays on the current credential instead of dumping you onto API keys over a network blip.\n- **Self-healing**: every run reconciles the store, settings, and credential store. Hand-deleting the `apiKeyHelper` is respected. A credential that Claude Code itself refreshed is harvested back into the pool (attributed to the right account by email via the profile API). A foreign `apiKeyHelper` you already had is preserved and restored when claude-pool leaves API-key mode.\n\nState lives in `~/.config/claude-pool/pool.json` (mode 0600), lock-protected (flock; `LockFileEx` on Windows) against concurrent hook/helper runs. The file is encrypted at rest with machine-bound AES-256-GCM — see [Security](#security).\n\n## Security\n\n`pool.json` holds your pooled OAuth credentials and API keys, so it is encrypted at rest with **machine-bound AES-256-GCM** (stdlib crypto only; the key is derived via HKDF-SHA256 from the machine id and username). A pre-existing plaintext file is read transparently and re-written encrypted on the next save.\n\nThis is a deliberately narrow defense, and worth being honest about:\n\n- **What it protects against:** automated credential scanners / info-stealers grepping known paths for `sk-ant-`, JWTs, or JSON key names, and accidental plaintext leaks (a stray git commit, screenshot, log, or backup). It also means one machine's `pool.json` is useless if copied to another machine.\n- **What it does *not* protect against:** a targeted local attacker. The key derivation is open source and the tool must decrypt unattended (no passphrase, OS keychain, or biometric prompt), so anyone who can run code as you on your machine can recover the keys. Treat this as obfuscation against bulk/accidental exposure, not as strong encryption.\n\n## CLI\n\nThe hooks drive everything through `claude-pool auto`; the same binary doubles as a CLI for inspecting and steering the pool by hand.\n\n```bash\nclaude-pool list           # accounts with live 5h/7d usage, then keys\nclaude-pool switch work    # switch to a specific account\nclaude-pool rm console1    # remove an account or API key\nclaude-pool status         # active auth profile as JSON (no network)\nclaude-pool helper         # apiKeyHelper hook for cc (managed by auto, not for manual use)\nclaude-pool version        # build version\n```\n\n`status` is network-free, so a custom statusline script can call it on every render. It prints `{\"mode\",\"name\"}` — `mode` is `account` or `apikey`, `name` is the active account or key id — and in API-key mode adds `\"resets_at\"` and `\"reset_in_seconds\"`: how long until an account is expected to free up and subscription auth resumes (read from the usage cache, omitted when unknown). For example, in a Claude Code [statusLine](https://code.claude.com/docs/en/statusline.md) script — a gray `[work]` on subscription, a red `[key:console2 40m]` billing warning while on an API key:\n\n```sh\njson=$(claude-pool status 2\u003e/dev/null)\nmode=$(printf '%s' \"$json\" | jq -r '.mode // empty')\nname=$(printf '%s' \"$json\" | jq -r '.name // empty')\nif [ \"$mode\" = \"apikey\" ]; then\n  secs=$(printf '%s' \"$json\" | jq -r '.reset_in_seconds // empty')\n  printf '\\033[91m[key:%s%s]\\033[0m' \"$name\" \"${secs:+ $(( (secs + 59) / 60 ))m}\"\nelif [ -n \"$name\" ]; then\n  printf '\\033[90m[%s]\\033[0m' \"$name\"\nfi\n```\n\nManual swapping, for use outside the hooks:\n\n```bash\nclaude-pool auto                               # pick the least-used account / fall back / recover\nclaude-pool auto --if-needed --threshold 0.9   # cheap path: poll only the current account,\n                                               # act only if it is past 90% (default 0.8)\nclaude-pool auto --launch -- --continue        # switch, then exec `claude --continue`\n```\n\n`--launch` always execs `claude` afterwards, even if the pool step failed — a pool error never blocks Claude Code from starting on whatever credential it already holds.\n\n### Building from source\n\nThe install scripts above fetch a prebuilt binary; build from source if you prefer:\n\n```bash\ngit clone https://github.com/unsafe9/claude-pool.git\ncd claude-pool\nmake install   # builds into ~/.local/bin/claude-pool\n```\n\nSource builds report version `dev` and are never replaced by the plugin's self-update.\n\n## Caveats\n\n- One active credential per machine: all concurrent Claude Code sessions share the credential store. Mid-session pickup of a swap is not guaranteed; restart Claude Code to apply it instantly.\n- On Windows, the first-run bootstrap runs through Git Bash (Claude Code resolves it from your Git for Windows install). Without Git for Windows there is no auto-install and the bootstrap hook reports a one-line error each session start — install the binary once with the PowerShell one-liner above; everything else works.\n- On Linux/WSL/Windows, credentials are a plaintext `~/.claude/.credentials.json` — that is Claude Code's own storage on those platforms; claude-pool reads and writes the same file in the same format (no change to your security posture either way).\n- On macOS, the first Keychain access may pop a permission prompt — choose **Always Allow** to avoid future prompts.\n- Toggling API-key mode rewrites `~/.claude/settings.json`. Symlinks are resolved and preserved, but JSON key order is not.\n- Running multiple consumer subscription accounts may sit against Anthropic's consumer terms of service. Use at your own risk.\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Funsafe9%2Fclaude-pool","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Funsafe9%2Fclaude-pool","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Funsafe9%2Fclaude-pool/lists"}