Running OpenCode in an Isolated Podman Container

I've been experimenting with open-weight language models for coding tasks. Rather than running these models locally, I wanted a simple way to connect an AI coding agent to different hosted inference providers while keeping its access to my filesystem under control.

The result is opencode-chat, a small wrapper around OpenCode that runs it inside disposable, rootless Podman containers.

Why OpenCode?

OpenCode is an open-source coding agent with support for different LLM providers, including services offering OpenAI-compatible APIs. This makes it a useful foundation for experimenting with open-weight models without committing to a particular model vendor or subscription.

Running large models locally would also mean investing in expensive GPU hardware, which I don't particularly want to do just for experimentation. Fortunately, there are numerous inference providers offering access to open models at increasingly competitive prices.

With OpenCode, I can switch between providers and models without changing the basic workflow.

Why isolate the agent?

Coding agents need filesystem access to inspect projects, modify files, and execute commands. That is also what makes them potentially dangerous.

I'm particularly cautious about giving an autonomous agent running on a model served by an unfamiliar provider unrestricted access to my machine.

There are two concerns: accidental data exposure and unintended filesystem modifications.

A model can behave unexpectedly, misunderstand instructions, or execute commands with consequences beyond the intended task. An agent may also encounter untrusted content inside a repository that influences its behavior.

Container isolation helps limit the consequences.

The goal isn't to create a perfectly secure sandbox. It's to reduce the blast radius of mistakes and limit which local files an agent can access or potentially transmit.

How it works

Each OpenCode session runs in a disposable rootless Podman container.

By default, the container has no host directory mounted. If I want the agent to work on a particular project, I explicitly provide its directory:

opencode-chat --cwd="$HOME/projects/example"

Only that directory is mounted into the container, with read/write access. The agent can inspect and modify the project, but it doesn't automatically receive access to my home directory, SSH keys, unrelated repositories, or other local files.

The container is removed when the session ends, along with its internal state.

Rootless Podman also avoids running the container with host root privileges. This is useful isolation, although containers still share the host kernel and shouldn't be treated as an absolute security boundary.

Importantly, the selected project remains writable and can still be damaged or deleted by the agent. Network access also remains enabled, so the container is not a complete defense against exfiltration. The protection comes primarily from limiting the filesystem content available to the agent.

Configuration and dependencies

I wanted to keep configuration straightforward.

The wrapper uses a .env file for the provider, API endpoint, API key, and model selection. Alternatively, it can load OpenCode's native configuration files.

The configuration is provider-agnostic, making it easy to switch between OpenAI-compatible inference services.

The container uses Debian Bookworm, with OpenCode installed from a version-pinned standalone binary archive. There is no need to install Node.js or npm on the host.

Additional Debian packages can be configured either persistently in the container image or temporarily for a single session. This allows the agent to use project-specific tools without installing them on my host system.

The wrapper also includes configuration checks, integration tests, and a small API connectivity test.

A practical compromise

This setup deliberately keeps ordinary network access and allows the agent to modify the selected project. Otherwise, it wouldn't be particularly useful as a coding assistant.

The important difference is that access to the rest of my filesystem is not granted implicitly.

It's a relatively small amount of infrastructure, but it gives me a consistent environment for trying different open models and inference providers while keeping accidental damage and data exposure more contained.

Configuration and additional tools

The wrapper keeps configuration in ~/.config/opencode-chat/.env. It has six settings, with the following defaults:

Setting Default Purpose
OPENCODE_CONFIG_MODE env Uses .env to generate OpenCode configuration, or native to load OpenCode's own configuration files.
LLM_PROVIDER featherless Identifies the LLM provider.
LLM_BASE_URL https://api.featherless.ai/v1 Specifies the provider's OpenAI-compatible API endpoint.
LLM_API_KEY Empty API credential for the selected provider.
LLM_MODEL Empty Model identifier expected by the provider.
OPENCODE_PACKAGES git,curl,jq Debian packages installed persistently in the container image.

Coding agents often need additional command-line tools. For example, a project might require git, unzip, or another utility that isn't included in the base image. Rather than installing these tools on my host system, I can make them available inside the container.

For tools I regularly use, I add them to OPENCODE_PACKAGES in .env. These packages become part of the persistent container image and remain available across sessions.

For occasional dependencies, the wrapper supports temporary package installation:

opencode-chat --cwd="$PWD" --packages=git,unzip

Alternatively, I can maintain a tools.conf file containing one Debian package name per line and load it with:

opencode-chat --cwd="$PWD" --packages-file=./tools.conf

Both options install the requested packages when the container starts. They disappear when the session ends, leaving the host and persistent image unchanged. This makes it easy to experiment with different tooling without cluttering my system.

The project is available on GitHub: Opencode Chat.