Niels V e6e5eadcf8 Allow opencode to run Docker images via a dind sidecar
opencode now drives a dedicated Docker-in-Docker container instead of the
host daemon, so it can build/run images and bring up compose stacks from
within its own container.

Notes:
- dind runs in PRIVILEGED mode, this required for a nested docker daemon.
- opencode itselfs remains unprivileged
- opencode talks to dind over TCP (DOCKER_HOST=tcp://dind:2375)
  Consequence: services started in dind are reachable at dind:<port>, not
  localhost.
- The workspace needs to be bind-mounted at the same absolute path in both containers
  so compose bind-mounts resolve inside the dind daemon.
- /var/lib/docker is persisted on a mounted volume to keep images warm across
restarts.
- uses the rpio registry mirror for quicker pulls
2026-07-06 12:51:32 +02:00
2026-07-02 12:54:55 +02:00
2026-07-02 12:54:55 +02:00

app-opencode

opencode packaged in a Docker container and wired to weave as the model provider. It ships with an LSP for TypeScript/JavaScript and Python baked in, so opencode gets real type-aware navigation out of the box. The default model is weave/glm-5.2.

The docs below are split into three parts: a Getting started walkthrough to run it the first time, How-to guides for specific tasks, and a Reference for the moving parts.

drc in the examples is shorthand for docker compose (alias drc='docker compose'). Substitute docker compose if you don't have the alias.

Getting started

A first run from a clean checkout.

  1. Get a weave API key. You need an account on weave.redpencil.io and/or an API key (ask us!).

  2. Create your local override. docker-compose.override.yml is gitignored and holds your key plus the repo you want opencode to work on. Create it with your key and mount:

    services:
      opencode:
        environment:
          WEAVE_API_KEY: "your-key-here"
        volumes:
          - /path/to/your/repo:/workspace/repo
    
  3. Start the container.

    drc up -d
    
  4. Open the TUI.

    drc exec opencode opencode
    

You're now in opencode, talking to weave/glm-5.2. Type /models to switch models, or just start prompting.

How-to guides

Switch the model in a session

In the TUI, type /models and pick from the registered weave models. This only changes the current session; to change the default for every session, edit opencode.json (see below).

Change the default model

Edit model (and optionally small_model) in config/opencode/opencode.json, then apply the change:

drc restart opencode

opencode.json is mounted into the container, so a restart is all that's needed.

Register a new weave model

Add the model under provider.weave.models in opencode.json:

"provider": {
  "weave": {
    "models": {
      "my-new-model": { "tools": true }
    }
  }
}

Then drc restart opencode. It will show up in the /models picker. See the model list on weave for an overview of available models. Need another model, please let us know :)

Copy text out of the TUI

Copying from the opencode TUI over Docker is fiddly: Shift+click to select the text, then Ctrl+Shift+C to copy. A plain copy doesn't work.

Connect opencode to a (backend) service

To let opencode call a service over HTTP, e.g. a stack you've brought up in dev mode and want the agent to follow up against, have that stack join opencode's network instead of publishing ports or going via the host.

opencode's stack creates a default network named app-opencode_default. Attach the dev-mode service to it as an external network:

# the dev-mode app stack
services:
  app:
    networks:
      - default
      - app-opencode_default

networks:
  app-opencode_default:
    external: true

opencode can then reach it at http://app:<port>, where app is the service name from that stack's compose and <port> is the container's internal port — no ports: publishing needed.

Note: Bring the opencode stack up first, so app-opencode_default exists before adding to your app.

Executing docker commands from opencode

The stack runs a dedicated dind (docker in docker) container, and opencode can drive it as a client (DOCKER_HOST=tcp://dind:2375). So from inside opencode you can build images, run containers, and docker compose up a project's stack. The agent can spin up and test the services it's working on.

A few things that differ from a normal host, because the daemon lives in dind:

  • Containers and published ports you start run on the dind daemon. Reach a running service at dind:<port>, not localhost:<port>. opencode does not share dind's network namespace, so localhost won't reach the stack.
  • The repo needs to be mounted at the same absolute path (/workspace/repo) in both the opencode and dind containers, so compose bind-mounts resolve correctly. Work on the checkout there; edits elsewhere won't be visible to the containers dind runs.
  • The dind image store is cached in ./data/dind-cache, so pulled images stay warm across restarts.
  • To access the services from the host machine, you will need to connect to the dind container or publish the necessary ports from the dind container to your host.

Note: Opencode itself doesn't run in a privileged container so it can't do privileged actions directly, but it can use the docker daemon in dind to do the same things. Because dind is privileged and in the host user namespace, a container started inside dind can mount the host's raw disk devices and reach the entire host filesystem, not only what you shared. This needs opencode to actively do it, but it's a well-known technique, not a theoretical edge case.

Reference

opencode.json keys

  • model / small_model — default model and the model used for lighter tasks. Both default to weave/glm-5.2.
  • provider.weave — the weave provider, using the @ai-sdk/openai-compatible adapter against https://weave.redpencil.io/v1 with the key from WEAVE_API_KEY.
  • provider.weave.models — the models offered in /models.
  • lsp — language servers baked into the image: typescript-language-server for TS/JS and pyright for Python.
  • permission — set to ask for read, edit, bash, and external-directory actions, so opencode prompts before acting.

Caveats

  • Copy from the TUI over Docker needs the Shift+click / Ctrl+Shift+C dance described above.
Description
No description provided
Readme 44 KiB