microsoft/TypeAgent
Publicmirrored fromhttps://github.com/microsoft/TypeAgentAvailable
.devcontainer/agent/devcontainer.json
180lines · modecode
| 1 | { |
| 2 | "name": "TypeAgent Development (Agent Worktrees)", |
| 3 | "build": { "dockerfile": "../Dockerfile" }, |
| 4 | |
| 5 | // Variant of the standard devcontainer where the container sees the |
| 6 | // workspace at the SAME absolute path as the host. This lets VS Code's |
| 7 | // Copilot CLI agent worktree feature work end-to-end: |
| 8 | // |
| 9 | // src/vs/platform/agentHost/node/copilot/copilotAgent.ts |
| 10 | // getCopilotWorktreesRoot() -> <parent>/<basename>.worktrees |
| 11 | // |
| 12 | // is hardcoded, so the only way to have host VS Code open an agent- |
| 13 | // created worktree at the same path the container created it is to |
| 14 | // make the parent directory a single bind mount with matching paths. |
| 15 | // |
| 16 | // This config is LOCAL-ONLY (Linux/macOS host with Docker). It will not |
| 17 | // work in Codespaces - there is no `localWorkspaceFolder` on the cloud |
| 18 | // host. Use ../devcontainer.json (the default config) for Codespaces. |
| 19 | // |
| 20 | // Prerequisites on the host: |
| 21 | // - Your host user's UID matches the `codespace` user inside the |
| 22 | // container. `updateRemoteUserUID` below handles the common case |
| 23 | // by re-chowning `codespace` to your host UID on first start. |
| 24 | // - The sibling `<repo>.worktrees` directory must exist on the host |
| 25 | // before container start (Docker bind-mount requirement). The |
| 26 | // `initializeCommand` below creates it automatically. |
| 27 | |
| 28 | "features": { |
| 29 | "ghcr.io/anthropics/devcontainer-features/claude-code:1.0": {}, |
| 30 | "ghcr.io/devcontainers/features/sshd:1": { |
| 31 | "version": "latest" |
| 32 | }, |
| 33 | "ghcr.io/devcontainers/features/git-lfs:1": { |
| 34 | "autoPull": false |
| 35 | }, |
| 36 | "ghcr.io/devcontainers/features/node:1": { |
| 37 | "version": "22", |
| 38 | "nodeGypDependencies": true |
| 39 | }, |
| 40 | "ghcr.io/devcontainers/features/python:1": { |
| 41 | "version": "3.12", |
| 42 | "installTools": true |
| 43 | }, |
| 44 | "ghcr.io/devcontainers/features/dotnet:2": { |
| 45 | "version": "8.0" |
| 46 | }, |
| 47 | "ghcr.io/devcontainers/features/azure-cli:1": {}, |
| 48 | "ghcr.io/devcontainers/features/github-cli:1": {}, |
| 49 | "ghcr.io/devcontainers/features/common-utils:2": { |
| 50 | "installZsh": true, |
| 51 | "configureZshAsDefaultShell": true, |
| 52 | "installOhMyZsh": true, |
| 53 | "username": "codespace", |
| 54 | "userUid": "1001", |
| 55 | "userGid": "1001" |
| 56 | } |
| 57 | }, |
| 58 | |
| 59 | // Re-chown the `codespace` user to the host user's UID/GID on container |
| 60 | // start so the bind-mounted source tree (owned by the host user) is |
| 61 | // writable from inside the container. |
| 62 | "updateRemoteUserUID": true, |
| 63 | |
| 64 | // Hardening for agent use: |
| 65 | // - userEnvProbe "none" stops the Dev Containers CLI from sourcing your |
| 66 | // host login shell and copying its environment (including any tokens |
| 67 | // or agent-friendly env vars) into the container. |
| 68 | // - runArgs apply Docker-level constraints: drop all capabilities then |
| 69 | // add back only those the post-create script needs (chown/dac_override |
| 70 | // /fowner for volume ownership fixes; setuid/setgid because sudo and |
| 71 | // the common-utils feature need them), and cap the process table to |
| 72 | // limit fork-bomb blast radius. |
| 73 | // |
| 74 | // Note: `--security-opt=no-new-privileges` is intentionally NOT set, |
| 75 | // because it blocks setuid binaries (including sudo), which |
| 76 | // post-create.sh needs to chown the named-volume mountpoints Docker |
| 77 | // creates as root:root on first start. |
| 78 | "userEnvProbe": "none", |
| 79 | "runArgs": [ |
| 80 | "--cap-drop=ALL", |
| 81 | // Needed by post-create.sh (chown volume mountpoints, sudo, common-utils) |
| 82 | "--cap-add=CHOWN", |
| 83 | "--cap-add=DAC_OVERRIDE", |
| 84 | "--cap-add=FOWNER", |
| 85 | "--cap-add=SETUID", |
| 86 | "--cap-add=SETGID", |
| 87 | // Needed by sudo to manipulate the capability bounding set, and by |
| 88 | // sshd's privilege separation (chroot, dropping caps on the child). |
| 89 | "--cap-add=SETPCAP", |
| 90 | "--cap-add=SYS_CHROOT", |
| 91 | "--cap-add=KILL", |
| 92 | // Needed if sshd binds a privileged port; harmless if it doesn't. |
| 93 | "--cap-add=NET_BIND_SERVICE", |
| 94 | // Silences `sudo: unable to send audit message` warnings; also used |
| 95 | // by sshd when logging auth events to the kernel audit subsystem. |
| 96 | "--cap-add=AUDIT_WRITE", |
| 97 | "--pids-limit=4096" |
| 98 | ], |
| 99 | |
| 100 | "appPort": ["127.0.0.1:2222:2222"], |
| 101 | |
| 102 | "forwardPorts": [8999, 8081, 8082, 3000, 3443], |
| 103 | "portsAttributes": { |
| 104 | "8999": { "label": "Agent Server (WebSocket)", "onAutoForward": "notify" }, |
| 105 | "8081": { "label": "Browser Agent (WebSocket)", "onAutoForward": "notify" }, |
| 106 | "8082": { "label": "Code Agent (WebSocket)", "onAutoForward": "notify" }, |
| 107 | "3000": { "label": "API Server (HTTP)", "onAutoForward": "notify" }, |
| 108 | "3443": { "label": "API Server (HTTPS)", "onAutoForward": "notify" } |
| 109 | }, |
| 110 | |
| 111 | // Ensure the sibling worktrees directory exists on the host before the |
| 112 | // container starts; Docker bind mounts fail if the source path is |
| 113 | // missing. Runs on the host, so we can use POSIX `mkdir -p` safely. |
| 114 | "initializeCommand": "mkdir -p '${localWorkspaceFolder}.worktrees'", |
| 115 | |
| 116 | // Mirror the host path INSIDE the container by bind-mounting the repo |
| 117 | // at its host absolute path. A second bind mount exposes the sibling |
| 118 | // `<repo>.worktrees` directory at the matching host path so that |
| 119 | // VS Code's Copilot CLI agent (which writes worktrees to a hardcoded |
| 120 | // `<dirname(repo)>/<basename(repo)>.worktrees`) resolves to the same |
| 121 | // location on host and container. |
| 122 | "workspaceMount": "source=${localWorkspaceFolder},target=${localWorkspaceFolder},type=bind,consistency=cached", |
| 123 | "workspaceFolder": "${localWorkspaceFolder}", |
| 124 | |
| 125 | "mounts": [ |
| 126 | // Sibling worktrees directory bound at the same host path so the |
| 127 | // Copilot CLI agent worktree feature resolves identically on both |
| 128 | // sides. |
| 129 | "source=${localWorkspaceFolder}.worktrees,target=${localWorkspaceFolder}.worktrees,type=bind,consistency=cached", |
| 130 | // Global pnpm store - shared across containers for fast installs. |
| 131 | "source=pnpm-global-store,target=/home/codespace/.local/share/pnpm/store,type=volume", |
| 132 | // Per-container node_modules stays on a named volume. We deliberately |
| 133 | // do NOT bind-mount this to the host: native modules (better-sqlite3, |
| 134 | // etc.) are compiled for the container's libc/arch and would clash |
| 135 | // with anything the host has built. |
| 136 | "source=typeagent-node_modules-${devcontainerId},target=${containerWorkspaceFolder}/ts/node_modules,type=volume", |
| 137 | "source=claude-code-config-${devcontainerId},target=/home/codespace/.claude,type=volume", |
| 138 | "source=copilot-cli-config-${devcontainerId},target=/home/codespace/.copilot,type=volume", |
| 139 | // VS Code server data (extensions, settings cache, workspace storage, history) |
| 140 | // so editor state survives container recreate. |
| 141 | "source=vscode-server-${devcontainerId},target=/home/codespace/.vscode-server,type=volume" |
| 142 | ], |
| 143 | |
| 144 | "containerEnv": { |
| 145 | "LOCAL_GIT_USER_NAME": "${localEnv:LOCAL_GIT_USER_NAME}", |
| 146 | "LOCAL_GIT_USER_EMAIL": "${localEnv:LOCAL_GIT_USER_EMAIL}" |
| 147 | }, |
| 148 | |
| 149 | "postCreateCommand": "bash .devcontainer/scripts/post-create.sh", |
| 150 | "postStartCommand": "bash .devcontainer/scripts/post-start.sh", |
| 151 | |
| 152 | "customizations": { |
| 153 | "vscode": { |
| 154 | "extensions": [ |
| 155 | "dbaeumer.vscode-eslint", |
| 156 | "esbenp.prettier-vscode", |
| 157 | "ms-python.python", |
| 158 | "ms-python.vscode-pylance", |
| 159 | "ms-dotnettools.csharp", |
| 160 | "ms-azuretools.vscode-azurefunctions", |
| 161 | "github.copilot", |
| 162 | "humao.rest-client" |
| 163 | ], |
| 164 | "settings": { |
| 165 | "editor.formatOnSave": true, |
| 166 | "editor.defaultFormatter": "esbenp.prettier-vscode", |
| 167 | "typescript.tsdk": "node_modules/typescript/lib", |
| 168 | "terminal.integrated.defaultProfile.linux": "zsh" |
| 169 | } |
| 170 | } |
| 171 | }, |
| 172 | |
| 173 | "remoteUser": "codespace", |
| 174 | |
| 175 | "hostRequirements": { |
| 176 | "cpus": 4, |
| 177 | "memory": "8gb", |
| 178 | "storage": "32gb" |
| 179 | } |
| 180 | } |
| 181 | |