Skip to content

Course · OpenCode · Getting started

Bring your own model

OpenCode needs a model before it does useful work, and the reason is the thing that sets it apart from single-vendor terminal agents. Claude Code is built around Anthropic’s models and Codex around OpenAI’s. OpenCode is provider-agnostic by design, which means the very first decision it hands back to you is one those tools largely make on your behalf: which provider’s model is going to run the loop? (The loop is the agent’s prompt, tool-call, and edit cycle - the next page walks one full turn of it.)

That’s not a hurdle. It’s the whole pitch. You bring a key you already have - Anthropic, OpenAI, an OpenRouter account, whatever’s in your drawer - or a model you serve locally, and OpenCode drives your repository with it (this course works against feedmill, an illustrative Go feed aggregator, but any repo you own works the same). So the first move isn’t a task. It’s wiring up credentials.

Open the TUI (OpenCode’s full-screen terminal interface - run opencode in your repo) and run the connect command. An illustrative rendering of the picker:

> /connect
Select a provider to authenticate
❯ Anthropic
OpenAI
OpenRouter
Google (Gemini / Vertex AI)
Groq
Amazon Bedrock
Azure OpenAI
… 75+ providers
Anthropic → paste API key: ********************************
✓ Connected. Credentials saved.

That list isn’t OpenCode trying to support a handful of vendors it had time for. It ships with 75+ providers preloaded (as of October 2026) from the Models.dev catalog - Anthropic, OpenAI, OpenRouter, Groq, Google, Amazon Bedrock, Azure OpenAI, and a long tail beyond - so the provider you already pay for is almost certainly already in the picker. For a hosted provider you’re not configuring an integration; you’re handing over a key.

A local model is the exception, because there is no key to paste. Ollama, LM Studio, and llama.cpp each run an OpenAI-compatible server on your machine, and you point OpenCode at it with a provider block in opencode.json (the config file at your repo root): the @ai-sdk/openai-compatible package, a baseURL, and the models to expose. For Ollama, the documented shape is this (as of October 2026; see the local-model sections of the providers documentation):

opencode.json
{
"$schema": "https://opencode.ai/config.json",
"provider": {
"ollama": {
"npm": "@ai-sdk/openai-compatible",
"name": "Ollama (local)",
"options": {
"baseURL": "http://localhost:11434/v1"
},
"models": {
"llama2": {
"name": "Llama 2"
}
}
}
}
}

Replace llama2 with a model you have pulled. /connect is not needed for these. Drive it with a local or custom model walks through the whole setup.

Prefer to stay on the command line, or scripting your setup? The same thing happens outside the TUI (the auth commands are documented in the CLI reference, as of October 2026):

Terminal window
$ opencode auth login

It walks you through the identical provider picker and key prompt, and on success drops the credential into ~/.local/share/opencode/auth.json. opencode auth list shows what you’ve connected and opencode auth logout removes one - handy when you’re rotating a key or clearing a machine you don’t own.

Connect more than one if you have them. There’s no penalty, and the providers and models chapter gets a lot more interesting once OpenCode can reach two or three providers at once. Parsing feedmill’s gnarly Atom edge cases is a different job from drafting its README, and being able to put a different model on each is exactly the leverage you’re buying here.

Connecting a provider unlocks its catalog; it doesn’t choose for you. That’s /models - an illustrative picker (catalogs move, so read yours live rather than off this page):

> /models
anthropic/claude-sonnet-4-5
anthropic/claude-opus-4-5
anthropic/claude-haiku-4-5
openai/gpt-5.2
openrouter/…
❯ select a model

OpenCode references every model as provider/model - the provider you connected, a slash, the model id. anthropic/claude-sonnet-4-5, openai/gpt-5.2, ollama/llama3.1. The slash is load-bearing: it’s why OpenCode can hold credentials for several providers at once and never has to guess which one you mean. /models lists what your connected providers offer; connect three and you’re choosing across all three in one menu. Connect nothing (and have no provider key in your environment) and the list holds at most the free models that OpenCode’s own Zen provider serves without a key (as of October 2026, per the provider loader in provider/provider.ts). Pick one here and it drives the loop from now on.

OpenCode remembers that pick. When it starts, it chooses the model in this order: the --model (-m) flag, then the model key in config, then the last model you used, then an internal default (as of October 2026; see “Loading models” in the models documentation).

Relying on the last-used model is fine while you’re trying providers out. Once you’ve settled, write the choice down: a model in config outranks the last-used model, so the repo starts on the same model for you, for a teammate, and on a fresh machine - as long as that machine has credentials for the provider the model names. The top-level model field in opencode.json is the project-wide default. Create opencode.json at the repo root if it doesn’t exist yet; the same key in your global config, ~/.config/opencode/opencode.json, sets a default for every repo, and the project file wins where both set it (config documentation, as of October 2026):

{
"$schema": "https://opencode.ai/config.json",
"model": "anthropic/claude-sonnet-4-5"
}

Drop that in feedmill’s opencode.json and every session in this repo starts on that model. Want to override it for a single run - say, to throw a cheaper model at a throwaway question - reach for the flag instead of editing config:

Terminal window
$ opencode run -m anthropic/claude-haiku-4-5 "what does the dedupe step key on?"

--model (or -m) takes the same provider/model string and wins for that one invocation, leaving your committed default untouched. The providers and models chapter leans on both of these hard, where putting the right model on the right job stops being a convenience and becomes the difference between a parser refactor that lands and one that flails. For now you need a default that lets the loop run. The default model sets the capability and the cost of every turn, so pick a capable mid-tier model as the default and pass -m when one run needs a cheaper or a stronger one.

A provider is connected and a model is chosen, which answers the question of whose model runs the loop. The next question is what the agent actually does with a prompt - understand one turn of the loop.