|
| 1 | +// For format details, see https://aka.ms/devcontainer.json |
| 2 | +{ |
| 3 | + "name": "Claude Code Sandbox", |
| 4 | + "dockerComposeFile": "docker-compose.yml", |
| 5 | + "service": "devcontainer", |
| 6 | + "workspaceFolder": "/workspace", |
| 7 | + // Capabilities required for iptables firewall setup |
| 8 | + "capAdd": ["NET_ADMIN", "NET_RAW"], |
| 9 | + "init": true, |
| 10 | + "updateRemoteUserUID": true, |
| 11 | + "remoteUser": "node", |
| 12 | + "otherPortsAttributes": { "onAutoForward": "silent" }, |
| 13 | + "customizations": { |
| 14 | + "vscode": { |
| 15 | + "extensions": [ |
| 16 | + // **AI Agents** |
| 17 | + // Claude Code - AI coding assistant with chat, inline edits, and terminal integration |
| 18 | + "anthropic.claude-code", |
| 19 | + |
| 20 | + // **Runtime** |
| 21 | + // Bun - Bun runtime support (debugging, lockfile viewer, bundler integration) |
| 22 | + "oven.bun-vscode", |
| 23 | + |
| 24 | + // **Code Quality** |
| 25 | + // OXC - Fast linter and formatter for JavaScript/TypeScript (Rust-based) |
| 26 | + "oxc.oxc-vscode", |
| 27 | + |
| 28 | + // **Tailwind** |
| 29 | + // Tailwind CSS IntelliSense - autocomplete, syntax highlighting, linting for Tailwind classes |
| 30 | + "bradlc.vscode-tailwindcss", |
| 31 | + // Tailwind Fold - collapse long Tailwind class strings in the editor for readability |
| 32 | + "stivo.tailwind-fold", |
| 33 | + |
| 34 | + // **General** |
| 35 | + // YAML - YAML language support (for workflows and docker-compose) |
| 36 | + "redhat.vscode-yaml", |
| 37 | + // Markdown Preview Github Styles - renders Markdown preview with GitHub's CSS |
| 38 | + "bierner.markdown-preview-github-styles", |
| 39 | + // Docker - Dockerfile and Compose syntax, linting, and image management |
| 40 | + "ms-azuretools.vscode-docker" |
| 41 | + ], |
| 42 | + "settings": { |
| 43 | + "terminal.integrated.defaultProfile.linux": "fish", |
| 44 | + "terminal.integrated.profiles.linux": { |
| 45 | + "fish": { "path": "fish" }, |
| 46 | + "bash": { "path": "bash", "icon": "terminal-bash" } |
| 47 | + }, |
| 48 | + "extensions.ignoreRecommendations": true, |
| 49 | + "editor.formatOnSave": true, |
| 50 | + "editor.defaultFormatter": "oxc.oxc-vscode", |
| 51 | + "editor.codeActionsOnSave": { |
| 52 | + "source.fixAll": "explicit", |
| 53 | + "source.organizeImports": "explicit" |
| 54 | + }, |
| 55 | + "window.title": "${localWorkspaceFolderBasename}", |
| 56 | + // Sandbox visual identity — Claude Dark theme with coral remote indicator |
| 57 | + "workbench.colorTheme": "Claude Dark", |
| 58 | + "workbench.colorCustomizations": { |
| 59 | + "statusBarItem.remoteBackground": "#C15F3C", |
| 60 | + "statusBarItem.remoteForeground": "#ffffff" |
| 61 | + }, |
| 62 | + // Allow Claude Code to skip permission prompts in sandbox |
| 63 | + "claudeCode.allowDangerouslySkipPermissions": true |
| 64 | + } |
| 65 | + } |
| 66 | + }, |
| 67 | + // Named volumes keep node_modules OFF the host machine and persist across rebuilds. |
| 68 | + // Each workspace with a package.json needs its own volume mount — without one, |
| 69 | + // node_modules lands in the bind mount and shows up on the host filesystem. |
| 70 | + // Dirs are pre-created in the image with node:node ownership, so fresh volumes |
| 71 | + // inherit correct permissions via Docker volume population. |
| 72 | + // |
| 73 | + // Customize the monorepo mounts below to match your project structure. |
| 74 | + // Remove any that don't exist in your project. |
| 75 | + "mounts": [ |
| 76 | + // ── node_modules isolation (one per workspace) ───────────────────── |
| 77 | + "source=sandbox-node-modules-root-${devcontainerId},target=/workspace/node_modules,type=volume", |
| 78 | + "source=sandbox-node-modules-api-${devcontainerId},target=/workspace/services/api/node_modules,type=volume", |
| 79 | + "source=sandbox-node-modules-app-${devcontainerId},target=/workspace/services/app/node_modules,type=volume", |
| 80 | + "source=sandbox-node-modules-www-${devcontainerId},target=/workspace/services/www/node_modules,type=volume", |
| 81 | + "source=sandbox-node-modules-shared-${devcontainerId},target=/workspace/packages/shared/node_modules,type=volume", |
| 82 | + "source=sandbox-node-modules-database-${devcontainerId},target=/workspace/packages/database/node_modules,type=volume", |
| 83 | + // ── Persistent config ────────────────────────────────────────────── |
| 84 | + "source=sandbox-fish-${devcontainerId},target=/home/node/.local/share/fish,type=volume", |
| 85 | + "source=sandbox-config-${devcontainerId},target=/home/node/.claude,type=volume", |
| 86 | + // ── Firewall script ──────────────────────────────────────────────── |
| 87 | + // The image provides iptables/ipset packages and sudo rule but NOT the script itself. |
| 88 | + // Each project provides its own script via bind mount to customize the domain allowlist. |
| 89 | + "source=${localWorkspaceFolder}/.devcontainer/claude-sandbox/init-firewall.sh,target=/usr/local/bin/init-firewall.sh,type=bind" |
| 90 | + ], |
| 91 | + "containerEnv": { |
| 92 | + "TZ": "${localEnv:TZ:America/Edmonton}", |
| 93 | + "DEVCONTAINER": "true", |
| 94 | + "NODE_OPTIONS": "--max-old-space-size=4096", |
| 95 | + "CLAUDE_CONFIG_DIR": "/home/node/.claude", |
| 96 | + // Required — the sandbox firewall blocks OAuth login, so the token must be |
| 97 | + // injected from the host. See "Sandbox Authentication" section in README. |
| 98 | + "CLAUDE_CODE_OAUTH_TOKEN": "${localEnv:CLAUDE_CODE_OAUTH_TOKEN}" |
| 99 | + }, |
| 100 | + // Runs before postStartCommand (firewall), so network is still available for browser downloads. |
| 101 | + // The find command chowns all node_modules volume mount points in one pass. |
| 102 | + "postCreateCommand": "sudo find /workspace -maxdepth 4 -name node_modules -type d -exec chown node {} + && sudo chown -R node /home/node/.claude && mise install && bun install && npx playwright install --only-shell", |
| 103 | + // Firewall init — script is bind-mounted from the project |
| 104 | + "postStartCommand": "sudo /usr/local/bin/init-firewall.sh", |
| 105 | + "waitFor": "postStartCommand" |
| 106 | +} |
0 commit comments