AI Coding AgentsAILLMSelf-Hosting
OpenCode with a local model: a private coding agent with Ollama or llama.cpp (Linux, Windows, Mac)
Before you start
- 15 min read
Boxes marked Run in terminal are what you type; plain text explains why. Check what you need first

What you get in one minute#
OpenCode is an open-source coding agent for your terminal, and with a model from Ollama or llama.cpp it works on your own machine, so your code never leaves it.
At a glance:
- What you get: a chat agent in the terminal that reads your project, edits files and runs commands, using a model on your own computer.
- Time needed: about 30 minutes, plus the model download.
- Difficulty: easy to medium. You edit one JSON file.
- You need: a computer with a decent GPU or lots of RAM, Ollama or llama.cpp, and Node.js or a package manager.
- Version used: OpenCode v1.19.4.
You tell the agent what you want. It reads files, proposes edits and asks before it runs risky commands. People pick OpenCode because it talks to 75+ providers and to local models, so you can start private and add a cloud model later.
| What | Value |
|---|---|
| Current version | v1.19.4 (GitHub release of 22 October 2026, marked "Latest") |
| Official image | ghcr.io/anomalyco/opencode:1.19.4 (GitHub Container Registry only, there is no official Docker Hub image) |
| Time needed | About 30 minutes |
| Memory use | Not measured by DIY Lab Hub. It depends on model and context length |
| Ports | Ollama 11434, llama-server 8080, optional OpenCode server 4096 |
| Official docs | opencode.ai/docs |
Why v1.19.4? The project has two release lines now. The changelog also shows V2 (v2.1.4 of 23 October 2026). We found no repeated reports of install failures or data loss for either line. V2 complaints are about moving over: V1 plugins do not run on V2, and both use the same opencode command. GitHub marks v1.19.4 as "Latest" and the install docs target it, so this guide uses it. Stay on it unless you have no plugins and want V2. We could only read search excerpts of forum threads, so check the open issues for your version before you pin.
The repository moved from sst/opencode to anomalyco/opencode. Old links still redirect. Use the new name.
How it fits together#
You type a task, OpenCode sends it with the available tools to your local model server, and every tool call passes the permission check before it touches your files.
Ollama or llama.cpp? This picture picks one for you.
Before you start#
You need a machine that can run a coding model, a terminal, and Ollama or llama.cpp. There is no official minimum hardware list. Context length costs memory, so more context needs more RAM or VRAM.
| System | What to have |
|---|---|
| Linux | A modern terminal (WezTerm, Alacritty, Ghostty or Kitty), Ollama or llama.cpp, Docker Engine with Compose only for the optional container |
| Windows | PowerShell, Ollama for Windows or llama.cpp. The OpenCode docs recommend WSL2 for the best experience. Docker Desktop with the WSL2 engine for the optional container |
| Mac | Terminal, Ollama or llama.cpp. Apple Silicon uses unified memory, so more memory means a bigger model |
Rough guide, our own estimate: a 30B model at Q4 wants about 24 GB of GPU or unified memory. Smaller models fit smaller machines but call tools less reliably (VERIFY on your hardware).
Checklist:
- [ ] Your config and projects are backed up (OpenCode edits files).
- [ ] Port 11434 (Ollama) or 8080 (llama-server) is free.
- [ ] You work inside a Git repository, so you can undo any change.
- [ ] A domain, DNS and ports 80/443 are ready, only if you use the Traefik section.
Check the tools:
docker --version docker compose version
Tested on: not run by DIY Lab Hub. Checked against the official docs on 2026-10-26.
Step 1: Install and start a local model#
Run the model first. OpenCode only needs its address. Pick Ollama (easier) or llama.cpp (more control).
Linux#
- Install Ollama and pull a coding model.
- Start the server with a 64K context.
curl -fsSL https://ollama.com/install.sh | sh ollama pull qwen3-coder:30b OLLAMA_CONTEXT_LENGTH=65536 ollama serve
If the installer already started a service, set the variable in the service instead and restart it.
Windows (PowerShell)#
- Install Ollama from ollama.com/download.
- Pull the model and start the server with a 64K context.
ollama pull qwen3-coder:30b $env:OLLAMA_CONTEXT_LENGTH = "65536" ollama serve
If the tray app already runs Ollama, quit it first, or set the variable for your user and restart the app.
Mac (Terminal)#
Same commands as Linux, with Homebrew for the install:
brew install ollama ollama pull qwen3-coder:30b OLLAMA_CONTEXT_LENGTH=65536 ollama serve
llama.cpp instead of Ollama (all systems)#
Start llama-server with your GGUF model. The alias must match the model key in your OpenCode config:
llama-server -m ./qwen3-coder-30b-a3b.gguf --port 8080 --alias qwen3-coder:a3b --jinja -c 65536
One unofficial guide says newer llama-server builds default to port 9931, so set --port 8080 yourself (VERIFY in the llama.cpp release notes).
Check it worked:
ollama ps
The model should be listed with a context of 65536 (VERIFY on your Ollama version). For llama-server, curl http://127.0.0.1:8080/v1/models should answer with JSON.
Potential issue: Ollama's OpenAI-compatible endpoint cannot set num_ctx per request, so set the context on the server as shown.
Step 2: Install OpenCode#
Use the official script, npm, Homebrew, Scoop or Chocolatey, and pin the version if you want it fixed.
| System | Command |
|---|---|
| Linux, Mac, WSL | curl -fsSL https://opencode.ai/install | bash |
| Any with Node.js | npm install -g [email protected] |
| Mac, Linux (Homebrew) | brew install anomalyco/tap/opencode |
| Windows | scoop install opencode, choco install opencode or npm |
The npm version pin is our own suggestion, not copied from the docs. The Homebrew tap above is the V1 one. Plain brew install opencode gives the newer line.
Linux#
curl -fsSL https://opencode.ai/install | bash opencode --version
Windows (PowerShell)#
scoop install opencode opencode --version
Mac (Terminal)#
brew install anomalyco/tap/opencode opencode --version
Check it worked: opencode --version prints a version number. Expect 1.19.4 if you pinned it.
Potential issue: if you ever install both release lines, the opencode command conflicts. Remove one first.
Step 3: Point OpenCode at your local model#
One JSON file tells OpenCode where the model lives. Save it as opencode.json in your project, or as the global ~/.config/opencode/opencode.json. A project file wins over the global one.
Linux#
Create the global file and open it in your editor:
mkdir -p ~/.config/opencode nano ~/.config/opencode/opencode.json
Windows (PowerShell)#
The OpenCode docs recommend WSL2 on Windows. In WSL the Linux path above applies. For a project file, create opencode.json in the project folder:
notepad opencode.json
Mac (Terminal)#
Same commands as Linux.
Paste one of the two blocks below, the same on every system. Ollama:
{
"$schema": "https://opencode.ai/config.json",
"provider": {
"ollama": {
"npm": "@ai-sdk/openai-compatible",
"name": "Ollama (local)",
"options": { "baseURL": "http://localhost:11434/v1" },
"models": {
"qwen3-coder:30b": {
"name": "Qwen3 Coder 30B",
"limit": { "context": 65536, "output": 8192 }
}
}
}
},
"model": "ollama/qwen3-coder:30b"
}
llama.cpp (the block from the OpenCode docs, with the model key matching --alias):
{
"$schema": "https://opencode.ai/config.json",
"provider": {
"llama.cpp": {
"npm": "@ai-sdk/openai-compatible",
"name": "llama-server (local)",
"options": { "baseURL": "http://127.0.0.1:8080/v1" },
"models": {
"qwen3-coder:a3b": {
"name": "Qwen3-Coder a3b (local)",
"limit": { "context": 65536, "output": 8192 }
}
}
}
},
"model": "llama.cpp/qwen3-coder:a3b"
}
The model reference is always <providerId>/<modelId>. The limit field comes from the llama.cpp example in the OpenCode docs.
Shortcut for Ollama users: ollama launch opencode starts OpenCode with an inline config for the model you pick. It does not overwrite your opencode.json. ollama launch opencode --config only writes the config without starting a session.
Which model? Ollama's page says OpenCode needs a context of 64K or higher. The OpenCode docs use Qwen3-Coder 30B-A3B as their local example. Small models often fail at tool calls (a tracked issue lists six cases), so start with a tool-trained coding model of 30B size if your machine can hold it. There is no official ranking.
| Model size | What to expect |
|---|---|
| Small (under 10B) | Fits easily, but tool calls fail more often |
| About 30B (MoE such as a3b) | Good balance, needs about 24 GB at Q4 (our estimate) |
| Cloud model | Not private. Add one only on purpose |
Step 4: Your first project#
Open a project folder, run opencode, let it write AGENTS.md, and try a safe task first.
Linux#
cd ~/myproject git status opencode
Windows (PowerShell)#
cd $HOME\myproject git status opencode
Mac (Terminal)#
Same commands as Linux.
Then, inside OpenCode:
- Type
/modelsand pick your local model. - Type
/init. It createsAGENTS.mdwith notes about your project. Commit that file. - Press Tab to switch to Plan mode (no edits) and ask: "Explain this repo."
- Press Tab again for Build mode and ask for one small change.
- Not happy? Type
/undo./redobrings it back.
Check it worked: the answer arrives and mentions files from your project. If the agent ignores tools, see Troubleshooting.
Permissions and safety#
A coding agent can delete files and run commands, so tighten the defaults. Each action is allow, ask or deny. The last matching rule wins. Most defaults are permissive. Reading .env files already needs approval.
{
"permission": {
"*": "ask",
"bash": {
"*": "ask",
"git status*": "allow",
"rm *": "deny",
"git push *": "deny"
},
"edit": "ask",
"webfetch": "deny"
}
}
Merge this into your opencode.json. Safety habits:
- Work inside Git, and commit before a long task.
- Avoid
opencode --auto. It approves everything that is not explicitly denied. - Deny
webfetchif you want a fully offline agent.
MCP servers (optional)#
MCP servers give the agent extra tools, but each one eats context. With a 64K window, add only the ones you need. Define them under mcp with type local or remote:
{
"mcp": {
"context7": { "type": "remote", "url": "https://mcp.context7.com/mcp" }
}
}
A remote MCP server sends data outside your machine. For a fully private setup, use local servers only.
Optional: run the OpenCode server in Docker#
Most people run OpenCode natively. Use the container only if you want a headless server. OpenCode can run opencode serve, which listens on 127.0.0.1:4096 by default and supports basic auth through OPENCODE_SERVER_PASSWORD.
This Compose file is based on the maintainer's example. DIY Lab Hub has not run it, so VERIFY that the entrypoint and the data paths match v1.19.4.
Linux#
mkdir -p ~/docker_volumes/opencode/{data,config,logs,backups}
echo "OPENCODE_SERVER_PASSWORD=<YOUR_PASSWORD>" > ~/docker_volumes/opencode/.env
chmod 600 ~/docker_volumes/opencode/.env
Windows (PowerShell)#
New-Item -ItemType Directory -Force "$HOME\docker_volumes\opencode\data","$HOME\docker_volumes\opencode\config","$HOME\docker_volumes\opencode\logs","$HOME\docker_volumes\opencode\backups" "OPENCODE_SERVER_PASSWORD=<YOUR_PASSWORD>" | Set-Content "$HOME\docker_volumes\opencode\.env"
Mac (Terminal)#
Same commands as Linux.
Save this as ~/docker_volumes/opencode/docker-compose.yml:
services:
opencode:
image: ghcr.io/anomalyco/opencode:1.19.4
container_name: opencode
command: ["serve", "--hostname", "0.0.0.0", "--port", "4096"]
env_file: .env
ports:
- "127.0.0.1:4096:4096"
extra_hosts:
- "host.docker.internal:host-gateway"
volumes:
- ./data:/root/.local/share/opencode
- ./config:/root/.config/opencode
- ./projects:/workspace
working_dir: /workspace
restart: unless-stopped
Inside the container the model is not on localhost. Use http://host.docker.internal:11434/v1 as the Ollama baseURL. Start it:
cd ~/docker_volumes/opencode docker compose up -d docker compose ps
Put it behind HTTPS (with or without Traefik)#
With Traefik#
This is for a server with a domain. If you only use OpenCode on your own computer, skip it. The labels below are our sketch, not from the OpenCode docs (VERIFY). Never expose the agent without a login in front of it.
docker network create proxy
Replace the ports: block of the Compose file with a network and labels:
networks:
- proxy
labels:
- traefik.enable=true
- traefik.http.routers.opencode.rule=Host(`<your-domain>`)
- traefik.http.routers.opencode.entrypoints=https
- traefik.http.routers.opencode.tls=true
- traefik.http.services.opencode.loadbalancer.server.port=4096
networks:
proxy:
external: true
Add an authentication middleware (for example basic auth or your login provider) to the router. Keep the router on your home network only.
Without Traefik: Caddy#
Choose this if you have no Traefik yet and run one small server. Caddy is one small program that gets and renews certificates by itself.
| Your case | What Caddy does | What you do |
|---|---|---|
| Public domain | Automatic Let's Encrypt certificate | Point a DNS A record at the server; open ports 80 and 443 |
| Home only, no domain | tls internal: Caddy's own local certificate | Trust Caddy's root certificate on each device (below) |
Caddyfile for OpenCode server (it listens on 127.0.0.1:4096 in this guide):
opencode.example.com {
reverse_proxy localhost:4096
}
Home-only variant (point the name opencode.home.arpa at the server in your router, Pi-hole or hosts file):
opencode.home.arpa {
tls internal
reverse_proxy localhost:4096
}
Run Caddy (Caddyfile in /etc/caddy/Caddyfile on Linux):
- Linux: install from the official apt repository (see caddyserver.com/docs/install), save the Caddyfile, then
sudo systemctl reload caddy. - Windows (PowerShell):
winget install CaddyServer.Caddy, thencaddy run --config Caddyfilein the folder with your Caddyfile. - Mac:
brew install caddy, thencaddy run --config Caddyfile. - Docker: add this service to the same compose file and put the Caddyfile in
~/docker_volumes/caddy/. Inside Docker, usereverse_proxy opencode:4096in the Caddyfile instead oflocalhost:4096.
caddy:
image: caddy:2.11.7
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ~/docker_volumes/caddy/Caddyfile:/etc/caddy/Caddyfile:ro
- ~/docker_volumes/caddy/data:/data
Home-only: trust Caddy's root certificate. It is pki/authorities/local/root.crt in Caddy's data folder.
- Linux: on the Caddy machine run
sudo caddy trust. On other Linux devices copyroot.crtto/usr/local/share/ca-certificates/and runsudo update-ca-certificates. - Windows:
caddy trustin an administrator PowerShell on the Caddy machine. On other devices double-clickroot.crtand install it into "Trusted Root Certification Authorities". - Mac:
caddy truston the Caddy machine. On other Macs addroot.crtin Keychain Access and set it to "Always Trust".
Keep the server password (OPENCODE_SERVER_PASSWORD) set. HTTPS alone is not a login, so never expose the agent without it.
Check it worked: curl -I https://opencode.example.com answers HTTP/2 401 (the password prompt) when the password is set, and HTTP/2 200 after you add -u user:password.
Security and testing#
Keep the agent private, keep secrets out of config files, and test what you exposed.
| Rule | Why |
|---|---|
Bind to 127.0.0.1 | Nobody else on the network can reach the agent |
Use {env:VAR} in opencode.json | API keys never sit in a file you might commit |
Keep .env at chmod 600 | Other users cannot read it |
Do not use opencode pair --remote in V2 | It exposes your server to the internet |
Deny webfetch, use local MCP only | Your code does not leave the machine |
Tests:
docker compose ps docker logs opencode --tail 50 curl -I https://<your-domain>
For the Traefik setup, the last command should answer with an HTTPS status line.
Troubleshooting#
| Problem | Solution |
|---|---|
ProviderInitError | The provider block is wrong or corrupted. Fix it, then rm -rf ~/.local/share/opencode and run /connect again |
AI_APICallError | Clear the provider cache: rm -rf ~/.cache/opencode, restart |
Model not found | Use <providerId>/<modelId>, for example ollama/qwen3-coder:30b |
| Tool calls ignored or poor output | Raise the context to 64K or more and use a tool-trained model |
| Cannot connect to llama-server | Pass --port 8080 and check the baseURL (VERIFY) |
docker.io/anomalyco/opencode ... not found | Wrong registry. Use ghcr.io/anomalyco/opencode |
| Web UI refuses connection in Docker | Start with serve --hostname 0.0.0.0 and publish the port |
Two opencode commands | V1 and V2 conflict. Remove one install |
Exact error: failed to resolve reference#
failed to resolve reference "docker.io/anomalyco/opencode:..." not found
The official image lives on GitHub Container Registry, not Docker Hub. Pull ghcr.io/anomalyco/opencode:1.19.4.
Known bugs#
- Small models can fail at tool calls (a tracked issue lists six cases). Use a larger or tool-trained model.
- V1 plugins fail on V2 with: "Plugin must export a default definition with an id and an effect or setup function." Port the plugin or stay on V1.
Diagnostic commands:
ollama ps docker logs opencode --tail 100 docker compose ps
Updates and backups#
Updates are manual, and a backup before each one takes a minute. Since v1.19.0, OpenCode no longer installs updates by itself. Type /update inside OpenCode, or reinstall the pinned version. For Docker, change the tag and run:
docker compose pull && docker compose up -d
Moving to V2 is a separate decision (opencode upgrade --major). Do it only with a fresh backup and no V1 plugins.
Linux#
tar czf ~/docker_volumes/opencode/backups/opencode-$(date +%F).tgz ~/.config/opencode ~/docker_volumes/opencode/data ~/docker_volumes/opencode/config (crontab -l 2>/dev/null; echo '0 3 * * * tar czf $HOME/docker_volumes/opencode/backups/opencode-$(date +\%F).tgz $HOME/.config/opencode $HOME/docker_volumes/opencode/data') | crontab -
Windows (PowerShell)#
Compress-Archive -Path "$HOME\.config\opencode","$HOME\docker_volumes\opencode\data" -DestinationPath "$HOME\docker_volumes\opencode\backups\opencode-$(Get-Date -Format yyyy-MM-dd).zip"
Schedule that command at 03:00 with Task Scheduler.
Mac (Terminal)#
Same commands as Linux. Use crontab -e or launchd for the schedule.
Restore test (do it once):
- Unpack the newest backup into an empty folder.
- Check that
opencode.jsonis inside. - Copy it to a test project and start
opencodethere.
mkdir /tmp/restore-test && tar xzf ~/docker_volumes/opencode/backups/opencode-*.tgz -C /tmp/restore-test find /tmp/restore-test -name opencode.json
Performance and resources#
Context length is the big knob. Bigger context needs more memory for the cache. 64K is the minimum for OpenCode, and the llama.cpp example in the docs uses 128K.
- A mixture-of-experts model (a3b) activates few parameters per token and is usually quicker than a dense 30B (general knowledge, VERIFY on your hardware).
- Every MCP server adds tokens to the context. Keep them few.
- Provider requests have a generous default timeout, so slow model starts do not break the first call.
- Watch the model with
ollama psand your GPU ordocker stats.
DIY Lab Hub did not measure RAM or speed for this guide.
FAQ#
Does my code leave my machine? Not with a local provider. It leaves only if you turn on webfetch, a remote MCP server or a cloud provider. Deny those in permission.
Ollama or llama.cpp? Ollama is easier, and ollama launch opencode wires everything up. llama.cpp gives finer control through flags such as -c and --jinja. For a first install, use Ollama. If you do not know Ollama yet, read our Ollama guide.
Why does the agent ignore its tools? Usually the model or the context. Check ollama ps, raise the context to 64K and try a tool-trained model.
Should I install V2? Only if you have no V1 plugins. V2 changes the plugin API and adds a shared background server.
Can I go back to an older version? Yes. Reinstall [email protected] or retag the image, then restore your backup.
Sources#
Read on 2026-10-26.
- OpenCode docs (install, CLI, config)
- OpenCode providers (Ollama and llama.cpp blocks)
- OpenCode server (
serve, port 4096, password) - OpenCode changelog (v2.1.4, 23 October 2026)
- OpenCode GitHub releases (v1.19.4, 22 October 2026)
- OpenCode container image (ghcr.io/anomalyco/opencode)
- Ollama: OpenCode integration (64K context rule)
- Caddy docs: automatic HTTPS, reverse_proxy, install - Caddy v2.11.7, image tag
caddy:2.11.7confirmed on Docker Hub, read on 2026-10-26
Checked against the official docs on 2026-10-26. The version numbers and the image tag were confirmed with the GitHub and registry APIs. No commands were run by DIY Lab Hub; items marked VERIFY are uncertain.