Run from the project directory you want to work on; claude.sh mounts it automatically. Removes WORKSPACE_DIR env var support and the named claude-secure-workspace Docker volume.
106 lines
4.8 KiB
Markdown
106 lines
4.8 KiB
Markdown
# Project Guidance
|
|
|
|
This file provides context and guidance for working with this project.
|
|
|
|
## Project Overview
|
|
|
|
**docker-claude** runs Claude Code inside a hardened Docker environment with a Squid proxy sidecar. The goal is full host encapsulation: Claude cannot access the host filesystem or network. All egress is routed through an allowlist-enforcing proxy.
|
|
|
|
## Architecture
|
|
|
|
Three containers managed by Docker Compose:
|
|
|
|
- **`claude`** — Claude Code CLI (`node:20-alpine`), runs as the built-in `node` user (UID 1000), isolated to an internal-only Docker network
|
|
- **`webui`** — Claude Code as a browser terminal via ttyd (`node:20-alpine`), `node` user (UID 1000), same network isolation, basic auth required
|
|
- **`proxy`** — Squid forward proxy (`alpine:3.21`), `squid` user, bridges the internal network to the internet with an egress allowlist
|
|
|
|
Key Docker network property: `claude-internal` has `internal: true`, meaning Docker adds no default gateway. The `claude` and `webui` containers physically cannot reach the internet without going through the `proxy` container.
|
|
|
|
The `webui` service reuses `claude/Dockerfile`. Its entrypoint (`claude/webui-entrypoint.sh`) starts `ttyd --credential user:pass claude` instead of `claude` directly.
|
|
|
|
Auth supports three modes (checked at startup by `claude.sh`):
|
|
- `ANTHROPIC_API_KEY` — API key
|
|
- `CLAUDE_CODE_OAUTH_TOKEN` — 1-year token from `claude setup-token` (headless-friendly)
|
|
- Neither set — Claude Code prompts for browser login on first run; port 54545 is published for the OAuth callback. Credentials persist in the `claude-config` named volume.
|
|
|
|
## File Structure
|
|
|
|
```
|
|
docker-claude/
|
|
├── claude.sh # Control script: start/stop/run/web/web-stop/update/logs/status/shell
|
|
├── docker-compose.yml # Service definitions and network topology
|
|
├── claude/
|
|
│ ├── Dockerfile # Claude Code + ttyd (node:20-alpine, UID 1000)
|
|
│ └── webui-entrypoint.sh # Entrypoint for webui: starts ttyd wrapping claude
|
|
├── proxy/
|
|
│ ├── Dockerfile # Squid proxy sidecar (alpine:3.21, squid user)
|
|
│ └── squid.conf # Squid ACL config — egress allowlist lives here
|
|
├── .env.example # Template for ANTHROPIC_API_KEY, WEBUI_PASSWORD, etc.
|
|
├── .gitignore # Excludes .env and logs
|
|
├── .dockerignore # Keeps .env out of build context
|
|
└── README.md # User documentation
|
|
```
|
|
|
|
## Development Workflow
|
|
|
|
```bash
|
|
chmod +x claude.sh
|
|
cp .env.example .env # set ANTHROPIC_API_KEY (and WEBUI_PASSWORD for web mode)
|
|
cd /path/to/project && ./claude.sh start # build + start proxy + launch Claude (mounts CWD as /workspace)
|
|
./claude.sh web # build + start proxy + webui (browser terminal on :7681)
|
|
./claude.sh update # rebuild images (no cache) after upstream updates
|
|
```
|
|
|
|
## Coding Standards
|
|
|
|
- Shell scripts use `set -euo pipefail`
|
|
- Dockerfiles use Alpine (`node:20-alpine`, `alpine:3.21`) for minimal attack surface
|
|
- Alpine packages use `apk add --no-cache`; no apt cache cleanup layer needed
|
|
- No capabilities granted; `no-new-privileges` on all containers
|
|
- `.env` is never committed (enforced by `.gitignore` and `.dockerignore`)
|
|
- Commit messages follow **Angular format**: `type(scope): summary`
|
|
|
|
## Extending the Egress Allowlist
|
|
|
|
Add domains to `proxy/squid.conf` under the `allowed_sites` ACL, then rebuild:
|
|
|
|
```bash
|
|
docker compose -p claude-secure build proxy
|
|
./claude.sh stop && ./claude.sh start
|
|
```
|
|
|
|
## Environment Persistence
|
|
|
|
This sandbox has a persistent environment file at `/etc/sandbox-persistent.sh`.
|
|
|
|
This file is automatically sourced in all shell contexts:
|
|
- **Non-interactive shells**: via `BASH_ENV=/etc/sandbox-persistent.sh`
|
|
- **Login shells**: via `/etc/profile.d/sandbox-persistent.sh`
|
|
- **Interactive shells**: via `/etc/bash.bashrc` and `~/.bashrc`
|
|
|
|
## Critical: Shell Completions Must NOT Be in the Persistent Environment File
|
|
|
|
**NEVER add shell completion scripts to `/etc/sandbox-persistent.sh`.**
|
|
|
|
Shell completion scripts will completely break the bash tool when sourced via the persistent environment file.
|
|
|
|
## Network access
|
|
|
|
There is a firewall in place to restrict outbound network access. If you need http/https access to
|
|
an external service, request it by running:
|
|
|
|
```bash
|
|
sbx policy allow network [domain]
|
|
```
|
|
|
|
## Git Authentication
|
|
|
|
The sandbox proxy handles GitHub authentication automatically by injecting credentials for HTTPS Git operations.
|
|
|
|
## Additional Notes
|
|
|
|
- Always read relevant files before making changes
|
|
- Run tests after making modifications
|
|
- Follow the existing code structure and patterns
|
|
- You have sudo permissions, so you can install necessary packages
|
|
- npm, pip and uv are already available for package management
|