CROWBOTDOCS
DISCORD CHAT LOG IN

Using crowbot with opencode

opencode reaches crowbot through the AI SDK's OpenAI-compatible provider: a config block. Works with opencode 1 and 2. The installer adds a plugin that refreshes the otherwise frozen model list at startup.

Install

shcurl -fsSL https://crowbot.sh/install.sh | bash

On Windows, in PowerShell (5.1 or 7):

powershellirm https://crowbot.sh/install.ps1 | iex

It asks whether to configure opencode globally or for one project, then takes your account number or pairs through the browser. Pairing creates a separate key for that machine, so a laptop is revocable without changing your account number. Non-interactive:

shcurl -fsSL https://crowbot.sh/install.sh | bash -s -- --global --key 4192083755612094
curl -fsSL https://crowbot.sh/install.sh | bash -s -- --local --pair
curl -fsSL https://crowbot.sh/install.sh | bash -s -- --global --pair --dry-run   # print, write nothing

The PowerShell installer takes the same flags as -Global, -Local, -Key, -Pair and -DryRun; iex cannot pass them, so use the script-block form:

powershell& ([scriptblock]::Create((irm https://crowbot.sh/install.ps1))) -Global -Key 4192083755612094
& ([scriptblock]::Create((irm https://crowbot.sh/install.ps1))) -Local -Pair

The installer merges into an existing config and keeps a timestamped backup. It only ever writes crowbot's provider entry, and it refuses to touch a config it cannot parse. An opencode 2 style providers.crowbot entry is replaced, because opencode 2 would prefer it to the one the installer writes.

Then run /models inside opencode and pick a crowbot model.

Keeping the model list current

Two files get written:

opencode.json the provider block, including a snapshot of the models
plugin/crowbot.js refreshes that model list at startup

The plugin loads from that directory: nothing to configure, no duplicate on re-run. It replaces only the model list from https://api.crowbot.sh/docs/opencode.json, never your key; unreachable, it gives up within ~2 s.

Delete plugin/crowbot.js if you would rather pin the model list. Re-run the installer when it needs updating.

The plugin needs opencode 1.3.4 or newer; on anything older the installer skips it. On opencode 2 it adds models we start serving after you installed, but it cannot retire or reprice the ones already in your opencode.json, because opencode 2 applies the file's own entries last. Re-run the installer for those.

Moved to opencode 2? Re-run the installer. A plugin from an earlier install only speaks opencode 1's plugin API, so opencode 2 lists it as failed under /plugins.

A 404 naming a model you thought you had means your config predates a rename; the error says what replaced it, and re-running the installer repoints you.

Config, by hand

The generated block with current models, limits and prices is always at https://api.crowbot.sh/docs/opencode.json.

Do not curl -o over your global config. ~/.config/opencode/opencode.json holds your other providers, agents, keybinds and MCP servers, and opencode merges settings across levels rather than replacing them. Redirecting the generated file over it deletes all of that. Paste the provider block into your existing file instead, or let the installer merge it.

json{
  "$schema": "https://opencode.ai/config.json",
  "provider": {
    "crowbot": {
      "npm": "@ai-sdk/openai-compatible",
      "name": "crowbot",
      "options": {
        "baseURL": "https://api.crowbot.sh/v1",
        "apiKey": "{env:CROWBOT_API_KEY}"
      },
      "models": {
        "kimi-k3.1-pro-crow": {
          "name": "Kimi K3.1 Pro [UNCENSORED]",
          "limit": {
            "context": 1048576,
            "output": 32768
          },
          "cost": {
            "input": 6.25,
            "output": 15.0,
            "cache_read": 0.625
          },
          "tool_call": true,
          "reasoning": true,
          "interleaved": "reasoning_content",
          "temperature": true,
          "attachment": true,
          "modalities": {
            "input": [
              "text",
              "image"
            ],
            "output": [
              "text"
            ]
          }
        },
        "crow-2": {
          "name": "GLM 5.3 [UNCENSORED]",
          "limit": {
            "context": 1000000,
            "output": 32768
          },
          "cost": {
            "input": 3.5,
            "output": 5.0,
            "cache_read": 0.5
          },
          "tool_call": true,
          "reasoning": true,
          "interleaved": "reasoning_content",
          "temperature": true,
          "attachment": false,
          "modalities": {
            "input": [
              "text"
            ],
            "output": [
              "text"
            ]
          }
        },
        "glm-5.3": {
          "name": "GLM 5.3 [Cyber] [UNCENSORED]",
          "limit": {
            "context": 1000000,
            "output": 131072
          },
          "cost": {
            "input": 1.35,
            "output": 4.0,
            "cache_read": 0.25
          },
          "tool_call": true,
          "reasoning": true,
          "interleaved": "reasoning_content",
          "temperature": true,
          "attachment": false,
          "modalities": {
            "input": [
              "text"
            ],
            "output": [
              "text"
            ]
          }
        },
        "glm-5.3-flash-crow": {
          "name": "GLM 5.3 Flash [UNCENSORED]",
          "limit": {
            "context": 1048576,
            "output": 32768
          },
          "cost": {
            "input": 0.2,
            "output": 0.6,
            "cache_read": 0.1
          },
          "tool_call": true,
          "reasoning": true,
          "interleaved": "reasoning_content",
          "temperature": true,
          "attachment": false,
          "modalities": {
            "input": [
              "text"
            ],
            "output": [
              "text"
            ]
          }
        },
        "deepseek-v4.1-flash-1017-crow": {
          "name": "DeepSeek V4.1 Flash 1017 [UNCENSORED]",
          "limit": {
            "context": 1000000,
            "output": 32768
          },
          "cost": {
            "input": 0.35,
            "output": 1.35,
            "cache_read": 0.015
          },
          "tool_call": true,
          "reasoning": true,
          "interleaved": "reasoning_content",
          "temperature": true,
          "attachment": false,
          "modalities": {
            "input": [
              "text"
            ],
            "output": [
              "text"
            ]
          }
        },
        "gpt-6.1-sol": {
          "name": "GPT 6.1 Sol",
          "limit": {
            "context": 1048576,
            "output": 128000
          },
          "cost": {
            "input": 0.16,
            "output": 0.8,
            "cache_read": 0.008
          },
          "tool_call": true,
          "reasoning": true,
          "interleaved": "reasoning_content",
          "temperature": true,
          "attachment": false,
          "modalities": {
            "input": [
              "text"
            ],
            "output": [
              "text"
            ]
          }
        },
        "kimi-k3.1-pro": {
          "name": "Kimi K3.1 Pro",
          "limit": {
            "context": 1048576,
            "output": 1048576
          },
          "cost": {
            "input": 0.21,
            "output": 1.05,
            "cache_read": 0.021
          },
          "tool_call": true,
          "reasoning": true,
          "interleaved": "reasoning_content",
          "temperature": true,
          "attachment": false,
          "modalities": {
            "input": [
              "text"
            ],
            "output": [
              "text"
            ]
          }
        },
        "deepseek-v4.1-flash": {
          "name": "DeepSeek V4.1 Flash 1017 [CHEAP]",
          "limit": {
            "context": 1048576,
            "output": 128000
          },
          "cost": {
            "input": 0.03,
            "output": 0.12,
            "cache_read": 0.0006
          },
          "tool_call": true,
          "reasoning": true,
          "interleaved": "reasoning_content",
          "temperature": true,
          "attachment": false,
          "modalities": {
            "input": [
              "text"
            ],
            "output": [
              "text"
            ]
          }
        },
        "glm-5.3-cheap": {
          "name": "GLM 5.3 [CHEAP]",
          "limit": {
            "context": 1048576,
            "output": 128000
          },
          "cost": {
            "input": 0.07,
            "output": 0.22,
            "cache_read": 0.013
          },
          "tool_call": true,
          "reasoning": true,
          "interleaved": "reasoning_content",
          "temperature": true,
          "attachment": false,
          "modalities": {
            "input": [
              "text"
            ],
            "output": [
              "text"
            ]
          }
        },
        "gemini-4-argon": {
          "name": "Gemini 4 Argon",
          "limit": {
            "context": 1048576,
            "output": 65536
          },
          "cost": {
            "input": 0.3,
            "output": 1.5,
            "cache_read": 0.015
          },
          "tool_call": true,
          "reasoning": true,
          "interleaved": "reasoning_content",
          "temperature": true,
          "attachment": false,
          "modalities": {
            "input": [
              "text"
            ],
            "output": [
              "text"
            ]
          }
        },
        "gemini-4-carbon": {
          "name": "Gemini 4 Carbon",
          "limit": {
            "context": 1048576,
            "output": 65536
          },
          "cost": {
            "input": 0.3,
            "output": 1.5,
            "cache_read": 0.015
          },
          "tool_call": true,
          "reasoning": true,
          "interleaved": "reasoning_content",
          "temperature": true,
          "attachment": false,
          "modalities": {
            "input": [
              "text"
            ],
            "output": [
              "text"
            ]
          }
        },
        "odin": {
          "name": "Odin [UNCENSORED]",
          "limit": {
            "context": 1048576,
            "output": 32768
          },
          "cost": {
            "input": 0.6,
            "output": 1.8,
            "cache_read": 0.012
          },
          "tool_call": true,
          "reasoning": true,
          "interleaved": "reasoning_content",
          "temperature": true,
          "attachment": false,
          "modalities": {
            "input": [
              "text"
            ],
            "output": [
              "text"
            ]
          }
        },
        "odin-cheap": {
          "name": "Odin [CHEAP]",
          "limit": {
            "context": 1048576,
            "output": 128000
          },
          "cost": {
            "input": 0.05,
            "output": 0.25,
            "cache_read": 0.005
          },
          "tool_call": true,
          "reasoning": true,
          "interleaved": "reasoning_content",
          "temperature": true,
          "attachment": false,
          "modalities": {
            "input": [
              "text"
            ],
            "output": [
              "text"
            ]
          }
        }
      }
    }
  }
}

Set the key the config expects:

shexport CROWBOT_API_KEY=4192083755612094      # your account number, no spaces

What each field is doing

field why it matters
npm @ai-sdk/openai-compatible is the right driver: we serve /v1/chat/completions, not /v1/responses
apiKey {env:CROWBOT_API_KEY} keeps your account number out of the file
tool_call true where the model calls tools; we translate them in both directions, so agent mode works
reasoning + interleaved "reasoning_content" is the field our SSE actually emits, so opencode renders the thinking trace instead of discarding it
temperature true where the model takes a sampling temperature; sampling parameters are forwarded as you send them
attachment true where the model reads images, so opencode lets you attach them
modalities image in only where the model reads images, text out; without it opencode 2 offers image input to every model
cost our rates, not the upstream vendor's — so opencode's spend display matches what you are actually charged
limit real context and output ceilings, so opencode truncates before we have to

Notes

  • Fund the account first. A new account is empty, so opencode gets an insufficient_balance 402 until you top up. See Quickstart.
  • Your system prompt is honoured. opencode's agent definition reaches the model unchanged and stays first. See API.
  • No proof-of-work on the API. The chat requires one per message; /v1 never does.
  • If a model shows up but every call fails, check /api/me for your balance first.