Running opencode in Dev Containers

It started with a small annoyance: I'd ask opencode to tweak a yarn project, and it would casually reach for npm. Nothing catastrophic, just the agent grabbing whichever binary the host happened to have lying around. You can scold an LLM into using the right tool, but "probably" isn't the guarantee I wanted.

Around the same time, I'd been moving my projects into Dev Containers. If a container already pins the language, package manager, and tooling a project expects, why not let the coding agent live inside that same box? Whatever isn't installed, it can't misuse.

The security story sealed it. LLMs are a juicy target for prompt injection, and an agent with full access to my host has full access to my browser profile, SSH keys, and saved credit cards. A Dev Container trims that blast radius to the project itself.

So I started hand-rolling opencode installs into every Dev Container I touched, which got old fast. The spec has a clean answer for that: a "feature", a reusable build step you drop into devcontainer.json. I packaged opencode as one and published it, both for myself and for anyone else tired of copy-pasting install scripts.

Installation & Configuration

Add the opencode feature to your Dev Container by including it in your devcontainer.json:

{
	"features": {
		"ghcr.io/danzilberdan/devcontainers/opencode:0": {}
	}
}

There's one loose end: credentials. opencode keeps provider auth in ~/.local/share/opencode/auth.json on the host, and the container can't see it by default. The fix is a hard link plus a bind mount.

From your project directory:

mkdir .opencode
cd .opencode
# Hard link to your host's opencode `auth.json`.
ln ~/.local/share/opencode/auth.json

Keep those credentials out of git:

.opencode/

Then expose the file to the container via devcontainer.json:

    "mounts": [
        {
            "source": "${localWorkspaceFolder}/.opencode/auth.json",
            "target": "/mnt/opencode-auth.json",
            "type": "bind"
        }
    ],

That's it. opencode inside the container now signs in with your host's providers, but only touches what the container lets it touch.

More details in the GitHub repository.