Claude Code, Codex and GitHub Copilot can all run commands and change files as they work. I want some control over the environment they do that in, including which tools are installed and what they can access.
VS Code dev containers let me define that environment in the repository. I can run the agents from a terminal inside the container, give them the project’s dependencies and keep their configuration across rebuilds.
This post walks through setting up all three tools in a local dev container, signing in and checking where their commands actually run. I’ll also cover what persists when you rebuild, and what the container can still access on your laptop.
Where the tools run
VS Code connects to a server inside the development container. The editor interface stays on your laptop, while the connected window’s integrated terminal and project tools run inside the container.
For the local Docker setup in this post:
| Component | Location |
|---|---|
| VS Code interface | Your laptop |
| Development container | Docker on your laptop |
| Integrated terminal, agent CLIs and project tools | Inside the container |
| Repository files | Your laptop, mounted into the container |
| AI model inference | The provider’s cloud service |
The model still runs in the provider’s cloud. Docker runs the CLI and the commands it executes on your machine. If you delegate a task to a cloud agent, that task runs in the cloud agent’s own environment.
Extensions can run locally or remotely, depending on their capabilities. Open a new integrated terminal in the connected VS Code window to run the agent commands inside the container. The VS Code Remote Development documentation has more on where extensions and the server run.
Configure Claude Code, Codex and GitHub Copilot
You need Docker, VS Code and the Dev Containers extension installed. Create .devcontainer/devcontainer.json in your repository:
{ "name": "AI development", "image": "mcr.microsoft.com/devcontainers/base:ubuntu", "remoteUser": "vscode", "features": { "ghcr.io/devcontainers/features/node:1": { "version": "24" }, "ghcr.io/anthropics/devcontainer-features/claude-code:1.0": {} }, "customizations": { "vscode": { "extensions": [ "GitHub.copilot", "GitHub.copilot-chat", "openai.chatgpt", "anthropic.claude-code" ] } }, "mounts": [ "source=claude-config-${devcontainerId},target=/home/vscode/.claude,type=volume", "source=codex-config-${devcontainerId},target=/home/vscode/.codex,type=volume", "source=copilot-config-${devcontainerId},target=/home/vscode/.copilot,type=volume" ], "containerEnv": { "CLAUDE_CONFIG_DIR": "/home/vscode/.claude" }, "postCreateCommand": "bash .devcontainer/post-create.sh"}
Then create .devcontainer/post-create.sh:
set -euo pipefailsudo mkdir -p \ /home/vscode/.claude \ /home/vscode/.codex \ /home/vscode/.copilotsudo chown -R "$(id -u):$(id -g)" \ /home/vscode/.claude \ /home/vscode/.codex \ /home/vscode/.copilotnpm install -g @openai/codex @github/copilot
Anthropic’s feature installs the Claude Code CLI. The script installs the Codex and GitHub Copilot CLIs and makes the three configuration directories writable by vscode. Change those paths if you use a different container user.
I’ve included all three tools’ VS Code integrations. You can also run claude, codex and copilot directly from the integrated terminal.
Node.js 24 meets GitHub Copilot CLI’s npm requirement. Anthropic’s :1.0 tag versions the feature itself; it doesn’t pin the Claude Code release installed by that feature.
The image tag and npm packages can resolve to newer releases on the next rebuild. For a shared team environment, I’d pin the image and tool versions after testing them.
Open the repository in the container
Run Dev Containers: Reopen in Container from the Command Palette. VS Code builds the environment and runs postCreateCommand after creating the container.
When you change the configuration, run Dev Containers: Rebuild Container. Saving the JSON doesn’t rebuild anything, and an existing host terminal stays on the host.
Check the connection indicator at the bottom-left of VS Code, then select Terminal → New Terminal and run:
cat /etc/os-releasewhoamipwdcopilot --versionclaude --versioncodex --version
Example output from my container, with the OS details shortened:
$ cat /etc/os-releasePRETTY_NAME="Ubuntu 26.04.1 LTS"NAME="Ubuntu"VERSION_ID="26.04"...$ whoamivscode$ pwd/workspaces/local-dev-container-blog-post$ copilot --versionGitHub Copilot CLI 1.0.105.Run 'copilot update' to check for updates.$ claude --version2.1.318 (Claude Code)$ codex --versioncodex-cli 0.166.0
Your OS and CLI versions may differ. With this configuration, you should see Ubuntu and the vscode user, with the workspace usually under /workspaces/.
If a command is missing, check the container creation log and VS Code’s connection indicator first. Installing another copy on your laptop won’t fix a missing container dependency. The VS Code dev container guide covers opening and managing the connected workspace.
Sign in inside the container
For GitHub Copilot’s editor features, use VS Code’s GitHub sign-in flow. For GitHub Copilot CLI, run:
copilot
Follow the /login prompt. If your access comes from an organisation, its policies must permit CLI usage.
For Claude Code, run claude and follow the sign-in prompts. If the browser callback cannot reach the container, follow the terminal’s code-entry instructions.
For Codex, run codex and follow its sign-in prompts. If browser login cannot return to the container, use:
codex login --device-auth
Device-code login must be enabled for your account or workspace. The official OpenAI authentication documentation covers the requirements and credential storage.
I’d sign in to one tool and try a small task before moving to the next. If something fails, there’s less to untangle.
Keep configuration and session history across rebuilds
The three named volumes preserve these directories when the container is replaced:
| Tool | Persisted directory |
|---|---|
| Claude Code | /home/vscode/.claude |
| Codex | /home/vscode/.codex |
| GitHub Copilot CLI | /home/vscode/.copilot |
${devcontainerId} gives each development container its own volume names. A rebuild reuses them, while separate development containers keep their own configuration directories.
CLAUDE_CONFIG_DIR points Claude Code at its mounted configuration directory. GitHub Copilot CLI keeps its configuration and session history under ~/.copilot, as described in its configuration directory reference.
Credentials need a little more care. These volumes preserve files in the mounted directories, but they can’t preserve an external operating-system keyring. GitHub Copilot CLI can use a system keychain; if one isn’t available, it can prompt to save the token in a configuration file. VS Code’s GitHub sign-in is separate from the CLI sign-ins.
Removing the container leaves those authentication files in the volumes. Delete the volumes to remove the persisted files too.
A rebuild stops running CLI processes. The saved history can survive, but you’ll need to restart the tool and use its resume workflow to continue a conversation.
Add the tools your repository needs
The Node.js and Claude Code entries are Dev Container Features: reusable installation steps that add tools to the environment.
The Dev Container Features catalogue includes official and community-maintained options for Python, Go, Azure CLI, Terraform, GitHub CLI and Kubernetes tooling. Each entry links to its documentation and supported options.
Check each feature’s maintainer and version options, add the ones you need to the features object, then rebuild.
For a Terraform repository, I’d include Terraform and Azure CLI here. The agent needs those tools inside the container and can’t automatically use the copies on my laptop. An application repository will have different dependencies, so I wouldn’t load every tool into a single starting configuration.
Use a separate environment for each repository
I’d start with one VS Code window and one container per repository. Reuse the starting configuration, then add the dependencies each project needs.
| Repository | Container tools | Example task |
|---|---|---|
| Platform infrastructure | Terraform and Azure CLI | GitHub Copilot updating a module |
| Application | Runtime and test dependencies | Codex implementing a feature |
| Website | Node.js and site dependencies | Claude Code editing a page |
The name field is only a display label. You can reuse it without making repositories share a container. Signing in with the same provider account doesn’t merge their conversations either.
Two agents in the same checkout can edit the same files. I’d use separate clones for independent changes while getting this setup working. Git worktrees are another option, provided their Git metadata is accessible inside the container.
Understand what the container can access
The mounted workspace is your working copy. An agent deleting a file there deletes it from the repository on your laptop too. Removing the container won’t undo that.
The agent can use credentials available inside the container. If you sign in to Azure CLI, that identity’s permissions still apply to real Azure resources. This configuration also leaves outbound networking unrestricted.
I’d keep normal approval prompts enabled and avoid mounting the whole host home directory or the host Docker socket. Codex’s Linux sandbox may need additional container configuration; check the official OpenAI sandbox guidance if commands fail because of sandbox restrictions.
A dev container means downloading images, waiting for builds and maintaining another environment. It also uses your machine’s CPU and memory. If one CLI on the host already does everything a project needs, I wouldn’t add a container out of habit. I’d use this setup where the repository’s dependencies or the need to control mounts justify that extra work.
