This repository has been archived on 2026-10-10. You can view files and clone it, but you cannot make any changes to its state, such as pushing and creating new issues, pull requests or comments.
opencode-sandbox/README.md
Jarek Rozanski 12760ed095
Docs
2026-09-27 20:18:49 +02:00

4.8 KiB

OpenCode Sandbox

A rootless Podman container for running OpenCode with a pinned toolchain — Java, Node, pnpm, git — without touching your host machine's environment.

What this gives you

  • A hash-pinned, integrity-verified build of OpenCode (not "latest" — an exact version, checked against a SHA256 captured at build time).
  • JDK 25 (LTS), Node 24 (LTS), pnpm, git, curl, openssh-client.
  • The current directory mounted read-write as /workspace.
  • OpenCode's config, data, and session state shared across every workdir/container, so logging in once carries over everywhere.
  • Every container joined to a shared Podman network so it can reach other dev containers by name.

Requirements

  • Podman (rootless).
  • On macOS: a running podman machine — make will start a stopped one automatically, but if you've never run Podman before you need to initialize one first:
    podman machine init
    
  • GNU Make (macOS's bundled Make 3.81 works fine; the Makefile deliberately avoids features added in 3.82+).

Usage

make build      # build (or rebuild) the container image
make opencode   # launch the OpenCode TUI in the current directory
make shell      # open a bash shell in the container instead

Run make opencode or make shell from any project directory — the image is shared, so there's nothing per-project to set up.

How it's put together

Containerfile — multi-stage build on debian:trixie-slim:

  • JDK and Node are copied in from their official upstream images (eclipse-temurin:25-jdk-noble, node:24-trixie-slim) rather than apt-installed, keeping the final image slim while staying on a mainstream glibc distro (Alpine/musl is avoided — it breaks JVM and native Node addon compatibility).
  • pnpm is installed via its own standalone installer script, pinned to a specific version.
  • OpenCode is downloaded directly from its canonical GitHub releases (github.com/anomalyco/opencode) for the container's architecture, and its SHA256 is checked against a hash pinned in the Containerfile before it's installed — there's no maintainer-published signature for OpenCode releases, so this hash is captured by hand and is the actual root of trust here. Bump OPENCODE_VERSION and re-run the sha256sum steps documented in the Containerfile's comments whenever you upgrade it.
  • A few build-time smoke tests (ldd, java -version, node --version, etc.) fail the build immediately if anything is broken, rather than surfacing at first make opencode.

Makefile — three targets only, as designed:

  • build builds the image.

  • opencode and shell both run the container with the same flags: --userns=keep-id (so files created in the container are owned by your real host user, not root — verified: rootless Podman's user-namespace remapping means id shows root inside the container's own namespace view, but the file lands on the host owned by your actual UID/GID), the current directory bind-mounted to /workspace, and OpenCode's three XDG directories bind-mounted from your home directory:

    Host path Container path Contents
    ~/.config/opencode /home/dev/.config/opencode settings, plugins, themes
    ~/.local/share/opencode /home/dev/.local/share/opencode auth, database, snapshots
    ~/.local/state/opencode /home/dev/.local/state/opencode session/model history, locks

    Because these are real host paths shared by every container regardless of workdir, logging into OpenCode once carries over to every project you use the sandbox in.

  • Both run targets join a shared, auto-created Podman network (opencode-sandbox-net) under a --network-alias derived from the current directory's name, so a container started from another dev-container setup on the same network can reach this one by that name (and vice versa).

macOS-specific notes

  • Podman on macOS runs everything inside a Linux VM (podman machine, backend libkrun/applehv, virtiofs file sharing). The Makefile detects this and starts a stopped machine automatically before build, opencode, or shell.
  • SELinux volume-relabeling suffixes (:Z/:z) are intentionally omitted — macOS's host filesystem has no SELinux concept, so they'd be a no-op.
  • Known virtiofs limitation: inotify/file-watch events from the host don't propagate into the container. Not a blocker for normal use, just worth knowing if a tool inside the container tries to watch /workspace for live host-side changes.

Connecting to other dev containers

Any other container you attach to the opencode-sandbox-net network (podman network connect opencode-sandbox-net <container>, or by starting it with --network opencode-sandbox-net) can resolve and reach this sandbox by its workdir-derived alias, and vice versa.