-
Notifications
You must be signed in to change notification settings - Fork 50
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
Open
shumkov
wants to merge
12
commits into
v3.1-dev
Choose a base branch
from
chore/devcontainer
base: v3.1-dev
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
82fff6a
chore: integrate claude into devcontainer
shumkov 044c89d
feat: cleanup
shumkov cc56191
chore(devcontainer): sync host plugins, agents, and skills into conta…
shumkov 4b338b2
docs(devcontainer): add claude login --print-link as in-container aut…
shumkov 7953b1d
chore(devcontainer): forward CLAUDE_CODE_OAUTH_TOKEN into container
shumkov b5c8168
Merge branch 'v3.1-dev' into chore/devcontainer
shumkov 9b1bee6
chore(devcontainer): fix symlink bug, remove tracked personal file, a…
shumkov 79d8e13
Merge branch 'v3.1-dev' into chore/devcontainer
shumkov abaf2fe
chore(devcontainer): remove ~/.claude.json from container staging
shumkov f069848
chore(devcontainer): make agent/skill host copy opt-in, remove auto p…
shumkov 1772527
chore(devcontainer): update docs to reflect new plugin/agent/skill co…
shumkov 1aa5810
chore(devcontainer): address reviewer feedback
shumkov File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| # Personal Claude Code agents and skills to copy from your host ~/.claude/ into the container. | ||
| # Copy this file to .env and customize. This file is gitignored. | ||
| # | ||
| # For plugins, use .claude/settings.local.json inside the container instead | ||
| # (auto-gitignored by Claude Code). | ||
| # | ||
| # Comma-separated names (agents without .md extension, skills as directory names) | ||
| CLAUDE_AGENTS= | ||
| CLAUDE_SKILLS= |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| .env | ||
| .claude-host-config/ | ||
| .main-git-resolved | ||
| .claude-config-resolved |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,224 @@ | ||
| # 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 | ||
|
|
||
| ### GitHub access (for git push/pull) | ||
|
|
||
| The easiest option is to export `GH_TOKEN` (or `GITHUB_TOKEN`) on your host. The devcontainer forwards it and configures HTTPS git automatically — no SSH key required: | ||
|
|
||
| ```bash | ||
| export GH_TOKEN=ghp_... # add to your shell profile | ||
| ``` | ||
|
|
||
| Alternatively, VS Code forwards your host's SSH agent into the container. Make sure your key is loaded: | ||
|
|
||
| ```bash | ||
| ssh-add --apple-use-keychain ~/.ssh/id_rsa # macOS | ||
| ssh-add ~/.ssh/id_rsa # Linux | ||
| ``` | ||
|
|
||
| ### Claude Code authentication | ||
|
|
||
| Authenticate using **one or both** methods. | ||
|
|
||
| ### Option A: OAuth (recommended) | ||
|
|
||
| Run on your **host machine** before opening the devcontainer: | ||
|
|
||
| ```bash | ||
| claude login | ||
| ``` | ||
|
|
||
| Your OAuth credentials (`~/.claude/.credentials.json`) are copied into the container. Optionally, personal agents and skills listed in `.devcontainer/.env` are also copied. No conversation history, project memories, settings, or plugins are transferred. If tokens expire, re-run `claude login` on the host and rebuild. | ||
|
|
||
| You can also log in from inside the container using the print-link flow (no browser redirect needed): | ||
|
|
||
| ```bash | ||
| claude login --print-link | ||
| ``` | ||
|
|
||
| ### Option B: OAuth Token | ||
|
|
||
| ```bash | ||
| export CLAUDE_CODE_OAUTH_TOKEN=<your-token> | ||
| ``` | ||
|
|
||
| Set this in your shell profile. The token is forwarded into the container automatically. | ||
|
|
||
| ### Option C: 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 | ||
| ``` | ||
|
|
||
| ## Claude Code customization | ||
|
|
||
| ### Plugins | ||
|
|
||
| Plugins are **not** copied from your host. Use `.claude/settings.local.json` inside the container to enable personal plugins — this file is automatically gitignored by Claude Code: | ||
|
|
||
| ```json | ||
| { | ||
| "enabledPlugins": { | ||
| "my-plugin@my-marketplace": true | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ### Agents & skills | ||
|
|
||
| Personal agents and skills are **not** copied automatically. To bring specific ones from your `~/.claude/` into the container, create a `.env` file: | ||
|
|
||
| ```bash | ||
| cp .devcontainer/.env.example .devcontainer/.env | ||
| ``` | ||
|
|
||
| Edit `.env` with comma-separated names: | ||
|
|
||
| ```bash | ||
| # Agents from ~/.claude/agents/ (without .md extension) | ||
| CLAUDE_AGENTS=blockchain-security-auditor,rust-engineer | ||
|
|
||
| # Skills from ~/.claude/skills/ (directory names) | ||
| CLAUDE_SKILLS=my-custom-skill | ||
| ``` | ||
|
|
||
| The `.env` file is gitignored — each developer configures their own. | ||
|
|
||
| ### Project-level settings | ||
|
|
||
| The project's `.claude/` directory is available inside the container via the workspace bind mount. Project-level agents (`.claude/agents/`) and skills (`.claude/skills/`) are automatically loaded by Claude Code. | ||
|
|
||
| ## Security Model | ||
|
|
||
| Claude Code runs with `bypassPermissions` inside the container — it can read, write, and execute anything. The container is the sandbox boundary. To minimize exposure: | ||
|
|
||
| - **Only OAuth credentials** are copied from the host (`~/.claude/.credentials.json`). No conversation history, project memories, settings, plugins, hooks, scripts, or debug logs are transferred. | ||
| - **Agents/skills** are only copied if explicitly listed in `.devcontainer/.env` — nothing personal leaks in by default. | ||
| - **A clean `settings.json`** is generated inside the container with `bypassPermissions` — your host's permission allowlists, MCP server configs, and hooks are not copied. | ||
| - **No shell history** is persisted or shared with the container. | ||
| - **The `.git` directory** is mounted read-write (required for commits/pushes). This is the main trust boundary — Claude can push code. | ||
|
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. You might find this useful: https://github.com/lklimek/claudius/blob/main/hooks/block-github-writes.sh |
||
|
|
||
| ## 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 make two changes to the `Dockerfile`: | ||
|
|
||
| 1. Add `iptables ipset iproute2 dnsutils` to the `apt-get install` block. | ||
| 2. After the apt-get block, add: | ||
| ```dockerfile | ||
| COPY init-firewall.sh /usr/local/bin/init-firewall.sh | ||
| RUN echo "vscode ALL=(root) NOPASSWD: /usr/local/bin/init-firewall.sh" > /etc/sudoers.d/firewall | ||
| ``` | ||
|
|
||
| See `init-firewall.sh` for the domain whitelist. | ||
|
|
||
| ## 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 credentials, settings, and optionally agents/skills from host | ||
|
|
||
| ## 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" | ||
|
|
||
| - Ensure `ANTHROPIC_API_KEY` is set in your host shell, **or** | ||
| - Run `claude login` on your host and rebuild the container, **or** | ||
| - Run `claude login --print-link` inside the container (no browser redirect needed) | ||
|
|
||
| ### `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` | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
Maybe just call scripts/setup-ai-agent-environment.sh ?