OpenCode takes a custom provider in opencode.json: the OpenAI-compatible package, a base URL, a key and the model ids. One block, and an uncensored build answers in the terminal with tool calls for edits and commands. The same ids work in Cursor and, through a router, in Claude Code.
Where the settings are
OpenCode reads opencode.json (or opencode.jsonc, JSON with comments) from the project root, and a global one from ~/.config/opencode/opencode.json. Both load; where the two set the same key, the project file wins. OPENCODE_CONFIG points at a file somewhere else.
Two TUI commands matter here: /connect stores a key for a provider (under Other for a custom one), and /models lists the providers and models from your config to pick from.
Steps
- Create a key in the console and put it in an environment variable in the shell that starts OpenCode:
export UNCENSOREDLLM_API_KEY="sk-ullm-live-…"- Add the provider to
opencode.jsonin the project, or to the global file to have it in every project. The ids undermodelsare the four OpenCode users call most here; any id on the models page goes in the same way, and the display names are from the catalog:
{ "$schema": "https://opencode.ai/config.json", "provider": { "uncensoredllm": { "npm": "@ai-sdk/openai-compatible", "name": "UncensoredLLM", "options": { "baseURL": "https://api.uncensoredllm.ai/v1", "apiKey": "{env:UNCENSOREDLLM_API_KEY}" }, "models": { "glm-5.3-uncensored": { "name": "GLM-5.3 Uncensored" }, "glm-5.3-flash-uncensored": { "name": "GLM-5.3 Flash Uncensored" }, "deepseek-v4.1-flash-abliterated": { "name": "DeepSeek V4.1 Flash Abliterated" }, "deepseek-v4-pro-uncensored": { "name": "DeepSeek V4 Pro Uncensored" } } } }, "model": "uncensoredllm/glm-5.3-uncensored"}- Start
opencodein the project. Themodelline already selectsglm-5.3-uncensored;/modelsswitches to another id under UncensoredLLM for the session.
To keep the key out of the environment, run /connect, choose Other, enter uncensoredllm as the provider id and paste the key; OpenCode stores it in ~/.local/share/opencode/auth.json. The provider block stays as above without the apiKey line, and the id in /connect has to match the key in the config.
What each setting does
- npm
- @ai-sdk/openai-compatiblethe AI SDK package OpenCode loads for the provider; this one speaks /v1/chat/completions, which is what the API serves
- name
- UncensoredLLMthe provider name in /models
- options.baseURL
- https://api.uncensoredllm.ai/v1where the requests go; the /v1 at the end matters
- options.apiKey
- {env:UNCENSOREDLLM_API_KEY}the whole sk-ullm- key, read from the variable at start; an unset variable becomes an empty string
- models
- id → { name }the ids the picker offers, each exactly as the models page shows it, with the name to display
- model
- uncensoredllm/glm-5.3-uncensoredthe default model, as provider id / model id; small_model takes the same form for title generation
Picking a model
OpenCode sends OpenAI-format requests through the package above, and every build on the models page answers in that format. An agent turn carries the conversation, the files OpenCode read and every tool result so far, so input tokens are most of the bill and a build with a low input price costs the least per turn. The last column says whether the build takes tool calls, which the agent loop needs for edits and shell commands.
| Model | One agent turn | Tool calls |
|---|---|---|
| GLM-5.3 Uncensored | $0.01 | model page |
| GLM-5.3 Flash Uncensored | $0.0047 | model page |
| DeepSeek V4.1 Flash Abliterated | $0.04 | model page |
| DeepSeek V4 Pro Uncensored | $0.04 | model page |
| GLM-5.3 Abliterated | $0.09 | model page |
| GLM-5.3 Flash Code Uncensored | $0.25 | model page |
| GLM-5.3 Uncensored | Uncensored | $0.282 | $0.846 |
| GLM-5.3 Flash Uncensored | Uncensored | $0.1053 | $0.3685 |
| DeepSeek V4.1 Flash Abliterated | Abliterated | $0.8488 | $1.6975 |
| DeepSeek V4 Pro Uncensored | Uncensored | $0.97 | $1.94 |
| GLM-5.3 Abliterated | Abliterated | $2.1825 | $4.365 |
| GLM-5.3 Flash Code Uncensored | Uncensored | $6.00 | $6.00 |
For coding specifically, the uncensored coding AI guide compares the code builds and costs a full coding day on each.
Check it
List the models your key can call; every id you put under models should be in the answer:
curl https://api.uncensoredllm.ai/v1/models -H "Authorization: Bearer sk-ullm-live-…"Then send one request the way OpenCode does. -i prints the headers: x-uplink-request-id names the request, and on a non-streamed answer x-uplink-charge is what it cost in USD.
curl -i https://api.uncensoredllm.ai/v1/chat/completions \ -H "Authorization: Bearer sk-ullm-live-…" \ -H "Content-Type: application/json" \ -d '{"model": "glm-5.3-uncensored", "messages": [{"role": "user", "content": "Reply with the single word ok."}]}'In OpenCode, send a message with one of your ids selected. The request shows on the console’s usage page with its tokens and its charge, and the user agent on it names the OpenCode version.
Errors and fixes
401 invalid_api_key: the key is wrong or revoked, orUNCENSOREDLLM_API_KEYwas not set in the shell that started OpenCode, soapiKeycame through empty. Export it and start OpenCode again, or copy the key again from the console.404 model_not_found: an id undermodelsis not on the models page. Check the spelling against the page; the id is the key, not thename.402 insufficient_balance: the balance does not cover the request. Top up in the console.402 monthly_limit_reachedmeans the key hit the monthly spend limit you set on it.403 scope_denied: the key is limited to certain models and this is not one of them.429 rate_limited: the key hit its rate limit. The response carriesretry-after.- Requests that never reach the API, or arrive at a path other than
/chat/completions: the provider is on the wrong package. Per the OpenCode docs,@ai-sdk/openai-compatibleis for endpoints that serve/v1/chat/completions, which this API does;@ai-sdk/openaiis for endpoints that serve/v1/responses. Keepnpmon the former. - The provider is missing from
/modelsafter/connect: the id entered in/connectdiffers from the key underproviderin the config. Make the two the same.
Questions
Yes, and so is any endpoint that answers the OpenAI chat completions format. OpenCode loads it through the @ai-sdk/openai-compatible package with a baseURL and a key; this API is one such endpoint, so the block above is the whole setup.
OpenCode ships a catalog of providers that /connect lists by name, and a custom entry for any other OpenAI-compatible API, added in opencode.json under provider with the package, the base URL and the model ids. This guide is the custom path.
Every model on the models page: all of them answer /v1/chat/completions in the OpenAI format with the same key, so any id there goes into the models map of the provider block as it is spelled on the page. See the models page.
Per token at the model’s price, from your prepaid balance, with no subscription. The table above costs one agent-sized turn on each build at the live price; a long session that repeats the same prefix bills the cached input tokens at the model’s cached rate.
Every model above is on the uncensored model list with its live price per million tokens. Per-token pricing sets the whole catalog side by side, and the family directory groups the builds by base model.