-
Notifications
You must be signed in to change notification settings - Fork 53
chore: integrate Claude Code into devcontainer for autonomus development #3166
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: v3.1-dev
Are you sure you want to change the base?
Changes from 1 commit
82fff6a
044c89d
cc56191
4b338b2
7953b1d
b5c8168
9b1bee6
79d8e13
abaf2fe
f069848
1772527
1aa5810
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| /Users/ivanshumkov/.claude | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,8 +1,11 @@ | ||
| # Use the official VS Code base image for dev containers | ||
| # Dash Platform Dev Container with Claude Code sandbox support | ||
| FROM mcr.microsoft.com/devcontainers/base:ubuntu | ||
|
|
||
| # Install dependencies | ||
| RUN apt-get update && apt-get install -y \ | ||
| ARG TZ=UTC | ||
| ENV TZ="$TZ" | ||
|
|
||
| # System dependencies for Rust, RocksDB, and protobuf | ||
| RUN apt-get update && apt-get install -y --no-install-recommends \ | ||
| build-essential \ | ||
| libssl-dev \ | ||
| pkg-config \ | ||
|
|
@@ -13,58 +16,90 @@ RUN apt-get update && apt-get install -y \ | |
| gnupg \ | ||
| lsb-release \ | ||
| software-properties-common \ | ||
| unzip | ||
| unzip \ | ||
| libsnappy-dev \ | ||
| # Developer tools | ||
| less \ | ||
| procps \ | ||
| fzf \ | ||
| man-db \ | ||
| ripgrep \ | ||
| fd-find \ | ||
| nano \ | ||
| vim \ | ||
| && apt-get clean && rm -rf /var/lib/apt/lists/* | ||
|
|
||
| # Switch to clang | ||
| RUN rm /usr/bin/cc && ln -s /usr/bin/clang /usr/bin/cc | ||
| # Use clang as default C compiler | ||
| RUN rm -f /usr/bin/cc && ln -s /usr/bin/clang /usr/bin/cc | ||
|
|
||
| # Install protoc - protobuf compiler (pin to 32.0) | ||
| # Alpine/system protoc may be outdated; install from releases | ||
| # Install protoc (pinned to 32.0) | ||
| ARG TARGETARCH | ||
| ARG PROTOC_VERSION=32.0 | ||
| RUN if [[ "$TARGETARCH" == "arm64" ]] ; then export PROTOC_ARCH=aarch_64; else export PROTOC_ARCH=x86_64; fi; \ | ||
| curl -Ls https://github.com/protocolbuffers/protobuf/releases/download/v${PROTOC_VERSION}/protoc-${PROTOC_VERSION}-linux-${PROTOC_ARCH}.zip \ | ||
| RUN if [ "$TARGETARCH" = "arm64" ]; then export PROTOC_ARCH=aarch_64; else export PROTOC_ARCH=x86_64; fi; \ | ||
| curl -Ls "https://github.com/protocolbuffers/protobuf/releases/download/v${PROTOC_VERSION}/protoc-${PROTOC_VERSION}-linux-${PROTOC_ARCH}.zip" \ | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe just call scripts/setup-ai-agent-environment.sh ? |
||
| -o /tmp/protoc.zip && \ | ||
| unzip -qd /opt/protoc /tmp/protoc.zip && \ | ||
| rm /tmp/protoc.zip && \ | ||
| ln -s /opt/protoc/bin/protoc /usr/bin/ | ||
|
|
||
| # Remove duplicate install; single install above is sufficient | ||
| # Install git-delta for better diffs | ||
| ARG GIT_DELTA_VERSION=0.18.2 | ||
| RUN ARCH=$(dpkg --print-architecture) && \ | ||
| curl -L "https://github.com/dandavison/delta/releases/download/${GIT_DELTA_VERSION}/git-delta_${GIT_DELTA_VERSION}_${ARCH}.deb" \ | ||
| -o /tmp/git-delta.deb && \ | ||
| dpkg -i /tmp/git-delta.deb && \ | ||
| rm /tmp/git-delta.deb | ||
|
|
||
| # Persist bash/zsh history | ||
| RUN mkdir -p /commandhistory && \ | ||
| touch /commandhistory/.bash_history /commandhistory/.zsh_history && \ | ||
| chown -R vscode:vscode /commandhistory | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. PROJ-008 (MEDIUM): This creates The README also states "No shell history is persisted or shared with the container" (Security Model section), which contradicts this Dockerfile setup. Suggestion: Either:
🤖 Claudius the Magnificent AI Code Review |
||
|
|
||
| # Switch to vscode user | ||
| # Switch to vscode user for Rust and cargo tools | ||
| USER vscode | ||
|
|
||
| ENV CARGO_HOME=/home/vscode/.cargo | ||
| ENV PATH=$CARGO_HOME/bin:$PATH | ||
|
|
||
| # TODO: It doesn't sharing PATH between stages, so we need "source $HOME/.cargo/env" everywhere | ||
| COPY rust-toolchain.toml . | ||
| RUN TOOLCHAIN_VERSION="$(grep channel rust-toolchain.toml | awk '{print $3}' | tr -d '"')" && \ | ||
| # Install Rust toolchain from rust-toolchain.toml | ||
| COPY --chown=vscode:vscode rust-toolchain.toml /tmp/rust-toolchain.toml | ||
| RUN TOOLCHAIN_VERSION="$(grep channel /tmp/rust-toolchain.toml | awk '{print $3}' | tr -d '"')" && \ | ||
| curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- \ | ||
| -y \ | ||
| --default-toolchain "${TOOLCHAIN_VERSION}" \ | ||
| --target wasm32-unknown-unknown | ||
| --target wasm32-unknown-unknown && \ | ||
| rm /tmp/rust-toolchain.toml | ||
|
|
||
| # Download and install cargo-binstall | ||
| ENV BINSTALL_VERSION=1.10.11 | ||
| # Install cargo-binstall for fast binary installs | ||
| ARG BINSTALL_VERSION=1.10.11 | ||
| RUN set -ex; \ | ||
| if [ "$TARGETARCH" = "amd64" ]; then \ | ||
| if [ "$(uname -m)" = "x86_64" ]; then \ | ||
| CARGO_BINSTALL_ARCH="x86_64-unknown-linux-musl"; \ | ||
| elif [ "$TARGETARCH" = "arm64" ] || [ "$TARGETARCH" = "aarch64" ]; then \ | ||
| elif [ "$(uname -m)" = "aarch64" ]; then \ | ||
| CARGO_BINSTALL_ARCH="aarch64-unknown-linux-musl"; \ | ||
| else \ | ||
| echo "Unsupported architecture: $TARGETARCH"; exit 1; \ | ||
| echo "Unsupported architecture: $(uname -m)"; exit 1; \ | ||
| fi; \ | ||
| DOWNLOAD_URL="https://github.com/cargo-bins/cargo-binstall/releases/download/v${BINSTALL_VERSION}/cargo-binstall-${CARGO_BINSTALL_ARCH}.tgz"; \ | ||
| curl -L --fail --show-error "$DOWNLOAD_URL" -o /tmp/cargo-binstall.tgz; \ | ||
| tar -xzf /tmp/cargo-binstall.tgz -C /tmp cargo-binstall; \ | ||
| chmod +x /tmp/cargo-binstall; \ | ||
| /tmp/cargo-binstall -y --force cargo-binstall; \ | ||
| rm /tmp/cargo-binstall; \ | ||
| cargo binstall -V | ||
| curl -L --fail --show-error \ | ||
| "https://github.com/cargo-bins/cargo-binstall/releases/download/v${BINSTALL_VERSION}/cargo-binstall-${CARGO_BINSTALL_ARCH}.tgz" \ | ||
| -o /tmp/cargo-binstall.tgz && \ | ||
| tar -xzf /tmp/cargo-binstall.tgz -C /tmp cargo-binstall && \ | ||
| chmod +x /tmp/cargo-binstall && \ | ||
| /tmp/cargo-binstall -y --force cargo-binstall && \ | ||
| rm /tmp/cargo-binstall.tgz /tmp/cargo-binstall | ||
|
|
||
| # Install wasm tools | ||
| RUN cargo binstall wasm-bindgen-cli@0.2.108 --locked \ | ||
| --no-discover-github-token --disable-telemetry --no-track --no-confirm && \ | ||
| cargo binstall wasm-pack --locked \ | ||
| --no-discover-github-token --disable-telemetry --no-track --no-confirm | ||
|
|
||
| # Prepare directories (need root for /workspace) | ||
| USER root | ||
| RUN mkdir -p /home/vscode/.claude /workspace && \ | ||
| chown -R vscode:vscode /home/vscode/.claude /workspace | ||
| USER vscode | ||
|
|
||
| RUN cargo binstall wasm-bindgen-cli@0.2.103 --locked \ | ||
| --no-discover-github-token \ | ||
| --disable-telemetry \ | ||
| --no-track \ | ||
| --no-confirm | ||
| ENV SHELL=/bin/zsh | ||
| ENV EDITOR=nano | ||
| ENV VISUAL=nano | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,164 @@ | ||
| # Dev Container | ||
|
|
||
| Sandboxed development environment for Dash Platform with Claude Code pre-configured for autonomous work. | ||
|
|
||
| ## What's Included | ||
|
|
||
| - **Rust 1.92** with `wasm32-unknown-unknown` target | ||
| - **Node.js 24** with yarn 4.12.0 (via corepack) | ||
| - **Docker-in-Docker** for dashmate | ||
| - **Claude Code** with `bypassPermissions` mode | ||
| - protoc 32.0, wasm-bindgen-cli 0.2.108, wasm-pack, cargo-binstall | ||
| - Developer tools: git-delta, ripgrep, fd, fzf | ||
|
|
||
| ## Prerequisites | ||
|
|
||
| ### SSH keys (for git push/pull) | ||
|
|
||
| VS Code forwards your host's SSH agent into the container automatically. Make sure your key is loaded: | ||
|
|
||
| ```bash | ||
| ssh-add --apple-use-keychain ~/.ssh/id_rsa # macOS | ||
| ssh-add ~/.ssh/id_rsa # Linux | ||
| ``` | ||
|
|
||
| Without this, `git push`/`git pull` will fail with `Permission denied (publickey)`. | ||
|
|
||
| ### Claude Code authentication | ||
|
|
||
| Authenticate using **one or both** methods. OAuth login must be done on the **host** — it does not work inside the container (the OAuth callback can't reach localhost in the container). | ||
|
|
||
| ### Option A: OAuth (recommended) | ||
|
|
||
| Run on your **host machine** before opening the devcontainer: | ||
|
|
||
| ```bash | ||
| claude login | ||
| ``` | ||
|
|
||
| Your `~/.claude/` config (credentials, skills, plugins) is automatically copied into the container on each rebuild. If tokens expire, re-run `claude login` on the host and rebuild. | ||
|
|
||
| ### Option B: API Key | ||
|
|
||
| ```bash | ||
| export ANTHROPIC_API_KEY=sk-ant-... | ||
| ``` | ||
|
|
||
| Set this in your shell profile so it's available when VS Code launches. | ||
|
|
||
| ## Usage with VS Code | ||
|
|
||
| 1. Install the [Dev Containers](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) extension | ||
| 2. Open this repository in VS Code | ||
| 3. Press `Ctrl+Shift+P` (or `Cmd+Shift+P` on macOS) and select **Dev Containers: Reopen in Container** | ||
| 4. Wait for the build (first time takes a while — Rust toolchain, etc.) | ||
| 5. Claude Code is ready in the integrated terminal: | ||
|
|
||
| ```bash | ||
| claude # runs with full permissions, no prompts | ||
| ``` | ||
|
|
||
| ### Personal extensions | ||
|
|
||
| The `devcontainer.json` includes shared team extensions (rust-analyzer, eslint, Claude Code, etc.). To add your own extensions to every dev container, set this in your **host** VS Code settings (`Cmd+,` → search "defaultExtensions"): | ||
|
|
||
| ```json | ||
| { | ||
| "dev.containers.defaultExtensions": [ | ||
| "github.copilot", | ||
| "vscodevim.vim" | ||
| ] | ||
| } | ||
| ``` | ||
|
|
||
| ## Usage with CLI (no VS Code) | ||
|
|
||
| You can use the [devcontainer CLI](https://github.com/devcontainers/cli) directly: | ||
|
|
||
| ```bash | ||
| # Install the CLI | ||
| npm install -g @devcontainers/cli | ||
|
|
||
| # Build the container | ||
| devcontainer build --workspace-folder . | ||
|
|
||
| # Start and enter the container | ||
| devcontainer up --workspace-folder . | ||
| devcontainer exec --workspace-folder . bash | ||
|
|
||
| # Run Claude Code directly | ||
| devcontainer exec --workspace-folder . claude --dangerously-skip-permissions | ||
| ``` | ||
|
|
||
| Or use Docker Compose / `docker exec` if you prefer: | ||
|
|
||
| ```bash | ||
| # Build | ||
| devcontainer build --workspace-folder . | ||
|
|
||
| # Start in background | ||
| devcontainer up --workspace-folder . | ||
|
|
||
| # Run Claude in headless mode (for CI/automation) | ||
| devcontainer exec --workspace-folder . claude -p "run the test suite" --dangerously-skip-permissions | ||
| ``` | ||
|
|
||
| ## Authentication Details | ||
|
|
||
| Your host's `~/.claude/` directory is mounted read-only into the container. On first create, the `post-create.sh` script: | ||
|
|
||
| 1. Copies your entire `~/.claude/` config (credentials, skills, plugins, etc.) into a persistent Docker volume | ||
| 2. Forces `bypassPermissions` mode on top of your settings | ||
| 3. Skips the safety confirmation prompt | ||
|
|
||
| Host config items that reference host-specific paths (MCP servers, hooks, etc.) are copied as-is. They will log warnings if the referenced binaries don't exist in the container — this is harmless. | ||
|
coderabbitai[bot] marked this conversation as resolved.
Outdated
|
||
|
|
||
| ## Network Firewall (optional) | ||
|
|
||
| By default, the container has unrestricted network access. To enable a restrictive firewall that only allows whitelisted services, add the following to `devcontainer.json`: | ||
|
|
||
| ```jsonc | ||
| "runArgs": ["--cap-add=NET_ADMIN", "--cap-add=NET_RAW"], | ||
| "postStartCommand": "sudo /usr/local/bin/init-firewall.sh", | ||
| "waitFor": "postStartCommand" | ||
| ``` | ||
|
|
||
| You'll also need to add `iptables ipset iproute2 dnsutils` to the `apt-get install` in the Dockerfile and uncomment the firewall COPY/sudoers block. See `init-firewall.sh` for the domain whitelist. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. PROJ-001 (MEDIUM): These instructions reference "uncomment the firewall COPY/sudoers block" but no such block exists in the current Dockerfile. A developer following this will hit a dead end. Suggestion: Either:
You'll also need to:
1. Add `iptables ipset iproute2 dnsutils` to the `apt-get install` in the Dockerfile
2. Add `COPY init-firewall.sh /usr/local/bin/init-firewall.sh` to the Dockerfile
3. Add a sudoers entry: `RUN echo "vscode ALL=(root) NOPASSWD: /usr/local/bin/init-firewall.sh" > /etc/sudoers.d/firewall`🤖 Claudius the Magnificent AI Code Review |
||
|
|
||
| ## Persistent Data | ||
|
|
||
| These items survive container rebuilds (stored in Docker named volumes): | ||
|
|
||
| - `~/.cargo/registry` and `~/.cargo/git` — Rust dependency cache | ||
| - `target/` — Rust build artifacts | ||
| - `~/.claude/` — Claude Code config, credentials, conversation history | ||
| - `/commandhistory/` — shell history | ||
|
|
||
| ## Troubleshooting | ||
|
|
||
| ### Git worktrees | ||
|
|
||
| Git worktrees are supported automatically. The `init-host.sh` script (runs on the host) detects whether you opened a worktree or the main repo and mounts the main `.git` directory into the container. The `post-create.sh` script creates the necessary symlinks so git resolves the worktree paths correctly. Commits and pushes from inside the container work as expected. | ||
|
|
||
| ### Claude says "not authenticated" | ||
|
|
||
| - Check that `ANTHROPIC_API_KEY` is set in your host shell, or | ||
| - Run `claude login` on your host before opening the devcontainer, or | ||
| - Run `claude login` inside the container | ||
|
|
||
| ### MCP server warnings at Claude startup | ||
|
|
||
| - Expected if your host config has MCP servers referencing macOS binaries. Harmless — Claude works fine without them. | ||
|
|
||
| ### `yarn install` fails | ||
|
|
||
| - Run `corepack enable` first (should be done by `post-create.sh`) | ||
|
|
||
| ### Docker commands fail inside the container | ||
|
|
||
| - Docker-in-Docker starts automatically. If it didn't, check `docker info`. | ||
|
|
||
| ### Firewall too restrictive (if enabled) | ||
|
|
||
| - Edit `.devcontainer/init-firewall.sh` to add domains | ||
| - Or temporarily flush rules: `sudo iptables -F OUTPUT` | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This file should not be committed — it contains a machine-specific path and exposes a developer's username.
This file contains a hardcoded personal path (
/Users/ivanshumkov/.claude) which:This file should be removed from the commit and added to
.gitignore:Proposed .gitignore addition
# Devcontainer host-resolved symlink (machine-specific) .devcontainer/.main-git-resolved .devcontainer/.claude-host-config +.devcontainer/.claude-config-resolvedThen remove this file from the repository:
🤖 Prompt for AI Agents