feat: add non-technical user onboarding

- setup.sh: interactive wizard for Docker check and auth configuration
- launch.sh: folder-picker launcher (macOS native dialog, zenity/kdialog on Linux, text fallback)
- launch.bat: Windows launcher using PowerShell folder browser + Git Bash
- claude.sh: friendlier error messages with actionable links; prompt setup.sh if .env missing
- hooks/pre-commit: add setup.sh and launch.sh to executable enforcement
- README: add Quick Start section aimed at non-technical users

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
docker-claude 2026-04-16 10:13:34 +02:00
parent 51e7ab2b08
commit f68ed674d0
6 changed files with 297 additions and 45 deletions

View file

@ -2,6 +2,38 @@
Runs [Claude Code](https://claude.ai/code) inside an isolated Docker environment with a proxy sidecar for controlled egress. Claude cannot access the host filesystem or network directly. Runs [Claude Code](https://claude.ai/code) inside an isolated Docker environment with a proxy sidecar for controlled egress. Claude cannot access the host filesystem or network directly.
## Quick Start
**1. Install Docker Desktop**
Download and install [Docker Desktop](https://www.docker.com/products/docker-desktop/) for your platform. It's free and includes everything needed — no extra tools required.
**2. Download this repo**
Clone or download and unzip this repository somewhere on your machine.
**3. Run setup**
- **macOS / Linux:** Open a terminal, navigate to the folder, and run:
```bash
./setup.sh
```
- **Windows:** Double-click `launch.bat` — it will run setup automatically on first launch.
Setup will ask how you want to authenticate (API key, subscription token, or browser login) and save your settings.
**4. Start Claude**
- **macOS / Linux:** Double-click `launch.sh`, or run it from a terminal:
```bash
./launch.sh
```
A folder picker will appear — select the project you want Claude to work on.
- **Windows:** Double-click `launch.bat`.
---
## Architecture ## Architecture
``` ```
@ -35,31 +67,17 @@ Runs [Claude Code](https://claude.ai/code) inside an isolated Docker environment
## Prerequisites ## Prerequisites
- Docker Engine 24+ - [Docker Desktop](https://www.docker.com/products/docker-desktop/) (includes Docker Engine and Compose)
- Docker Compose v2 plugin (`docker compose version`)
## Setup
```bash
# 1. Clone / copy this repo
git clone <repo> docker-claude && cd docker-claude
# 2. Configure credentials (see Authentication below)
cp .env.example .env
$EDITOR .env
# 3. Make the control script executable
chmod +x claude.sh
```
## Authentication ## Authentication
Three options — pick one and set it in `.env`: Three options — `./setup.sh` will guide you through picking one:
### Option 1 — API key ### Option 1 — API key
```bash ```bash
ANTHROPIC_API_KEY=sk-ant-... ANTHROPIC_API_KEY=sk-ant-...
``` ```
Get a key at [console.anthropic.com](https://console.anthropic.com/settings/keys).
### Option 2 — OAuth token (subscription, headless-friendly) ### Option 2 — OAuth token (subscription, headless-friendly)
@ -67,7 +85,7 @@ Run this **on your host** (not inside the container) to generate a 1-year token:
```bash ```bash
claude setup-token claude setup-token
``` ```
Then set the printed token in `.env`: Then paste the token into setup, or set it manually in `.env`:
```bash ```bash
CLAUDE_CODE_OAUTH_TOKEN=... CLAUDE_CODE_OAUTH_TOKEN=...
``` ```
@ -75,26 +93,22 @@ CLAUDE_CODE_OAUTH_TOKEN=...
### Option 3 — Browser OAuth (interactive) ### Option 3 — Browser OAuth (interactive)
Leave both keys unset. On first run, Claude Code will print a login URL. Leave both keys unset. On first run, Claude Code will print a login URL.
Port 54545 must be reachable from your browser for the OAuth callback: Port 54545 must be reachable from your browser for the OAuth callback.
```bash
sbx ports <sandbox-name> --publish 54545:54545/tcp
```
Then run `./claude.sh start` and follow the prompt. Credentials are stored in
`~/.claude` on the host and reused on every subsequent run.
## Usage ## Usage
### Normal use
```bash ```bash
# Start proxy, pull latest images, launch Claude Code in the current directory ./launch.sh # folder picker → starts Claude in the selected directory
cd ~/myproject
./claude.sh start
``` ```
### Other commands ### CLI / power users
```bash ```bash
cd ~/myproject
./claude.sh start
./claude.sh stop # Stop and remove all containers ./claude.sh stop # Stop and remove all containers
./claude.sh update # Pull latest images from the registry ./claude.sh update # Pull latest images from the registry
./claude.sh logs # Tail proxy logs ./claude.sh logs # Tail proxy logs
@ -104,8 +118,6 @@ cd ~/myproject
### Building locally ### Building locally
`build.sh` builds images from source using the local Dockerfiles:
```bash ```bash
./build.sh # build with layer cache ./build.sh # build with layer cache
./build.sh --no-cache # force full rebuild ./build.sh --no-cache # force full rebuild

View file

@ -16,24 +16,36 @@ error() { echo -e "${RED}[-]${NC} $*" >&2; }
# ─── Helpers ────────────────────────────────────────────────────────────────── # ─── Helpers ──────────────────────────────────────────────────────────────────
check_deps() { check_deps() {
command -v docker &>/dev/null \ if ! command -v docker &>/dev/null; then
|| { error "Docker is not installed. https://docs.docker.com/get-docker/"; exit 1; } error "Docker is not installed."
docker compose version &>/dev/null 2>&1 \ error " → Download Docker Desktop (free): https://www.docker.com/products/docker-desktop/"
|| { error "Docker Compose v2 plugin is required."; exit 1; } exit 1
fi
if ! docker info &>/dev/null 2>&1; then
error "Docker is not running."
error " → Open Docker Desktop and wait for it to finish starting, then try again."
exit 1
fi
if ! docker compose version &>/dev/null 2>&1; then
error "Docker Compose is not available."
error " → Download Docker Desktop (includes Compose): https://www.docker.com/products/docker-desktop/"
exit 1
fi
} }
load_env() { load_env() {
local env_file="$SCRIPT_DIR/.env" local env_file="$SCRIPT_DIR/.env"
if [[ -f "$env_file" ]]; then if [[ ! -f "$env_file" ]]; then
warn "Not set up yet. Run ./setup.sh first."
exit 1
fi
# shellcheck disable=SC1090 # shellcheck disable=SC1090
set -a; source "$env_file"; set +a set -a; source "$env_file"; set +a
fi
if [[ -z "${ANTHROPIC_API_KEY:-}" && -z "${CLAUDE_CODE_OAUTH_TOKEN:-}" ]]; then if [[ -z "${ANTHROPIC_API_KEY:-}" && -z "${CLAUDE_CODE_OAUTH_TOKEN:-}" ]]; then
warn "No ANTHROPIC_API_KEY or CLAUDE_CODE_OAUTH_TOKEN found." warn "No credentials found — Claude will ask you to log in via browser."
warn "Claude Code will prompt you to authenticate on first run." warn "A login URL will appear below. Open it to authenticate."
warn " Option 1 (API key): set ANTHROPIC_API_KEY in .env" warn "(To skip this prompt in future, run ./setup.sh to configure credentials.)"
warn " Option 2 (token): run 'claude setup-token' and set CLAUDE_CODE_OAUTH_TOKEN in .env" echo ""
warn " Option 3 (browser): log in when prompted; port 54545 must be reachable from your browser."
fi fi
} }

View file

@ -2,7 +2,7 @@
# Ensure control scripts stay executable. # Ensure control scripts stay executable.
set -euo pipefail set -euo pipefail
SCRIPTS=(claude.sh build.sh hooks/pre-commit) SCRIPTS=(claude.sh build.sh setup.sh launch.sh hooks/pre-commit)
for f in "${SCRIPTS[@]}"; do for f in "${SCRIPTS[@]}"; do
if [[ -f "$f" && ! -x "$f" ]]; then if [[ -f "$f" && ! -x "$f" ]]; then

55
launch.bat Normal file
View file

@ -0,0 +1,55 @@
@echo off
:: launch.bat — Pick a project folder and start Claude Code (Windows)
setlocal enabledelayedexpansion
set "SCRIPT_DIR=%~dp0"
set "SCRIPT_DIR=%SCRIPT_DIR:~0,-1%"
:: ── Check for bash (Git Bash or WSL) ─────────────────────────────────────────
where bash >nul 2>&1
if %errorlevel% neq 0 (
echo Git Bash is required to run docker-claude on Windows.
echo.
echo Download it at: https://git-scm.com/download/win
echo Install with default options, then double-click this file again.
pause
exit /b 1
)
:: ── First-time setup ──────────────────────────────────────────────────────────
if not exist "%SCRIPT_DIR%\.env" (
echo Looks like this is your first time. Running setup...
echo.
bash "%SCRIPT_DIR%/setup.sh"
if %errorlevel% neq 0 ( pause & exit /b 1 )
echo.
)
:: ── Folder picker via PowerShell ──────────────────────────────────────────────
set "PROJECT_FOLDER="
for /f "usebackq tokens=*" %%i in (`powershell -NoProfile -Command ^
"Add-Type -AssemblyName System.Windows.Forms; ^
$d = New-Object System.Windows.Forms.FolderBrowserDialog; ^
$d.Description = 'Select the project folder to work on'; ^
$d.RootFolder = 'MyComputer'; ^
$d.ShowNewFolderButton = $false; ^
if ($d.ShowDialog() -eq 'OK') { Write-Output $d.SelectedPath } else { exit 1 }"`) do (
set "PROJECT_FOLDER=%%i"
)
if not defined PROJECT_FOLDER (
echo No folder selected. Exiting.
pause
exit /b 1
)
:: ── Launch ────────────────────────────────────────────────────────────────────
:: Convert Windows path to Unix path for bash
for /f "usebackq tokens=*" %%i in (`bash -c "cygpath -u '!PROJECT_FOLDER!'"`) do (
set "UNIX_FOLDER=%%i"
)
bash -c "cd '!UNIX_FOLDER!' && '!SCRIPT_DIR:/=\..\..\!/claude.sh' start" 2>nul || ^
bash -c "cd '!UNIX_FOLDER!' && bash '$(cygpath -u '!SCRIPT_DIR!')/claude.sh' start"
pause

62
launch.sh Executable file
View file

@ -0,0 +1,62 @@
#!/usr/bin/env bash
# launch.sh — Pick a project folder and start Claude Code
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# ─── First-time setup ─────────────────────────────────────────────────────────
if [[ ! -f "$SCRIPT_DIR/.env" ]]; then
echo "Looks like this is your first time. Running setup..."
echo ""
"$SCRIPT_DIR/setup.sh" || exit 1
echo ""
fi
# ─── Folder picker ────────────────────────────────────────────────────────────
pick_folder() {
if [[ "$OSTYPE" == "darwin"* ]]; then
# macOS — native Finder dialog
osascript -e \
'tell application "Finder" to POSIX path of (choose folder with prompt "Select the project folder to work on:")' \
2>/dev/null | tr -d '\n'
elif command -v zenity &>/dev/null; then
# Linux — GNOME/GTK dialog
zenity --file-selection --directory \
--title="Select your project folder" 2>/dev/null
elif command -v kdialog &>/dev/null; then
# Linux — KDE dialog
kdialog --getexistingdirectory "$HOME" \
--title "Select your project folder" 2>/dev/null
else
echo ""
fi
}
folder=$(pick_folder || true)
# Fallback: text prompt (no GUI available, or user cancelled dialog)
if [[ -z "$folder" ]]; then
echo "Enter the path to your project folder"
echo "(Tip: you can drag the folder into this window, then press Enter)"
echo ""
read -rp "> " folder
# Clean up: strip surrounding quotes and trailing whitespace from drag-and-drop
folder="${folder%"${folder##*[![:space:]]}"}"
folder="${folder#\'}" ; folder="${folder%\'}"
folder="${folder#\"}" ; folder="${folder%\"}"
# Expand ~ to home directory
folder="${folder/#\~/$HOME}"
fi
if [[ -z "$folder" ]]; then
echo "No folder selected. Exiting."
exit 1
fi
if [[ ! -d "$folder" ]]; then
echo "Folder not found: $folder"
exit 1
fi
cd "$folder"
exec "$SCRIPT_DIR/claude.sh" start

111
setup.sh Executable file
View file

@ -0,0 +1,111 @@
#!/usr/bin/env bash
# setup.sh — First-time setup wizard for docker-claude
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ENV_FILE="$SCRIPT_DIR/.env"
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; BOLD='\033[1m'; NC='\033[0m'
info() { echo -e "${GREEN}[+]${NC} $*"; }
warn() { echo -e "${YELLOW}[!]${NC} $*"; }
error() { echo -e "${RED}[✗]${NC} $*" >&2; }
step() { echo -e "\n${BOLD}$*${NC}"; }
# ─── Check Docker ─────────────────────────────────────────────────────────────
check_docker() {
step "Checking Docker..."
if ! command -v docker &>/dev/null; then
error "Docker is not installed."
echo " → Download Docker Desktop (free): https://www.docker.com/products/docker-desktop/"
echo " It includes everything you need — no extra tools required."
exit 1
fi
if ! docker info &>/dev/null 2>&1; then
error "Docker is installed but not running."
echo " → Open Docker Desktop and wait for the whale icon to stop animating,"
echo " then run this setup again."
exit 1
fi
if ! docker compose version &>/dev/null 2>&1; then
error "Docker Compose is not available."
echo " → Download Docker Desktop (includes Compose): https://www.docker.com/products/docker-desktop/"
exit 1
fi
info "Docker is ready."
}
# ─── Auth setup ───────────────────────────────────────────────────────────────
setup_auth() {
step "Authentication"
echo " How would you like to sign in to Claude?"
echo ""
echo " 1) Anthropic API key (pay-per-use)"
echo " Get one at: https://console.anthropic.com/settings/keys"
echo ""
echo " 2) Claude subscription (Claude Pro or Max)"
echo " Generates a token from your existing subscription."
echo ""
echo " 3) Browser login (sign in when Claude first starts)"
echo ""
read -rp " Choice [1/2/3, default: 3]: " choice
choice="${choice:-3}"
case "$choice" in
1)
echo ""
read -rp " Paste your API key (sk-ant-...): " api_key
if [[ -z "$api_key" ]]; then
error "No API key entered. Run setup again when you have one."
exit 1
fi
echo "ANTHROPIC_API_KEY=$api_key" > "$ENV_FILE"
;;
2)
echo ""
echo " You'll need to run 'claude setup-token' on your host to generate a token."
echo " If Claude Code is installed natively, run that command now and paste the result."
echo " Otherwise choose option 3 (browser login)."
echo ""
read -rp " Paste your OAuth token: " token
if [[ -z "$token" ]]; then
error "No token entered. Run setup again when you have one."
exit 1
fi
echo "CLAUDE_CODE_OAUTH_TOKEN=$token" > "$ENV_FILE"
;;
3)
touch "$ENV_FILE"
warn "Browser login selected."
warn "When Claude starts for the first time, it will print a login URL."
warn "Open that URL in your browser to sign in."
;;
*)
error "Invalid choice: $choice"
exit 1
;;
esac
}
# ─── Main ─────────────────────────────────────────────────────────────────────
echo -e "\n${BOLD}docker-claude setup${NC}"
echo "────────────────────"
if [[ -f "$ENV_FILE" ]]; then
warn ".env already exists (setup was already run)."
read -rp " Reconfigure authentication? [y/N]: " confirm
if [[ "${confirm,,}" != "y" ]]; then
info "Setup skipped. Run ./launch.sh to start Claude."
exit 0
fi
fi
check_docker
setup_auth
echo ""
info "Setup complete!"
info "→ Run ./launch.sh to start Claude Code."