From 12760ed09509f4e8bda218858989769e538af7d0 Mon Sep 17 00:00:00 2001 From: Jarek Rozanski Date: Sun, 27 Sep 2026 20:18:49 +0200 Subject: [PATCH] Docs --- README.md | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..1ecfba1 --- /dev/null +++ b/README.md @@ -0,0 +1,62 @@ +# OpenCode Sandbox + +A rootless Podman container for running [OpenCode](https://github.com/anomalyco/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](https://podman.io/) (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 `, or by starting it with `--network opencode-sandbox-net`) can resolve and reach this sandbox by its workdir-derived alias, and vice versa.