Pools
Coding agents on a pool
A friend pool's spare GPUs can back Claude Code, Cursor, Cline, and Continue for free. Point the tool at NeuronPool's OpenAI-compatible /v1, authenticate with a pool-scoped API key, and (when the tool can send extra headers) set X-NeuronPool-Route: pool. Jobs stay inside the pool, never touch the ledger, and show up on the pool usage page.
Shared coordinates
| Field | Value |
|---|---|
| Worker origin (until T66 custom domain) | https://neuronpool.damnknee.workers.dev |
| OpenAI-compatible base URL | https://neuronpool.damnknee.workers.dev/v1 |
| Intended partner hostname | https://api.neuronpool.dev/v1 |
| Catalog | GET /v1/models |
| Chat (free pool path) | POST /v1/chat/completions |
| Auth | Authorization: Bearer sk-neuronpool-… |
| Free pool (never billed) | header X-NeuronPool-Route: pool |
| Pool dashboard | /pools/<pool_id> (HTML) |
| Create a pool | /dashboard/pools (HTML form) or POST /v1/pools |
| Mint a pool-scoped key | pool page, or POST /v1/api-keys with pool_id |
Until api.neuronpool.dev resolves, paste the Worker URL. Never commit a key. Max completion budget on the coordinator is 4096 tokens (DEFAULT_MAX_OUTPUT_TOKENS).
Recommended models
Pick a chat id the pool actually has resident (GET /v1/models). Defaults for coding-agent presets:
| Catalog id | Why |
|---|---|
qwen3-30b-a3b | Stronger coding / agent loop when a pool host has it loaded |
gpt-oss-20b | Default chat preset; wide context; good fallback |
Other chat ids (llama-3.1-8b-instruct, qwen2.5-7b-instruct, gemma-3-12b-it, llama-3.2-1b-instruct, …) work the same way. Continue @codebase / indexing uses nomic-embed-text on POST /v1/embeddings; that path honors the same pool-scoped key and X-NeuronPool-Route: pool as chat.
neuronpool-tiny-chat is a 128-token dogfood GGUF. Agent CLIs (Claude Code, Continue) send system/tool prompts larger than that — use a catalog id with at least a few thousand context tokens (llama-3.2-1b-instruct and up). The host omits runner-added logprobs when the request includes tools so Continue's default tool+stream call is accepted by llama.cpp.
Routing
| How you call | What happens |
|---|---|
| Pool-scoped key, no route header | Default prefer-pool: try the pool first. Falls back to billed public only if that pool set allow_public_spend=1. |
Header X-NeuronPool-Route: pool | Strict pool. Never billed. No public fallback. Empty pool → no hosts (503). |
| Unscoped buyer key, no header | public (billed). Do not use this for "free on our GPUs." |
A completed pool job returns X-NeuronPool-Pool: <pool_id> (and X-NeuronPool-Host as a pseudonym). That header is the proof the request stayed inside the pool.
POST /v1/messages (Anthropic Messages, T32) honors the same X-NeuronPool-Route / pool-scoped-key defaults as /v1/chat/completions. A completed pool job returns X-NeuronPool-Pool. Claude Code can use the Anthropic path as a free pool backend.
Get a pool-scoped key
You must be a member of the pool (owner, admin, or invitee). A non-member pool_id is 403 and no key is minted.
- Sign up / log in. Create a pool at
/dashboard/pools(HTML form) or join via an invite link (/join/<code>). JSONPOST /v1/poolsstill works. - Attach an owned host from the pool page, or
neuronpool pool join <code>thenneuronpool serve. - On the pool page, mint a pool-scoped key. The secret is shown once. The dashboard Create API key form stays unscoped (public default).
- Optional API equivalent (plaintext is returned once):
# Session cookie from a logged-in browser (DevTools → Application → Cookies).
# pool_id is the id from GET /v1/pools or the pool page URL.
curl -sS https://neuronpool.damnknee.workers.dev/v1/api-keys \
-H "Cookie: $NEURONPOOL_SESSION" \
-H "Content-Type: application/json" \
-d '{"name":"coding-agents","pool_id":"pool_…"}'
Response includes key (sk-neuronpool-…), prefix, and pool_id. Store the secret in the tool's password / secrets field, not in git.
List existing keys (prefix + scoped pool, never the secret):
curl -sS https://neuronpool.damnknee.workers.dev/v1/api-keys \
-H "Cookie: $NEURONPOOL_SESSION"
Smoke test (proves the pool path before any IDE)
export NEURONPOOL_API_KEY='sk-neuronpool-…'
export NP='https://neuronpool.damnknee.workers.dev/v1'
curl -sS "$NP/models" \
-H "Authorization: Bearer $NEURONPOOL_API_KEY"
curl -sS -D - "$NP/chat/completions" \
-H "Authorization: Bearer $NEURONPOOL_API_KEY" \
-H "X-NeuronPool-Route: pool" \
-H "Content-Type: application/json" \
-d '{"model":"gpt-oss-20b","stream":false,"messages":[{"role":"user","content":"ping"}]}'
curl -sS -D - "$NP/embeddings" \
-H "Authorization: Bearer $NEURONPOOL_API_KEY" \
-H "X-NeuronPool-Route: pool" \
-H "Content-Type: application/json" \
-d '{"model":"nomic-embed-text","input":"ping"}'
Expect HTTP 200, catalog ids on /models, a choices[0].message.content reply on chat, an embeddings data[0].embedding array, and response header X-NeuronPool-Pool matching your pool on both. A 402 on this request means you hit the public path (wrong key or missing header). A 503 / no_hosts means no online pool host has that model — load it or pick an id from /v1/models. Fair-use 429 pool_quota_exceeded is limits.md.
Claude Code
Claude Code speaks the Anthropic Messages API (POST /v1/messages). NeuronPool implements that shape and honors X-NeuronPool-Route plus the pool-scoped key default (prefer-pool). A completed pool job returns X-NeuronPool-Pool.
Exact config (Anthropic path — free on a pool-scoped key)
ANTHROPIC_BASE_URL is the origin, not /v1. Claude Code appends /v1/messages.
export ANTHROPIC_BASE_URL="https://neuronpool.damnknee.workers.dev"
export ANTHROPIC_AUTH_TOKEN="$NEURONPOOL_API_KEY"
export ANTHROPIC_API_KEY=""
export ANTHROPIC_MODEL="gpt-oss-20b"
export ANTHROPIC_DEFAULT_SONNET_MODEL="qwen3-30b-a3b"
export ANTHROPIC_DEFAULT_HAIKU_MODEL="gpt-oss-20b"
export ANTHROPIC_CUSTOM_HEADERS="X-NeuronPool-Route: pool"
Persistent (~/.claude/settings.json):
{
"env": {
"ANTHROPIC_BASE_URL": "https://neuronpool.damnknee.workers.dev",
"ANTHROPIC_AUTH_TOKEN": "sk-neuronpool-…",
"ANTHROPIC_API_KEY": "",
"ANTHROPIC_MODEL": "gpt-oss-20b",
"ANTHROPIC_DEFAULT_SONNET_MODEL": "qwen3-30b-a3b",
"ANTHROPIC_DEFAULT_HAIKU_MODEL": "gpt-oss-20b",
"ANTHROPIC_CUSTOM_HEADERS": "X-NeuronPool-Route: pool"
}
}
Then claude and send a one-line prompt. ANTHROPIC_CUSTOM_HEADERS is the strict-pool pin; a pool-scoped key without the header still prefers the pool and will not spend credits unless that pool set allow_public_spend=1.
| Field | Value |
|---|---|
| Base URL (origin) | https://neuronpool.damnknee.workers.dev |
| Key | pool-scoped sk-neuronpool-… (ANTHROPIC_AUTH_TOKEN → Authorization: Bearer …; x-api-key is also accepted) |
| Model id | qwen3-30b-a3b or gpt-oss-20b |
| Free pool? | Yes — /v1/messages honors X-NeuronPool-Route and the pool-scoped key default. |
Cursor
Cursor's BYOK path is OpenAI-compatible POST /v1/chat/completions. There is no extra-headers field in Settings → Models, so mint a pool-scoped key (default prefer-pool) and leave allow_public_spend off on the pool so a miss never spends credits.
Chat and Agent require a logged-in Cursor account. Settings can save the OpenAI key and Override Base URL while you are logged out, but Chat will not use them. A logged-out send fails with Authentication error / ERROR_NOT_LOGGED_IN to https://api2.cursor.sh, not a NeuronPool 4xx. Disposable *@agentmail.to signups are blocked. cursor-agent --endpoint talks to Cursor Cloud, not this BYOK override — it is not a substitute.
- Sign in to Cursor (a real account; not a disposable inbox).
- Cursor Settings → Models.
- Enable OpenAI API Key and paste the pool-scoped
sk-neuronpool-…. - Enable Override OpenAI Base URL:
https://neuronpool.damnknee.workers.dev/v1 - Add model → catalog id
gpt-oss-20b(andqwen3-30b-a3bif a host has it). Use the API id, not a display name. - Disable other provider keys if they steal the picker. Click Verify.
- In Chat / Agent, select that custom model and send
ping.
| Field | Value |
|---|---|
| Base URL | https://neuronpool.damnknee.workers.dev/v1 |
| Key | pool-scoped sk-neuronpool-… |
| Model id | gpt-oss-20b or qwen3-30b-a3b |
| Route header | not available in the UI — rely on the pool-scoped key default |
Cursor Tab / Cloud Agents / Automations do not use this BYOK override; only local Chat / Agent. Agent mode posts to POST /v1/responses; that path is translated onto the same chat job pipeline (including pool routing). Ask / Chat use /v1/chat/completions.
Login gate (Cursor 3.19 desktop): Settings → Models accepts the OpenAI key, Override Base URL, and a custom catalog id before sign-in, but Chat / Agent replace Send with Log in. A Cursor account is required to complete a chat. Disposable inboxes (for example *@agentmail.to) are rejected at authenticator.cursor.sh with Access blocked, please contact support — use a real Cursor login, not a throwaway mailbox. The official cursor agent / agent CLI authenticates to https://api2.cursor.sh (Cursor-account key), not this OpenAI-compatible BYOK path — --endpoint + a NeuronPool key is rejected as invalid.
Cline
Cline Settings → API Provider → OpenAI Compatible. Full generic recipe: docs/integrations/clients.md (Cline). For a pool:
- Base URL:
https://neuronpool.damnknee.workers.dev/v1 - API Key: pool-scoped
sk-neuronpool-… - Model: refresh from
/v1/models, or typegpt-oss-20b/qwen3-30b-a3b. - Custom Headers (API Configuration → Add Header), when the UI still exposes it:
| Header | Value |
|---|---|
X-NeuronPool-Route | pool |
If a Cline build dropped Custom Headers, the pool-scoped key default (prefer-pool) is enough as long as the pool has not opted into public spend.
VS Code settings.json equivalent (key via Cline's secret field, not git):
{
"cline.apiProvider": "openai-compatible",
"cline.openAiBaseUrl": "https://neuronpool.damnknee.workers.dev/v1",
"cline.openAiModelId": "gpt-oss-20b"
}
Then one Cline chat: Reply with the single word pong. Expect a streamed reply. Optional: capture response headers on the Worker (X-NeuronPool-Pool) via the smoke-test curl using the same key.
Cline CLI (headless)
The cline npm CLI is a different surface from the VS Code panel.
cline auth --provider openai-compatible \
--apikey "$NEURONPOOL_API_KEY" \
--modelid gpt-oss-20b \
--baseurl https://neuronpool.damnknee.workers.dev/v1
--provider openai-compatible posts to /v1/chat/completions (same path as the VS Code OpenAI Compatible panel). --provider openai-native posts to /v1/responses (now implemented on this coordinator). Cline's native tools arrive as Responses functions ({type:"function", name}) plus extras such as image_generation; the translator wraps functions into OpenAI chat tools and drops non-function types so llama.cpp can parse them.
The CLI may open two chat requests at once. A host with max_concurrency=1 can 503 no_failover_host on the second while the first still completes on the pool (billable=0). Raise host concurrency, or use a single-stream VS Code chat. 1B-class models often invent a fake tool name that llama.cpp drops — the host retries once without tools. Cline's default system + tools prompt is ~8.3k tokens; start llama-server with -c 16384 or larger.
Continue
Continue uses provider: openai + apiBase (must include /v1). Copy into ~/.continue/config.yaml. Store the key in Continue secrets (${{ secrets.NEURONPOOL_API_KEY }}), not in the file.
name: NeuronPool pool
version: 1.0.0
schema: v1
models:
- name: Pool gpt-oss-20b
provider: openai
model: gpt-oss-20b
apiBase: https://neuronpool.damnknee.workers.dev/v1
apiKey: ${{ secrets.NEURONPOOL_API_KEY }}
roles: [chat, edit, apply]
requestOptions:
headers:
X-NeuronPool-Route: pool
- name: Pool qwen3-30b-a3b
provider: openai
model: qwen3-30b-a3b
apiBase: https://neuronpool.damnknee.workers.dev/v1
apiKey: ${{ secrets.NEURONPOOL_API_KEY }}
roles: [chat, edit, apply]
requestOptions:
headers:
X-NeuronPool-Route: pool
- name: Pool nomic-embed-text
provider: openai
model: nomic-embed-text
apiBase: https://neuronpool.damnknee.workers.dev/v1
apiKey: ${{ secrets.NEURONPOOL_API_KEY }}
roles: [embed]
requestOptions:
headers:
X-NeuronPool-Route: pool
Legacy ~/.continue/config.json:
{
"models": [
{
"title": "Pool gpt-oss-20b",
"provider": "openai",
"model": "gpt-oss-20b",
"apiBase": "https://neuronpool.damnknee.workers.dev/v1",
"apiKey": "sk-neuronpool-…",
"requestOptions": {
"headers": { "X-NeuronPool-Route": "pool" }
}
}
]
}
Reload the window, pick Pool gpt-oss-20b, send ping. @codebase / indexing uses Pool nomic-embed-text (POST /v1/embeddings) and stays on the pool when that model is resident. Paid unscoped Continue presets (no route header) are in clients/continue.config.yaml.
Continue CLI (headless)
The cn CLI (npx @continuedev/cli) uses the same OpenAI-compatible /v1/chat/completions path. Point --config at a yaml like the block above (local origin + pool-scoped key + X-NeuronPool-Route: pool):
npx --yes @continuedev/cli \
--config ~/.continue/config.yaml \
--readonly -p --silent \
"Reply with the single word pong."