A VS Code DevContainer configuration that provides isolated, reproducible development environments with intelligent host integration.
- Isolated Environment: Container with sandboxed home directory to prevent pollution of host home
- Claude AI Integration: Automatic bind mounts for
.claudeconfig and state persistence - GPG Signing: Forwards host GPG agent socket into the container for commit and tag signing
- GPU Passthrough: Exposes host render nodes to the webgpu (Vulkan) backend in both execution modes, by the mechanism each kernel driver needs (see AGENTS.md)
- Smart Mount System: Selective bind mounts preserve tool configurations while isolating the container
- Automatic Setup: Self-configuring initialisation script
- Cross-Platform: Works on Windows, Linux, and macOS with automatic path translation
- Development-Optimized Security: Runs with elevated privileges for debugging and advanced development scenarios (development use only)
The development container is built on
amery/docker-builder, extending
the docker-apptly-builder image with:
- Go: Full Go development environment
- Node.js: JavaScript/TypeScript runtime and tooling
- VS Code Server: Pre-configured for DevContainer support
- Build Tools: Essential compilation and development utilities
The docker-builder project provides the foundation for this DevContainer, including the base images, build system, and container runtime wrapper. For details on available base images and the build infrastructure, see the docker-builder documentation.
- Docker, installed and running
- Windows: Docker Desktop with the WSL 2 backend (WSL 2 itself must be installed and enabled)
- macOS: Docker Desktop
- Linux: Docker Engine
- Visual Studio Code with the Dev Containers extension
- Git on your
PATH- Windows: install Git for Windows.
GitHub Desktop's bundled git is not enough — a full git must be on
your
PATHfor cloning and VS Code's Git integration.
- Windows: install Git for Windows.
GitHub Desktop's bundled git is not enough — a full git must be on
your
- Node.js on your
PATH. VS Code'sinitializeCommandrunsnode .devcontainer/init.json the host before building the container, so a standalone Node.js is required.- The runtime bundled inside VS Code (Electron) does not count: it is
not exposed as a
nodecommand onPATH.
- The runtime bundled inside VS Code (Electron) does not count: it is
not exposed as a
-
Clone the repository:
git clone <repository-url> cd dev-env
-
Open in VS Code:
code . -
When VS Code opens, click "Reopen in Container" when prompted (or use Command Palette → "Dev Containers: Reopen in Container")
The container will automatically initialise on first run. The initialisation process:
- Detects your operating system (Windows, Linux, or macOS)
- Runs the appropriate script (
init.ps1for Windows,init.shfor Unix-like systems) - Creates necessary directories and configures mounts for Claude AI integration
- Handles path translation on Windows (e.g.
C:\Users\john→/C/Users/john) - Pulls the base image on first run (if not already present) to read its metadata
- Generates a custom Dockerfile with user-specific metadata, and with the host's GPU render group when there is one
.devcontainer/ # VS Code DevContainer configuration
├── devcontainer.json # Container settings and mounts (auto-updated)
├── Dockerfile # Auto-generated by init scripts
├── init.js # Cross-platform entry point (Node.js)
├── init.sh # Linux/macOS initialisation script
└── init.ps1 # Windows PowerShell initialisation script
.docker-run-cache/ # Container runtime storage (git-ignored)
└── ${HOME}/ # Sandboxed home directory
docker/ # Base container definitions
├── Dockerfile # Base image configuration
├── gpu.sh # Host GPU discovery (sourced by both modes)
└── run.sh # Container runtime script
run.sh # Symlink to docker/run.sh (workspace root marker)
go.work # Go workspace configuration
This environment supports two complementary workflows:
Open the workspace in VS Code and use the "Reopen in Container" feature. The container runs continuously with VS Code Server, providing integrated terminal, debugging, and extensions.
- Best for: Interactive development, debugging, IDE features
- Lifecycle: Managed by VS Code (start, stop, rebuild)
- Terminal: Opens directly inside container
- User: Matches host UID/GID via entrypoint
Use the x helper to execute commands in containers. On the host,
each invocation creates a new container via docker-builder-run.
Inside the container, run.sh detects /.dockerenv and passes
through directly.
- Best for: Host-side builds, CI/CD, quick commands, nested workspaces
- Lifecycle: Per-command (container created and destroyed)
- Persistent State: Sandboxed home and tool configurations
(
.claude) survive across invocations - Terminal: Executes on host, trampolines to container
- Container-Aware: Also works inside the container (passthrough)
- User: Same UID/GID matching via entrypoint
Both workflows use the same base image and entrypoint, ensuring
consistent behaviour. Scripts never include x in their commands; this
makes them portable between DevContainer (direct execution) and host
(x ./script.sh).
The x script provides intelligent workspace detection and command
execution via the docker-builder-run trampoline. Both are published
as release assets by
docker-builder.
Download the latest x and docker-builder-run from
docker-builder releases
and place them on your PATH:
INSTALL=~/.local/bin
mkdir -p "$INSTALL"
BASE=https://github.com/amery/docker-builder/releases/latest/download
curl -L -o "$INSTALL/x" "$BASE/x"
curl -L -o "$INSTALL/docker-builder-run" "$BASE/docker-builder-run"
chmod +x "$INSTALL/x" "$INSTALL/docker-builder-run"# Find workspace root
x --root
# Execute command in container (finds and calls run.sh)
x make build
x go test ./...
x pwd # Returns actual directory, not /
# Works from any subdirectory
cd src/myproject
x make # Still finds workspace root run.sh
# Pass through if no run.sh found
x echo "hello"-
Workspace Detection: Searches for
run.shby checking:.repodirectory (for repo tool workspaces)- Git workspace root: tries superproject first (
git rev-parse --show-superproject-working-tree), falls back to repository root (git rev-parse --show-toplevel) - Parent directories up to filesystem root (brute force)
-
Trampoline Execution: When
run.shis found on the host:xcallsrun.shwith your commandrun.shinvokes docker-builder-run- docker-builder-run creates fresh container
- Entrypoint sets up user and navigates to CURDIR
- Your command executes in correct directory
-
Container Passthrough: If
run.shdetects/.dockerenv(inside a container), it skips docker and executes the command directly -
Fallback: If no
run.shis found, executes command directly on host
- Script Portability: Write scripts without
x; they work in DevContainer and viax ./script.shfrom host - Directory Preservation: Entrypoint sets CURDIR so
x pwdreturns actual directory - Submodule Aware: Finds correct workspace in nested Git repositories
- Consistent Environment: Same image and entrypoint as DevContainer
# Start VS Code DevContainer for interactive work
code .
# Click "Reopen in Container" when prompted
# In VS Code terminal (inside container):
./build.sh # Runs directly in container
make test # Runs in container environment
# From host terminal, use `x`:
x ./build.sh # Creates fresh container, runs script
x make test # Same behaviour as in DevContainer
# Both execute identically: never put 'x' in scripts# From any subdirectory, use `x` to run commands in the container
cd src/myapp
x go build ./...
x go test -v
# Check workspace root
x --root
# Directory preserved in container
x pwd # Returns /path/to/src/myapp, not /# Invoke scripts via `x` from host (never include `x` in scripts)
x ./build.sh
x ./test.sh
# Or call `x` with commands directly
x make clean
x make build
x make test
# Scripts remain portable: work in both DevContainer and via `x`The container sets these environment variables:
WS: Workspace root pathCURDIR: Current working directory at invocationGOPATH: Go path (set to workspace for Go projects)
Login shells additionally point CLI clients at a host Ollama daemon, when
host.docker.internal resolves (a silent no-op otherwise):
OLLAMA_HOST:host.docker.internal:11434, unless already setOPENAI_BASE_URL,OPENAI_API_KEY: srclight's embedding client has no Ollama override, so it rides Ollama's OpenAI-compatible APISRCLIGHT_EMBED_REQUEST_TIMEOUT: raised for slow local embedding
The OpenAI block is skipped when OPENAI_BASE_URL is already set, so a real
OpenAI endpoint configured earlier still wins. These come from the baked
/etc/profile.d/ollama.sh (see docker/Dockerfile), not the entrypoint, so
they apply to login shells in both modes. For the host-side reachability
requirements, see AGENTS.md.
- "Reopen in Container" not appearing: Ensure Docker is running and the Dev Containers extension is installed in VS Code
- Mount permission errors: Run
git statusto ensure the repository is clean, then rebuild the container - Claude configuration not persisting: Rebuild the container
(DevContainer) or verify
docker-builder-runis installed (CLI) - Windows path issues: The system automatically detects WSL vs Docker Desktop and translates paths accordingly
- Windows username issues: Special characters and spaces in Windows usernames are automatically sanitized for Linux compatibility
If you encounter issues, try rebuilding:
-
Quick Rebuild: Command Palette → "Dev Containers: Rebuild Container"
- Reuses cached Docker layers when possible
- Faster but may not pick up base image updates
-
Clean Rebuild: Command Palette → "Dev Containers: Rebuild Container Without Cache"
- Removes all cached layers and rebuilds from scratch
- Downloads latest base image updates
- Ensures you have the newest versions of Go, Node.js, and tools
You can also access these options from VS Code's UI:
- Click the remote indicator (bottom-left corner)
- Select "Rebuild Container" or "Rebuild Container Without Cache"
This project is a specialized implementation of docker-builder:
- Extends: Uses docker-builder's
docker-apptly-builderbase image - Leverages:
docker-builder-runfor container execution - Demonstrates: How to create DevContainer environments on top of docker-builder infrastructure
When docker-builder is updated:
- Base image improvements automatically benefit this environment
- Breaking changes may require updates to the Dockerfile or configuration
- Updates to
docker-builder-runimprove container execution
- AGENTS.md - Technical implementation details for AI agents and developers
- LICENCE.txt - Project license information
- docker-builder - Base infrastructure documentation
See LICENCE.txt for details.