- Shell 80.3%
- PHP 10.1%
- Go 9.6%
| .claude | ||
| cc | ||
| cc-cleanup | ||
| docker-compose.postgres.yml | ||
| docker-compose.yml | ||
| Dockerfile.go | ||
| Dockerfile.node | ||
| Dockerfile.php | ||
| entrypoint.sh | ||
| README.md | ||
Claude Code Worktree Runner
Run Claude Code in --dangerously-skip-permissions mode inside a Docker container, against an isolated Git worktree of your project. Each feature branch gets its own worktree, container, and Postgres database.
Supports PHP (Symfony), Node.js, and Go projects.
Prerequisites
- Docker with Compose v2 (
docker compose) - Git
- An active Claude Code login (
claudeCLI authenticated on the host)
Installation
- Clone or copy this directory somewhere permanent:
cp -r /path/to/docker ~/Work/docker
- Add the directory to your
PATH, or symlink the scripts:
# Option A: add to PATH (in ~/.bashrc or ~/.zshrc)
export PATH="$HOME/Work/docker:$PATH"
# Option B: symlink into a directory already on PATH
ln -s ~/Work/docker/cc ~/.local/bin/cc
ln -s ~/Work/docker/cc-cleanup ~/.local/bin/cc-cleanup
- Build the Docker images (one-time, per language you use):
cd ~/Work/docker
# Build only what you need:
docker compose --profile php build
docker compose --profile node build
docker compose --profile go build
Rebuild after modifying a Dockerfile:
docker compose --profile php build --no-cache
Usage
Run from the root of any Git repository:
# Auto-detects language from project files (composer.json / package.json / go.mod)
cc feat/new-api
# Explicit language override
cc -l php feat/auth-rework
# Custom host port (default: 8000)
cc -p 8001 feat/second-feature
This will:
- Create a Git worktree at
../<project>.feat-new-apiwith a new branchfeat/new-api - Copy
.env.localinto the worktree (if present) - Start the shared Postgres container (if not already running)
- Create a Postgres database named after the project and branch
- Start the language-appropriate container with:
- Dependencies installed (
composer install/npm install/go mod download) - Dev server running on
:8000 - Claude Code launched interactively
- Dependencies installed (
You'll be dropped directly into the Claude Code interface.
Dev servers
| Language | Server | Bind address |
|---|---|---|
| PHP | Symfony CLI (symfony server:start) |
0.0.0.0:8000 |
| Node | npm run dev or npm start |
0.0.0.0:8000 (via HOST env var) |
| Go | air (if config exists) or go run . |
Application-defined |
Note: Node and Go dev servers must be configured in your project to listen on 0.0.0.0:8000 for the port mapping to work from the host. The HOST=0.0.0.0 and PORT=8000 environment variables are set automatically, but not all frameworks read them. Check your framework's docs if the dev server is unreachable.
Running multiple worktrees simultaneously
Each worktree gets its own container and database. Use -p to avoid port collisions:
cc feat/api-v2 # port 8000
cc -p 8001 feat/admin-panel # port 8001
Environment variables
The following are available inside the container:
| Variable | Value |
|---|---|
DATABASE_URL |
postgresql://claude:claude@cc-postgres:5432/<db_name> |
CC_DB_NAME |
Database name (derived from project + branch) |
CC_LANG |
php, node, or go |
APP_ENV |
dev (PHP only) |
PGPASSWORD |
claude |
ANTHROPIC_API_KEY |
Passed through from host (if set) |
Cleanup
Run from the same project directory where you ran cc:
cc-cleanup feat/new-api
This will:
- Drop the Postgres database for the branch
- Stop and remove the app container
- Remove the Git worktree
- Optionally delete the Git branch (prompts for confirmation)
Stopping the shared Postgres
Postgres runs independently and persists across worktrees. To stop it:
docker compose -f ~/Work/docker/docker-compose.postgres.yml down
To stop it and delete all data:
docker compose -f ~/Work/docker/docker-compose.postgres.yml down -v
Pruning the Go module cache
Go modules are cached in a Docker volume to avoid re-downloading. To clear it:
docker volume rm cc-gomod
File layout
~/Work/docker/
cc Main script (add to PATH)
cc-cleanup Cleanup script
docker-compose.yml App containers (profiles: php, node, go)
docker-compose.postgres.yml Shared Postgres 17
Dockerfile.php PHP 8.5 + Symfony CLI + Composer
Dockerfile.node Node.js 24 LTS
Dockerfile.go Go 1.26 + air + golangci-lint
entrypoint.sh Shared container entrypoint
How it works
Host Docker
---- ------
~/projects/myapp/
| cc-net (Docker network)
|-- cc feat/xyz |
| | |-- cc-postgres (shared, persistent)
| |-- git worktree add | Postgres 17, volume: cc-pgdata
| | ../myapp.feat-xyz |
| | |-- myapp-feat-xyz-php (per worktree)
| |-- docker compose run | /app -> ../myapp.feat-xyz
| | php | ~/.claude mounted
| | | Dev server on :8000
| +-- Claude Code session | Claude Code (interactive)
| |
~/projects/myapp.feat-xyz/ |-- myapp-feat-xyz-go (another worktree)
(git worktree) | ...
Troubleshooting
Port already in use: Use -p to pick a different port, or check what's running with ss -tlnp | grep :8000.
Postgres not starting: Check if another Postgres is running on the host: ss -tlnp | grep :5432. The shared Postgres container does not bind to the host network, so this should not conflict unless the Docker network has issues. Run docker logs cc-postgres to inspect.
Dev server unreachable from host: The server inside the container must listen on 0.0.0.0, not 127.0.0.1. Configure your framework accordingly.
File permission errors: The container user's UID/GID is matched to your host user at build time. If you change host users, rebuild the images.
Claude Code authentication: Auth tokens are mounted from ~/.claude on the host. If you see login prompts, run claude on the host first to authenticate. Alternatively, set ANTHROPIC_API_KEY in your shell environment.