Skip to content

About

Security-focused Docker container for running OpenCode

Resources

Stars

1 star

Watchers

0 watching

Forks

Latest commit

 

History

32 Commits

Folders and files

Repository files navigation

OpenCode Container

Security-focused rootless Podman setup for running OpenCode with restricted filesystem access and Podman-in-Podman support.

Quick Start

# From your project directory:
./path/to/opencode.sh

# Update to latest version
./path/to/opencode.sh update

Requirements

  • Rootless Podman on the host (tested with 3.4.4 on Ubuntu 22.04)

  • Podman user API socket enabled:

    systemctl --user enable --now podman.socket
  • For --kvm: membership in the host kvm group

First Run

On first run, the container builds with the latest OpenCode version. The version is stored in .opencode-version next to opencode.sh. Subsequent runs use the stored version (no automatic update checks). Run ./path/to/opencode.sh update to update to the latest version.

Usage

# Mount current working directory
./path/to/opencode.sh

# Mount specific path(s) - first path is the working directory
./path/to/opencode.sh /path/to/project
./path/to/opencode.sh /path/to/project /path/to/otherdir

# Update to latest version
./path/to/opencode.sh update

When paths are provided, they are resolved relative to the current working directory. Relative paths (e.g., ./upmon) are supported. All paths are validated before starting the container.

Mounted Paths

  • Project directory (first path argument, or current working directory if no args)
  • Additional directories (subsequent path arguments, each mounted at the same path inside the container)
  • This tooling repo (mounted at the same path) - provides the shared-browser skill and browser-cli/browser.sh to every project
  • ~/.config/opencode/ - OpenCode settings and API key
  • ~/.local/share/opencode/ - OpenCode data
  • ~/.ssh/config and ~/.ssh/sockets - SSH access (OpenCode can SSH without password or key through existing connections shared via ControlPath)
  • $XDG_RUNTIME_DIR/podman/podman.sock - rootless Podman API socket (for running tests)
  • /tmp/.X11-unix - X11 forwarding (clipboard)
  • .opencode/tmp/<project-key> - per-project scratch space mounted at /tmp/opencode

The per-project scratch space keeps OpenCode's temp directory writable even when the container image contains a stale root-owned /tmp/opencode. Wipe all projects' temp directories with:

./cleanup-tmps.sh

Podman-in-Podman

The container ships a statically linked podman-remote client whose version matches the host's Podman (passed as the PODMAN_VERSION build arg; the libpod remote API is not cross-version compatible). A docker shim forwards to it, so both podman ... and docker ... work inside the container.

Both talk to the host's rootless, user-owned Podman API socket — no privileged daemon and no root-equivalent /var/run/docker.sock is mounted. Containers started from inside OpenCode run with the host user's privileges, and the launcher uses --userns=keep-id so file ownership in mounted directories stays consistent.

Shared Browser

browser.sh runs one detached Chromium per project, headless by default. The agent drives it over an auto-allocated localhost CDP endpoint; no window is mapped on your desktop, so browser work cannot steal focus. Different projects get separate containers, profiles and endpoints, so their sessions are independent. Open tabs and session cookies are restored across stops and mode switches (use browser.sh rather than raw podman stop so Chromium flushes state).

For human-in-the-loop logins, expose the same profile in a headful window and hide it again afterwards:

./browser.sh start      # build image on first run, then start headless
./browser.sh login      # show the same profile headful for a login
./browser.sh headless   # hide it again (same profile/tabs)
./browser.sh status
./browser.sh list
./browser.sh stop
./browser.sh stop-all

Logins persist in browser-profile/<project-key>/. Agents drive the browser through browser-cli/ (a small playwright-core CLI speaking CDP); the global shared-browser skill documents the workflow, so OpenCode loads browser instructions on demand instead of carrying MCP tool schemas in every request. Install once: cd browser-cli && npm install. The skill source lives in skills/shared-browser/ and is registered via skills.paths in the host's ~/.config/opencode/opencode.json.

About

Security-focused Docker container for running OpenCode

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages