Kilo Code takes a custom OpenAI-compatible provider two ways: a dialog in the extension’s Providers settings, and a provider block in kilo.jsonc that the extension and the Kilo CLI both read. Either one, and an uncensored build answers in the chat panel and in the terminal, with tool calls for edits and commands. The same ids work in Cursor, OpenCode and, through a router, Claude Code.
Where the settings are
In the editor extension: Settings (the gear icon) → Providers tab → Custom provider, at the bottom of the list. The dialog takes the provider, its base URL, the key and the models. The same screen is where Kilo Code lists the providers it ships with.
In the Kilo CLI, and for anything the dialog does not expose: kilo.jsonc (or kilo.json). The global file is ~/.config/kilo/kilo.jsonc; a project file is ./kilo.jsonc or a file inside ./.kilo/. Both load, the project file wins on the same key, and the CLI needs a restart after an edit. Per the Custom Models docs, token limits, tool calling and variants for a custom model are set in this file, whichever client you use.
Picking a model is the same in both: the model selector in the chat prompt area or /models in the extension, /models in the CLI.
Steps
Create a key in the console first. Then take either path; they end in the same place.
In the extension
- Settings → Providers → Custom provider.
- Provider ID:
uncensoredllm. Display name:UncensoredLLM. - Provider API: OpenAI Compatible. This API serves
/v1/chat/completions, which is the format that option speaks; the other two options are for Responses and Messages endpoints. - Base URL:
https://api.uncensoredllm.ai/v1. API key: the wholesk-ullm-key. - Models: with a valid base URL and key, Kilo Code fetches the list from
/v1/modelsand shows it as a searchable picker. Tick the ids you want, or add them by id and display name. Start with these three:
glm-5.3-uncensoredglm-5.3-flash-uncensoreddeepseek-v4.1-flash-abliterated- Leave Headers empty and click Submit. The ids appear in the model selector in the chat prompt area; pick one and send a message.
In kilo.jsonc
- Put the key in the environment of the shell that starts Kilo:
export UNCENSOREDLLM_API_KEY="sk-ullm-live-…"- Add the provider block to the global
~/.config/kilo/kilo.jsonc. The key underproviderfollows the Kilo docs’ own OpenAI-compatible example; the names and prices undermodelsare from the catalog, and any id on the models page goes in the same way:
{ "$schema": "https://app.kilo.ai/config.json", "model": "openai-compatible/glm-5.3-uncensored", "provider": { "openai-compatible": { "options": { "apiKey": "{env:UNCENSOREDLLM_API_KEY}", "baseURL": "https://api.uncensoredllm.ai/v1" }, "models": { "glm-5.3-uncensored": { // "tool_call": true, once the model page lists tool calls "name": "GLM-5.3 Uncensored", "cost": { "input": 0.282, "output": 0.846, "cache_read": 0.0799 } }, "glm-5.3-flash-uncensored": { // "tool_call": true, once the model page lists tool calls "name": "GLM-5.3 Flash Uncensored", "cost": { "input": 0.10528, "output": 0.36848, "cache_read": 0.010528 } }, "deepseek-v4.1-flash-abliterated": { // "tool_call": true, once the model page lists tool calls "name": "DeepSeek V4.1 Flash Abliterated", "cost": { "input": 0.84875, "output": 1.6975, "cache_read": 0.1455 } } } } }}- Start
kiloin the project. Themodelline selectsglm-5.3-uncensored;/modelsswitches to another id under openai-compatible for the session, andkilo -m openai-compatible/glm-5.3-uncensoredpicks one for a single run.
The {env:UNCENSOREDLLM_API_KEY} reference resolves only in trusted config: the global file, a file passed through KILO_CONFIG, or an organization-managed one. In a project kilo.jsonc it is ignored with a warning, so the block belongs in the global file, or the project file carries the block without apiKey and the global file carries only the key.
What each setting does
- Provider API
- OpenAI Compatiblethe request format the dialog uses: Chat Completions, which is what this API serves
- Base URL / options.baseURL
- https://api.uncensoredllm.ai/v1where the requests go; the /v1 at the end matters. The dialog also takes a full /chat/completions URL
- API key / options.apiKey
- {env:UNCENSOREDLLM_API_KEY}the whole sk-ullm- key, typed in the dialog or read from the variable in the global file
- Models / models
- id → { name, … }the ids the picker offers, each exactly as the models page shows it; the config key is the id sent to the API unless an `id` field overrides it
- tool_call
- truetells Kilo the model takes tool calls, which the agent needs for file edits and terminal commands; set it where the model page lists tool calls
- limit
- { context, output }the context window and the longest answer, in tokens; the model page states them. With context unset, Kilo never compacts the conversation
- cost
- { input, output, cache_read }USD per million tokens, from the catalog above, so kilo stats and the session cost line match the bill
- model
- openai-compatible/glm-5.3-uncensoredthe default, as provider key / model id; small_model and agent.<name>.model take the same form
Picking a model
Kilo Code sends OpenAI-format requests through the OpenAI Compatible adapter, and every build on the models page answers in that format. An agent turn carries the conversation, the files Kilo 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; that is the tool_call flag above, and the agent loop needs it 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 |
Kilo keeps separate roles: the main model, a Small Model for session titles and commit messages, a Subagent Model for the task tool. All three are set under Settings → Models or as small_model and subagent_model in kilo.jsonc. A fast build as the small model and a strong one as the main model keeps the housekeeping calls off the expensive id. 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; this is the same request the dialog’s model picker makes, so every id it offered should be in the answer:
curl https://api.uncensoredllm.ai/v1/models -H "Authorization: Bearer sk-ullm-live-…"Then send one request the way Kilo Code 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."}]}'On the CLI side, confirm the block loaded:
kilo models openai-compatibleIt lists the ids under models; kilo config check reports anything wrong in the file. Then send a message in Kilo with one of your ids selected. The request shows on the console’s usage page with its tokens and its charge.
Errors and fixes
401 invalid_api_key, or “Invalid API Key” in the dialog: the key is wrong or revoked, orUNCENSOREDLLM_API_KEYwas not set in the shell that started Kilo, soapiKeycame through empty. Copy it again from the console, or export it and start Kilo again.404 model_not_found, or “Model Not Found” in the dialog: the id is not on the models page. Check the spelling against the page; in the file, the key undermodelsis what is sent, notname.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.- The dialog’s model list stays empty: the fetch runs only once the base URL and the key are both valid. Fix either, click Fetch models, or add the ids by hand.
- A warning that
{env:UNCENSOREDLLM_API_KEY}was ignored: the reference sits in a projectkilo.jsonc. Move the block to~/.config/kilo/kilo.jsonc, or pass the file throughKILO_CONFIG. kilo modelsdoes not list the provider: the key inmodeldoes not matchprovider key / model keyin the block, or the CLI was not restarted after the edit.kilo debug configprints what loaded.- The agent explains an edit but never makes it:
tool_callis unset on that model, so Kilo sends no tools. Add"tool_call": trueto the entry once the model page lists tool calls. - The conversation grows until requests fail:
limit.contextis unset, which Kilo reads as zero and stops compacting. Setlimitfrom the model page. - Connection errors with a full URL in Base URL: the path has to end in
/chat/completions.https://api.uncensoredllm.ai/v1alone is the simpler form.
Questions
Yes. The Providers settings end in a Custom provider dialog whose Provider API field has an OpenAI Compatible option for Chat Completions endpoints, and kilo.jsonc takes the same provider as a block with a baseURL and an apiKey. This API is such an endpoint, so either path above is the whole setup.
A key from this console, in full, with the sk-ullm- prefix. In the dialog it goes in the API key field; in the file it is read from an environment variable through {env:…}, which Kilo resolves only in the global config or a file passed through KILO_CONFIG, never in a project file.
Yes. Providers sit side by side in the model selector and in /models, so the custom one is a second entry, not a replacement. The whitelist key on a provider block narrows what it offers, and the per-agent model keys pin a subagent to a cheaper id while the main agent stays on a strong one.
They work on the builds that take tool calls, and Kilo only sends tools when tool_call is true on the model. The table above says which builds the catalog confirms; for the rest, the model page says, and the flag goes into the entry once it does. See the models page.
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.