GETTING STARTED
Overview
pool-anything is an agentic-code-tool-style helper for API keys: it reads your provider list, gathers keys into pools, rotates them, and integrates with your development tools. Available on your machine, behind one local endpoint, with a browser UI.
pool-anything is an AI-powered quota assistant that helps you build features, fix bugs, and automate development tasks. It understands your entire key inventory and can work across multiple providers and tools to get things done.
Get started
pool-anything runs as one server: the web UI, the JSON API, and the proxy. Choose how you run it below to get started. Most setups require a Node.js 22+ subscription or a local checkout. The terminal, Docker, and source builds all support custom providers.
Global install (recommended) — macOS, Linux, WSL, PowerShell, CMD:
npm i -g pool-anything # one-time install (server core: 0 deps; shell: Ink + React)
pool-anything # → assistant shell (list pools, add keys…)
pool-anything serve # → http://localhost:3000, data in ~/.pool-anything/From source — macOS, Linux, WSL:
npm install # dev deps only: tsx, typescript
npm run dev # http://localhost:3000, reloads as you editFrom source — Windows PowerShell:
npm install; npm run dev # → http://localhost:3000From source — Windows CMD:
npm install && npm run devCheck it's alive:
curl localhost:3000/health # → ok
curl localhost:3000/api/db/ping # → {"ok":true,…}Docker (maps the SQLite volume):
docker run -p 3000:3000 -v ./data:/app/data pool-anythingDocker Compose override:
PORT=3000 docker compose upCompiled output:
npm run build && npm run start:distInit the database directly:
npm run db:init -- --seedIf you see The token '&&' is not a valid statement separator, you're in PowerShell, not CMD. If you see 'npm' is not recognized as an internal or external command, you're in CMD, not PowerShell. Your prompt shows PS C:\… when you're in PowerShell and C:\… when you're in CMD.
If the install command fails with syntax errors near unexpected token '<', a 403, or another curl error, see Troubleshoot installation to match the error to a fix and for alternative install methods.
36 providers ship preconfigured so pool-anything can use the registry auth style. If a provider is missing, setups do not need a code change: a pool with your own base_url works instead.
~/.pool-anything/pool-anything.db; source checkouts use data/pool-anything.db — so you stay on the latest cursor either way. Override with LOCAL_DB_PATH (or pool-anything --db).You can also install with apt, dnf, or apk equivalents for Node 22 on Debian, Fedora, RHEL, and Alpine.
Then start pool-anything in any project. Replace your-project with the path to a project directory on your machine:
cd your-project
npm run devYou'll be prompted to add keys on first run. If you've set the LOCAL_DB_PATH environment variable, pool-anything skips the default path and asks you to approve the key instead. That's it! Continue with the Quickstart →
What you can do
Here are some of the ways you can use pool-anything:
/proxy endpoint instead of juggling keys by hand. See the proxy.cursor % keys.length.GET /api/pools/:id/next returns the next masked key and advances the cursor; POST /consume records tokens too.query:param injection are handled per provider. See injection table.base_url, key_header, key_prefix override at runtime.curl -X POST localhost:3000/api/pools/1/proxy -d '{"path":"…"}'./usage rolls up SUM(tokens) with quota and remaining where the registry knows them.data/pool-anything.db and the pools move with you.Use pool-anything everywhere
Each surface connects to the same underlying pool engine, so your repo's pools, keys, and usage files, settings, and MCP servers work across all of them.
Beyond the Terminal and UI surfaces above, pool-anything integrates with scripted, chat, and browser workflows:
| What I want to do | Best option |
|---|---|
| Gather keys in a browser UI | Pools overview |
| Manage pools in plain language | Assistant shell: pool-anything, then list pools, add keys to groq, watch groq |
| Send one request with rotation + auth | Proxy endpoint |
| Peek at the next key without spending it | GET …/next |
| Start a task locally, continue on mobile | REST everywhere |
| Run rotation on a recurring schedule | Consume + cron |
| Automate PR reviews and issue triage | Proxy in CI |
| Get automatic masked views on every key | Key manager |
| Route bug reports from Slack to pull requests | Proxy + webhook |
| Build custom agents for your own workflows | Registry + proxy |
Next steps
Once you've installed pool-anything, these guides help you go deeper.
Quickstart — your first pool
- Open localhost:3000 and search a provider — say, groq.
- Click it. The setup dialog creates a pool for that provider.
- Paste an API key, press Enter. Repeat for every key you own.
- Press Done. The pool now appears on Pools and in the API key manager.
- Send traffic through it:
curl -X POST localhost:3000/api/pools/1/proxy \
-H 'content-type: application/json' \
-d '{"path":"/openai/v1/models","method":"GET"}'key_id and label that served it, so you can see keys take turns. Add "tokens": N to count usage too.Prefer the terminal? The assistant shell does steps 1–4 without a browser: run pool-anything, then create pool Prod for groq and add keys to groq (paste one key per line, blank line finishes).
Run it
You need Node.js 22 or newer (the app uses the built-in node:sqlite module and native fetch). Nothing else — there are no runtime npm dependencies.
npm i -g pool-anything # one-time install
pool-anything # assistant shell (list pools, add keys to groq, serve)
pool-anything serve # http://localhost:3000 (--port, --open, --db, --data-dir)Prefer source? npm install then npm run dev serves the same UI with file watching.
Scripts & environment
| Script | What it does |
|---|---|
npm run dev | Main server on :3000 with file watching. |
npm start | Main server once, no watch. |
npm run build | Type-check and compile to dist/. |
npm run start:dist | Run the compiled output. |
npm run db:init | Create the local database (-- --seed adds a sample row). |
PORTMain server port, default 3000.HOSTInterface to bind, default 127.0.0.1 (loopback — the API has no auth).PROXY_TIMEOUT_MSPer-attempt upstream timeout, default 30000.ALLOW_PRIVATE_UPSTREAM1 disables SSRF protections — tests/loopback only, never in prod.LOCAL_DB_PATHOverride where the SQLite file lives — default ~/.pool-anything/pool-anything.db for global installs, data/pool-anything.db in a checkout (pool-anything --db sets the same thing).POOL_DATA_DIRData-directory alternative: <dir>/pool-anything.db (pool-anything --data-dir sets the same thing).How pooling works
Most providers hand each key its own small rate limit: requests per minute, tokens per day. pool-anything gathers N keys for the same provider into one pool and does four things with them: Pool, Rotate (cursor % keys.length), Proxy, and Track. It ships with 36 preconfigured providers and a JSON API for everything else.
Storage
One SQLite file through Node's built-in DatabaseSync. The schema creates itself at startup; totals are computed on read with SUM() — no counters to drift.
CREATE TABLE pools (id, provider, name, cursor, …);
CREATE TABLE pool_keys (id, pool_id, label, api_key, …);
CREATE TABLE usage (id, pool_id, key_id, tokens, …);HTTP API
Base URL http://localhost:3000. Bodies and responses are JSON; errors are { "error": "…" }. List endpoints always mask keys — only the single-key view returns a raw value.
Every provider in the registry, with base URL, auth style, quota notes, docs link, and logo.
All pools, newest first: id, provider, name, cursor, base_url, key_header, key_prefix, created_at.
Create a pool. provider and name are required; overrides fall back to the registry when empty.
{ "provider": "groq", "name": "groq pool" }Pool summary with usage: key count, tokens used, quota and remaining, plus a per-key breakdown.
Delete the pool with its keys and usage records.
Rotation endpoints
Return the next key, masked, and advance the cursor. 400 if the pool has no keys, 404 if it doesn't exist.
{ "key_id": 2, "label": "key 2", "masked": "gsk_…9f" }Rotate to the next key and record usage against it. tokens must be a positive integer.
Usage rollup: pool total, quota, remaining, and per-key sums.
The proxy
Pick the next key, inject its credentials, forward the request, record usage, report back. path is appended to the pool's base URL; method defaults to POST.
{ "path": "/chat/completions", "method": "POST", "tokens": 24 }| Shape | Injection | Seen on |
|---|---|---|
Authorization + prefix | Authorization: Bearer <key> | Groq, OpenAI, OpenRouter |
| Plain header + prefix | <name><prefix><key> | x-api-key (Anthropic), xi-api-key (ElevenLabs) |
query:<param> | ?<param>=<key> | Mapbox, Google Maps, OpenWeather |
Provider extras (like anthropic-version) merge in automatically. Network failures return 502 { "error": "upstream unreachable" }.
Key endpoints
List keys, masked: id, label, masked, info, created_at.
Add a key. Send label and api_key → { "id": 7 }.
One key in full — the only endpoint that returns the raw value.
Update any of label, api_key, info.
Remove a key → { "ok": true }.
Also answering
GET /health | Plain-text ok liveness probe. |
GET /api/db/ping | Database path and row count. |
GET /logos/<name> | Provider logos, one-hour cache. |
Project layout
One HTTP server, one SQLite file, one JSON registry.
pool-anything/
├── src/server.ts # UI + JSON API + proxy (:3000)
├── src/pool/ # schema, providers, rotation
├── data/providers.json # the registry
└── landing/ # this siteProvider registry
data/providers.json is a flat array. Malformed rows are filtered out; a built-in fallback applies if the file can't be read.
| Field | Meaning |
|---|---|
id · name | Registry key and display name. |
baseUrl | Upstream root; the proxy appends the caller's path. |
keyHeader · keyPrefix | Where the key goes — header plus prefix, or query:<param>. |
extraHeaders | Always-sent headers, like anthropic-version. |
quota | Human-readable free-tier notes, shown in the UI. |
poolable | true by default, false for control-plane only. |
Security
- Keys are stored plaintext in SQLite; the file stays out of version control.
- List endpoints mask keys. Only GET /keys/:id returns a raw value.
- There is no auth on the API — localhost or behind your own gate.
- Logo paths are validated; request bodies cap at 1 MB.
- Upstream responses pass through as text, capped at 4000 chars — treat them as untrusted.
