Select the model of OpenCode in Docker: the free model, OpenCode Go or OpenRouter

Introduction

This article is part of a larger manual, OpenCode in Docker on Ubuntu 24.04.

The manual shows how to run OpenCode with the --auto option inside a Docker container.

With --auto the agent does not ask you before each command, so the container limits what it can reach: the agent works only in one git worktree, a separate copy of the project.

This article explains how a task gets its model: where the model is set, how to check it before you start, and how to run a task on a paid model of OpenCode Go or OpenRouter, for one run or for every run.

Where the model comes from

A run uses the model that the config file of the container names, unless you name another model with -m.

The config file is container/tools/ai/docker/opencode.jsonc in your main checkout.

You wrote it in step 4 (the config and the container notes).

The launcher mounts this file into every container, read-only, as /work/opencode.jsonc, and OpenCode reads it when it starts. Which model the file names:

grep '"model"' container/tools/ai/docker/opencode.jsonc

"model": "opencode/deepseek-v4.1-flash-free",

The same check in the shell of step 6 (check what the container sees) shows what OpenCode itself read:

opencode debug config | grep -A3 '"model": {'

"model": { "providerID": "opencode", "model": "deepseek-v4.1-flash-free" },

The first choice: the free OpenCode model

The model in the file is the current free OpenCode model.

It is the first choice of this setup: it costs nothing and needs no key, so the container holds no key.

A run without -m and without a key option runs on it.

That is why the commands of the manual use the free model unless they say otherwise.

Another model for one run: -m

-m after run picks the model for this run only.

A paid model also needs its key: put the key option of the launcher and its file before the worktree.

The config file does not change, so the next run without -m runs on the free model again:

RunModel
container/tools/ai/opencode-docker.sh ../site-agent-<task> run "<what to do>"the model of the config file: the free OpenCode model
container/tools/ai/opencode-docker.sh --opencode-key ~/.config/opencode-agent/opencode.key ../site-agent-<task> run -m opencode-go/deepseek-v4.1-flash "<what to do>"DeepSeek V4.1 Flash through OpenCode Go, for this run
container/tools/ai/opencode-docker.sh --openrouter-key ~/.config/opencode-agent/openrouter.key ../site-agent-<task> run -m openrouter/deepseek/deepseek-v4.1-flash "<what to do>"DeepSeek V4.1 Flash through OpenRouter, for this run

The model ids are the lines of opencode models in the shell of step 6, for example opencode models | grep '^opencode-go/' or opencode models | grep '^openrouter/'.

Prices change, so check them before a long task (verify prices before budgeting).

A paid model needs a key

The key has to be in the container, and the agent can read it.

Use a key made for this, with a spending limit, and never mount the auth.json of the host.

The container gets the key in one of two ways:

Without a key the run stops at once, before it sends anything.

Tested on a throwaway volume, with -m and no key:

Error: Model unavailable: openrouter/deepseek/deepseek-v4.1-flash

Which model a run really used

The first line of the output of a run is the agent and the model, as in the demo with the free model:

> build ยท deepseek-v4.1-flash-free

Another model for every run

Change the model line in the config file on the host.

The launcher mounts the file of your main checkout, so the next run uses the new model without a commit.

With a paid model there, every run needs its key, and the free model is then the one you pick with -m.

Article author: Klavdiya Kondakova

Banner image