A Docker-based wrapper for running Claude Code in an isolated, containerized environment.
- Docker installed and running
sudoaccess for installation (copies script to/usr/local/bin)- Bash shell
Clone the repository and run the installation script:
git clone https://github.com/agejevasv/clauded.git
cd clauded
./install.shThe installation script will:
- Build the Docker image (
clauded:latest) based ondevcontainers/universal:2which includes Go, Node, Python, Java, .NET, Ruby, PHP, Rust, and common dev tools - Copy the
claudedcommand to/usr/local/bin - Install Claude Code CLI into the image
To rebuild the image without cache:
./install.sh --forceRun Claude Code in your current directory:
claudedThis mounts your current working directory to /workspace in the container and starts Claude Code.
Run in sandbox mode (no host directory mounted):
clauded --sandbox
# or
clauded -sDrop into a bash shell inside the already-running container:
clauded shell
# target a specific profile's container:
clauded --profile=work shell
# run a one-off command instead of an interactive shell:
clauded shell -c "uv tool install ruff"The shell runs as the codespace user in /workspace. Note that only
/workspace (your mounted directory) and /home/codespace (the persistent
volume) survive a restart — because the container runs with --rm, anything
installed elsewhere (e.g. apt packages, /usr, /etc) is lost when it stops.
For permanent system-wide changes, edit the Dockerfile and rebuild with
./install.sh.
By default no ports are published — the container uses bridge networking with
nothing forwarded. To reach a server running inside the container from the host,
publish its port at start time with --port (alias: --publish):
# server in the container listens on 4242 -> reachable at localhost:4242
clauded --port 4242
# map to a different host port (host:container)
clauded --port 8080:4242
# bind to a specific host interface, or publish several ports
clauded --port 127.0.0.1:4242:4242 --port 9229A bare number (--port 4242) is expanded to 4242:4242; anything more specific
is passed straight to docker run -p. The flag is repeatable.
Ports must be published when the container starts. If an instance is already running, attaching to it (option 1) cannot add mappings — restart it (option 2) for new
--portvalues to take effect.
Run multiple isolated Claude Code instances side-by-side using --profile:
clauded --profile=work
clauded --profile=chatEach profile gets:
- Its own container (
clauded-container-<name>) — multiple profiles can run in parallel without triggering the instance-management prompt. - Its own persistent volume (
clauded-volume-<name>) — settings, selected model, and todos are independent. Changing the model in one profile does not affect any other profile. (Memory and session transcripts are the exception: they live in the project directory, so profiles working on the same project share them — see Project Memory and Transcripts.)
If the default clauded-volume already exists when a new profile is created, the profile volume is seeded from it, so any existing OAuth credentials carry over and you don't need to log in again. If the default volume doesn't exist yet, the profile starts empty and Claude Code will prompt for login on first run, just like a fresh install. After creation, each profile is fully independent — re-authenticating in one profile does not propagate to the others.
All arguments (except --sandbox/-s) are passed directly to the Claude Code CLI:
# Show version
clauded --version
# Start with specific model
clauded --model sonnet
# Combine with sandbox mode
clauded -s --help- Container Creation: Creates a persistent Docker volume for Claude Code configuration
- Directory Mounting: Mounts your current directory (unless in sandbox mode)
- Security Masking: Automatically creates tmpfs overlays for sensitive directories to prevent access
When running with a mounted directory, these subdirectories are automatically masked with tmpfs if they exist:
.env.sshconfig/credentialsconfig/secretscredentialssecrets
If you try to start clauded while another instance is running, you'll see options to:
- Attach to running container - Connect to the existing instance (uses existing configuration, meaning new directory won't be mounted)
- Stop and restart - Stop the previous instance and start fresh with new configuration
- Exit - Cancel the operation
Claude Code configuration is stored in a persistent Docker volume named clauded-volume, mounted at /home/codespace. This preserves your settings, authentication, and preferences across container restarts.
To reset configuration, remove the volume:
docker volume rm clauded-volumeClaude Code stores per-project state — its memory files and session transcripts —
under ~/.claude/projects/<slug>, where the slug is derived from the working
directory. Since clauded always mounts your project at /workspace, that slug
is always -workspace, so every host project would otherwise share a single
store inside clauded-volume.
To avoid that, non-sandbox runs bind two directories back into your project:
| Host path | Contents |
|---|---|
.claude/memory/ |
Memory files and the MEMORY.md index |
.claude/transcripts/ |
Session transcripts (*.jsonl) and per-session state |
Consequences worth knowing:
-
Memory and history follow the code — clone the repo elsewhere and they come with it.
-
--continue/--resumenow list only this project's sessions instead of every project you've ever opened. -
Memory files are plain Markdown, so they show up in
git statusand can be reviewed in diffs or shared with the repo. Add.claude/memory/to.gitignoreif you'd rather keep them local. -
Transcripts get large (hundreds of MB is normal). Ignore them:
.claude/transcripts/ -
Both are shared across profiles, since they belong to the project rather than to the profile.
-
Sandbox mode (
--sandbox) has no host directory, so it keeps using the volume.
Existing state from before this change is still in the volume, just shadowed by the mounts. To retrieve it:
docker run --rm -v clauded-volume:/v alpine ls /v/.claude/projects/-workspaceTo enable gh CLI access and HTTPS-based git operations inside the container, provide a GITHUB_TOKEN. The token is used to authenticate the gh CLI and to automatically rewrite SSH git URLs (git@github.com:) to HTTPS, so cloning, pushing, and PR workflows work without SSH keys.
You can provide the token in two ways:
Option 1 — Environment variable (recommended for CI or ephemeral use):
export GITHUB_TOKEN="ghp_..."
claudedOption 2 — .env file (recommended for personal use):
Create a .env file in the directory where you run clauded:
GITHUB_TOKEN="ghp_..."The .env file is automatically sourced before the container starts. It is also masked inside the container via a tmpfs overlay, so Claude Code cannot read the file's contents.
Tip: You can create a fine-grained personal access token at https://github.com/settings/tokens with only the repository permissions you need.
Remove the installed command:
sudo rm /usr/local/bin/claudedRemove the Docker image:
docker rmi clauded:latestRemove the configuration volume:
docker volume rm clauded-volume- The container runs with
no-new-privilegesflag to prevent privilege escalation - Sensitive directories are masked by default when mounting host directories
- Claude CLI is downloaded from the official source (
https://claude.ai/install.sh) - The entrypoint validates UID/GID inputs to prevent injection attacks
Docker image not found: Run ./install.sh to build the image
Permission denied: Ensure Docker is running and your user has Docker permissions
Installation fails: Try ./install.sh --force to rebuild without cache
MIT License - See LICENSE file for details