tool-containers
Menu
GitHub (opens in new tab)

Run Claude Code with Docker Compose

The claude service runs Claude Code on the directory in WORKSPACE. compose.sh checks that WORKSPACE is an absolute path, because Compose would resolve a relative one against this directory, then runs docker compose here.

Images
  • GHCRghcr.io/hambn/claude-code
  • Docker Hubdocker.io/hambn/claude-code
Use case
Repeatable local sessions
Upstream
github.com/anthropics/claude-code (opens in new tab)
Source
tools/ai/claude-code/docs/docker-compose (opens in new tab)
On this page

Prerequisites

  • Docker Engine with the Compose v2 plugin.
  • An Anthropic API key in ANTHROPIC_API_KEY.

Run Claude Code

Shell
export ANTHROPIC_API_KEY=sk-ant-...
WORKSPACE="$PWD" ./compose.sh run --rm claude

Arguments after the service name go to claude, for example ./compose.sh run --rm claude -p "list the TODOs".

Run without registry access

On a connected machine, run docker save ghcr.io/hambn/claude-code:ubuntu-browser -o claude-code.tar. On the offline host, load it and use the air-gapped file, which sets pull_policy: never:

Shell
docker load -i claude-code.tar
WORKSPACE="$PWD" ./compose.sh -f airgapped.docker-compose.yml run --rm claude

Variables

Variable Required Purpose
ANTHROPIC_API_KEY yes Passed to the container; Compose stops if it is unset.
WORKSPACE yes Absolute host path mounted at /workspace.
CLAUDE_CODE_IMAGE no Image for both Compose files. Defaults to ghcr.io/hambn/claude-code:ubuntu-browser; set a digest reference to pin one build.

Workspace

WORKSPACE is mounted at /workspace. Claude Code runs as UID 1000, so new files belong to UID 1000 on the host.

Files

File contents

airgapped.docker-compose.yml14 lines
# Offline: docker load -i claude-code.tar first, then
# WORKSPACE="$PWD" ./compose.sh -f airgapped.docker-compose.yml run --rm claude
name: claude-code

services:
  claude:
    image: ${CLAUDE_CODE_IMAGE:-ghcr.io/hambn/claude-code:ubuntu-browser}
    pull_policy: never
    environment:
      ANTHROPIC_API_KEY: ${ANTHROPIC_API_KEY:?Set ANTHROPIC_API_KEY}
    volumes:
      - ${WORKSPACE:?Set WORKSPACE to an absolute host path}:/workspace
    stdin_open: true
    tty: true
compose.sh18 lines
#!/usr/bin/env bash
# Compose resolves relative paths against this directory, so require an absolute WORKSPACE.
set -euo pipefail

case "${WORKSPACE:-}" in
/*) ;;
"")
    echo "Set WORKSPACE to an absolute host path." >&2
    exit 2
    ;;
*)
    echo "WORKSPACE must be an absolute host path: $WORKSPACE" >&2
    exit 2
    ;;
esac

cd -- "$(dirname -- "${BASH_SOURCE[0]}")"
exec docker compose "$@"
docker-compose.yml12 lines
# WORKSPACE="$PWD" ./compose.sh run --rm claude
name: claude-code

services:
  claude:
    image: ${CLAUDE_CODE_IMAGE:-ghcr.io/hambn/claude-code:ubuntu-browser}
    environment:
      ANTHROPIC_API_KEY: ${ANTHROPIC_API_KEY:?Set ANTHROPIC_API_KEY}
    volumes:
      - ${WORKSPACE:?Set WORKSPACE to an absolute host path}:/workspace
    stdin_open: true
    tty: true

Topics