A containerized sandbox environment for running OpenCode AI in an isolated Docker container.
  • Shell 36.7%
  • Dockerfile 33.9%
  • Makefile 24%
  • JavaScript 5.4%
Find a file
Infrapunks Bot c11adf5213
Some checks failed
pre-commit-check / pre-commit (push) Successful in 6s
Ensure container image tag matches latest Git tag / tag_latest (push) Successful in 5s
Release / release (push) Successful in 21s
CI Pipeline for building and pushing Docker images (staging and latest) / build_and_push_temp (push) Successful in 10m22s
CI Pipeline for building and pushing Docker images (staging and latest) / trivy_scan (push) Failing after 1m34s
CI Pipeline for building and pushing Docker images (staging and latest) / push_final (push) Has been skipped
chore: sync repo configuration
2026-08-05 11:11:44 +02:00
.forgejo/workflows chore(docker): update git.bueraner.de/murdoc/docker-semantic-release:latest docker digest to dfa4c20 2026-07-31 09:11:21 +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
.gitignore chore: add .worktrees folder 2026-07-15 05:00:26 +02:00
.markdownlint.jsonc chore: ignore markdownlint check MD001 2026-04-23 18:39:31 +02:00
.pre-commit-config.yaml chore: sync repo configuration 2026-08-05 11:11:44 +02:00
AGENTS.md fix(docker): move sandbox base image to node 24 lts 2026-07-15 04:56:52 +02:00
CHANGELOG.md chore(release): 0.4.4 [skip ci] 2026-07-15 13:27:41 +02:00
Dockerfile chore(deps): update dependency hadolint/hadolint to v2.15.1 2026-08-04 05:14:36 +00:00
Makefile build: add multi-arch support and fix hooks 2026-02-12 18:00:44 +01:00
README.md fix(docker): move sandbox base image to node 24 lts 2026-07-15 04:56:52 +02:00
release.config.mjs chore: add release config 2026-02-07 11:18:21 +01:00
renovate.json fix(docker): repair debian package pin updates 2026-07-11 08:58:05 +02: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.

Debian package pins in Dockerfile use Renovate comments with datasource=deb suite=bookworm ... and are matched by a regex-based customManager in renovate.json. Keep the comment and the corresponding ENV ..._VERSION line adjacent so Renovate can update the pin.

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.
  • Debian package version pins in Dockerfile are updated by Renovate via a regex customManager in renovate.json; preserve the suite=bookworm metadata in the adjacent # renovate: comment when editing them.
  • 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:24-bookworm-slim
  • docker-cli: 27.4.0
  • docker-buildx: 0.35.0
  • opencode-ai: 1.17.18
  • pre-commit: 4.6.0
  • ripgrep: 13.0.0-4+b2
  • shellcheck: 0.9.0-1
  • starship: 1.26.0

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