Custom & Local Models

Copair ships with capability data for ~60 well-known model families. When you point it at something it doesn't recognize — a fine-tune, a renamed GGUF, a private endpoint, a brand-new release — it asks you to declare the model rather than silently guessing. This page is the one-line fix.

When you need this

You need a model_overrides entry when copair doesn't recognize your model ID. That covers:

  • Local models with custom names (Ollama tags, llama.cpp GGUFs, LM Studio identifiers)
  • Fine-tunes and merges (my-org/qwen-finetune-7b)
  • Models newer than your copair version
  • Any OpenAI-compatible endpoint serving a non-standard model name

If copair does recognize your model, you don't need anything here — it derives sensible defaults automatically. Run copair --explain-model <id> to check.

The error you saw

If copair refused to start with something like this, you're in the right place:

Unknown model "my-finetune-7b" (normalized: "my-finetune-7b"). Add it to
model_overrides in your config with at least `tier: small | large`.
See: https://copair.dugleelabs.io/docs/custom-and-local-models

Or check the shipped registry: data/model-capabilities.json

This is deliberate. Before, an unknown model silently fell back to large-tier defaults — which quietly disengaged the small-model harness for models that needed it and led to wasted tokens and confusing behavior. Now copair tells you exactly what to declare.

Minimal config

Add the model to model_overrides in ~/.copair/config.yaml with at least a tier:

version: 1

model_overrides:
  my-finetune-7b:
    tier: small   # or large

That's the whole fix. tier: small engages the small-model harness (one-tool-at-a-time prompting, format reminders, the loop guard, format-error repair). tier: large runs without it. Everything else — preferred tool-call format, context window, max output — is derived from generic defaults. Override more fields only if those defaults are wrong for your endpoint.

The key is the model id (the id: you configured for the provider), not the provider alias. Copair normalizes it for you, so org prefixes like Qwen/ and host prefixes like Bedrock's qwen. are handled automatically — write the id as you have it.

Field reference

Every field below is optional except where your endpoint differs from the defaults. Set only what you need; the rest falls through.

FieldTypeWhat it controls
tiersmall | largeWhether the small-model harness engages. The one field unknown models must set.
context_windownumberTotal token budget for context-limit detection. Default 32k.
max_tokensnumberMax output tokens. Default 4k.
preferred_formatqwen-xml | dsml | fenced-block | nativeTool-call markup to prompt for. Derived from the model family by default.
native_tool_callingreliable | unreliable | noneWhether to trust the provider's native tool-calling API.
recommended_harnessobjectFine-grained harness flags (max_tool_calls, max_turns, …).

A fuller record:

model_overrides:
  my-finetune-7b:
    tier: small
    context_window: 131072
    max_tokens: 8192
    preferred_format: qwen-xml

See Model Capabilities for how these values resolve and what --explain-model shows.

Common patterns

The local-server config below pairs a provider block (how to reach the server) with a model_overrides entry (how to classify the model). The two are independent — model_overrides keys are model ids, not provider aliases.

Ollama

version: 1
default_model: local

providers:
  ollama:
    type: openai-compatible
    base_url: http://localhost:11434/v1
    models:
      local:
        id: my-finetune-7b      # `ollama list` name
        supports_tool_calling: false

model_overrides:
  my-finetune-7b:
    tier: small

llama.cpp

providers:
  llamacpp:
    type: openai-compatible
    base_url: http://localhost:8080/v1
    models:
      local:
        id: qwen2.5-coder-7b-instruct-q4_k_m   # the GGUF name the server reports
        supports_tool_calling: false

model_overrides:
  qwen2.5-coder-7b-instruct-q4_k_m:
    tier: small

vLLM

providers:
  vllm:
    type: openai-compatible
    base_url: http://localhost:8000/v1
    models:
      local:
        id: my-org/Qwen2.5-7B-finetune        # the --served-model-name

model_overrides:
  my-org/Qwen2.5-7B-finetune:
    tier: small

LM Studio

providers:
  lm_studio:
    type: openai-compatible
    base_url: http://localhost:1234/v1
    models:
      local:
        id: my-finetune-7b                     # the model name shown in LM Studio
        supports_tool_calling: false

model_overrides:
  my-finetune-7b:
    tier: small

Custom OpenAI-compatible providers

Any endpoint speaking the OpenAI chat-completions protocol works the same way: declare the provider as type: openai-compatible, point base_url at it, and add a model_overrides entry for whatever model id it serves. API keys interpolate from the environment:

providers:
  my_host:
    type: openai-compatible
    base_url: https://api.example.com/v1
    api_key: ${MY_HOST_API_KEY}
    models:
      house-model:
        id: house-llm-v2

model_overrides:
  house-llm-v2:
    tier: large

Amazon Bedrock

Copair doesn't ship a native Bedrock provider (no AWS SigV4 signing), but you can use Bedrock-hosted models through an OpenAI-compatible gateway in front of Bedrock — for example LiteLLM or the Bedrock Access Gateway. Run the gateway, then point copair at it like any other OpenAI-compatible endpoint:

providers:
  bedrock:
    type: openai-compatible
    base_url: http://localhost:4000/v1   # your gateway's OpenAI endpoint
    api_key: ${LITELLM_MASTER_KEY}        # or whatever the gateway expects
    models:
      qwen-coder:
        id: qwen.qwen3-coder-480b-a35b-v1:0   # the Bedrock model id, as-is

model_overrides:
  qwen.qwen3-coder-480b-a35b-v1:0:
    tier: large

You can write the Bedrock model id exactly as Bedrock names it — copair normalizes host prefixes (anthropic., qwen., regional us. / eu.) before matching, so qwen.qwen3-coder-480b-a35b-v1:0 classifies the same as the Ollama or Together form of the same model. If the specific SKU isn't in copair's shipped data, add the model_overrides entry shown above with at least a tier. Run copair --explain-model <bedrock-id> to confirm how it resolves.

Troubleshooting

Still seeing Unknown model "X" after adding the entry. The override key must match the model id, not the provider alias. Run copair --explain-model <id> with the exact id from your provider config — the normalized form it prints is what model_overrides matches against.

The model behaves oddly / burns tokens. It may be on the wrong tier. A small open-weight model set to tier: large runs without the harness it needs; a large model set to tier: small gets unnecessary scaffolding. Flip the tier and compare.

Tool calls aren't parsing. Set preferred_format to match what your model actually emits — qwen-xml for Qwen-family, dsml for DeepSeek, fenced-block as a generic fallback. copair --explain-model <id> shows the format copair will prompt for.

For the full resolution model and field semantics, see Model Capabilities.

Last updated June 2, 2026