---
title: "Custom models"
description: "Add model entries for a supported provider API with minimal and full examples."
---

# Custom Models

Add custom providers and models such as Ollama, vLLM, LM Studio, and proxies through `models.json`. Atomic reads one file from the active agent directory, normally `~/.atomic/agent/models.json`. Set `ATOMIC_CODING_AGENT_DIR`/`PI_CODING_AGENT_DIR` to use another directory.

Atomic does not read project-scoped `.atomic/models.json`, fall back to `~/.pi/agent/models.json`, or merge `.pi` and `.atomic` model configuration files. The legacy `.pi` fallback applies only to configuration that explicitly uses layered paths, such as `auth.json`.

The interactive `/model` selector and `/scoped-models` show the current authenticated snapshot immediately. They refresh network-backed catalogs in the background for up to 15 seconds. A direct `/model <model_name>` first checks for an exact cached match. Only a miss waits for the bounded refresh, then falls back to the cache if refresh stalls or fails. Closing either selector cancels its refresh.

If refresh times out or fails, the selector reports that it is using cached models. You do not need to reset `auth.json` or `~/.atomic` for a slow catalog. Login and logout remain effective even if an older refresh finishes later.

A complete `defaultProvider`/`defaultModel` pair in `settings.json` is resolved after built-in, configured, and extension providers register. If the provider remains unsupported, interactive mode reports a generic saved-configuration warning and leaves model selection open instead of routing the session to a different provider. Print and JSON modes write that diagnostic to stderr and exit nonzero before prompting, keeping JSON stdout JSONL-clean. RPC rejects `prompt` with the same correlated diagnostic until an explicit successful `set_model` selects an available model or an explicit model cycle returns a different available model. A null or unchanged cycle result does not clear the condition. If the provider is supported but the model is unknown or lacks authentication, normal automatic selection of an available authenticated model continues. Valid custom- and extension-provider defaults resolve once their provider registration is available. See [Settings](/settings#model-&-thinking).

For editor completion and validation of providers, models, and `compat` fields, add `"$schema": "https://raw.githubusercontent.com/bastani-inc/atomic/main/packages/coding-agent/schemas/models.schema.json"` to `models.json`.

## Where to go next

This page shows minimal and full `models.json` examples you can copy. [Models Configuration](/models-configuration) lists every provider, model, override, and compatibility field directly from the schema. For extended examples, derived variants, and API behavior, see the [Model configuration guide](/models/reference).

For choosing which model to use rather than how to declare one, see [Model selection](/models/model-selection).

## Use classifier models

Classifier models answer typed questions about JSON state instead of chatting. They do not appear in `/model`. Enable [codemode](/tools#codemode), list them with `models.getAvailableOfType("classifier")`, and call `models.classify(model, { state, questions })`. See [Codemode](/codemode#classify) for question and answer shapes.

OpenAI's GPT-6 Luna Decisions classifier is `openai-decisions/gpt-6-luna`. It uses the [Decisions API](https://developers.openai.com/api/docs/guides/decisions), which needs an OpenAI API key. It has no `/login` entry of its own and reuses the first key it finds, in this order: a key saved for `openai-api`, a key saved for `openai`, then `OPENAI_API_KEY`. ChatGPT sign-in on `openai` does not work with it and is skipped, so with only a ChatGPT sign-in the classifier stays unavailable until you save an API key with `/login openai-api` or set `OPENAI_API_KEY`. `openai/gpt-6-luna` always means the chat model.

GPT-6 Luna accepts up to 128 image blocks through `images`, alongside the JSON state. Other classifiers reject images unless their catalog input and API support them. Refused answers produce an error result. The endpoint rejects inputs above 922K tokens; very large inputs, currently above roughly 600K tokens, can hit its gateway time limit. These 504 responses are not retried, so reduce the input before trying again.

TypeSafe Jev and Cloudflare Clef classifiers are also available through their providers. The direct TypeSafe classifiers, `typesafe/jev-latest` and `typesafe/jev-1.14.0`, accept up to 262K tokens and PNG or JPEG images through `images`; see [TypeSafe Jev](/providers#typesafe-jev). On Workers AI, Jev (`typesafe/jev`, `typesafe/jev-1.14.0`) takes PNG and JPEG images, and Clef, Clef Flash, and Clef Omni take PNG, JPEG, and WebP images, at most four per request. OpenRouter's Jev and Clef models accept images when their catalog entry lists image input. Jev from `vercel-ai-gateway` and `opencode` takes text only. [Local llama.cpp models](/llama-cpp#classification) support native decision models and a next-token-probability fallback for chat models.

Each System One service takes images in its own request format, which the model's `compat.imageInput` selects. Built-in models set it, so overriding a provider's `baseUrl` keeps it. A custom provider that proxies another service's classifiers sets `imageInput` and `sendImageOptInHeader` in its provider-level `compat` in `models.json`; see [System One compatibility](/models-configuration#typesafe-system-one). OpenRouter in particular answers requests in TypeSafe's format without an error but drops the images, so a proxy that reaches OpenRouter needs `"imageInput": "state-image-urls"` and `"sendImageOptInHeader": false`.

## Table of Contents

- [Minimal Example](/models#minimal-example)
- [Full Example](/models#full-example)
- [Supported APIs](/models/reference#supported-apis)
- [Provider Configuration](/models/reference#provider-configuration)
- [Model Configuration](/models/reference#model-configuration)
- [GPT-6-Astra Built-in Models](/models/reference#gpt-6-astra-built-in-models)
- [GPT-6.1 Sol](/models/reference#gpt-6-1-sol)
- [Request-wide Cost Tiers](/models/reference#request-wide-cost-tiers)
- [Overriding Built-in Providers](/models/reference#overriding-built-in-providers)
- [Per-model Overrides](/models/reference#per-model-overrides)
- [Derived Fast Model Variants](/models/reference#derived-fast-model-variants)
- [Anthropic Messages Compatibility](/models/reference#anthropic-messages-compatibility)
- [OpenAI Compatibility](/models/reference#openai-compatibility)

## Minimal Example

For local models (Ollama, LM Studio, vLLM), only `id` is required per model:

```json
{
  "providers": {
    "ollama": {
      "baseUrl": "http://localhost:11434/v1",
      "api": "openai-completions",
      "apiKey": "ollama",
      "models": [
        { "id": "llama3.1:8b" },
        { "id": "qwen2.5-coder:7b" }
      ]
    }
  }
}
```

The `apiKey` is required but Ollama ignores it, so any value works.

To route a built-in provider through a proxy, set only its `baseUrl`. Its models and authentication stay unchanged:

```json
{
  "providers": {
    "anthropic": { "baseUrl": "https://proxy.example.com/v1" }
  }
}
```

Some OpenAI-compatible servers do not understand the `developer` role used for reasoning-capable models. For those providers, set `compat.supportsDeveloperRole` to `false` so Atomic sends the system prompt as a `system` message instead. If the server also does not support `reasoning_effort`, set `compat.supportsReasoningEffort` to `false` too.

You can set `compat` at the provider level to apply to all models, or at the model level to override a specific model. This commonly applies to Ollama, vLLM, SGLang, and similar OpenAI-compatible servers.

```json
{
  "providers": {
    "ollama": {
      "baseUrl": "http://localhost:11434/v1",
      "api": "openai-completions",
      "apiKey": "ollama",
      "compat": {
        "supportsDeveloperRole": false,
        "supportsReasoningEffort": false
      },
      "models": [
        {
          "id": "gpt-oss:20b",
          "reasoning": true
        }
      ]
    }
  }
}
```

## Full Example

Override defaults when you need specific values:

```json
{
  "providers": {
    "ollama": {
      "baseUrl": "http://localhost:11434/v1",
      "api": "openai-completions",
      "apiKey": "ollama",
      "models": [
        {
          "id": "llama3.1:8b",
          "name": "Llama 3.1 8B (Local)",
          "reasoning": false,
          "input": ["text"],
          "contextWindow": 128000,
          "maxTokens": 32000,
          "cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
        }
      ]
    }
  }
}
```

Open `/model` after editing the active agent directory's `models.json` to apply changes without restarting. Invalid edits report an error.

## Google AI Studio Example

Use `google-generative-ai` with a `baseUrl` to add models from Google AI Studio, including custom Gemma 4 entries:

```json
{
  "providers": {
    "my-google": {
      "baseUrl": "https://generativelanguage.googleapis.com/v1beta",
      "api": "google-generative-ai",
      "apiKey": "$GEMINI_API_KEY",
      "models": [
        {
          "id": "gemma-4-31b-it",
          "name": "Gemma 4 31B",
          "input": ["text", "image"],
          "contextWindow": 262144,
          "reasoning": true
        }
      ]
    }
  }
}
```

The `baseUrl` is required when adding custom models to the `google-generative-ai` API type.

## Supported APIs

Moved to [Model configuration reference](/models/reference#supported-apis).

## Provider Configuration

Moved to [Model configuration reference](/models/reference#provider-configuration).

### Value Resolution

Moved to [Model configuration reference](/models/reference#value-resolution).

### Custom Headers

Moved to [Model configuration reference](/models/reference#custom-headers).

## Model Configuration

Moved to [Model configuration reference](/models/reference#model-configuration).

### Sampling Parameters

Moved to [Model configuration reference](/models/reference#sampling-parameters).

### Sampling by Thinking Level

Moved to [Model configuration reference](/models/reference#sampling-by-thinking-level).

### Request-wide Cost Tiers

Moved to [Model configuration reference](/models/reference#request-wide-cost-tiers).

### Thinking Level Map

Moved to [Model configuration reference](/models/reference#thinking-level-map).

### Context Window

Moved to [Model configuration reference](/models/reference#context-window).

## Overriding Built-in Providers

Moved to [Model configuration reference](/models/reference#overriding-built-in-providers).

## Per-model Overrides

Moved to [Model configuration reference](/models/reference#per-model-overrides).

## Derived Fast Model Variants

Moved to [Model configuration reference](/models/reference#derived-fast-model-variants).

## Anthropic Messages Compatibility

Moved to [Model configuration reference](/models/reference#anthropic-messages-compatibility).

### Forced tool use on Claude Fable 5.1

Moved to [Model configuration reference](/models/reference#forced-tool-use-on-claude-fable-5-1).

### Preserved thinking and model switches

Moved to [Model configuration reference](/models/reference#preserved-thinking-and-model-switches).

## OpenAI Compatibility

Moved to [Model configuration reference](/models/reference#openai-compatibility).

### Constrained tool sampling

Moved to [Model configuration reference](/models/reference#constrained-tool-sampling).

### Catalog freshness and precedence

Moved to [Model configuration reference](/models/reference#catalog-freshness-and-precedence).

## GPT-6-Astra Built-in Models

Moved to [Model configuration reference](/models/reference#gpt-6-astra-built-in-models).
