docker agent is Docker’s agent runtime (the CLI plugin built on the open-source cagent project — you’ll
see that name in ~/.config/cagent). Its whole contract is a single YAML file: one block describing agents,
one describing models. Nothing stops you from pointing the model block at localhost, which is the
interesting part — the same declarative agent, tools and all, running against a model on your own machine.
The whole file
agents:
root:
description: Software Engineer
instruction: You are a helpful assistant.
model: omlx
commands:
cheese: What is the best French cheese?
# Optional tools – adjust to your taste
toolsets:
- type: filesystem
- type: shell
- type: think
- type: script
shell:
get_ip:
cmd: "curl -s https://ipinfo.io | jq -r .ip"
description: "Get public IP"
models:
omlx:
provider: openai
model: gemma-4-e4b-it-4bit
base_url: http://localhost:8000/v1
token_key: OMLX_API_KEYRun it:
docker agent run ./config.yamlThat’s it — no image to build, no compose file. The TUI opens and you’re talking to a model served from your own laptop.
What each block does
agents.root — root is the entry point. A file with a single agent is the common case; add siblings
and the extra agents become delegates the root can hand work to. description is what other agents see,
instruction is the system prompt the model sees.
model: omlx — a reference into the models map, not a model name. The indirection is what makes the
config portable: swap the omlx definition for a hosted provider and every agent follows.
commands — named prompt shortcuts, exposed as slash commands in the session. cheese above becomes
/cheese, which expands to its instruction and sends it. Handy for the three or four prompts you retype
every day (/review-diff, /explain-this-error).
toolsets — what the agent is allowed to do. filesystem, shell and think are built-in types;
script is the escape hatch that turns any shell one-liner into a named tool with a description the model
can reason about. docker agent toolsets lists all the built-in types (there are 26, including git,
memory, rag, mcp and fetch).
models.omlx — provider: openai here means the OpenAI wire protocol, not OpenAI the company. Any
server that speaks /v1/chat/completions works: mlx-omni-server
(the omlx in this config), llama.cpp’s server, LM Studio, vLLM, Ollama’s compat endpoint. The base_url
must include the /v1 suffix.
Verify before you trust it
Two subcommands are worth knowing. debug toolsets resolves the config and prints the exact tools the
model will be offered:
docker agent debug toolsets ./config.yaml12 tool(s) for root:
+ directory_tree - Get a recursive tree view of files and directories as a JSON structure.
+ edit_file - Make line-based edits to a text file. ...
+ list_directory - Get a detailed listing of all files and directories in a specified path.
+ read_file - Read the contents of a file from the file system. ...
+ read_multiple_files - Read the contents of multiple files simultaneously.
+ search_files_content - Searches for text or regex patterns ...
+ write_file - Create a new file or completely overwrite an existing file with new content.
+ create_directory - Create one or more new directories or nested directory structures.
+ remove_directory - Remove one or more empty directories.
+ shell - Executes the given shell command with zsh on macOS.
+ think - Use the tool to think about something. ...
+ get_ip - Get public IPNote that - type: filesystem alone expanded to nine tools, write_file and edit_file among them. On a
small local model, that’s a lot of surface area — drop the toolsets you don’t need rather than pasting the
list from a tutorial.
And debug config prints the canonical form, with every default filled in — the fastest way to see what
the parser actually made of your file:
docker agent debug config ./config.yaml--dry-run is the third useful one: it initializes the agent, validates everything, and exits without
calling the model.
Two gotchas
token_key is optional. It names an environment variable, and if you declare it, it must be set —
otherwise the run aborts before reaching the model:
The following environment variables must be set:
- OMLX_API_KEYMost local servers don’t check the key at all, so you can simply omit the line. Keep it only if your server
enforces one (then docker agent setup will store the value in ~/.config/cagent/.env for you, or use
--env-from-file).
Custom script tools can take typed parameters. get_ip above takes none, which is why it’s a one-liner.
For anything parameterized, declare args and the model fills them in:
- type: script
shell:
dig_host:
cmd: "dig +short $HOST"
description: "Resolve a hostname to an IP"
args:
HOST:
type: string
description: "hostname to resolve"
required: [HOST]If you don’t have a local server yet
Docker Model Runner skips the whole models block — it pulls and serves the model itself:
docker agent run --model dmr/ai/qwen3 ./config.yamlThat needs Model Runner enabled in Docker Desktop (the agent talks to it on 127.0.0.1:12434, and says so
loudly if it isn’t listening); the model is pulled on first use, and docker model ls shows what you already
have.
Or run docker agent setup for an interactive walk through providers and local endpoints. Either way, the
agent definition stays the same file — which is the point. The YAML is the assistant; where the tokens come
from is a swappable detail.
Same idea, different front-end: opencode.json wires a terminal coding
agent to the same local endpoint, if what you want is a coding TUI rather than a declarative agent.
Tested with docker agent v1.122.0.