diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..0d243fc --- /dev/null +++ b/.dockerignore @@ -0,0 +1,63 @@ +# Dependencies +node_modules/ +**/node_modules/ +# Keep bun.lock for Docker builds +# *.lock + +# Build outputs (will be generated in container) +dist/ +client/dist/ + +# State and runtime data +.openui/ +.env +.env.local + +# IDE and editor files +.vscode/ +.idea/ +*.swp +*.swo +*~ +.DS_Store +*.sublime-* + +# Git +.git/ +.gitignore + +# CI/CD +.github/ +.gitlab-ci.yml + +# Documentation (keep README.md) +*.md +!README.md + +# Test files +**/*.test.ts +**/*.test.js +**/__tests__/ +**/coverage/ + +# Logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Temporary files +*.tmp +.cache/ + +# Claude Code plugin (installed at runtime) +claude-code-plugin/ + +# Docker files (don't include in image) +Dockerfile* +docker-compose*.yml +.dockerignore + +# Plans and development files +.claude/ +plans/ diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..3b7ff9d --- /dev/null +++ b/.env.example @@ -0,0 +1,80 @@ +# ============================================ +# OpenUI Docker Configuration +# ============================================ + +# Server Configuration +NODE_ENV=production +PORT=6968 +OPENUI_QUIET=1 + +# ============================================ +# Project Directory (HYBRID MODE ONLY) +# ============================================ +# Absolute path to your project directory on host +# This path must match both host and container mount points +# PROJECT_DIR=/path/to/your/projects + +# Example: PROJECT_DIR=/home/user/code +# Example: PROJECT_DIR=$(pwd)/projects + +# ============================================ +# Git Configuration +# ============================================ +# Used for commits made by AI agents +GIT_AUTHOR_NAME=Your Name +GIT_AUTHOR_EMAIL=your.email@example.com + +# ============================================ +# API Keys (OPTIONAL) +# ============================================ +# Only required if your AI tools need API access +# ANTHROPIC_API_KEY=your_anthropic_api_key_here +# GITHUB_TOKEN=your_github_token_here +# LINEAR_API_KEY=your_linear_api_key_here + +# ============================================ +# Deployment Mode +# ============================================ +# Options: full | hybrid +DEPLOYMENT_MODE=full + +# ============================================ +# Claude Code Configuration (FULL MODE ONLY) +# ============================================ +# Claude Code will be auto-installed in container +# But you can specify a version or custom install path +# CLAUDE_VERSION=latest +# CLAUDE_INSTALL_DIR=/usr/local/bin + +# ============================================ +# Resource Limits (FULL MODE ONLY) +# ============================================ +# Adjust based on your host's available resources +MAX_CPUS=4 +MAX_MEMORY=4G + +# ============================================ +# Hybrid Mode Agent Execution (HYBRID MODE ONLY) +# ============================================ +# How should agents be spawned in hybrid mode? +# Options: ssh | docker-cli | named-pipe +# HYBRID_AGENT_SPAWN_METHOD=ssh + +# SSH configuration for ssh method +# SSH_HOST=localhost +# SSH_USER=root +# SSH_PORT=22 + +# ============================================ +# Volume Configuration +# ============================================ +# Where to persist OpenUI state +STATE_VOLUME_NAME=openui-state +PLUGIN_VOLUME_NAME=openui-plugin + +# ============================================ +# Development Settings (OPTIONAL) +# ============================================ +# Enable for debugging +# DEBUG=1 +# LOG_LEVEL=verbose diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..64b487e --- /dev/null +++ b/Dockerfile @@ -0,0 +1,88 @@ +# Stage 1: Build frontend (Alpine is fine for building) +FROM oven/bun:1.3-alpine AS builder + +WORKDIR /app + +# Install build dependencies +RUN apk add --no-cache \ + git \ + python3 \ + make \ + g++ + +# Copy package files +COPY package.json bun.lock ./ +COPY client/package.json client/bun.lock* ./client/ + +# Install dependencies +RUN bun install +WORKDIR /app/client +RUN bun install +WORKDIR /app + +# Copy source code +COPY . . + +# Build frontend +WORKDIR /app/client +RUN bun run build + +# Stage 2: Production image (Debian for glibc compatibility with bun-pty) +FROM oven/bun:1.3-debian + +WORKDIR /app + +# Install runtime dependencies +RUN apt-get update && apt-get install -y --no-install-recommends \ + bash \ + git \ + python3 \ + curl \ + ca-certificates \ + && rm -rf /var/lib/apt/lists/* + +# Install Node.js using NodeSource (more reliable than Debian npm) +RUN curl -fsSL https://deb.nodesource.com/setup_22.x | bash - && \ + apt-get install -y nodejs && \ + rm -rf /var/lib/apt/lists/* + +# Install AI Agent CLI tools globally via npm +RUN npm install -g @anthropic-ai/claude-code opencode-ai + +# Install Ralph (autonomous Claude Code loop) +RUN git clone --depth 1 https://github.com/frankbria/ralph-claude-code.git /opt/ralph && \ + chmod +x /opt/ralph/install.sh && \ + cd /opt/ralph && ./install.sh || true && \ + ln -sf /opt/ralph/ralph /usr/local/bin/ralph && \ + ln -sf /opt/ralph/ralph-setup /usr/local/bin/ralph-setup + +# Copy backend dependencies +COPY package.json bun.lock ./ +RUN bun install --production + +# Copy built frontend from builder +COPY --from=builder /app/client/dist ./client/dist + +# Copy server and bin directories +COPY server ./server +COPY bin ./bin + +# Create directories for runtime +RUN mkdir -p /app/.openui && \ + chmod 755 /app/bin/openui.ts + +# Expose ports +# 6968: Backend server + WebSocket +EXPOSE 6968 + +# Health check +HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ + CMD curl -f http://localhost:6968/api/config || exit 1 + +# Set environment defaults +ENV NODE_ENV=production \ + PORT=6968 \ + OPENUI_QUIET=1 + +# Run the server +CMD ["bun", "run", "/app/server/index.ts"] diff --git a/docker-compose.full.yml b/docker-compose.full.yml new file mode 100644 index 0000000..225a279 --- /dev/null +++ b/docker-compose.full.yml @@ -0,0 +1,73 @@ +services: + openui: + build: + context: . + dockerfile: Dockerfile + container_name: openui-full + restart: unless-stopped + + # Port mappings + ports: + - "6968:6968" # Backend + WebSocket + + # Project directory mounts + # Mount your projects here so agents can work on them + volumes: + # State persistence + - openui-state:/root/.openui + + # Plugin directory + - openui-plugin:/root/.openui/claude-code-plugin + + # Project directories - MOUNT YOUR PROJECTS HERE + # Examples: + - ./projects:/projects + + # Or mount specific projects: + # - /path/to/project1:/projects/project1 + # - /path/to/project2:/projects/project2 + + # Git credentials for cloning + - ${HOME}/.gitconfig:/root/.gitconfig:ro + - ${HOME}/.ssh:/root/.ssh:ro + + # Environment variables + environment: + - NODE_ENV=production + - PORT=6968 + - LAUNCH_CWD=/projects + - OPENUI_QUIET=1 + + # Git configuration + - GIT_AUTHOR_NAME=${GIT_AUTHOR_NAME:-OpenUI} + - GIT_AUTHOR_EMAIL=${GIT_AUTHOR_EMAIL:-openui@local} + + # Claude Code API key (if using Claude API) + - ${ANTHROPIC_API_KEY:+ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}} + + # Working directory inside container + working_dir: /app + + # Network mode + network_mode: bridge + + # Resource limits (optional but recommended) + deploy: + resources: + limits: + cpus: '4' + memory: 4G + reservations: + cpus: '1' + memory: 1G + + # Keep container running + stdin_open: true + tty: true + +volumes: + # Persist OpenUI state and plugin + openui-state: + driver: local + openui-plugin: + driver: local diff --git a/docker-compose.hybrid.yml b/docker-compose.hybrid.yml new file mode 100644 index 0000000..ce624b4 --- /dev/null +++ b/docker-compose.hybrid.yml @@ -0,0 +1,68 @@ +# HYBRID MODE - OpenUI UI in container, AI agents on host +# For Linux/Ubuntu systems where host networking works correctly. +# NOTE: This mode runs the UI in a container but expects AI tools (claude, opencode, ralph) +# to be installed on the HOST system, not inside the container. + +services: + openui: + build: + context: . + dockerfile: Dockerfile + container_name: openui-hybrid + restart: unless-stopped + + # NOTE: When using network_mode: host, the ports directive is ignored. + # The container uses the host's network directly, so port 6968 is exposed on localhost. + + # Volume mounts for hybrid mode + volumes: + # State persistence + - openui-state:/root/.openui + + # Plugin directory (synced with host) + - ${HOME}/.openui/claude-code-plugin:/root/.openui/claude-code-plugin + + # Project directories - MUST MATCH HOST PATHS for agents to work correctly + # When agents spawn on the host, they need to see the same paths + - ${PROJECT_DIR:-./projects}:${PROJECT_DIR:-/projects} + + # Docker socket for spawning containers/commands on host + - /var/run/docker.sock:/var/run/docker.sock + + # Mount host AI tools into container (required for hybrid mode) + # These paths may vary based on your installation method + - /usr/local/bin/claude:/usr/local/bin/host-claude:ro + - /usr/local/bin/opencode:/usr/local/bin/host-opencode:ro + - /usr/local/bin/ralph:/usr/local/bin/host-ralph:ro + + # Git credentials + - ${HOME}/.gitconfig:/root/.gitconfig:ro + - ${HOME}/.ssh:/root/.ssh:ro + + # Environment variables + environment: + - NODE_ENV=production + - PORT=6968 + - LAUNCH_CWD=${PROJECT_DIR:-/projects} + - OPENUI_QUIET=1 + + # Hybrid mode flag + - OPENUI_HYBRID_MODE=true + + # Anthropic API key (required for Claude Code) + - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY:-} + + # Working directory (must be /app for static file serving) + working_dir: /app + + # Network mode: host gives full access to host network + # This works properly on Linux but NOT on macOS/Windows Docker Desktop + network_mode: host + + # Keep container running + stdin_open: true + tty: true + +volumes: + openui-state: + driver: local