holyclaude-ai-workstation
HolyClaude AI Workstation
Skill by ara.so — Daily 2026 Skills collection.
HolyClaude is a containerized AI development workstation that bundles Claude Code CLI, a CloudCLI web UI, Chromium headless browser with Playwright, 5 AI CLIs (Claude, Gemini, OpenAI Codex, Cursor, TaskMaster AI), and 50+ dev tools into a single Docker image. One docker compose up replaces hours of manual setup.
Installation
Prerequisites
- Docker + Docker Compose installed
- Existing Anthropic account (Max/Pro subscription or API key)
Quick Start
mkdir holyclaude && cd holyclaude
Create docker-compose.yaml:
services:
holyclaude:
image: CoderLuii/HolyClaude:latest
container_name: holyclaude
hostname: holyclaude
restart: unless-stopped
shm_size: 2g
ports:
- "3001:3001"
volumes:
- ./data/claude:/root/.claude
- ./data/config:/root/.config
- ./projects:/workspace
environment:
- PUID=1000
- PGID=1000
docker compose up -d
# Open http://localhost:3001
Image Variants
# Full image — all tools pre-installed (recommended)
docker pull CoderLuii/HolyClaude:latest
# Slim image — smaller download, tools installed on demand
docker pull CoderLuii/HolyClaude:slim
# Pinned version for production stability
docker pull CoderLuii/HolyClaude:1.2.3
docker pull CoderLuii/HolyClaude:1.2.3-slim
Full Docker Compose Configuration
services:
holyclaude:
image: CoderLuii/HolyClaude:latest
container_name: holyclaude
hostname: holyclaude
restart: unless-stopped
shm_size: 2g # Required for Chromium
ports:
- "3001:3001" # CloudCLI web UI
volumes:
- ./data/claude:/root/.claude # Claude credentials & config (persisted)
- ./data/config:/root/.config # App config (persisted)
- ./projects:/workspace # Your project files
environment:
# User/group IDs (match host user to avoid permission issues)
- PUID=1000
- PGID=1000
# AI provider API keys (optional — can also set via web UI)
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
- GEMINI_API_KEY=${GEMINI_API_KEY}
- OPENAI_API_KEY=${OPENAI_API_KEY}
- CURSOR_API_KEY=${CURSOR_API_KEY}
# NAS/SMB mount polling (enable if using Synology/QNAP)
- CHOKIDAR_USEPOLLING=true
# Notification webhooks (optional)
- DISCORD_WEBHOOK_URL=${DISCORD_WEBHOOK_URL}
- SLACK_WEBHOOK_URL=${SLACK_WEBHOOK_URL}
security_opt:
- seccomp:unconfined # Required for Chromium sandbox
Environment Variable Reference
| Variable | Required | Description |
|---|---|---|
PUID |
Recommended | Host user ID (run id -u to find yours) |
PGID |
Recommended | Host group ID (run id -g to find yours) |
ANTHROPIC_API_KEY |
Optional | Anthropic API key (alternative to OAuth login) |
GEMINI_API_KEY |
Optional | Google AI API key for Gemini CLI |
OPENAI_API_KEY |
Optional | OpenAI API key for Codex CLI |
CURSOR_API_KEY |
Optional | Cursor API key |
CHOKIDAR_USEPOLLING |
NAS only | Set true for SMB/NFS mounts |
DISCORD_WEBHOOK_URL |
Optional | Discord notifications |
SLACK_WEBHOOK_URL |
Optional | Slack notifications |
Authentication
Method 1: OAuth (Claude Max/Pro Subscription)
- Open
http://localhost:3001 - Create a CloudCLI account (10 seconds)
- Sign in with your Anthropic account via OAuth
- No API key needed — uses your existing subscription
Method 2: API Key
environment:
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
Or paste the key directly in the CloudCLI web UI settings.
Credential Persistence
Credentials are stored in the bind-mounted volume:
./data/claude/ → /root/.claude/
./data/config/ → /root/.config/
Credentials survive container restarts, updates, and recreation.
Platform-Specific Configuration
Linux (amd64/arm64) — Default
# No extra config needed
shm_size: 2g
macOS (Docker Desktop)
# Works out of the box with Docker Desktop
shm_size: 2g
Windows (WSL2 + Docker Desktop)
# Requires WSL2 backend enabled in Docker Desktop
shm_size: 2g
Synology / QNAP NAS
environment:
- CHOKIDAR_USEPOLLING=true # Fixes file watching on SMB mounts
volumes:
- /volume1/docker/holyclaude/data/claude:/root/.claude
- /volume1/docker/holyclaude/projects:/workspace
Kubernetes (ARM64 / Oracle Cloud Graviton)
# arm64 image is published alongside amd64
image: CoderLuii/HolyClaude:latest # multi-arch manifest auto-selects correct arch
What's Inside the Container
AI CLIs
| CLI | Invocation | Key Provider |
|---|---|---|
| Claude Code | claude |
Anthropic (ANTHROPIC_API_KEY or OAuth) |
| Gemini CLI | gemini |
Google (GEMINI_API_KEY) |
| OpenAI Codex | codex |
OpenAI (OPENAI_API_KEY) |
| Cursor | cursor |
Cursor (CURSOR_API_KEY) |
| TaskMaster AI | task-master |
Uses configured AI provider keys |
Headless Browser Stack
- Chromium — pre-installed and configured
- Xvfb — virtual display on
:99 - Playwright — configured and ready
- Shared memory —
shm_size: 2gpre-configured (fixes the 64MB Docker default)
Dev Tools (50+)
- Languages: Node.js, Python 3, TypeScript, Bun, Deno
- Package managers: npm, yarn, pnpm, pip, cargo
- Database clients: PostgreSQL, MySQL, SQLite, Redis CLI
- Cloud CLIs: AWS CLI, Google Cloud SDK, Azure CLI
- Dev tools: GitHub CLI (
gh), Git, curl, jq, ripgrep, fd - Process manager: s6-overlay (auto-restart, graceful shutdown)
Working with Projects
Mount your project directory
volumes:
- ./projects:/workspace
# Or mount a specific project:
- /path/to/my-app:/workspace/my-app
Inside the container
# Access the container shell
docker exec -it holyclaude bash
# Navigate to workspace
cd /workspace
# Run Claude Code directly
claude
# Run other AI CLIs
gemini
codex
Playwright / Headless Browser Usage
Playwright is pre-configured. Use it from Claude Code tasks or directly:
// playwright.config.ts — already works inside the container
import { defineConfig } from '@playwright/test';
export default defineConfig({
use: {
// Chromium is pre-installed, no download needed
browserName: 'chromium',
launchOptions: {
args: [
'--no-sandbox',
'--disable-setuid-sandbox',
'--disable-dev-shm-usage', // Use /tmp instead of /dev/shm
],
},
},
});
// Direct Playwright usage inside container
import { chromium } from 'playwright';
const browser = await chromium.launch({
args: [
'--no-sandbox',
'--disable-setuid-sandbox',
'--disable-dev-shm-usage',
],
});
const page = await browser.newPage();
await page.goto('https://example.com');
const screenshot = await page.screenshot({ path: '/workspace/screenshot.png' });
await browser.close();
# Run Playwright tests inside container
docker exec -it holyclaude bash -c "cd /workspace && npx playwright test"
# Run with headed mode via Xvfb
docker exec -it holyclaude bash -c "DISPLAY=:99 npx playwright test --headed"
Updating HolyClaude
# Pull latest image
docker compose pull
# Recreate container with new image (zero data loss — data is in bind mounts)
docker compose up -d
# Or explicit recreation
docker compose down && docker compose up -d
Pinned Version Strategy
# For production: pin to a specific version
image: CoderLuii/HolyClaude:1.2.3
# Update by changing the tag and running:
docker compose up -d
Data & Persistence
holyclaude/
├── docker-compose.yaml
├── data/
│ ├── claude/ # Claude credentials, .claude.json, history
│ └── config/ # CloudCLI and app configuration
└── projects/ # Your workspace (mount your code here)
All credentials and config survive:
- Container restarts
docker compose down && up- Image updates via
docker compose pull - Container recreation
Common Patterns
Pattern: Multiple Projects
volumes:
- ./data/claude:/root/.claude
- ./data/config:/root/.config
- ~/code/project-a:/workspace/project-a
- ~/code/project-b:/workspace/project-b
- ~/code/project-c:/workspace/project-c
Pattern: Read-only API Keys via .env file
# .env (never commit this)
ANTHROPIC_API_KEY=sk-ant-...
GEMINI_API_KEY=AIza...
OPENAI_API_KEY=sk-...
# docker-compose.yaml
services:
holyclaude:
env_file: .env
Pattern: Custom Port
ports:
- "8080:3001" # Access via http://localhost:8080
Pattern: Remote Server Access
ports:
- "0.0.0.0:3001:3001" # Accessible from network
# Then access via http://your-server-ip:3001
# Recommend putting behind nginx/Caddy with HTTPS for production
Pattern: Nginx Reverse Proxy
services:
holyclaude:
image: CoderLuii/HolyClaude:latest
# Don't expose ports directly — nginx handles it
expose:
- "3001"
networks:
- web
nginx:
image: nginx:alpine
ports:
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf
- ./certs:/etc/nginx/certs
networks:
- web
networks:
web:
Troubleshooting
Container won't start
# Check logs
docker compose logs holyclaude
# Check if port 3001 is already in use
lsof -i :3001
Chromium crashes / headless browser fails
# Ensure shm_size is set (CRITICAL)
shm_size: 2g
# Ensure seccomp is unconfined
security_opt:
- seccomp:unconfined
# Verify display is available inside container
docker exec holyclaude bash -c "echo $DISPLAY"
# Should output: :99
Permission denied errors on bind mounts
environment:
- PUID=1000 # Must match your host user: `id -u`
- PGID=1000 # Must match your host group: `id -g`
# Fix existing permissions on host
sudo chown -R 1000:1000 ./data ./projects
File watching broken on NAS / SMB mounts
environment:
- CHOKIDAR_USEPOLLING=true
Claude Code installer hangs
This is pre-solved in HolyClaude — the container sets the correct WORKDIR ownership. If you're building a custom image on top:
# Ensure WORKDIR is not root-owned before running Claude Code installer
RUN chown -R node:node /app
WORKDIR /app
SQLite locks on NAS mount
volumes:
# Move SQLite databases to a local volume, not NAS mount
- holyclaude-db:/root/.local/share/holyclaude
- /nas/mount:/workspace # NAS mount only for project files
volumes:
holyclaude-db:
Claude Code authentication lost after restart
# Ensure this volume is mounted (credentials live here)
volumes:
- ./data/claude:/root/.claude
Process keeps dying / not restarting
HolyClaude uses s6-overlay for process supervision. Check service status:
docker exec holyclaude s6-svstat /run/service/cloudcli
docker exec holyclaude s6-svstat /run/service/xvfb
Building Locally
git clone https://github.com/CoderLuii/HolyClaude.git
cd HolyClaude
# Build full image
docker build -t holyclaude:local .
# Build slim image
docker build -t holyclaude:local-slim --target slim .
# Build for specific platform
docker buildx build --platform linux/arm64 -t holyclaude:arm64 .
# Run your local build
docker run -d \
--name holyclaude \
--shm-size=2g \
-p 3001:3001 \
-v $(pwd)/data/claude:/root/.claude \
holyclaude:local
Quick Reference
# Start
docker compose up -d
# Stop
docker compose down
# View logs (live)
docker compose logs -f holyclaude
# Shell access
docker exec -it holyclaude bash
# Update to latest
docker compose pull && docker compose up -d
# Restart only the container
docker compose restart holyclaude
# Check resource usage
docker stats holyclaude