Choose a Model
For a built-in provider, start with /login, then choose a model with /model. Use custom model configuration only when KnightCode does not already include the provider or...
For a built-in provider, start with /login, then choose a model with /model. Use custom model configuration only when KnightCode does not already include the provider or endpoint you need.
Choose a connection
| What you have | Recommended setup |
|---|---|
| A supported subscription | Sign in through /login |
| A provider API key | Store it through /login or set its environment variable |
| A local GGUF model | Connect KnightCode to the llama.cpp router |
| An OpenAI-, Anthropic-, or Google-compatible endpoint | Add it to models.json |
| A provider with a custom protocol or authentication flow | Build or install a provider extension |
Browse the model catalog for current providers, model IDs, capabilities, context limits, and pricing. KnightCode starts with its bundled catalog and can overlay newer catalog data from knightcode.dev. Cached catalog data remains available offline; run knightcode update --models to force a refresh.
Authenticate
Run /login and select a provider. KnightCode stores credentials in auth.json. Run /logout to remove stored credentials for a provider.
You can instead provide an API key through the provider's environment variable. This is useful in CI and other environments where KnightCode should not write credentials. Providers lists the variables and provider-specific setup.
When several credential sources are configured, KnightCode uses a runtime --api-key first, then a stored auth.json credential, an apiKey from models.json, and finally the provider's environment variables or ambient cloud credentials. Provider extensions can define their own authentication behavior.
Keep auth.json and any credential commands private. Project settings and extensions can execute inside the KnightCode process after you trust a project. Review Security before loading configuration from an untrusted directory.
Select a model
Run /model to search available models. The picker shows models whose providers have usable authentication. Press Ctrl+S (or Ctrl+D, if your terminal swallows Ctrl+S) on a model to save it as the default for new sessions.
Run /thinking to select the thinking level for the current model. Press Ctrl+S or Ctrl+D there to save the startup level. KnightCode limits the choices to levels supported by the selected model.
Ctrl+P cycles through available models. Use /scoped-models to control that cycle and save the selection, or configure model patterns through Settings.
A session records model and thinking-level changes. Resuming the session restores them without changing defaults for new sessions.
Connect local models
KnightCode integrates directly with the llama.cpp router. The router discovers GGUF files and loads models on demand. KnightCode's /llama command manages the router, while /model selects one of its loaded models.
Follow Local Models with llama.cpp for server startup, model layout, downloads, and connection troubleshooting.
For Ollama, LM Studio, vLLM, SGLang, and other compatible servers, configure a compatible endpoint in models.json.
Configure a compatible endpoint
Use models.json when an endpoint speaks an API KnightCode already supports. This includes most Ollama, LM Studio, vLLM, SGLang, and proxy deployments.
{
"$schema": "https://knightcode.dev/schemas/models.schema.json",
"providers": {
"ollama": {
"baseUrl": "http://localhost:11434/v1",
"api": "openai-completions",
"apiKey": "ollama",
"models": [
{ "id": "qwen2.5-coder:7b" }
]
}
}
}The dummy key makes the model available to KnightCode; Ollama ignores it. For an authenticated endpoint, apiKey and header values can use $NAME or ${NAME} environment interpolation, a literal value, or a leading !command. $$ and $! produce a literal $ and !. Commands in models.json run at request time and are not cached by KnightCode.
Opening /model reloads the file. A models entry adds or replaces a model with the same ID on that provider. Use modelOverrides to change metadata for an existing built-in or extension-provided model without replacing the provider's model list. Unknown override IDs are ignored.
To route a built-in provider through a proxy, set only its baseUrl. Its models and authentication stay unchanged:
{
"providers": {
"anthropic": { "baseUrl": "https://proxy.example.com/v1" }
}
}Models Configuration lists every field.
Describe model input and caching
Use inputLimits.images.resize to control how KnightCode encodes new image attachments, read results, and tool-result images before storing them in conversation history:
{
"id": "vision-model",
"input": ["text", "image"],
"inputLimits": {
"images": {
"resize": {
"maxWidth": 1568,
"maxHeight": 1568,
"maxBytes": 524288,
"jpegQuality": 75
}
}
}
}maxBytes limits the base64-encoded payload. Omitted resize fields use conservative defaults of 2000 by 2000 pixels, 4.5 MiB encoded, and JPEG quality 80. Images are encoded once; changing models does not rewrite historical images. The catalog can also describe hard request limits with inputLimits.maxRequestBytes, images.maxPerMessage, and images.maxPerRequest, but KnightCode does not yet rewrite or reject history based on them.
Use promptCache to declare the provider's best-effort cache lifetime in seconds for the short or long retention tier:
{ "id": "claude-sonnet-5", "promptCache": { "short": 300, "long": 3600 } }Choose the conservative end of any published range. A model without a lifetime for the active tier is not eligible for cache warming. A modelOverrides entry can set inputLimits or promptCache for a built-in or extension model, including a model accessed through a validated proxy. See cacheWarming.
Configure sampling by thinking level
OpenAI-compatible APIs support free-form samplingParams model defaults and samplingParamsByThinkingLevel overrides. The latter uses KnightCode thinking-level keys (off, minimal, low, medium, high, xhigh, and max), not provider values from thinkingLevelMap:
{
"id": "qwen-thinking-model",
"reasoning": true,
"samplingParams": {
"temperature": 1.0,
"top_p": 0.95
},
"samplingParamsByThinkingLevel": {
"off": {
"temperature": 0.7,
"top_p": 0.8
},
"high": {
"top_k": 20
}
}
}KnightCode first clamps unsupported thinking levels, then merges model samplingParams, the effective level's override, and request-level samplingParams in that order. Later values win per key. Missing levels inherit the model defaults. modelOverrides merges per-level entries per key with the base model. These fields apply only to openai-completions, openai-responses, and azure-openai-responses; other APIs ignore them.
Compatibility settings should describe verified differences in the endpoint's request or response behavior. Do not enable them based only on an endpoint advertising OpenAI or Anthropic compatibility.
Use classifier models
Classifier models do not chat. They answer typed questions about JSON state: pick one of several choices, answer yes or no, or give a score, each with probabilities. KnightCode includes TypeSafe's Jev model from these providers, Cloudflare's Clef, Clef Flash, and Clef Omni models from Workers AI and OpenRouter, and OpenAI's GPT-6 Luna through the Decisions API:
| Provider | Model IDs | Authentication |
|---|---|---|
typesafe | jev-latest | TYPESAFE_API_KEY |
openrouter | typesafe/jev-1.13, typesafe/jev-1.14, ~typesafe/jev-latest, cloudflare/clef, cloudflare/clef-flash, cloudflare/clef-omni | OPENROUTER_API_KEY or /login |
cloudflare-workers-ai | typesafe/jev, typesafe/jev-1.14.0, @cf/cloudflare/clef, @cf/cloudflare/clef-flash, @cf/cloudflare/clef-omni | CLOUDFLARE_API_KEY and CLOUDFLARE_ACCOUNT_ID |
vercel-ai-gateway | typesafe-ai/jev | AI_GATEWAY_API_KEY |
opencode | jev-1.13, jev-1.13-free | OPENCODE_API_KEY |
openai | gpt-6-luna | OPENAI_API_KEY |
A llama.cpp router lists decision models as native classifiers, and also lists each chat model as a classifier.
OpenAI's Decisions API needs an API key. ChatGPT sign-in does not work with it, so gpt-6-luna is not listed as available while openai is logged in through /login, even when OPENAI_API_KEY is set; log out of openai to use the key. The API rejects inputs above 922K tokens, but requests that run longer than about five seconds, currently above roughly 600K input tokens, fail with a gateway timeout.
Classifier models do not appear in /model. The classifier gate uses one to screen risky tool calls. The model reaches them through the codemode tool, which is off unless an MCP server turned it on. Enable it with "defaultTools": ["+codemode"] in settings. Scripts then list classifier models with models.getAvailableOfType("classifier") and call models.classify(model, { state, questions }):
const jev = await models.getModelOfType("classifier", "typesafe", "jev-latest");
const result = await models.classify(jev, {
state: { message: "The change works, thanks." },
questions: {
approved: {
type: "bool",
instructions: "Does the user approve of the result?",
criteria: { true: "Approval", false: "No approval" },
},
},
});
return result.answers;Codemode describes the question and answer types.
Classifier models whose input includes "image" also judge images passed in images; other classifier models return an error for them. Image input works with GPT-6 Luna, with Jev from typesafe and cloudflare-workers-ai, with Clef from cloudflare-workers-ai, and with the OpenRouter models whose catalog lists image input. Jev takes PNG and JPEG images, and image input is experimental on TypeSafe's own API. Clef takes PNG, JPEG, and WebP images, at most four per request. Jev from vercel-ai-gateway and opencode takes text only.
Each System One service takes images in its own request format, set by the model's compat.imageInput. Built-in models set it, so overriding a provider's baseUrl keeps it. A custom provider that proxies another service's classifiers sets it in its provider-level compat in models.json (see System One compatibility). OpenRouter in particular answers requests in TypeSafe's format without an error but drops the images.
When the service reports token counts, as all System One services do, result.usage carries them with their cost. KnightCode adds the usage of a script's classifier calls to the codemode tool result, so it counts toward the session cost in the footer and /session. The cost uses the model's catalog price; models without one, such as TypeSafe's direct jev-latest, report tokens at no cost.
Extensions call classifiers through ctx.modelRegistry.classify(), without codemode. Virtual models can use them to route requests; see the jev-router.ts example.
Use image models
Image models generate images from a prompt and optional input images. KnightCode lists OpenRouter's image models, such as google/gemini-2.5-flash-image and black-forest-labs/flux.2-pro, under the openrouter provider; they use the same OPENROUTER_API_KEY or /login credential as its chat models.
Like classifier models, image models do not appear in /model; the model reaches them through the codemode tool. Scripts list them with models.getAvailableOfType("image") and call models.generateImages(model, { input }). The result's output holds base64 image blocks, which image() attaches to the codemode result so the model sees them:
const painter = await models.getModelOfType("image", "openrouter", "google/gemini-2.5-flash-image");
const result = await models.generateImages(painter, {
input: [{ type: "text", text: "A red fox in the snow, watercolor" }],
});
if (result.stopReason !== "stop") return result.errorMessage;
for (const block of result.output) if (block.type === "image") image(block);input can also contain { type: "image", data, mimeType } blocks to edit or use as references. KnightCode adds the usage of a script's image calls to the codemode tool result, like classifier calls. Generated images are not saved to disk. Codemode describes the full API.
Extensions generate images through ctx.modelRegistry.generateImages(), without codemode.
Add a custom provider
Use an extension when the provider needs custom streaming, model discovery, or authentication behavior. See Custom Providers for the extension workflow.
Troubleshooting
A model does not appear
Confirm that its provider has usable authentication. Custom models can load from models.json but remain unavailable in /model until KnightCode can resolve credentials. For llama.cpp, only models currently loaded by the router appear.
Authentication works in one shell only
Check whether the key came from an environment variable rather than auth.json. Environment variables must be present in the process that starts KnightCode.
Sign-in opens a browser on a remote machine
Complete the provider's headless authentication flow when available. Some providers let you paste the final redirect URL or authorization code back into KnightCode. See Authenticate interactively.
A compatible endpoint rejects requests
Check its API type and compatibility settings in models.json. The upstream server must support the corresponding request fields and behavior.
Plan mode
Plan mode separates investigation from implementation. Enter with /plan, or send a task with /plan . The model explores, asks about unresolved trade-offs, and submits a...
Sessions and Context
KnightCode saves a conversation as a session. The active branch of that session supplies conversation history for the next model request. Use session commands to continue work,...