A containerized sandbox environment for running OpenCode AI in an isolated Docker container.
  • Shell 37.1%
  • Dockerfile 33.1%
  • Makefile 24.3%
  • JavaScript 5.5%
Find a file
Patrick Kirchhoff 5c4fad790b
Some checks failed
CI Pipeline for building and pushing Docker images (staging and latest) / build_and_push_temp (push) Successful in 13m57s
Ensure container image tag matches latest Git tag / tag_latest (push) Successful in 59s
Release / release (push) Successful in 8s
CI Pipeline for building and pushing Docker images (staging and latest) / trivy_scan (push) Failing after 2s
CI Pipeline for building and pushing Docker images (staging and latest) / push_final (push) Has been skipped
Merge pull request 'chore(docker): update git.bueraner.de/murdoc/docker-semantic-release:latest docker digest to 906def4' (#57) from renovate-git-bueraner-de-murdoc-docker-semantic-release-latest into main
2026-03-20 20:49:47 +00:00
.forgejo/workflows chore(docker): update git.bueraner.de/murdoc/docker-semantic-release:latest docker digest to 906def4 2026-03-20 06:06:54 +00:00
.githooks build: add multi-arch support and fix hooks 2026-02-12 18:00:44 +01:00
scripts test: add smoke test runner 2026-02-06 20:31:27 +01:00
skills docs(skill): add trivy scan guidance 2026-02-06 20:32:40 +01:00
.editorconfig chore(tooling): add pre-commit hooks and hadolint linting 2026-02-06 20:29:43 +01:00
.markdownlint.jsonc chore(markdownlint): add markdownlint configuration 2026-02-17 23:12:52 +01:00
.pre-commit-config.yaml chore(deps): update pre-commit hook bridgecrewio/checkov to v3.2.510 2026-03-18 12:09:42 +00:00
AGENTS.md feat: add ripgrep package 2026-02-21 18:24:09 +01:00
CHANGELOG.md chore(release): 0.4.1 [skip ci] 2026-02-24 18:41:58 +01:00
Dockerfile chore(deps): update dependency npm to v11.12.0 2026-03-19 22:07:25 +00:00
Makefile build: add multi-arch support and fix hooks 2026-02-12 18:00:44 +01:00
README.md feat: add ripgrep package 2026-02-21 18:24:09 +01:00
release.config.mjs chore: add release config 2026-02-07 11:18:21 +01:00
renovate.json chore(tooling): add pre-commit hooks and hadolint linting 2026-02-06 20:29:43 +01:00
run.sh feat: add possibility to use the remote container 2026-02-21 10:42:03 +01:00

opencode-sandbox

Minimal Docker-based sandbox for running opencode with a consistent toolchain.

Requirements

  • Docker (CLI + running daemon)
  • Docker Buildx (for multi-arch builds)
  • Make
  • pre-commit
  • hadolint (optional, for Dockerfile linting)
  • OpenCode configured on the host system

Quick Start

make build
make run

This runs the opencode-sandbox image and drops you into opencode with the current directory mounted at /workspace.

Common Tasks

make help
make build
make run
make install-hooks
make lint-dockerfile
make test

make help is the default target and prints available commands.

Usage Examples

Pass extra arguments to the containerized opencode command by appending them after make run:

make run -- --help
make run -- --model openai/gpt-5.2-codex

You can also call run.sh directly if you want to avoid Make:

./run.sh --help

Override the container user (defaults to uid/gid 1000):

OPENCODE_DOCKER_UID=1000 OPENCODE_DOCKER_GID=1000 ./run.sh
# or
OPENCODE_DOCKER_USER=node ./run.sh

Conventional Commits

Install the commit-msg hook to enforce Conventional Commits:

make install-hooks

This also installs and configures the pre-commit hook using:

pre-commit install --allow-missing-config

The hook validates the first line of the commit message. Format:

<type>(optional-scope)!: <description>

Examples:

feat(api): add rate limiting
fix: handle empty config

The OpenCode skill definition is stored at skills/conventional-commits/SKILL.md. Copy it to ~/.config/opencode/skills/conventional-commits/SKILL.md if you want to enable it in your local OpenCode config.

Dockerfile Linting

The Dockerfile skill is stored at skills/dockerfile/SKILL.md. It requires running hadolint whenever the Dockerfile changes and only fixing findings after explicit user approval.

Run hadolint locally with:

make lint-dockerfile

If you're inside a container without Docker access, run hadolint on the host or via the built image:

docker build -t opencode-sandbox .
docker run --rm -v "$PWD:/workspace:ro" opencode-sandbox hadolint /workspace/Dockerfile

Testing

Run the lightweight smoke tests:

make test

Tests run via scripts/test.sh, which requires bash.

Run a single test by name:

TEST=syntax-run-sh make test

Install a Shell Alias

make install-bash
# or
make install-zsh

After installing, reload your shell:

source ~/.bashrc
# or
source ~/.zshrc

This adds an opencode-sandbox alias that runs run.sh from your current directory.

Uninstall the Alias

make uninstall-bash
# or
make uninstall-zsh

Notes

  • The container runs with --cap-drop=ALL and --network=bridge.
  • The container user defaults to uid/gid 1000:1000; override with OPENCODE_DOCKER_USER or OPENCODE_DOCKER_UID/OPENCODE_DOCKER_GID.
  • The container image includes the Starship prompt for interactive bash shells.
  • Container image: https://git.bueraner.de/murdoc/-/packages/container/opencode-sandbox/latest
  • Host mounts are defined in run.sh and should stay in sync with any scripts or targets that run the container. See run.sh for the canonical list.
  • OpenCode host config/data/cache/state are mounted into the container: ~/.config/opencode, ~/.local/share/opencode, ~/.cache/opencode, ~/.local/state/opencode.
  • Pre-commit cache is mounted via a Docker named volume at /home/node/.cache/pre-commit (default volume: opencode-pre-commit-cache) to speed up repeated hook runs.
  • run.sh initializes cache volume permissions on startup so the container user can write to ~/.cache/pre-commit.
  • Override the pre-commit cache volume name with OPENCODE_PRE_COMMIT_VOLUME when needed.
  • Git config is mounted read-only at ~/.config/git.
  • Starship cache is set to /tmp/starship inside the container to avoid permission issues on host-mounted paths.
  • If /var/run/docker.sock exists on the host, it is mounted into the container to enable Docker-in-Docker via the host daemon. The socket group id is added to the container user to avoid permission errors.
  • Mounts use read-only where possible; if you see permission issues, check file ownership on the host paths and the mount flags in run.sh.
  • The image tag is opencode-sandbox.

Clipboard (X11)

run.sh forwards X11 when DISPLAY is set and mounts /tmp/.X11-unix plus $XAUTHORITY (if present). The image includes xclip for clipboard access.

Host setup (once per login):

xhost +local:docker

Example usage inside the container:

printf 'hello\n' | xclip -selection clipboard
xclip -selection clipboard -o

Clipboard (Wayland)

run.sh forwards Wayland when WAYLAND_DISPLAY and XDG_RUNTIME_DIR are set and the compositor socket exists. The image includes wl-clipboard.

Example usage inside the container:

printf 'hello\n' | wl-copy
wl-paste

Versions

  • Base image: node:23-slim
  • docker-cli: 27.4.0
  • docker-buildx: 0.31.1
  • opencode-ai: 1.1.53
  • pre-commit: 4.5.1
  • ripgrep: 13.0.0-4+b2
  • shellcheck: 0.9.0-1
  • starship: 1.20.1

Troubleshooting

  • docker: command not found: Install Docker and ensure the docker CLI is on your PATH.
  • Cannot connect to the Docker daemon: Start Docker Desktop (macOS/Windows) or dockerd (Linux), then re-run make build or make run.
  • Permission errors on /var/run/docker.sock: Add your user to the docker group or use Docker Desktop, then log out/in.
  • Wayland clipboard not working: ensure WAYLAND_DISPLAY and XDG_RUNTIME_DIR are set on the host and the socket exists at $XDG_RUNTIME_DIR/$WAYLAND_DISPLAY.

Cleaning Up

make uninstall-bash
# or
make uninstall-zsh
docker rmi opencode-sandbox