An open API service indexing awesome lists of open source software.

https://github.com/alanbem/dclaude

Run Claude Code CLI in Docker - no local installation needed. Full MCP support, persistent sessions, and seamless host integration.
https://github.com/alanbem/dclaude

anthropic claude claude-code cli containerization devtools docker mcp

Last synced: 17 days ago
JSON representation

Run Claude Code CLI in Docker - no local installation needed. Full MCP support, persistent sessions, and seamless host integration.

Awesome Lists containing this project

README

          

# dclaude

[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Docker Hub](https://img.shields.io/docker/v/alanbem/dclaude?label=Docker%20Hub)](https://hub.docker.com/r/alanbem/dclaude)
[![npm](https://img.shields.io/npm/v/@alanbem/dclaude)](https://www.npmjs.com/package/@alanbem/dclaude)

Run Claude Code CLI in Docker - no local installation needed. Full MCP support, persistent sessions, and seamless host integration.

## Why dclaude?

**Claude Code CLI is powerful, but installing it locally means:**
- Node.js version conflicts
- Global npm packages cluttering your system
- MCP servers needing specific Python/Node setups
- Different behavior across machines

**dclaude solves this by running Claude in a container that feels native:**
- Your files appear at the same paths (no `/app` or `/workspace` confusion)
- Docker commands work (socket is mounted)
- SSH keys and git config just work
- Homebrew included - easy migration from local macOS setup
- Works on Linux, macOS, and Windows
- **Safer `--dangerously-skip-permissions`** - container isolation means Claude can only access your project, not your whole system

## Quick Start

### Install via NPM (Recommended)

```bash
npm install -g @alanbem/dclaude
dclaude
```

### Install from source

```bash
# Clone and install
git clone https://github.com/alanbem/dclaude.git ~/tools/dclaude
sudo ln -s ~/tools/dclaude/dclaude /usr/local/bin/dclaude

# Run (pulls image from Docker Hub automatically)
dclaude
```

## Basic Usage

**dclaude passes all arguments directly to Claude CLI** - use it exactly as you would use `claude`:

```bash
# Start Claude interactively
dclaude

# Run with a prompt
dclaude "fix the bug in main.js"

# All Claude CLI flags work
dclaude --version
dclaude -p "explain this code"
dclaude --model sonnet
dclaude --resume

# Execute commands in the container
dclaude exec npm install
dclaude exec brew install ripgrep
```

## How It Works

dclaude creates a container that mirrors your host environment:

1. **Path Mirroring**: Your current directory is mounted at the *same path*
- On host: `/Users/alice/projects/myapp`
- In container: `/Users/alice/projects/myapp`
- All your file paths just work

2. **Docker Access**: The Docker socket is mounted, so Claude can build images, run containers, and manage compose stacks

3. **Persistent Sessions**: Containers persist by default - installed tools and configuration survive across sessions

4. **Smart Networking**: Auto-detects whether host networking is available for localhost access

## Persistent vs Ephemeral Containers

**Persistent (default)** - Container survives between sessions:
```bash
dclaude # Uses existing container or creates new one
dclaude exec brew install fd # Install tools - they persist
dclaude exec # Open a shell in the container
```

**Ephemeral** - Fresh container each time:
```bash
DCLAUDE_RM=true dclaude # Container removed after exit
```

Use persistent for development (faster startup, tools persist). Use ephemeral for CI/CD or when you want a clean slate.

## Features

### SSH Authentication

dclaude automatically handles SSH for git operations:

```bash
# Auto-detect best method (default)
dclaude

# Force SSH agent forwarding (most secure)
DCLAUDE_GIT_AUTH=agent-forwarding dclaude

# Mount ~/.ssh directory (most compatible)
DCLAUDE_GIT_AUTH=key-mount dclaude
```

Make sure your SSH key is loaded: `ssh-add -l`

### Homebrew Support

Install tools that persist across sessions:

```bash
dclaude exec brew install ripgrep fd bat jq
dclaude exec brew install node@20 python@3.12
```

### GitHub CLI

Authenticate once, use everywhere:

```bash
dclaude gh # Interactive GitHub login
dclaude exec gh pr list # Use gh commands
```

### SSH Server for IDEs

Connect JetBrains Gateway, VS Code Remote, or any SSH client:

```bash
dclaude ssh # Start SSH server, shows port
# Connect: ssh claude@localhost -p
# Password: claude
```

### Chrome DevTools Integration

Control Chrome via MCP for browser automation:

```bash
dclaude chrome # Launch Chrome with DevTools
dclaude # Claude can now interact with the browser
```

### iTerm2 Shell Integration

If you use iTerm2 on macOS, dclaude automatically enables [iTerm2 Shell Integration](https://iterm2.com/documentation-shell-integration.html):

- **Click URLs in output** - Opens in your Mac's browser
- **imgcat** - Display images inline in terminal
- **it2copy** - Copy to Mac clipboard from inside container
- **Marks** - Navigate between command prompts

This only activates when running in iTerm2. To disable:

```bash
DCLAUDE_ITERM2=false dclaude
```

### System Context

dclaude automatically tells Claude about its container environment so it can give better suggestions:

- **Network mode** - Whether `localhost` works or needs `host.docker.internal`
- **Docker access** - Whether Docker commands are available
- **SSH auth method** - How git authentication is configured
- **Path mirroring** - That file paths match the host

This helps Claude understand its environment without you explaining it. Disable if needed:

```bash
DCLAUDE_SYSTEM_CONTEXT=false dclaude
```

## Environment Variables

| Variable | Default | Description |
|----------|---------|-------------|
| `DCLAUDE_RM` | `false` | Remove container on exit (ephemeral mode) |
| `DCLAUDE_TAG` | `latest` | Docker image tag |
| `DCLAUDE_NAMESPACE` | (none) | Namespace for isolated credentials/config |
| `DCLAUDE_NETWORK` | `auto` | Network mode: `auto`, `host`, `bridge` |
| `DCLAUDE_GIT_AUTH` | `auto` | SSH auth: `auto`, `agent-forwarding`, `key-mount`, `none` |
| `DCLAUDE_MOUNT_ROOT` | (working dir) | Mount parent directory for sibling access |
| `DCLAUDE_DEBUG` | `false` | Enable debug output |
| `DCLAUDE_QUIET` | `false` | Suppress info messages |
| `DCLAUDE_NO_UPDATE` | `false` | Skip image update check |
| `DCLAUDE_SYSTEM_CONTEXT` | `true` | Inform Claude about container environment |
| `DCLAUDE_ITERM2` | `true` | Enable iTerm2 shell integration (only affects iTerm2) |

## Configuration File

Create a `.dclaude` file at your project root to configure dclaude for that directory tree:

```bash
# ~/projects/mycompany/.dclaude
NAMESPACE=mycompany
NETWORK=host
DEBUG=true
```

dclaude walks up the directory tree to find `.dclaude` files. Any dclaude session started from that directory or any subdirectory will use these settings.

**Supported variables:**

| Variable | Description |
|----------|-------------|
| `NAMESPACE` | Isolate credentials/config (see Namespace Isolation) |
| `NETWORK` | Network mode (`host`, `bridge`) |
| `GIT_AUTH` | Git auth mode |
| `MOUNT_ROOT` | Mount directory (relative to config file, or absolute path) |
| `DEBUG` | Enable debug output (`true`, `false`) |
| `CHROME_PORT` | Chrome DevTools port |

**Precedence:** Environment variables override `.dclaude` file settings.

## Namespace Isolation

Use namespaces to maintain completely separate environments with different credentials and settings.

**Use case:** You have both a personal Anthropic subscription and a company subscription. You want to keep them completely separate.

**Option 1: Using `.dclaude` file (recommended)**
```bash
# Create config at company project root
echo "NAMESPACE=mycompany" > ~/projects/mycompany/.dclaude

# Now any dclaude in that tree uses company credentials
cd ~/projects/mycompany/api/src
dclaude # Uses mycompany namespace automatically
```

**Option 2: Using environment variable**
```bash
DCLAUDE_NAMESPACE=mycompany dclaude
```

**Option 3: Shell alias**
```bash
# Add to ~/.bashrc or ~/.zshrc
alias dclaude-work='DCLAUDE_NAMESPACE=mycompany dclaude'
```

Each namespace gets its own:
- Claude credentials and API key
- Claude settings and preferences
- Git configuration
- Container instance

## Mount Root (Parent Directory Access)

By default, dclaude only mounts the current working directory. Use `MOUNT_ROOT` to mount a parent directory, enabling access to sibling directories.

**Use case:** You're working in a subdirectory but need access to related projects:

```text
/Users/alan/projects/mycompany/
├── shared-libs/ # Common libraries
├── api-service/ # API backend
├── web-app/ # Frontend
└── infrastructure/
└── terraform/ # ← You're here, but need access to siblings
```

**Option 1: Using `.dclaude` file (recommended)**
```bash
# Create config at the directory you want as mount root
echo "MOUNT_ROOT=." > ~/projects/mycompany/.dclaude

# Relative paths are resolved from config file's directory
echo "MOUNT_ROOT=.." > ~/projects/mycompany/subdir/.dclaude # mounts mycompany/
```

**Option 2: Using environment variable**
```bash
# Relative path (from working directory)
DCLAUDE_MOUNT_ROOT=../.. dclaude

# Absolute path
DCLAUDE_MOUNT_ROOT=/Users/alan/projects/mycompany dclaude
```

Now Claude can see and work with all sibling directories while your working directory remains `terraform/`.

## Networking

dclaude auto-detects the best networking mode:

**Host mode** (when available):
- Direct `localhost` access to host services
- Works on: Linux, macOS with OrbStack/Docker Desktop beta, Windows with Docker Desktop beta

**Bridge mode** (fallback):
- Use `host.docker.internal` instead of `localhost`
- Standard Docker networking

Force a specific mode:
```bash
DCLAUDE_NETWORK=host dclaude
DCLAUDE_NETWORK=bridge dclaude
```

## Platform Support

| Platform | Status | Notes |
|----------|--------|-------|
| Linux | Full support | Host networking available |
| macOS | Full support | Host networking with OrbStack or Docker Desktop beta |
| Windows | Full support | WSL2/Docker Desktop, host networking with beta features |

## What's Included

The container includes:
- **Ubuntu 24.04 LTS** base
- **Claude Code CLI** (latest)
- **Node.js 20+**, **Python 3** with pip
- **Homebrew/Linuxbrew** for package management
- **Docker CLI** and **Docker Compose**
- **Git**, **GitHub CLI** (`gh`), common dev tools
- **tmux** for session management
- **SSH server** for IDE integration

## Troubleshooting

**Docker not running?**
```bash
# Make sure Docker Desktop is running, or on Linux:
sudo systemctl start docker
```

**Permission denied on Docker socket?**
```bash
# Linux: Add yourself to the docker group
sudo usermod -aG docker $USER
# Then logout and login
```

**Can't access localhost services?**
```bash
# Check what network mode is being used
DCLAUDE_DEBUG=true dclaude

# Try forcing host mode
DCLAUDE_NETWORK=host dclaude

# Or use host.docker.internal in bridge mode
```

**SSH keys not working?**
```bash
# Make sure your key is loaded
ssh-add -l

# If empty, load your key
ssh-add ~/.ssh/id_ed25519
```

**Installed tools disappearing?**
```bash
# Make sure you're using persistent mode (default)
# If you set DCLAUDE_RM=true, tools won't persist
dclaude exec brew install # This persists
```

**Directories appear empty inside container? (OrbStack)**

This is a [known OrbStack 2.0.x bug](https://github.com/orbstack/orbstack/issues/2103) where VirtioFS caches stale directory entries. Directories that existed before upgrading to OrbStack 2.0 may appear empty inside the container.

```bash
# Fix: rename the directory to clear the cache
mv problematic-dir problematic-dir.tmp && mv problematic-dir.tmp problematic-dir

# Or restart OrbStack completely (clears all caches)
```

Upgrading to the latest OrbStack version may also help.

## Project Structure

```text
.
├── dclaude # Launcher script (runs on host)
├── docker/
│ ├── Dockerfile # Container image definition
│ ├── README.md # Docker Hub documentation
│ ├── usr/local/bin/
│ │ └── docker-entrypoint.sh
│ └── home/claude/
│ └── .tmux.conf
├── .github/workflows/ # CI/CD (lint, scan, publish)
├── completions/ # Shell completions (bash, zsh)
├── Makefile # Development commands
└── package.json # NPM package config
```

## Development

Want to modify dclaude? Build and test locally:

```bash
# Build local image
make build # Creates alanbem/dclaude:local

# Test
make test

# Use your local image
DCLAUDE_TAG=local dclaude
```

## Contributing

Contributions welcome! Submit a Pull Request.

## License

MIT - see [LICENSE](LICENSE)

## Links

- [Docker Hub](https://hub.docker.com/r/alanbem/dclaude)
- [npm](https://www.npmjs.com/package/@alanbem/dclaude)
- [Issues](https://github.com/alanbem/dclaude/issues)
- [Discussions](https://github.com/alanbem/dclaude/discussions)