models.json Configuration Guide
Overview
models.json is a configuration file used to customize the model list and control the model dropdown display. This configuration supports two levels:
- User-level:
~/.codebuddy/models.json- Global configuration applicable to all projects - Project-level:
<workspace>/.codebuddy/models.json- Project-specific configuration with higher priority than user-level
Configuration File Locations
User-level Configuration
~/.codebuddy/models.jsonProject-level Configuration
<project-root>/.codebuddy/models.jsonConfiguration Priority
Configuration merge priority from highest to lowest:
- Project-level models.json
- User-level models.json
- Built-in default configuration
Project-level configuration will override user-level configuration for the same model definitions (based on id field matching). availableModels field: project-level completely overrides user-level, no merging.
Configuration Structure
json
{
"models": [
{
"id": "model-id",
"name": "Model Display Name",
"vendor": "vendor-name",
"apiKey": "sk-actual-api-key-value",
"maxInputTokens": 200000,
"maxOutputTokens": 8192,
"url": "https://api.example.com/v1/chat/completions",
"temperature": 0.7,
"supportsToolCall": true,
"supportsImages": true
}
],
"availableModels": ["model-id-1", "model-id-2"]
}Configuration Field Description
models
Type: Array<LanguageModel>
Define custom model list. You can add new models or override built-in model configurations.
LanguageModel Fields
| Field | Type | Required | Description |
|---|---|---|---|
id | string | ✓ | Model unique identifier |
name | string | - | Model display name |
vendor | string | - | Model vendor (e.g., OpenAI, Google) |
apiKey | string | - | API key, supports environment variable references (see Security Configuration below) |
maxInputTokens | number | - | Maximum input tokens |
maxOutputTokens | number | - | Maximum output tokens |
url | string | - | API endpoint URL, supports environment variable references (must be complete interface path, typically ending with /chat/completions) |
temperature | number | - | Sampling temperature, range 0-2, higher values produce more random output, lower values produce more deterministic output |
supportsToolCall | boolean | - | Whether tool calls are supported |
supportsImages | boolean | - | Whether image input is supported |
supportsReasoning | boolean | - | Whether reasoning mode is supported |
relatedModels | object | - | Related model configuration, specifies which model id to use in different scenarios (lite/reasoning/vision/longContext/subagent). See Configuring Related Models for details |
Important Notes:
- Currently only supports OpenAI interface format API
urlfield must be the complete interface path, typically ending with/chat/completions- Examples:
https://api.openai.com/v1/chat/completionsorhttp://localhost:11434/v1/chat/completions
Security Configuration: Using Environment Variable References
To avoid storing API keys in plain text in configuration files, the apiKey and url fields support environment variable reference syntax ${VAR_NAME}.
Syntax Format:
${ENVIRONMENT_VARIABLE_NAME}Configuration Example:
json
{
"models": [
{
"id": "gpt-4o",
"name": "GPT-4o",
"vendor": "OpenAI",
"apiKey": "${OPENAI_API_KEY}",
"url": "https://api.openai.com/v1/chat/completions"
}
]
}Setting Environment Variables:
bash
# Add to ~/.zshrc or ~/.bashrc
export OPENAI_API_KEY="sk-your-actual-api-key"
# Or set temporarily at startup
OPENAI_API_KEY="sk-xxx" codebuddyUsing System Keychain (macOS):
bash
# Store key in Keychain
security add-generic-password -a "$USER" -s "openai-api-key" -w "sk-xxx"
# Configure auto-export in ~/.zshrc
export OPENAI_API_KEY=$(security find-generic-password -s "openai-api-key" -w 2>/dev/null)Important Notes:
- Environment variables are resolved at CLI startup
- If an environment variable doesn't exist, the original placeholder is retained (which will cause API call failures)
- It's recommended to set
models.jsonfile permissions to600(owner read/write only) - Do not commit configuration files containing actual keys to version control systems
availableModels
Type: Array<string>
Control which models are displayed in the model dropdown list. Only model IDs listed in this array will be shown in the UI.
- If not configured or empty array, all models are displayed
- When configured, only listed model IDs are displayed
- Can include both built-in and custom model IDs
Use Cases
1. Add Custom Model
Add new model configuration at user or project level:
json
{
"models": [
{
"id": "my-custom-model",
"name": "My Custom Model",
"vendor": "OpenAI",
"apiKey": "sk-custom-key-here",
"maxInputTokens": 128000,
"maxOutputTokens": 4096,
"url": "https://api.myservice.com/v1/chat/completions",
"supportsToolCall": true
}
]
}2. Override Built-in Model Configuration
Modify default parameters of built-in models:
json
{
"models": [
{
"id": "gpt-4-turbo",
"name": "GPT-4 Turbo (Custom Endpoint)",
"vendor": "OpenAI",
"url": "https://my-proxy.example.com/v1/chat/completions",
"apiKey": "sk-your-key-here"
}
]
}3. Limit Available Model List
Only display specific models in the dropdown list:
json
{
"availableModels": [
"gpt-4-turbo",
"gpt-4o",
"my-custom-model"
]
}4. Project-Specific Configuration
Use different models or API endpoints for specific projects:
Project A (.codebuddy/models.json):
json
{
"models": [
{
"id": "project-a-model",
"name": "Project A Model",
"vendor": "OpenAI",
"url": "https://project-a-api.example.com/v1/chat/completions",
"apiKey": "sk-project-a-key",
"maxInputTokens": 100000,
"maxOutputTokens": 4096
}
],
"availableModels": ["project-a-model", "gpt-4-turbo"]
}Hot Reload
Configuration file supports hot reload:
- File changes are automatically detected
- Uses 1 second debounce delay to avoid frequent reloads
- Configuration updates are automatically synced to the application
Monitored files:
~/.codebuddy/models.json(user-level)<workspace>/.codebuddy/models.json(project-level)
Tagging System
Models added through models.json are automatically tagged with the custom tag for easy identification and filtering in the UI.
Merge Strategy
Configuration uses SmartMerge strategy:
- Model configurations with the same ID are overridden
- Models with different IDs are appended
- Project-level configuration takes priority over user-level configuration
availableModelsfiltering is executed after all merging is complete
Example Configurations
API Endpoint URL Format
Must use complete path: All custom model url fields should typically end with /chat/completions.
✅ Correct Examples:
https://api.openai.com/v1/chat/completions
https://api.myservice.com/v1/chat/completions
http://localhost:11434/v1/chat/completions
https://my-proxy.example.com/v1/chat/completions❌ Incorrect Examples:
https://api.openai.com/v1
https://api.myservice.com
http://localhost:11434OpenRouter Platform Configuration Example
Using OpenRouter to access various models:
json
{
"models": [
{
"id": "openai/gpt-4o",
"name": "open-router-model",
"url": "https://openrouter.ai/api/v1/chat/completions",
"apiKey": "sk-or-v1-your-openrouter-api-key",
"maxInputTokens": 128000,
"maxOutputTokens": 4096,
"supportsToolCall": true,
"supportsImages": false
}
]
}DeepSeek Platform Configuration Example
Using DeepSeek models (once url is configured, even entries with the same id as cloud defaults take effect with "full replacement" semantics and are not overridden by cloud default merges):
json
{
"models": [
{
"id": "deepseek-v4-pro",
"name": "DeepSeek V4 Pro",
"vendor": "DeepSeek",
"url": "https://api.deepseek.com/v1/chat/completions",
"apiKey": "${DEEPSEEK_API_KEY}",
"maxInputTokens": 128000,
"maxOutputTokens": 8192,
"supportsToolCall": true,
"supportsImages": false
},
{
"id": "deepseek-v4-flash",
"name": "DeepSeek V4 Flash",
"vendor": "DeepSeek",
"url": "https://api.deepseek.com/v1/chat/completions",
"apiKey": "${DEEPSEEK_API_KEY}",
"maxInputTokens": 128000,
"maxOutputTokens": 8192,
"supportsToolCall": true,
"supportsImages": false
}
],
"availableModels": [
"deepseek-v4-pro",
"deepseek-v4-flash"
]
}Set the API key environment variable and start:
bash
export DEEPSEEK_API_KEY="<your-deepseek-api-key>"
codebuddy --model deepseek-v4-proTip: If you prefer not to maintain a
models.json, you can also connect to DeepSeek entirely through environment variables. See env-vars.md DeepSeek Integration Example.
Configuring Related Models
During a single CodeBuddy Code session, the model is switched based on the scenario, to avoid using a large model for simple tasks or a general-purpose model for requests that need reasoning / vision / long-context. These scenarios are declared via the relatedModels field on a model entry.
Supported scenarios (variant type):
| Scenario | Purpose | Current Status |
|---|---|---|
lite | Lightweight fast model, used for background extraction, summarization, and other low-value requests; also the model corresponding to the Agent tool's model: "lite" parameter | Active |
reasoning | Reasoning-enhanced model, used for complex reasoning requiring deep thinking; the model corresponding to the Agent tool's model: "reasoning" parameter | Active |
subagent | Default model used by sub-agents / team members | Reserved, not yet active — sub-agents use a separate subagents resolution chain and do not read this field |
vision | Vision understanding model, used for requests that need to process images | Reserved, not yet active — the type is defined but there is no call site consuming this variant |
longContext | Long-context model, used for requests with very long context | Reserved, not yet active — the type is defined but there is no call site consuming this variant |
Currently actually usable: only the two variants
liteandreasoningare consumed by the agent-manager and mapped into the model switching logic.subagent/vision/longContextare only kept in the type definitions, reserved for future iterations; writing them intorelatedModelstoday will not error but will also have no effect.
Key rule (must-read for custom models):
Custom models added via
models.jsondo not inherit the product's built-indefaultRelatedModels. If a custom main model does not declarerelatedModels, and there is no environment variable orvariantModelsoverride,liteandreasoningwill fall back to the main model. Sub-agents do not readrelatedModels.subagent, but sub-agents configured asliteorreasoningwill still go through the variant resolution chain to determine the concrete model.
Configuration example (DeepSeek main model + flash as lite / reasoning):
json
{
"models": [
{
"id": "deepseek-v4-pro",
"name": "DeepSeek V4 Pro",
"vendor": "DeepSeek",
"url": "https://api.deepseek.com/v1/chat/completions",
"apiKey": "${DEEPSEEK_API_KEY}",
"maxInputTokens": 128000,
"maxOutputTokens": 8192,
"supportsToolCall": true,
"relatedModels": {
"lite": "deepseek-v4-flash",
"reasoning": "deepseek-v4-pro"
}
},
{
"id": "deepseek-v4-flash",
"name": "DeepSeek V4 Flash",
"vendor": "DeepSeek",
"url": "https://api.deepseek.com/v1/chat/completions",
"apiKey": "${DEEPSEEK_API_KEY}",
"maxInputTokens": 128000,
"maxOutputTokens": 8192,
"supportsToolCall": true
}
],
"availableModels": [
"deepseek-v4-pro",
"deepseek-v4-flash"
]
}Variant resolution priority (from highest to lowest; currently only lite / reasoning go through this resolution chain):
- Corresponding environment variables (
CODEBUDDY_SMALL_FAST_MODELforlite,CODEBUDDY_BIG_SLOW_MODELforreasoning) - Project-level
variantModels[variant] - User global
variantModels[variant] relatedModels[variant]on the current main model entry- The product's built-in
defaultRelatedModels[variant](only takes effect for built-in models; custom models skip this step) - Fall back to the main model itself
variantModels is stored in settings.json and can also be edited via the /model:lite / /model:reasoning commands. It is suitable for fixing lite / reasoning to specific models within the user or project scope; relatedModels is suitable for letting the mapping follow the current main model.
Built-in sub-agent resolution priority (from highest to lowest):
CODEBUDDY_CODE_SUBAGENT_MODEL, universally covers all sub-agents- The Agent tool's
modelparameter - Project-level
subagents.agents.<subagent-name>.model - User global
subagents.agents.<subagent-name>.model - Product built-in declaration, e.g.,
Exploreuseslite - Inherit the main conversation model
Sub-agent models do not read relatedModels.subagent. When a sub-agent is configured as lite or reasoning, it will continue through the variant resolution chain above to determine the concrete model.
The following configuration should be written to user-level or project-level settings.json:
json
{
"subagents": {
"agents": {
"Explore": { "model": "lite" },
"Plan": { "model": "reasoning" }
}
},
"variantModels": {
"lite": "<fast-model-id>",
"reasoning": "<reasoning-model-id>"
}
}When to use different configuration approaches:
- Use
relatedModelsto let scenario mapping follow the main model. - Use
variantModelsor/modelto fix specificlite/reasoningmodels within the user or project scope. - Use
subagents.agents.<subagent-name>.modelor/agentsto select models or scenario variants for built-in sub-agents individually. - Use model environment variables for CI-level overrides. Environment variables take priority over persistent settings; after unsetting, the lower-priority settings will take effect again.
Complete Example
json
{
"models": [
{
"id": "gpt-4o",
"name": "GPT-4o",
"vendor": "OpenAI",
"apiKey": "sk-your-openai-key",
"maxInputTokens": 128000,
"maxOutputTokens": 16384,
"supportsToolCall": true,
"supportsImages": true
},
{
"id": "my-local-llm",
"name": "My Local LLM",
"vendor": "Ollama",
"url": "http://localhost:11434/v1/chat/completions",
"apiKey": "ollama",
"maxInputTokens": 8192,
"maxOutputTokens": 2048,
"supportsToolCall": true
}
],
"availableModels": [
"gpt-4o",
"my-local-llm"
]
}Troubleshooting
Configuration Not Taking Effect
- Check if JSON format is correct
- Confirm file path is correct
- View log output to confirm configuration is loaded
- Confirm API keys in environment variables are set
Model Not Showing in List
- Check if model ID is listed in
availableModels - Confirm
modelsconfiguration is correct - Verify all required fields (
id,name,provider) are provided
Hot Reload Not Triggered
- Configuration file changes have 1 second debounce delay
- Ensure file is actually saved to disk
- Check if file watching started normally (view debug logs)