This commit is contained in:
Julius Zeidler 2026-04-14 20:11:24 +02:00
commit c01102b641
10 changed files with 554 additions and 0 deletions

163
claude.sh Executable file
View file

@ -0,0 +1,163 @@
#!/usr/bin/env bash
# claude.sh — Manage the isolated Claude Code Docker environment
# Usage: ./claude.sh <command> [args]
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
COMPOSE_FILE="$SCRIPT_DIR/docker-compose.yml"
PROJECT="claude-secure"
# ─── Colours ──────────────────────────────────────────────────────────────────
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; NC='\033[0m'
info() { echo -e "${GREEN}[+]${NC} $*"; }
warn() { echo -e "${YELLOW}[!]${NC} $*"; }
error() { echo -e "${RED}[-]${NC} $*" >&2; }
# ─── Dependency check ─────────────────────────────────────────────────────────
check_deps() {
if ! command -v docker &>/dev/null; then
error "Docker is not installed. https://docs.docker.com/get-docker/"
exit 1
fi
if ! docker compose version &>/dev/null 2>&1; then
error "Docker Compose v2 plugin is required."
exit 1
fi
}
# ─── Environment loading ──────────────────────────────────────────────────────
load_env() {
local env_file="$SCRIPT_DIR/.env"
if [[ -f "$env_file" ]]; then
# shellcheck disable=SC1090
set -a; source "$env_file"; set +a
fi
if [[ -z "${ANTHROPIC_API_KEY:-}" ]]; then
error "ANTHROPIC_API_KEY is not set."
error "Copy .env.example → .env and add your key, or export it in your shell."
exit 1
fi
}
# ─── Workspace volume resolution ──────────────────────────────────────────────
# Default: named Docker volume (fully isolated).
# Override: export WORKSPACE_DIR=/path/to/project before running.
workspace_flag() {
if [[ -n "${WORKSPACE_DIR:-}" ]]; then
local abs
abs="$(realpath "${WORKSPACE_DIR}")"
if [[ ! -d "$abs" ]]; then
error "WORKSPACE_DIR does not exist: $abs"
exit 1
fi
echo "--volume ${abs}:/workspace:z"
else
echo "--volume ${PROJECT}-workspace:/workspace"
fi
}
# ─── Compose wrapper ──────────────────────────────────────────────────────────
dc() { docker compose -f "$COMPOSE_FILE" -p "$PROJECT" "$@"; }
# ─── Commands ─────────────────────────────────────────────────────────────────
cmd_start() {
check_deps
load_env
info "Building images..."
dc build
info "Starting proxy sidecar..."
dc up -d proxy
info "Waiting for proxy health check..."
dc up -d proxy # no-op if already healthy; compose waits via depends_on
info "Launching Claude Code..."
# shellcheck disable=SC2046
dc run --rm $(workspace_flag) claude "$@"
}
cmd_stop() {
check_deps
info "Stopping all containers..."
dc down
info "Done."
}
cmd_run() {
check_deps
load_env
info "Ensuring proxy is running..."
dc up -d proxy
info "Launching Claude Code..."
# shellcheck disable=SC2046
dc run --rm $(workspace_flag) claude "$@"
}
cmd_update() {
check_deps
info "Rebuilding images (no cache)..."
dc build --no-cache
info "Update complete. Run './claude.sh start' to launch."
}
cmd_logs() {
check_deps
local svc="${1:-proxy}"
dc logs -f "$svc"
}
cmd_status() {
check_deps
dc ps
}
cmd_shell() {
check_deps
load_env
warn "Opening debug shell inside Claude container (non-Claude entrypoint)."
# shellcheck disable=SC2046
dc run --rm --entrypoint /bin/bash $(workspace_flag) claude
}
cmd_help() {
cat <<EOF
Usage: $(basename "$0") <command> [args]
Commands:
start [args] Build images, start proxy, launch Claude Code
run [args] Start proxy if needed, launch Claude Code
stop Stop and remove all containers
update Rebuild images without cache
logs [svc] Tail logs (default: proxy)
status Show container status
shell Open a bash shell in the Claude container (debug)
help Show this message
Environment variables:
ANTHROPIC_API_KEY Required. Set in .env or exported in your shell.
WORKSPACE_DIR Optional. Absolute path to mount as /workspace.
Defaults to a named Docker volume (fully isolated).
Examples:
./claude.sh start
WORKSPACE_DIR=\$HOME/myproject ./claude.sh run
./claude.sh logs proxy
./claude.sh shell
EOF
}
# ─── Dispatch ─────────────────────────────────────────────────────────────────
case "${1:-help}" in
start) shift; cmd_start "$@" ;;
stop) cmd_stop ;;
run) shift; cmd_run "$@" ;;
update) cmd_update ;;
logs) shift; cmd_logs "${1:-}" ;;
status) cmd_status ;;
shell) cmd_shell ;;
help|-h|--help) cmd_help ;;
*)
error "Unknown command: ${1}"
cmd_help
exit 1
;;
esac