Skip to content

Provider presets

How to pick a curated API provider without memorising URLs, model ids, or auth headers — and how to extend the catalogue with custom endpoints.

What a preset gives you

A preset bundles the three things a first-party provider needs: the wire, the endpoint URL, and the default model id. Auth is bundled too — every built-in preset sends Authorization: Bearer <key> instead of the Anthropic SDK's default X-Api-Key header (the SDK default would 401 against MiniMax and Z.ai).

Use a preset when you don't want to memorise:

  • base_url (e.g. https://api.minimax.io/anthropic)
  • the right provider (openai vs anthropic)
  • the default model id
  • the right auth header

A preset folds into the override chain via setdefault semantics — an explicit CLI flag, env var, or file entry always wins over the preset's default for the same knob. The preset never silently overwrites something you set.

Built-in presets

id label base_url default model models key_url
minimax MiniMax https://api.minimax.io/anthropic MiniMax-M3 (1M ctx) MiniMax-M3, MiniMax-M2.7, MiniMax-M2.7-highspeed, MiniMax-M2.5, MiniMax-M2.5-highspeed, MiniMax-M2.1, MiniMax-M2.1-highspeed, MiniMax-M2 https://api.minimax.io/usercenter/charge
zai Z.ai https://api.z.ai/api/anthropic glm-5.2 (1M ctx) glm-5.2, glm-5.1, glm-5-turbo, glm-4.7, glm-4.5-air, glm-4.5, glm-4.5-flash https://z.ai/manage-apikey/apikey-list

The Anthropic-preset rows (MiniMax, Z.ai) ride the same thinking.type knob as real Anthropic — enabled / disabled / adaptive (the model-writable form). Defaults to adaptive so a vanilla install keeps the previous turn-on reasoning behavior. Change the knob with KIN_THINKING_TYPE=disabled uv run kin (env) or thinking_type = "disabled" in settings.toml; flip it live with /settings on and let kin propose the diff. The reasoning-depth preset (Z.ai's 8-value vocabulary, etc.) is the effort knob — see /effort for the live setter.

Note

Z.ai's glm-5.2 default uses the 1M-context long-context tier — the tier is reached via context_window = 1000000 in settings, not via the model id. MiniMax's MiniMax-M3 ships plain with 1M context; the long-context tier is configurable on the MiniMax side. The [1m] suffix is a Claude Code SDK convention, not a Z.ai wire-level model id. Use plain glm-5.2 and set context_window = 1000000 for the 1M tier; the suffix produces model_not_found on a raw SDK call.

The /providers command

/providers opens a modal listing the built-ins + any [[providers]] rows already on file. The API-key field is focused on open — just type the key; Up/Down or a mouse click both just pick a row (they update the description pane and refocus the key field — they don't save). Hit Enter or click Save to actually commit. The worker writes the choice back to ~/.kin/settings.toml and switches the running session to it live — no restart — toasting "switched to {provider}". The file write is still the persistent baseline that feeds new sessions (see Configuration); the live swap is fail-closed (a backend that won't build leaves the current one untouched). The pick is refused while a turn is running.

/providers [name] opens the modal pre-selected on the named preset (built-in or [[providers]] id). Unknown ids refuse before opening the modal so a typo doesn't silently no-op.

For the full key reference, see Slash commands; for the modal's row shortcuts, see Keybindings & cursor mode.

/providers vs /model vs the picker

The three surfaces funnel through one swap helper, but only /providers writes a key:

Surface When to use Writes
/providers Enter a key + set up a provider end-to-end (the canonical key-entry surface) provider_preset + provider_keys[<id>] (read-merged) + model + (for customs) [[providers]] row
/model <id> (inline) Swap to a model id you already know; silent when a key resolves, else refuses with a hint provider_preset + model (no key write)
/model (bare, picker) Browse across providers with the keyboard; the ✓ key badge shows which are ready provider_preset + model (no key write)

All three flows funnel through commands_mixin._swap_to_providersave_global_settings(...) (the human-only writer) → Session.set_provider(...) — so a swap is durable across restarts and takes effect on the running session immediately. Keys are entered only via /providers; /model never prompts for one.

Other surfaces

Three surfaces reach the same preset machinery, in this precedence order:

Surface Example When to use
CLI flag uv run kin --preset minimax A one-off override (highest precedence)
Env var KIN_PRESET=zai uv run kin A shell-level override (above the file)
Settings key provider_preset = "minimax" in ~/.kin/settings.toml Persistent baseline

The modal writes the file layer and swaps the live backend in place. The file is still what new sessions read; /reload re-applies an edited settings.toml to a running session without a restart too.

A raw base_url default isn't switchable-back-to

A plain top-level base_url + model in settings.toml (e.g. a local vLLM/llama.cpp endpoint with no provider_preset) works fine as your launch default, but it's not a catalogue entry/model and /providers only list built-ins + [[providers]] rows. Swap away from it via /providers <other> and there's nothing left pointing back at it. If you want to swap back and forth, give it a [[providers]] row too (see Custom endpoints below) — an auth-less local server just omits the key (/providers treats an empty field as fine to save; no key is ever required, only merged in when typed).

Custom endpoints

/providers → "Custom endpoint…" → enter name + URL + wire (anthropic or openai) + model. The modal writes a [[providers]] row to ~/.kin/settings.toml and sets provider_preset to the name.

Manual [[providers]] block (the modal's write target):

[[providers]]
id = "openrouter"
label = "OpenRouter"
provider = "openai"
base_url = "https://openrouter.ai/api/v1"
default_model = "anthropic/claude-3.7-sonnet"
models = ["anthropic/claude-3.7-sonnet"]
# extra_headers = { "X-Tenant-ID" = "acme" }    # optional

A custom row's id can shadow a built-in (so operators can override a built-in's URL without code changes), but the built-in lookup runs first so the curated catalogue wins for the common case. After saving, /providers openrouter opens the modal pre-selected on the custom row.

Row keys: model vs default_model vs models

The three keys do different things, and a row that confuses them renders an empty group in /model (the header shows but there's nothing to pick):

Key What it does
default_model The model id the factory pre-fills when this preset is active and no other model was set. Also seeds models if no models list was given (see below).
models The catalogue the /model picker iterates for this row. Multiple ids → multiple pickable rows.
model Convenience alias for default_model — same key, just shorter. Honored ONLY when default_model is unset. Useful for one-line rows like a vLLM stable-alias setup: model = "default".

Two safety nets so the one-line shape still surfaces a pickable row:

  • model = "default" is accepted as an alias for default_model.
  • When neither models nor default_model is set, but model is, the model id seeds models = (model,) too — the picker renders one row.
# Minimal: single-model / stable-alias custom endpoint.
[[providers]]
id = "vllm"
label = "vLLM (tailnet)"
provider = "anthropic"
base_url = "http://kin-one:8000/v1"
model = "default"                # alias for default_model; seeds models = ["default"]

If you want the picker to show every model your server actually serves, prefer the explicit two-key form — or wire /providers's "Custom endpoint…" form, which writes both default_model and (when known) models for you.

The curated catalogue is not a silent cap

The built-in lists cover the verified ids from each provider's official docs. A model id not in the catalogue is still reachable:

  • KIN_MODEL=<id> uv run kin (overrides the preset's default)
  • --model <id> (CLI override)
  • A [[providers]] row that names it

The catalogue is the curated subset the harness is willing to ship defaults for; nothing stops you from picking another model id on the same wire.

Preset auth is Bearer, not x-api-key

Built-in presets send Authorization: Bearer <key> because MiniMax and Z.ai both reject the Anthropic SDK's default X-Api-Key header. The factory routes the resolved key into the SDK's auth_token= slot (not api_key=) so only Bearer rides the wire. A non-preset AnthropicBackend(api_key=...) still uses x-api-key as before — no behaviour change for users who aren't using presets.

The GLOBAL_ONLY safety boundary

provider_preset and providers are global-only keys — honored from the global file, the environment, or a CLI flag, but stripped (with a warning) from any project .kin/settings.toml. A cloned repo's project file can't silently retarget your wire to a third-party endpoint and silently route your global api_key through it. The threat model is identical to base_url / api_key being global-only — see settings.toml keys for the rest of the denylist and the rationale.