> ## Documentation Index
> Fetch the complete documentation index at: https://docs.getcanonic.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Configuring an LLM

> canonic's answer path is fully deterministic; an LLM is optional and only used to draft context.

An LLM is **optional**; canonic's answer path is fully deterministic and never calls one. It's only used to *draft* semantics/knowledge during setup and reconciliation. The `llm:` block in `canonic.yaml` supports four providers, all behind the same interface.

<Tabs>
  <Tab title="openai_compatible">
    Local runtimes (Ollama, vLLM, LM Studio, llama.cpp, TGI) or any hosted OpenAI-compatible endpoint. `base_url` is required; a key is optional (local servers typically need none):

    ```yaml theme={null}
    llm:
      provider: openai_compatible
      base_url: http://127.0.0.1:11434/v1   # Ollama; swap for any OpenAI-compatible endpoint
      model: gemma-4-e2b-it-4bit
      api_key_ref: env:CANONIC_LLM_API_KEY   # optional
    ```
  </Tab>

  <Tab title="anthropic">
    Claude, called directly. No `base_url` needed; `api_key_ref` is required:

    ```yaml theme={null}
    llm:
      provider: anthropic
      model: claude-opus-4-8
      api_key_ref: env:ANTHROPIC_API_KEY
    ```
  </Tab>

  <Tab title="openai">
    OpenAI's hosted API directly (not a self-hosted/compatible endpoint). No `base_url` needed; `api_key_ref` is required:

    ```yaml theme={null}
    llm:
      provider: openai
      model: gpt-4o
      api_key_ref: env:OPENAI_API_KEY
    ```
  </Tab>

  <Tab title="github_copilot">
    Routed through your GitHub Copilot subscription. No `base_url`, and **no `api_key_ref`**: authentication is a one-time device-code flow (a browser prompt on first use); the resulting credential is cached on disk and reused after that:

    ```yaml theme={null}
    llm:
      provider: github_copilot
      model: gpt-4.1
    ```

    <Warning>
      Structured/schema-constrained output (used for drafting) isn't honored by every model Copilot proxies; Claude and most GPT models silently return prose instead of JSON. Stick to a model litellm marks as schema-capable for this provider (`gpt-4.1`, `gpt-5`, `gpt-5.1`, `gpt-5.2`) if you hit `structured_output_unsupported`.
    </Warning>
  </Tab>
</Tabs>

## One interface, any provider

All four are reached through [litellm](https://github.com/BerriAI/litellm) behind one interface; no per-provider branching anywhere else in canonic. `tasks:` optionally overrides the model per task (`draft`, `reconcile`):

```yaml theme={null}
llm:
  provider: anthropic
  model: claude-haiku-4-5
  api_key_ref: env:ANTHROPIC_API_KEY
  tasks:
    reconcile: claude-opus-4-8   # a harder task gets a stronger model
```

## Air-gapped mode

Under `runtime.air_gapped: true`, only a local endpoint (loopback, or an allowlisted host via `runtime.allow_cidrs`) is accepted; `openai`, `anthropic`, and `github_copilot` all call a fixed public endpoint and are rejected outright in that mode.
