Overview
The launch script automates the startup process by ensuring the proxy server is running (via Docker or Node.js) and then starting Claude Code with the correct environment variables.
Command
bash scripts/launch.sh [claude-code-args...]
Any arguments passed to the launch script are forwarded to Claude Code.
Startup logic
The script follows this decision flow:
#!/usr/bin/env bash
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
PORT="${COPILOT_PROXY_PORT:-18080}"
AUTH_FILE="${COPILOT_AUTH_FILE:-$HOME/.claude-copilot-auth.json}"
Authentication check
if [ ! -f "$AUTH_FILE" ]; then
echo "✗ Not authenticated. Run authentication first:"
echo " node $SCRIPT_DIR/auth.mjs"
exit 1
fi
Error handling: Exits with code 1 if no auth file exists, directing user to authenticate first
Proxy detection
if curl -s "http://localhost:$PORT/health" > /dev/null 2>&1; then
echo "✓ Proxy already running on port $PORT"
else
# Start proxy...
fi
Health check: Uses /health endpoint to detect running proxy instances
Docker vs Node.js fallback
The script prioritizes Docker but falls back to Node.js if Docker is unavailable:
Docker path
if command -v docker &> /dev/null && docker info &> /dev/null 2>&1; then
echo "Starting proxy via Docker (restart: always)..."
cd "$PROJECT_DIR"
docker-compose up -d --build 2>/dev/null || docker compose up -d --build
# Wait for proxy to be ready
for i in $(seq 1 30); do
if curl -s "http://localhost:$PORT/health" > /dev/null 2>&1; then
break
fi
sleep 0.5
done
if ! curl -s "http://localhost:$PORT/health" > /dev/null 2>&1; then
echo "✗ Docker proxy failed to start, falling back to node..."
node "$SCRIPT_DIR/proxy.mjs" &
PROXY_PID=$!
# ... wait and verify
trap "kill $PROXY_PID 2>/dev/null" EXIT
else
echo "✓ Proxy running in Docker (auto-restarts on reboot)"
fi
else
# ... Node.js path
fi
Benefits of Docker:
- Persistent background process
- Auto-restart on system reboot
- Clean process isolation
Fallback to Node.js:
- No Docker installation required
- Started as background process
- Cleaned up on script exit
Node.js path
echo "Starting proxy server (no Docker found)..."
node "$SCRIPT_DIR/proxy.mjs" &
PROXY_PID=$!
for i in $(seq 1 30); do
if curl -s "http://localhost:$PORT/health" > /dev/null 2>&1; then break; fi
sleep 0.2
done
if ! curl -s "http://localhost:$PORT/health" > /dev/null 2>&1; then
echo "✗ Proxy failed to start"
kill $PROXY_PID 2>/dev/null
exit 1
fi
echo "✓ Proxy started (PID: $PROXY_PID)"
trap "echo 'Stopping proxy...'; kill $PROXY_PID 2>/dev/null" EXIT
Process management:
- Background process with captured PID
- Automatic cleanup on script exit via
trap
- Verification via health check polling
Health check polling
The script polls the /health endpoint to verify successful startup:
for i in $(seq 1 30); do
if curl -s "http://localhost:$PORT/health" > /dev/null 2>&1; then
break
fi
sleep 0.5
done
Parameters:
- Maximum attempts: 30
- Poll interval: 0.5 seconds (Docker) or 0.2 seconds (Node.js)
- Total timeout: ~15 seconds (Docker) or ~6 seconds (Node.js)
Verification:
if ! curl -s "http://localhost:$PORT/health" > /dev/null 2>&1; then
echo "✗ Proxy failed to start"
exit 1
fi
Environment variable handling
Configuration variables
Port for proxy serverCOPILOT_PROXY_PORT=8080 bash scripts/launch.sh
COPILOT_AUTH_FILE
string
default:"~/.claude-copilot-auth.json"
Authentication file locationCOPILOT_AUTH_FILE=/custom/auth.json bash scripts/launch.sh
Claude Code variables
The script sets these environment variables for Claude Code:
ANTHROPIC_BASE_URL="http://localhost:$PORT" \
ANTHROPIC_API_KEY="copilot-proxy" \
claude "$@"
Base URL for Anthropic API requests (points to local proxy)
API key value (can be any non-empty string)
Path resolution
The script dynamically resolves paths to work from any directory:
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
Variables:
SCRIPT_DIR: Absolute path to scripts directory
PROJECT_DIR: Absolute path to project root
BASH_SOURCE[0]: Path to the script itself
Usage:
# Works from any directory
cd /tmp
/path/to/claude-code-copilot/scripts/launch.sh
# Also works
cd /path/to/claude-code-copilot
./scripts/launch.sh
Error handling
Missing authentication
if [ ! -f "$AUTH_FILE" ]; then
echo "✗ Not authenticated. Run authentication first:"
echo " node $SCRIPT_DIR/auth.mjs"
exit 1
fi
Exit code: 1
User guidance: Provides exact command to run for authentication
Proxy startup failure
if ! curl -s "http://localhost:$PORT/health" > /dev/null 2>&1; then
echo "✗ Proxy failed to start"
kill $PROXY_PID 2>/dev/null
exit 1
fi
Exit code: 1
Cleanup: Kills background process before exiting
Docker fallback
if ! curl -s "http://localhost:$PORT/health" > /dev/null 2>&1; then
echo "✗ Docker proxy failed to start, falling back to node..."
node "$SCRIPT_DIR/proxy.mjs" &
PROXY_PID=$!
# ... continue with Node.js path
fi
Behavior: Automatically tries Node.js if Docker fails, ensuring maximum reliability
Process cleanup
When running in Node.js mode, the script ensures cleanup on exit:
trap "echo 'Stopping proxy...'; kill $PROXY_PID 2>/dev/null" EXIT
Trap signal: EXIT - Triggered on script termination (normal or error)
Cleanup actions:
- Print status message
- Kill proxy process
- Suppress error if process already exited
Note: Docker containers are not cleaned up on exit since they’re configured with restart: always for persistence
Usage examples
Basic usage
Starts proxy and launches Claude Code with default settings.
Pass arguments to Claude Code
bash scripts/launch.sh --help
bash scripts/launch.sh chat
bash scripts/launch.sh --model claude-opus-4-6
All arguments are forwarded via "$@".
Custom port
COPILOT_PROXY_PORT=8080 bash scripts/launch.sh
Custom auth file
COPILOT_AUTH_FILE=~/.my-auth.json bash scripts/launch.sh
Example output
Docker path
✓ Proxy already running on port 18080
Starting Claude Code via Copilot...
[Claude Code starts...]
Node.js path (first run)
Starting proxy server (no Docker found)...
✓ Proxy started (PID: 12345)
Starting Claude Code via Copilot...
[Claude Code starts...]
^C
Stopping proxy...
Authentication error
✗ Not authenticated. Run authentication first:
node /path/to/scripts/auth.mjs
Integration with Docker Compose
When Docker is available, the script uses Docker Compose:
docker-compose up -d --build 2>/dev/null || docker compose up -d --build
Compatibility: Tries both docker-compose (older) and docker compose (newer) commands
Flags:
-d: Detached mode (background)
--build: Rebuild image if needed
Benefits:
- Container persists after script exits
- Automatic restart on system reboot
- Consistent environment
Dependencies
The script requires these commands to be available:
HTTP client for health checks
Node.js runtime for proxy server
Container runtime (falls back to Node.js if unavailable)
Exit codes
| Code | Meaning |
|---|
| 0 | Success (Claude Code exited normally) |
| 1 | Authentication missing or proxy startup failed |
| Other | Propagated from Claude Code exit status |