Reusable devcontainer for AI-assisted development with Claude Code. Python 3.13, Node.js 22, automatic macOS Keychain auth forwarding, and safety guardrails.
| File | Purpose |
|---|---|
Dockerfile |
Python 3.13 + Node 22 + Playwright deps + uv |
devcontainer.json |
16GB memory limit, Claude config mounts, git identity |
extract-claude-auth.sh |
Extracts Claude Code OAuth tokens from macOS Keychain |
post-create.sh |
Installs Claude Code + project setup (customize per repo) |
post-start.sh |
Forwards credentials + symlinks host paths on every start |
claude-dev.sh |
Launches Claude Code with --dangerously-skip-permissions + safety rules |
guardrail-hook.sh |
Blocks secret reads, host config writes, git push from container |
cp -r .devcontainer/ /path/to/your-project/.devcontainer/Open .devcontainer/post-create.sh and uncomment the sections relevant to your project:
Python project:
uv sync --extra dev
uv tool install --editable --force "$REPO"Node.js project:
npm ci --prefix "$REPO"Frontend with separate directory:
sudo chown vscode:vscode "$REPO/frontend/node_modules"
npm ci --prefix "$REPO/frontend"
npm run build --prefix "$REPO/frontend"Edit devcontainer.json to add bind mounts for data directories your project needs:
Cmd+Shift+P → "Dev Containers: Reopen in Container"
- Docker runtime: OrbStack (recommended for Mac) or Docker Desktop
- Claude Code: Must be logged in on the host first (
claudein terminal) - OrbStack memory: Set to 16GB+ in OrbStack Settings → System → Memory limit
Two ways to launch:
claude # Normal permissions — prompts for tool approval
claude-dev # Skip permissions + safety guardrails (for trusted repos)claude-dev enables frictionless development while blocking:
- Reading credential/secret files
- Modifying host Claude config (bind-mounted)
git push(no SSH keys in container — push from host)
- Before container starts (
initializeCommand):extract-claude-auth.shreads your Claude Code OAuth tokens from macOS Keychain and writes them to~/.config/devcontainer-auth/claude-oauth.json - On every container start (
postStartCommand):post-start.shcopies those tokens into the container's~/.claude/.credentials.json - No browser login needed inside the container
If you see a macOS Keychain access prompt, that's the extraction script — safe to allow.
The container is configured with a hard 16GB memory limit and no swap (--memory=16g --memory-swap=16g). This prevents OOM kills during parallel Claude Code agent execution.
Adjust in devcontainer.json → runArgs if your machine has more/less RAM. Leave ~8GB for macOS.
guardrail-hook.sh is a PreToolUse hook template. To activate it, add to your Claude Code settings (inside container):
{
"hooks": {
"PreToolUse": [
{ "command": "/workspace/.devcontainer/guardrail-hook.sh" }
]
}
}Or extend it with project-specific rules (e.g., blocking writes to a bind-mounted data directory).
- VS Code extensions: Add to
devcontainer.json→customizations.vscode.extensions - Environment variables: Add
"containerEnv"block or use--env-fileinrunArgs - Named volumes: Use for directories that need Linux-specific binaries (e.g.,
node_modules)