Initial scaffold: Debian-based opencode v1.4.0 dev container
Dockerfile with Node.js 22, git, ssh, fzf, ripgrep, fd, non-root user. Entrypoint auto-configures provider from env vars. docker-compose with workspace mount, SSH keys, and persistent data volume.
This commit is contained in:
@@ -0,0 +1,5 @@
|
|||||||
|
.git
|
||||||
|
.env
|
||||||
|
*.md
|
||||||
|
LICENSE
|
||||||
|
.DS_Store
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
# opencode-devbox environment configuration
|
||||||
|
# Copy this file to .env and fill in your values:
|
||||||
|
# cp .env.example .env
|
||||||
|
|
||||||
|
# ── LLM Provider ─────────────────────────────────────────────────────
|
||||||
|
# Which provider to auto-configure (anthropic, openai, amazon-bedrock)
|
||||||
|
OPENCODE_PROVIDER=anthropic
|
||||||
|
|
||||||
|
# Model override (optional, defaults per provider)
|
||||||
|
# OPENCODE_MODEL=anthropic/claude-sonnet-4-5
|
||||||
|
|
||||||
|
# ── API Keys (set the one matching your provider) ────────────────────
|
||||||
|
ANTHROPIC_API_KEY=
|
||||||
|
# OPENAI_API_KEY=
|
||||||
|
# GEMINI_API_KEY=
|
||||||
|
|
||||||
|
# ── AWS Bedrock (if using amazon-bedrock provider) ───────────────────
|
||||||
|
# AWS_REGION=eu-west-1
|
||||||
|
# AWS_PROFILE=default
|
||||||
|
# AWS_ACCESS_KEY_ID=
|
||||||
|
# AWS_SECRET_ACCESS_KEY=
|
||||||
|
|
||||||
|
# ── Git Configuration ────────────────────────────────────────────────
|
||||||
|
GIT_USER_NAME=
|
||||||
|
GIT_USER_EMAIL=
|
||||||
|
|
||||||
|
# ── Workspace ────────────────────────────────────────────────────────
|
||||||
|
# Path on host to mount as /workspace in the container
|
||||||
|
WORKSPACE_PATH=~/projects
|
||||||
|
|
||||||
|
# Path to SSH keys on host
|
||||||
|
SSH_KEY_PATH=~/.ssh
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
.env
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
*~
|
||||||
|
.DS_Store
|
||||||
+98
@@ -0,0 +1,98 @@
|
|||||||
|
# opencode-devbox — portable AI dev environment
|
||||||
|
# Debian-based container with opencode and configurable dev tools
|
||||||
|
|
||||||
|
ARG DEBIAN_VERSION=bookworm-slim
|
||||||
|
FROM debian:${DEBIAN_VERSION} AS base
|
||||||
|
|
||||||
|
ARG TARGETARCH
|
||||||
|
ARG OPENCODE_VERSION=1.4.0
|
||||||
|
|
||||||
|
LABEL maintainer="joakimp"
|
||||||
|
LABEL description="Portable opencode developer container"
|
||||||
|
LABEL org.opencontainers.image.source="https://gitea.jordbo.se/joakimp/opencode-devbox"
|
||||||
|
|
||||||
|
# Avoid interactive prompts during build
|
||||||
|
ENV DEBIAN_FRONTEND=noninteractive
|
||||||
|
|
||||||
|
# ── Core system packages ─────────────────────────────────────────────
|
||||||
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
|
ca-certificates \
|
||||||
|
curl \
|
||||||
|
wget \
|
||||||
|
git \
|
||||||
|
git-lfs \
|
||||||
|
openssh-client \
|
||||||
|
gnupg \
|
||||||
|
jq \
|
||||||
|
ripgrep \
|
||||||
|
fd-find \
|
||||||
|
fzf \
|
||||||
|
tree \
|
||||||
|
less \
|
||||||
|
vim-tiny \
|
||||||
|
sudo \
|
||||||
|
locales \
|
||||||
|
procps \
|
||||||
|
&& ln -s /usr/bin/fdfind /usr/local/bin/fd \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# Set locale
|
||||||
|
RUN sed -i '/en_US.UTF-8/s/^# //g' /etc/locale.gen && locale-gen
|
||||||
|
ENV LANG=en_US.UTF-8
|
||||||
|
ENV LANGUAGE=en_US:en
|
||||||
|
ENV LC_ALL=en_US.UTF-8
|
||||||
|
|
||||||
|
# ── Node.js (required for opencode v1.x install + MCP servers) ──────
|
||||||
|
ARG NODE_VERSION=22
|
||||||
|
RUN curl -fsSL https://deb.nodesource.com/setup_${NODE_VERSION}.x | bash - && \
|
||||||
|
apt-get install -y --no-install-recommends nodejs && \
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# ── Install opencode via npm ─────────────────────────────────────────
|
||||||
|
# v1.x is distributed as an npm package with platform-specific binaries
|
||||||
|
RUN npm install -g opencode-ai@${OPENCODE_VERSION} && \
|
||||||
|
opencode --version
|
||||||
|
|
||||||
|
# ── Optional: Python ─────────────────────────────────────────────────
|
||||||
|
ARG INSTALL_PYTHON=false
|
||||||
|
RUN if [ "${INSTALL_PYTHON}" = "true" ]; then \
|
||||||
|
apt-get update && apt-get install -y --no-install-recommends \
|
||||||
|
python3 python3-pip python3-venv && \
|
||||||
|
rm -rf /var/lib/apt/lists/*; \
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── Optional: Go ─────────────────────────────────────────────────────
|
||||||
|
ARG INSTALL_GO=false
|
||||||
|
ARG GO_VERSION=1.23.4
|
||||||
|
RUN if [ "${INSTALL_GO}" = "true" ]; then \
|
||||||
|
GOARCH=$(case "${TARGETARCH}" in amd64) echo "amd64" ;; arm64) echo "arm64" ;; *) echo "amd64" ;; esac) && \
|
||||||
|
curl -fsSL "https://go.dev/dl/go${GO_VERSION}.linux-${GOARCH}.tar.gz" | tar -C /usr/local -xz && \
|
||||||
|
ln -s /usr/local/go/bin/go /usr/local/bin/go && \
|
||||||
|
ln -s /usr/local/go/bin/gofmt /usr/local/bin/gofmt; \
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── Non-root user ────────────────────────────────────────────────────
|
||||||
|
ARG USER_NAME=developer
|
||||||
|
ARG USER_UID=1000
|
||||||
|
ARG USER_GID=1000
|
||||||
|
|
||||||
|
RUN groupadd --gid ${USER_GID} ${USER_NAME} && \
|
||||||
|
useradd --uid ${USER_UID} --gid ${USER_GID} -m -s /bin/bash ${USER_NAME} && \
|
||||||
|
echo "${USER_NAME} ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers.d/${USER_NAME}
|
||||||
|
|
||||||
|
# Create standard directories
|
||||||
|
RUN mkdir -p /workspace \
|
||||||
|
/home/${USER_NAME}/.config/opencode \
|
||||||
|
/home/${USER_NAME}/.local/share/opencode \
|
||||||
|
/home/${USER_NAME}/.ssh && \
|
||||||
|
chown -R ${USER_NAME}:${USER_NAME} /workspace /home/${USER_NAME}
|
||||||
|
|
||||||
|
# ── Entrypoint ────────────────────────────────────────────────────────
|
||||||
|
COPY entrypoint.sh /usr/local/bin/entrypoint.sh
|
||||||
|
RUN chmod +x /usr/local/bin/entrypoint.sh
|
||||||
|
|
||||||
|
USER ${USER_NAME}
|
||||||
|
WORKDIR /workspace
|
||||||
|
|
||||||
|
ENTRYPOINT ["entrypoint.sh"]
|
||||||
|
CMD ["opencode"]
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
# opencode-devbox
|
||||||
|
|
||||||
|
Portable AI developer environment in a Docker container. Run [opencode](https://opencode.ai) on any Docker-capable machine with configurable LLM providers, dev tools, and host filesystem access.
|
||||||
|
|
||||||
|
## Why?
|
||||||
|
|
||||||
|
The official `ghcr.io/anomalyco/opencode` image (now archived) was Alpine-based and minimal — no git, no dev tools, broken PTY support due to musl/glibc incompatibility. This project provides a **Debian-based, production-ready** alternative using the current v1.x release.
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Clone
|
||||||
|
git clone ssh://gitea.jordbo.se:2222/joakimp/opencode-devbox.git
|
||||||
|
cd opencode-devbox
|
||||||
|
|
||||||
|
# Configure
|
||||||
|
cp .env.example .env
|
||||||
|
# Edit .env with your provider, API key, workspace path, git config
|
||||||
|
|
||||||
|
# Build and run
|
||||||
|
docker compose run --rm devbox
|
||||||
|
```
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- **Debian bookworm** base — glibc, full PTY/terminal support
|
||||||
|
- **Configurable providers** — Anthropic, OpenAI, AWS Bedrock via env vars
|
||||||
|
- **Host filesystem access** — bind mount any directory as `/workspace`
|
||||||
|
- **SSH key forwarding** — git push/pull to private repos
|
||||||
|
- **MCP server support** — Node.js included for `npx`-based MCP servers
|
||||||
|
- **Non-root user** — runs as `developer` (UID 1000) with sudo
|
||||||
|
- **Optional runtimes** — Python, Go via build args (Node.js always included — required for opencode v1.x)
|
||||||
|
- **Multi-arch** — amd64 and arm64
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
### Environment Variables
|
||||||
|
|
||||||
|
| Variable | Description | Default |
|
||||||
|
|---|---|---|
|
||||||
|
| `OPENCODE_PROVIDER` | LLM provider (`anthropic`, `openai`, `amazon-bedrock`) | `anthropic` |
|
||||||
|
| `OPENCODE_MODEL` | Model override | Provider default |
|
||||||
|
| `ANTHROPIC_API_KEY` | Anthropic API key | — |
|
||||||
|
| `OPENAI_API_KEY` | OpenAI API key | — |
|
||||||
|
| `AWS_REGION` | AWS region for Bedrock | `us-east-1` |
|
||||||
|
| `GIT_USER_NAME` | Git commit author name | — |
|
||||||
|
| `GIT_USER_EMAIL` | Git commit author email | — |
|
||||||
|
| `WORKSPACE_PATH` | Host path to mount | `.` |
|
||||||
|
| `SSH_KEY_PATH` | Host SSH key directory | `~/.ssh` |
|
||||||
|
|
||||||
|
### Custom opencode config
|
||||||
|
|
||||||
|
Mount your own `opencode.json` for full control (MCP servers, custom models, etc.):
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
volumes:
|
||||||
|
- ./my-opencode.json:/home/developer/.config/opencode/opencode.json:ro
|
||||||
|
```
|
||||||
|
|
||||||
|
### Build Args
|
||||||
|
|
||||||
|
Enable optional language runtimes:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose build --build-arg INSTALL_PYTHON=true --build-arg INSTALL_GO=true
|
||||||
|
```
|
||||||
|
|
||||||
|
| Arg | Default | Description |
|
||||||
|
|---|---|---|
|
||||||
|
| `INSTALL_PYTHON` | `false` | Python 3 + pip + venv |
|
||||||
|
| `INSTALL_GO` | `false` | Go toolchain |
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
```
|
||||||
|
Host Machine
|
||||||
|
├── ~/projects/my-app ──bind mount──▶ /workspace (container)
|
||||||
|
├── ~/.ssh ──bind mount──▶ /home/developer/.ssh (ro)
|
||||||
|
└── .env ──env vars───▶ provider config + API keys
|
||||||
|
|
||||||
|
Container (Debian bookworm)
|
||||||
|
├── opencode binary
|
||||||
|
├── git, ssh, ripgrep, fd, jq, curl
|
||||||
|
├── Node.js (for MCP servers)
|
||||||
|
├── entrypoint.sh (SSH perms, git config, provider setup)
|
||||||
|
└── /workspace ← your code lives here
|
||||||
|
```
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
MIT
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
# opencode-devbox docker-compose
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# cp .env.example .env # configure your provider and keys
|
||||||
|
# docker compose up -d
|
||||||
|
# docker compose exec devbox opencode
|
||||||
|
#
|
||||||
|
# Or for interactive one-shot:
|
||||||
|
# docker compose run --rm devbox
|
||||||
|
|
||||||
|
services:
|
||||||
|
devbox:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
args:
|
||||||
|
INSTALL_PYTHON: "false"
|
||||||
|
INSTALL_GO: "false"
|
||||||
|
image: opencode-devbox:latest
|
||||||
|
container_name: opencode-devbox
|
||||||
|
stdin_open: true
|
||||||
|
tty: true
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
environment:
|
||||||
|
- TERM=xterm-256color
|
||||||
|
volumes:
|
||||||
|
# Host workspace — mount your project here
|
||||||
|
- ${WORKSPACE_PATH:-.}:/workspace
|
||||||
|
|
||||||
|
# SSH keys (read-only) — for git push/pull
|
||||||
|
- ${SSH_KEY_PATH:-~/.ssh}:/home/developer/.ssh:ro
|
||||||
|
|
||||||
|
# Optional: mount your own opencode config
|
||||||
|
# - ./config/opencode.json:/home/developer/.config/opencode/opencode.json:ro
|
||||||
|
|
||||||
|
# Optional: persist opencode data (auth, memory, etc.)
|
||||||
|
- devbox-data:/home/developer/.local/share/opencode
|
||||||
|
|
||||||
|
# Optional: AWS credentials for Bedrock
|
||||||
|
# - ~/.aws:/home/developer/.aws:ro
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
devbox-data:
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# ── SSH key permissions ──────────────────────────────────────────────
|
||||||
|
# If SSH keys are mounted, fix permissions (bind mounts may have wrong perms)
|
||||||
|
if [ -d "$HOME/.ssh" ] && [ "$(ls -A "$HOME/.ssh" 2>/dev/null)" ]; then
|
||||||
|
chmod 700 "$HOME/.ssh"
|
||||||
|
find "$HOME/.ssh" -type f -name "id_*" ! -name "*.pub" -exec chmod 600 {} \; 2>/dev/null || true
|
||||||
|
find "$HOME/.ssh" -type f -name "*.pub" -exec chmod 644 {} \; 2>/dev/null || true
|
||||||
|
[ -f "$HOME/.ssh/known_hosts" ] && chmod 644 "$HOME/.ssh/known_hosts"
|
||||||
|
[ -f "$HOME/.ssh/config" ] && chmod 600 "$HOME/.ssh/config"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── Git config defaults ──────────────────────────────────────────────
|
||||||
|
# Set git config from env vars if not already configured via mounted .gitconfig
|
||||||
|
if [ -n "${GIT_USER_NAME:-}" ] && ! git config --global user.name &>/dev/null; then
|
||||||
|
git config --global user.name "$GIT_USER_NAME"
|
||||||
|
fi
|
||||||
|
if [ -n "${GIT_USER_EMAIL:-}" ] && ! git config --global user.email &>/dev/null; then
|
||||||
|
git config --global user.email "$GIT_USER_EMAIL"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── Generate opencode config from env vars if no config mounted ──────
|
||||||
|
CONFIG_DIR="$HOME/.config/opencode"
|
||||||
|
CONFIG_FILE="$CONFIG_DIR/opencode.json"
|
||||||
|
|
||||||
|
if [ ! -f "$CONFIG_FILE" ] && [ -n "${OPENCODE_PROVIDER:-}" ]; then
|
||||||
|
echo "Generating opencode config for provider: $OPENCODE_PROVIDER"
|
||||||
|
mkdir -p "$CONFIG_DIR"
|
||||||
|
|
||||||
|
# Build provider-specific config
|
||||||
|
case "$OPENCODE_PROVIDER" in
|
||||||
|
anthropic)
|
||||||
|
cat > "$CONFIG_FILE" <<EOF
|
||||||
|
{
|
||||||
|
"\$schema": "https://opencode.ai/config.json",
|
||||||
|
"model": "${OPENCODE_MODEL:-anthropic/claude-sonnet-4-5}",
|
||||||
|
"share": "disabled",
|
||||||
|
"autoupdate": false
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
;;
|
||||||
|
openai)
|
||||||
|
cat > "$CONFIG_FILE" <<EOF
|
||||||
|
{
|
||||||
|
"\$schema": "https://opencode.ai/config.json",
|
||||||
|
"model": "${OPENCODE_MODEL:-openai/gpt-4o}",
|
||||||
|
"share": "disabled",
|
||||||
|
"autoupdate": false
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
;;
|
||||||
|
amazon-bedrock)
|
||||||
|
cat > "$CONFIG_FILE" <<EOF
|
||||||
|
{
|
||||||
|
"\$schema": "https://opencode.ai/config.json",
|
||||||
|
"model": "${OPENCODE_MODEL:-amazon-bedrock/anthropic.claude-sonnet-4-5-v1}",
|
||||||
|
"share": "disabled",
|
||||||
|
"autoupdate": false,
|
||||||
|
"provider": {
|
||||||
|
"amazon-bedrock": {
|
||||||
|
"options": {
|
||||||
|
"region": "${AWS_REGION:-us-east-1}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
cat > "$CONFIG_FILE" <<EOF
|
||||||
|
{
|
||||||
|
"\$schema": "https://opencode.ai/config.json",
|
||||||
|
"model": "${OPENCODE_MODEL:-anthropic/claude-sonnet-4-5}",
|
||||||
|
"share": "disabled",
|
||||||
|
"autoupdate": false
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── Execute command ──────────────────────────────────────────────────
|
||||||
|
exec "$@"
|
||||||
Reference in New Issue
Block a user