{"id":47759002,"url":"https://github.com/coderluii/holycode","last_synced_at":"2026-05-27T21:00:28.842Z","repository":{"id":350139452,"uuid":"1205494589","full_name":"CoderLuii/HolyCode","owner":"CoderLuii","description":"AI coding workstation: OpenCode + Claude subscription support + 30+ tools + headless browser + multi-agent orchestration","archived":false,"fork":false,"pushed_at":"2026-05-27T19:11:27.000Z","size":4603,"stargazers_count":35,"open_issues_count":2,"forks_count":7,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-05-27T19:24:01.817Z","etag":null,"topics":["ai","ai-coding","anthropic","coding-agent","container","developer-tools","devtools","docker","docker-compose","gemini","headless-browser","openai","opencode","playwright","self-hosted"],"latest_commit_sha":null,"homepage":"https://holycode.coderluii.dev","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/CoderLuii.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":".github/CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":".github/CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":".github/SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":"CoderLuii","buy_me_a_coffee":"CoderLuii","custom":["https://www.paypal.com/donate/?hosted_button_id=PM2UXGVSTHDNL"]}},"created_at":"2026-04-09T02:34:21.000Z","updated_at":"2026-05-27T19:11:33.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/CoderLuii/HolyCode","commit_stats":null,"previous_names":["coderluii/holycode"],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/CoderLuii/HolyCode","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CoderLuii%2FHolyCode","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CoderLuii%2FHolyCode/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CoderLuii%2FHolyCode/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CoderLuii%2FHolyCode/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/CoderLuii","download_url":"https://codeload.github.com/CoderLuii/HolyCode/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CoderLuii%2FHolyCode/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33583399,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-27T02:00:06.184Z","response_time":53,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai","ai-coding","anthropic","coding-agent","container","developer-tools","devtools","docker","docker-compose","gemini","headless-browser","openai","opencode","playwright","self-hosted"],"created_at":"2026-04-03T05:02:13.304Z","updated_at":"2026-05-27T21:00:28.821Z","avatar_url":"https://github.com/CoderLuii.png","language":"Shell","funding_links":["https://github.com/sponsors/CoderLuii","https://buymeacoffee.com/CoderLuii","https://www.paypal.com/donate/?hosted_button_id=PM2UXGVSTHDNL"],"categories":[],"sub_categories":[],"readme":"🌍 **English** | [Español](docs/translations/README.es.md) | [Français](docs/translations/README.fr.md) | [Italiano](docs/translations/README.it.md) | [Português](docs/translations/README.pt.md) | [Deutsch](docs/translations/README.de.md) | [Русский](docs/translations/README.ru.md) | [हिन्दी](docs/translations/README.hi.md) | [中文](docs/translations/README.zh.md) | [日本語](docs/translations/README.ja.md) | [한국어](docs/translations/README.ko.md)\n\n\u003ca name=\"top\"\u003e\u003c/a\u003e\n\n# \u003cimg src=\"assets/logo.png\" alt=\"HolyCode\" width=\"39\" valign=\"bottom\"\u003e HolyCode\n\n\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"assets/hero.png\" alt=\"HolyCode Banner\" width=\"100%\" /\u003e\n\u003c/div\u003e\n\n\u003cp align=\"center\"\u003e\n\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n[![Docker Pulls](https://badgen.net/docker/pulls/coderluii/holycode?icon=docker)](https://hub.docker.com/r/coderluii/holycode)\n[![Full Image](https://img.shields.io/docker/image-size/coderluii/holycode/latest?label=full\u0026color=blue\u0026logo=docker)](https://hub.docker.com/r/coderluii/holycode)\n[![GitHub Stars](https://img.shields.io/github/stars/coderluii/holycode?style=social)](https://github.com/coderluii/holycode)\n[![Twitter Follow](https://img.shields.io/twitter/follow/CoderLuii?style=social)](https://x.com/CoderLuii)\n[![PayPal](https://img.shields.io/badge/Donate-PayPal-blue.svg)](https://www.paypal.com/donate/?hosted_button_id=PM2UXGVSTHDNL)\n[![Buy Me A Coffee](https://img.shields.io/badge/Buy%20Me%20A%20Coffee-support-yellow.svg?style=flat\u0026logo=buy-me-a-coffee)](https://buymeacoffee.com/CoderLuii)\n[![Website](https://img.shields.io/badge/website-coderluii.dev-orange?logo=astro)](https://coderluii.dev)\n[![GitHub Release](https://img.shields.io/github/v/release/coderluii/holycode)](https://github.com/coderluii/holycode/releases)\n[![Issues](https://img.shields.io/github/issues/coderluii/holycode)](https://github.com/coderluii/holycode/issues)\n[![Contributors](https://img.shields.io/github/contributors/coderluii/holycode)](https://github.com/coderluii/holycode/graphs/contributors)\n\n\u003c/p\u003e\n\n### One container. Every tool. Any provider.\n\nOpenCode running in a container with everything already installed. 50+ dev tools, 10+ AI providers, headless browser, persistent state, and two serious upgrades on top: Hermes Agent and Paperclip. Drop it on any machine and pick up exactly where you left off.\n\n**Hermes Agent turns HolyCode into a meta-agent runtime.** You get a smarter planning layer on top of OpenCode, an API surface on port `8642`, MCP support, messaging adapters, and a clean way to let a \"brain\" delegate code work into the local container instead of bolting that together yourself.\n\n**Paperclip turns HolyCode into an agent board.** You get a dashboard on port `3100` where you create a company, hire OpenCode-backed workers, wake them on heartbeat, and manage agent work from a real UI instead of hand-rolling scripts around `opencode run`.\n\n**Works with your Claude subscription.** Enable the Claude Auth plugin and use your existing Claude Max/Pro plan. No separate API key needed.\n\n**Multi-agent orchestration built in.** Enable oh-my-openagent and turn OpenCode into a coordinated agent system with parallel execution.\n\n**You were going to spend an hour getting your environment back. Or you could just `docker compose up` and get a coding workstation, a meta-agent, and an agent board in one shot.**\n\u003e **Don't want to self-host?** [HolyCode Cloud](https://holycode.coderluii.dev/cloud) is coming. Same tools, zero setup. Early access is free.\n\n---\n\n## What is this?\n\nYou know the drill. You get your dev environment exactly right. Then you switch machines. Or rebuild a container. Or your system decides today is the day it dies.\n\nSuddenly you're reinstalling tools. Hunting down config files. Re-entering API keys. Wondering why ripgrep isn't on PATH anymore. Figuring out why Chromium won't launch because Docker gives containers 64MB of shared memory. Then Xvfb isn't configured. Then the UID inside the container doesn't match your host and everything is permission denied.\n\n**HolyCode is the container I built after solving every single one of those problems.**\n\nIt wraps [OpenCode](https://opencode.ai), an AI coding agent with a built-in web UI. All your settings, sessions, MCP configs, plugins, and tool history live in a bind mount outside the container. Rebuild, update, or move to a new machine. Your state comes right back.\n\nIt's the same idea as [HolyClaude](https://github.com/coderluii/holyclaude) but wrapping OpenCode instead of Claude Code. And here's the thing: OpenCode isn't locked to one provider. Point it at Anthropic, OpenAI, Google Gemini, Groq, AWS Bedrock, or Azure OpenAI. Same container, your choice of model.\n\n50+ dev tools, two language runtimes, a headless browser stack, process supervision, and two bundled orchestration layers. All wired up, all ready on first boot. I've been running this on my own server. Every bug has been hit, diagnosed, and fixed.\n\nYou pull it. You run it. You open your browser. You build.\n\n---\n\n## Table of Contents\n\n| | Section |\n|---|---------|\n| 1 | [Quick Start](#-quick-start) |\n| 2 | [HolyCode Cloud](#-holycode-cloud-coming-soon) |\n| 3 | [Platform Support](#-platform-support) |\n| 4 | [Why HolyCode](#-why-holycode) |\n| 5 | [Provider Support](#-provider-support) |\n| 6 | [Docker Compose - Quick](#-docker-compose---quick) |\n| 7 | [Docker Compose - Full](#-docker-compose---full) |\n| 8 | [Podman](#-podman) |\n| 9 | [Environment Variables](#-environment-variables) |\n| 10 | [What's Inside](#-whats-inside) |\n| 11 | [Bundled Services](#-bundled-services) |\n| 12 | [Architecture](#-architecture) |\n| 13 | [CLI Usage](#-cli-usage) |\n| 14 | [Data and Persistence](#-data-and-persistence) |\n| 15 | [Permissions](#-permissions) |\n| 16 | [Upgrading](#-upgrading) |\n| 17 | [Troubleshooting](#-troubleshooting) |\n| 18 | [Building Locally](#-building-locally) |\n| 19 | [Contributing](#-contributing) |\n| 20 | [Support](#-support) |\n| 21 | [License](#-license) |\n\n---\n\n## 🚀 Quick Start\n\n**Step 1.** Pull the image.\n\n```bash\ndocker pull coderluii/holycode:latest\n```\n\n**Step 2.** Create a `docker-compose.yaml`.\n\n```yaml\nservices:\n  holycode:\n    image: coderluii/holycode:latest\n    container_name: holycode\n    restart: unless-stopped\n    shm_size: 2g\n    ports:\n      - \"4096:4096\"\n    volumes:\n      - ./data/opencode:/home/opencode\n      - ./local-cache/opencode:/home/opencode/.cache/opencode\n      - ./workspace:/workspace\n    environment:\n      - PUID=1000\n      - PGID=1000\n      - ANTHROPIC_API_KEY=your-key-here\n```\n\nIn that example, `/home/opencode` is the fixed path **inside** the container. On the host, `./data/opencode` and `./local-cache/opencode` are just example bind-mount paths relative to the folder containing your `docker-compose.yaml`. You can replace them with any host paths you want.\n\n**Step 3.** Start it.\n\n```bash\ndocker compose up -d\n```\n\nOpen http://localhost:4096. You're in.\n\n\u003e The shipped `docker-compose.yaml` uses `${ANTHROPIC_API_KEY}` syntax which reads from your shell environment or a `.env` file. Copy `.env.example` to `.env` and fill in your API key.\n\n\u003e `./data/opencode` is only an example host path. If your compose file lives at `/opt/holycode`, that same bind mount becomes `/opt/holycode/data/opencode` on the host.\n\n\u003e Keep `./local-cache/opencode` on local disk. If this project folder lives on NAS/CIFS/SMB storage, change that cache mount to an absolute local host path instead.\n\n\u003cp align=\"right\"\u003e\n  \u003ca href=\"#top\"\u003eback to top\u003c/a\u003e\n\u003c/p\u003e\n\n---\n\n## ☁ HolyCode Cloud (Coming Soon)\n\nDon't want to self-host? We're building a managed version of HolyCode.\n\nSame 50+ tools. Same 10+ providers. Same persistent state. No Docker. No terminal. Just open your browser and code.\n\n**What you get with Cloud:**\n- Zero setup. No Docker, no config files, no terminal commands.\n- Works on any device. Laptop, tablet, phone. Open a browser and go.\n- Always updated. Latest OpenCode, latest tools. We handle it.\n- Your state follows you. Sessions, settings, MCP configs saved between uses.\n\n**Early access is free.** No credit card required.\n\n**[Claim your spot](https://holycode.coderluii.dev/cloud)**\n\n\u003cp align=\"right\"\u003e\n  \u003ca href=\"#top\"\u003eback to top\u003c/a\u003e\n\u003c/p\u003e\n\n---\n\n## 💻 Platform Support\n\n| Platform | Architecture | Status |\n|----------|-------------|--------|\n| Linux | amd64 | Supported |\n| Linux | arm64 | Supported |\n| macOS (Docker Desktop) | amd64 / arm64 | Supported |\n| Windows (WSL2) | amd64 | Supported |\n\n\u003cp align=\"right\"\u003e\n  \u003ca href=\"#top\"\u003eback to top\u003c/a\u003e\n\u003c/p\u003e\n\n---\n\n## ⚡ Why HolyCode\n\nI built this because I was tired of re-doing the same setup every time. Installing OpenCode, wiring up a headless browser, fixing permission issues, debugging process supervision. Every. Time.\n\nSo I made a container that does all of it. And then I hit every possible bug so you don't have to.\n\n| | HolyCode | DIY |\n|---|----------|-----|\n| Time to first working session | Under 2 minutes | 30-60 minutes |\n| Chromium + Xvfb headless browser | Pre-configured | Research, install, debug yourself |\n| Dev tool suite (ripgrep, fzf, lazygit, etc.) | Pre-installed | Hunt down and install one by one |\n| State persistence across rebuilds | Automatic via bind mount | Manual bind mounts, easy to misconfigure |\n| UID/GID file permission remapping | Built-in PUID/PGID | Dockerfile chmod hacks |\n| Multi-arch support | amd64 + arm64 out of the box | Build and push both yourself |\n| Updates | `docker pull` + `compose up` | Rebuild from scratch, hope nothing breaks |\n\n\u003cp align=\"right\"\u003e\n  \u003ca href=\"#top\"\u003eback to top\u003c/a\u003e\n\u003c/p\u003e\n\n---\n\n## 🤖 Provider Support\n\nOpenCode is provider-agnostic. Set whichever API key you use and you're done.\n\n| Provider | Environment Variable | Notes |\n|----------|---------------------|-------|\n| Anthropic | `ANTHROPIC_API_KEY` | Claude models |\n| OpenAI | `OPENAI_API_KEY` | GPT models |\n| Google Gemini | `GEMINI_API_KEY` | Gemini models |\n| Groq | `GROQ_API_KEY` | Fast inference |\n| AWS Bedrock | `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_REGION` | Set all three |\n| Azure OpenAI | `AZURE_OPENAI_ENDPOINT`, `AZURE_OPENAI_API_KEY`, `AZURE_OPENAI_API_VERSION` | Set all three |\n| GitHub | `GITHUB_TOKEN` | GitHub Copilot via OpenAI-compatible endpoint |\n| Vertex AI | (configured via OpenCode) | Google Vertex AI models |\n| GitHub Models | (configured via OpenCode) | GitHub-hosted models |\n| Ollama | (configured via OpenCode) | Local models via Ollama |\n\nYou only need to set keys for providers you actually use. Everything else is optional and ignored.\n\nVertex AI, GitHub Models, and Ollama are configured through OpenCode's provider system. Run `opencode providers login` inside the container.\n\n\u003cp align=\"right\"\u003e\n  \u003ca href=\"#top\"\u003eback to top\u003c/a\u003e\n\u003c/p\u003e\n\n---\n\n## 📋 Docker Compose - Quick\n\nThe minimal setup. Copy, fill in your key, run.\n\n```yaml\nservices:\n  holycode:\n    image: coderluii/holycode:latest\n    container_name: holycode\n    restart: unless-stopped\n    shm_size: 2g              # Required for Chromium stability\n    ports:\n      - \"4096:4096\"           # OpenCode web UI\n    volumes:\n      - ./data/opencode:/home/opencode\n      - ./local-cache/opencode:/home/opencode/.cache/opencode\n      - ./workspace:/workspace  # Your project files\n    environment:\n      - PUID=1000\n      - PGID=1000\n      - ANTHROPIC_API_KEY=your-key-here  # Or swap for any provider key\n```\n\n\u003cp align=\"right\"\u003e\n  \u003ca href=\"#top\"\u003eback to top\u003c/a\u003e\n\u003c/p\u003e\n\n---\n\n## 📄 Docker Compose - Full\n\nEvery option documented. Copy to `docker-compose.yaml` and uncomment what you need.\n\n```yaml\n# HolyCode - Full Configuration Reference\n# Copy this file to docker-compose.yaml and customize.\n# All options documented. Uncomment what you need.\n\nservices:\n  holycode:\n    image: coderluii/holycode:latest\n    container_name: holycode\n    restart: unless-stopped\n    shm_size: 2g\n\n    ports:\n      - \"4096:4096\"   # OpenCode web UI\n\n    volumes:\n      # --- Main HolyCode data ---\n      # Pick any host path you want here. This path maps to /home/opencode in the container.\n      # It can live on local disk or network storage.\n      - ./data/opencode:/home/opencode\n\n      # --- Cache path ---\n      # Keep this one on LOCAL disk for plugin/cache reliability.\n      # If your main data path lives on NAS/CIFS/SMB, make this a separate local path.\n      - ./local-cache/opencode:/home/opencode/.cache/opencode\n\n      # --- Workspace ---\n      - ./workspace:/workspace   # Your project files\n\n    environment:\n      # --- Container user ---\n      - PUID=1000                # Match your host UID for file permissions\n      - PGID=1000                # Match your host GID for file permissions\n\n      # --- Git identity (used on first boot) ---\n      # - GIT_USER_NAME=Your Name\n      # - GIT_USER_EMAIL=you@example.com\n\n      # --- AI provider API keys (add the ones you use) ---\n      - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY:-}\n      # - OPENAI_API_KEY=${OPENAI_API_KEY:-}\n      # - GEMINI_API_KEY=${GEMINI_API_KEY:-}\n      # - GROQ_API_KEY=${GROQ_API_KEY:-}\n      # - GITHUB_TOKEN=${GITHUB_TOKEN:-}\n\n      # --- AWS Bedrock (uncomment all 3 for Bedrock) ---\n      # - AWS_ACCESS_KEY_ID=\n      # - AWS_SECRET_ACCESS_KEY=\n      # - AWS_REGION=us-east-1\n\n      # --- Azure OpenAI (uncomment all 3 for Azure) ---\n      # - AZURE_OPENAI_ENDPOINT=\n      # - AZURE_OPENAI_API_KEY=\n      # - AZURE_OPENAI_API_VERSION=\n\n      # --- OpenCode behavior (set by default in image, override if needed) ---\n      # - OPENCODE_DISABLE_AUTOUPDATE=true\n      # - OPENCODE_DISABLE_TERMINAL_TITLE=true\n      # - OPENCODE_MODEL=claude-sonnet-4-6\n      # - OPENCODE_PERMISSION=auto\n      # - OPENCODE_DISABLE_LSP_DOWNLOAD=true\n      # - OPENCODE_DISABLE_AUTOCOMPACT=true\n      # - OPENCODE_ENABLE_EXA=true\n\n      # --- Web UI Security (basic auth for opencode web) ---\n      # - OPENCODE_SERVER_PASSWORD=your-password\n      # - OPENCODE_SERVER_USERNAME=opencode\n\n      # --- Claude Auth (use Claude subscription instead of API key) ---\n      # Reads credentials from ./data/opencode/.claude/.credentials.json\n      # NOTE: May violate Anthropic TOS. Use at your own risk.\n      # Toggle on/off with docker compose down \u0026\u0026 up -d\n      # - ENABLE_CLAUDE_AUTH=true\n\n      # --- oh-my-openagent (multi-agent orchestration for OpenCode) ---\n      # Enables the plugin through OpenCode config on container start\n      # Toggle on/off with docker compose down \u0026\u0026 up -d\n      # - ENABLE_OH_MY_OPENAGENT=true\n```\n\nFor the optional CLIProxyAPI sidecar, use the shipped `docker-compose.full.yaml` profile instead of the quick-start compose:\n\n```bash\ndocker compose -f docker-compose.full.yaml --profile cliproxyapi up -d\n```\n\nHolyCode reaches that sidecar at `http://cliproxyapi:8317/v1` inside the Compose network. The sidecar is disabled by default and does not replace Claude Auth.\n\n\u003cp align=\"right\"\u003e\n  \u003ca href=\"#top\"\u003eback to top\u003c/a\u003e\n\u003c/p\u003e\n\n---\n\n## 🐳 Podman\n\nPrefer Podman? HolyCode uses the same container image there too. The Podman guide covers the minimal `podman run` setup, env-file usage, SELinux labels, rootless permissions, and update/recreate behavior.\n\n**[Read the Podman guide](docs/podman.md)**\n\n\u003cp align=\"right\"\u003e\n  \u003ca href=\"#top\"\u003eback to top\u003c/a\u003e\n\u003c/p\u003e\n\n---\n\n## 🔧 Environment Variables\n\n| Variable | Default | Purpose |\n|----------|---------|---------|\n| `PUID` | `1000` | Container user UID, match your host for correct file ownership |\n| `PGID` | `1000` | Container user GID, match your host for correct file ownership |\n| `GIT_USER_NAME` | `HolyCode User` | Git identity configured on first boot |\n| `GIT_USER_EMAIL` | `noreply@holycode.local` | Git identity configured on first boot |\n| `ANTHROPIC_API_KEY` | (none) | Anthropic Claude |\n| `OPENAI_API_KEY` | (none) | OpenAI GPT models |\n| `GEMINI_API_KEY` | (none) | Google Gemini |\n| `GROQ_API_KEY` | (none) | Groq fast inference |\n| `GITHUB_TOKEN` | (none) | GitHub CLI auth and Copilot |\n| `AWS_ACCESS_KEY_ID` | (none) | AWS Bedrock - set all three AWS vars |\n| `AWS_SECRET_ACCESS_KEY` | (none) | AWS Bedrock |\n| `AWS_REGION` | (none) | AWS Bedrock region (e.g. `us-east-1`) |\n| `AZURE_OPENAI_ENDPOINT` | (none) | Azure OpenAI - set all three Azure vars |\n| `AZURE_OPENAI_API_KEY` | (none) | Azure OpenAI |\n| `AZURE_OPENAI_API_VERSION` | (none) | Azure OpenAI API version |\n| `OPENCODE_DISABLE_AUTOUPDATE` | `true` | Prevent OpenCode from self-updating inside the container (does not affect plugins) |\n| `OPENCODE_DISABLE_TERMINAL_TITLE` | `true` | Prevent OpenCode from changing the terminal title |\n| `OPENCODE_MODEL` | (none) | Override the default model |\n| `OPENCODE_PERMISSION` | (none) | Set to `auto` to skip permission prompts |\n| `OPENCODE_DISABLE_LSP_DOWNLOAD` | (none) | Disable automatic LSP server downloads |\n| `OPENCODE_DISABLE_AUTOCOMPACT` | (none) | Disable automatic context compaction |\n| `OPENCODE_ENABLE_EXA` | (none) | Enable Exa web search integration |\n| `OPENCODE_SERVER_PASSWORD` | (none) | Protect the web UI with basic auth |\n| `OPENCODE_SERVER_USERNAME` | `opencode` | Username for web UI basic auth |\n| `ENABLE_CLAUDE_AUTH` | (none) | Set to `true` to use Claude subscription instead of API key |\n| `ENABLE_OH_MY_OPENAGENT` | (none) | Set to `true` to enable multi-agent orchestration plugin |\n| `ENABLE_PAPERCLIP` | (none) | Set to `true` to start the Paperclip dashboard and agent board |\n| `PAPERCLIP_PORT` | `3100` | Override the container port used by Paperclip |\n| `PAPERCLIP_INSTANCE_ID` | `default` | Local Paperclip instance name for isolated state |\n| `PAPERCLIP_DEPLOYMENT_MODE` | `authenticated` | Docker-safe Paperclip startup mode; HolyCode defaults this away from `local_trusted` |\n| `PAPERCLIP_ALLOWED_HOSTNAMES` | (none) | Comma-separated Paperclip remote hostnames/IPs to allow; use hostname/IP only, no scheme or port |\n| `ENABLE_HERMES` | (none) | Set to `true` to start Hermes as a bundled meta-agent API |\n| `HERMES_PORT` | `8642` | Override the container port used by Hermes |\n| `CLIPROXYAPI_ENABLED` | (none) | Set to `true` to add the optional OpenCode `cliproxyapi` provider |\n| `CLIPROXYAPI_BASE_URL` | `http://cliproxyapi:8317/v1` | CLIProxyAPI OpenAI-compatible base URL from the HolyCode container |\n| `CLIPROXYAPI_API_KEY` | (none) | Optional API key for CLIProxyAPI, stored only as an OpenCode env reference when set |\n| `CLIPROXYAPI_MODEL` | (none) | Optional primary model key exposed as `cliproxyapi/\u003cmodel\u003e` |\n| `CLIPROXYAPI_SMALL_MODEL` | (none) | Optional smaller/faster model key exposed as `cliproxyapi/\u003cmodel\u003e` |\n| `HOLYCODE_PLUGIN_UPDATE` | `manual` | Plugin update mode: `manual` (install if missing) or `auto` (install and update on boot) |\n\n\u003e Plugin toggles (`ENABLE_CLAUDE_AUTH`, `ENABLE_OH_MY_OPENAGENT`) take effect on container restart. Set the env var and run `docker compose down \u0026\u0026 up -d`.\n\n\u003e `HOLYCODE_PLUGIN_UPDATE` controls plugin package updates. `manual` (default) installs enabled plugins only if they are missing. `auto` installs missing plugins and updates enabled plugins on every boot. This is separate from `OPENCODE_DISABLE_AUTOUPDATE`, which only affects OpenCode itself.\n\n\u003e `ENABLE_OH_MY_OPENAGENT=true` enables the plugin through the main OpenCode config at `/home/opencode/.config/opencode/opencode.json`. On the host, that file appears under whatever host path you bind to `/home/opencode`. On boot, HolyCode also checks whether the plugin package is missing and installs it if needed.\n\n\u003e `ENABLE_OH_MY_OPENAGENT=true` enables the plugin and exposes the built-in `/oh-my-openagent-setup` skill. The skill only appears when the plugin is enabled. Use it to create or update the plugin-specific config file at `~/.config/opencode/oh-my-openagent.jsonc`.\n\n\u003e `ENABLE_PAPERCLIP=true` starts Paperclip on port `3100` inside the container. Open the dashboard, create a company, then hire OpenCode-backed agents there. Paperclip persists under `~/.paperclip` automatically.\n\n\u003e HolyCode forces `PAPERCLIP_DEPLOYMENT_MODE=authenticated` by default because Paperclip's upstream `local_trusted` mode only allows loopback binding. In Docker, that would block port publishing on `0.0.0.0`.\n\n\u003e `PAPERCLIP_ALLOWED_HOSTNAMES` lets Paperclip accept listed LAN/private hostnames or IPs. Use comma-separated hostname/IP values only, without `http://`, `https://`, or ports. Restart the container after changing it. The hostname guard and Paperclip authentication stay enabled.\n\n\u003e `ENABLE_HERMES=true` starts Hermes on port `8642` inside the container. Hermes persists under `~/.hermes`, uses the already-installed `opencode` binary, and can expose an OpenAI-compatible API while delegating code work back into HolyCode.\n\n\u003e Hermes is an API service, not a landing page. A `404` at `http://localhost:8642/` is expected. The important signal is that the port is listening and the process stays healthy.\n\n\u003e `CLIPROXYAPI_ENABLED=true` adds a separate OpenCode provider named `cliproxyapi`. It does not change `ENABLE_CLAUDE_AUTH`, does not touch `/home/opencode/.claude`, and does not set global `ANTHROPIC_*` proxy variables. When using the full-compose sidecar, keep `CLIPROXYAPI_BASE_URL=http://cliproxyapi:8317/v1`.\n\n\u003e CLIProxyAPI sidecar state lives under `./local-cache/cliproxyapi-config`, `./local-cache/cliproxyapi-auth`, and `./local-cache/cliproxyapi-logs`. The API port `8317` is not published to the host by default; uncomment loopback-only host publishing in `docker-compose.full.yaml` only when you need local setup/admin access.\n\n\u003e `GIT_USER_NAME` and `GIT_USER_EMAIL` are only applied on first boot. To re-apply, delete the sentinel file and restart: `docker exec holycode rm /home/opencode/.config/opencode/.holycode-bootstrapped` then `docker compose restart`.\n\n\u003cp align=\"right\"\u003e\n  \u003ca href=\"#top\"\u003eback to top\u003c/a\u003e\n\u003c/p\u003e\n\n---\n\n## 📦 What's Inside\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eCore tools\u003c/strong\u003e\u003c/summary\u003e\n\n| Tool | Purpose |\n|------|---------|\n| `git` | Version control |\n| `ripgrep` | Fast file content search |\n| `fd` | Fast file finder |\n| `fzf` | Fuzzy finder |\n| `bat` | Cat with syntax highlighting |\n| `eza` | Modern ls replacement |\n| `lazygit` | Terminal git UI |\n| `delta` | Better git diffs |\n| `gh` | GitHub CLI |\n| `htop` | Process monitor |\n| `tar` | Archive creation and extraction |\n| `tree` | Directory tree visualization |\n| `less` | Paged file viewer |\n| `vim` | Terminal text editor |\n| `tmux` | Terminal multiplexer |\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eLanguage runtimes\u003c/strong\u003e\u003c/summary\u003e\n\n| Runtime | Version |\n|---------|---------|\n| Node.js | 22 (LTS) |\n| npm | Bundled with Node.js 22 |\n| Python | 3 (system) |\n| pip | Bundled with Python 3 |\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eDev tools\u003c/strong\u003e\u003c/summary\u003e\n\n| Tool | Purpose |\n|------|---------|\n| `curl` | HTTP requests |\n| `wget` | File downloads |\n| `jq` | JSON processing |\n| `unzip` / `zip` | Archive tools |\n| `ssh` | Remote access |\n| `build-essential` + `pkg-config` | Native npm addon compilation |\n| `python3-venv` | Python virtual environments |\n| `procps` | Process tools: ps, top |\n| `iproute2` | Network tools: ip, ss |\n| `lsof` | Open file diagnostics |\n| OpenSSL | Crypto and cert tools (via base image) |\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eBrowser stack\u003c/strong\u003e\u003c/summary\u003e\n\n| Component | Purpose |\n|-----------|---------|\n| Chromium | Headless browser engine |\n| Xvfb | Virtual framebuffer display server |\n| Playwright | Browser automation framework |\n\nThe browser stack runs headless out of the box. No display server, no GPU, no extra config needed. Playwright and Puppeteer scripts work as expected.\n\nIncludes Liberation, DejaVu, Noto, and Noto Color Emoji fonts for correct page rendering and screenshots.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eBundled services\u003c/strong\u003e\u003c/summary\u003e\n\n| Service | Purpose |\n|---------|---------|\n| Hermes Agent | Self-improving meta-agent with MCP, messaging adapters, and OpenCode delegation |\n| Paperclip | Local agent board that hires OpenCode workers and wakes them on heartbeat |\n| CLIProxyAPI sidecar | Optional full-compose profile for centralized OpenAI-compatible account/model routing |\n| Claude Code CLI | Installed for Claude subscription auth flows via `ENABLE_CLAUDE_AUTH` |\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eProcess management\u003c/strong\u003e\u003c/summary\u003e\n\n| Component | Purpose |\n|-----------|---------|\n| s6-overlay v3 | Process supervisor and init system |\n| Custom entrypoint | UID/GID remapping, git setup, bootstrap |\n\ns6-overlay supervises OpenCode and Xvfb. If a process crashes, it restarts automatically. Container restart policies stay clean because the supervisor handles it internally.\n\n\u003c/details\u003e\n\n\u003cp align=\"right\"\u003e\n  \u003ca href=\"#top\"\u003eback to top\u003c/a\u003e\n\u003c/p\u003e\n\n---\n\n## 🧩 Bundled Services\n\nHolyCode now ships with three optional layers on top of OpenCode. You do **not** need them to use the container. But if plain OpenCode gives you the hands, these add coordination, a control room, and centralized model routing.\n\n- **Hermes Agent** is for when you want a smarter coordinator sitting above OpenCode.\n- **Paperclip** is for when you want a board, a workflow, and actual agent management instead of just one-off prompts.\n- **CLIProxyAPI** is for when you want one OpenAI-compatible endpoint that can route models/accounts through a separate sidecar.\n\nFlip the env var, restart the container, and the service comes up alongside the normal web UI.\n\n### Hermes Agent\n\nHermes is the \"smarter brain\" option. It runs as a bundled meta-agent, exposes an API service on port `8642`, and delegates coding work by calling the local `opencode` binary that HolyCode already ships.\n\nWhy that matters:\n\n- **Planning above execution.** OpenCode does the hands-on coding. Hermes gives you a layer that can reason, coordinate, and delegate down into that local worker.\n- **API-ready agent runtime.** You can point other tooling at Hermes instead of wiring your own service around OpenCode.\n- **MCP and messaging in the same box.** HolyCode already solves the dev-environment side. Hermes adds the \"agent platform\" layer on top.\n- **Persistent agent state.** Its data lives under `~/.hermes`, so rebuilds don't wipe the runtime you just configured.\n\nIf you want HolyCode to feel less like \"a container with a coding tool\" and more like \"an AI runtime you can build systems on top of,\" Hermes is the part that changes that.\n\nTurn it on with:\n\n```yaml\nenvironment:\n  - ENABLE_HERMES=true\n  - HERMES_PORT=8642\n```\n\nHermes state lives under `/home/opencode/.hermes`, so it follows the same persistence story as the rest of HolyCode.\n\n### Paperclip\n\nPaperclip is the \"agent board\" option. It gives you a local dashboard on port `3100` where you create a company, hire agents, and let those agents wake up on schedule. Under the hood it spawns `opencode run` processes, so the workers are still HolyCode.\n\nWhy that matters:\n\n- **A real control surface.** You stop treating agents like random shell commands and start treating them like a team with roles, tasks, and wake cycles.\n- **OpenCode-backed workers, not a toy layer.** The board is Paperclip. The actual worker execution is still HolyCode doing real coding work.\n- **Faster delegation experiments.** Create a company, assign work, and see how an agent workflow feels without building the orchestration stack yourself.\n- **Persistent board state.** Data, config, storage, and embedded Postgres all live under `~/.paperclip`.\n\nIf Hermes is the brain, Paperclip is the control room. It's the thing you turn on when you want to manage agent work, not just launch it.\n\nTurn it on with:\n\n```yaml\nenvironment:\n  - ENABLE_PAPERCLIP=true\n  - PAPERCLIP_PORT=3100\n  - PAPERCLIP_DEPLOYMENT_MODE=authenticated\n  - PAPERCLIP_ALLOWED_HOSTNAMES=192.168.1.50,my-host.local\n```\n\nPaperclip state lives under `/home/opencode/.paperclip`. HolyCode bootstraps it in `authenticated` mode so Docker port publishing works cleanly. Open the dashboard, set up your company, and hire OpenCode-backed employees from there.\n\nWhen opening Paperclip from another machine, set `PAPERCLIP_ALLOWED_HOSTNAMES` to the hostname or IP from the browser URL, without `http://`, `https://`, or `:3100`. Use commas for multiple values and restart the container after changes. This only allowlists those private hostnames; it does not make Paperclip public or disable authentication.\n\n### CLIProxyAPI\n\nCLIProxyAPI is the \"model router\" option. It runs as an optional sidecar from the full Compose reference and exposes an OpenAI-compatible API on port `8317` inside the Docker network. HolyCode can add a separate OpenCode provider named `cliproxyapi` that points at that sidecar.\n\nWhy that matters:\n\n- **One provider surface.** OpenCode can use `cliproxyapi/\u003cmodel\u003e` while CLIProxyAPI handles the account/model routing behind it.\n- **Isolated from Claude Auth.** This does not replace `ENABLE_CLAUDE_AUTH`, does not touch `/home/opencode/.claude`, and does not set global Anthropic proxy variables.\n- **No default host exposure.** The sidecar is reachable by HolyCode over Docker DNS as `http://cliproxyapi:8317/v1`; host port publishing is loopback-only and commented out by default.\n- **Separate state.** Config, auth, and logs live under `./local-cache/cliproxyapi-*`, not under the OpenCode home or Claude credential folder.\n\nTurn it on with:\n\n```yaml\nenvironment:\n  - CLIPROXYAPI_ENABLED=true\n  - CLIPROXYAPI_BASE_URL=http://cliproxyapi:8317/v1\n  - CLIPROXYAPI_API_KEY=\n  - CLIPROXYAPI_MODEL=your-model-id\n```\n\nThen start the full Compose profile:\n\n```bash\ndocker compose -f docker-compose.full.yaml --profile cliproxyapi up -d\n```\n\nCreate `./local-cache/cliproxyapi-config/config.yaml` before enabling the profile. Put CLIProxyAPI API keys/OAuth state in its own mounted config/auth paths; do not reuse `/home/opencode/.claude`.\n\n\u003cp align=\"right\"\u003e\n  \u003ca href=\"#top\"\u003eback to top\u003c/a\u003e\n\u003c/p\u003e\n\n---\n\n## 🏗 Architecture\n\n```mermaid\ngraph TD\n    A[docker compose up -d] --\u003e B[entrypoint.sh]\n    B --\u003e C[UID/GID Remap]\n    C --\u003e D[Plugin and Service Toggles]\n    D --\u003e E{First Boot?}\n    E --\u003e|Yes| F[bootstrap.sh]\n    E --\u003e|No| G[s6-overlay /init]\n    F --\u003e G\n    G --\u003e H[Xvfb :99]\n    G --\u003e I[opencode web :4096]\n    G --\u003e Q[Hermes API :8642]\n    G --\u003e R[Paperclip UI :3100]\n    A --\u003e U[CLIProxyAPI sidecar :8317 internal]\n    I --\u003e J[Web UI]\n    J --\u003e K[Your Browser]\n    I --\u003e L[CLI Access]\n    L --\u003e M[docker exec -it holycode bash]\n    M --\u003e N[opencode TUI]\n    M --\u003e O[opencode run 'message']\n    M --\u003e P[opencode attach localhost:4096]\n    Q --\u003e S[Meta-agent API clients]\n    R --\u003e T[Agent board and CEO invite]\n    I --\u003e U\n```\n\nThe entrypoint handles user remapping, plugin toggles, optional bundled-service toggles, CLIProxyAPI provider injection, and first-boot setup. s6-overlay supervises Xvfb, the OpenCode web server, and any optional bundled services you enabled inside the HolyCode container. The CLIProxyAPI sidecar is a separate Compose service. Access the web UI at port 4096, Hermes on 8642, or Paperclip on 3100 when those services are enabled.\n\n\u003cp align=\"right\"\u003e\n  \u003ca href=\"#top\"\u003eback to top\u003c/a\u003e\n\u003c/p\u003e\n\n---\n\n## 💻 CLI Usage\n\nThe web UI at port 4096 is the primary interface. But you can also use OpenCode directly from the command line inside the container.\n\n### Interactive TUI\n\n```bash\ndocker exec -it holycode bash\nopencode\n```\n\nThis opens OpenCode's full terminal UI with all the same features as the web version.\n\n### One-shot commands\n\nRun a single prompt without entering the TUI:\n\n```bash\ndocker exec -it holycode bash -c \"opencode run 'explain this codebase'\"\n```\n\n### Attach to the running server\n\nConnect a local TUI session to the already-running OpenCode web server:\n\n```bash\ndocker exec -it holycode bash -c \"opencode attach http://localhost:4096\"\n```\n\nThis shares the same session as the web UI. Changes in one appear in the other.\n\n### Provider management\n\nList and configure AI providers from inside the container:\n\n```bash\ndocker exec -it holycode bash -c \"opencode providers list\"\ndocker exec -it holycode bash -c \"opencode providers login\"\n```\n\n### oh-my-openagent setup and reconfiguration\n\nIf you enabled `ENABLE_OH_MY_OPENAGENT=true`, the `/oh-my-openagent-setup` skill becomes available. Use it to create or refresh the plugin-specific config:\n\n```text\n/oh-my-openagent-setup\n```\n\nThat flow is the supported path for:\n\n- first-time oh-my-openagent setup\n- reconfiguring after adding or removing providers\n- restoring the intended picker defaults so only the primary agents are visible\n\nHolyCode's default picker policy is:\n\n- visible: `sisyphus`, `hephaestus`, `prometheus`, `atlas`\n- hidden subagents: `oracle`, `librarian`, `explore`, `metis`, `momus`, `multimodal-looker`, `sisyphus-junior`\n\nIf you add a new provider later and the visible default model still looks stale, rerun `/oh-my-openagent-setup`, then run:\n\n```bash\ndocker exec -it holycode bash -c \"bunx oh-my-opencode doctor\"\ndocker exec -it holycode bash -c \"bunx oh-my-opencode refresh-model-capabilities\"\n```\n\nHolyCode can guide the supported refresh path, but upstream OpenCode and oh-my-openagent model-resolution behavior still controls the final visible model state.\n\n### Useful commands\n\n| Command | What it does |\n|---------|-------------|\n| `opencode` | Launch the TUI |\n| `opencode run 'message'` | One-shot prompt |\n| `opencode attach \u003curl\u003e` | Attach TUI to running server |\n| `opencode web --port 4096` | Start web server (already running via s6) |\n| `opencode serve` | Headless API server |\n| `opencode providers list` | Show configured providers |\n| `opencode providers login` | Add or switch provider |\n| `bunx oh-my-opencode doctor` | Diagnose oh-my-openagent config and model resolution |\n| `bunx oh-my-opencode refresh-model-capabilities` | Refresh provider/model capability cache after provider changes |\n| `opencode models` | List available models |\n| `opencode models \u003cprovider\u003e` | List models for a specific provider |\n| `opencode stats` | Show token usage and costs |\n| `opencode session list` | List past sessions |\n| `opencode export \u003csessionID\u003e` | Export session as JSON |\n| `opencode plugin \u003cmodule\u003e` | Install a plugin |\n| `opencode upgrade` | Upgrade OpenCode (disabled by default in container) |\n\n\u003cp align=\"right\"\u003e\n  \u003ca href=\"#top\"\u003eback to top\u003c/a\u003e\n\u003c/p\u003e\n\n---\n\n## 💾 Data and Persistence\n\nMost OpenCode state lives under `/home/opencode` inside the container. On the host, that data appears wherever you bind-mount `/home/opencode`. In the default examples below, the host path is `./data/opencode`, but you can replace it with any path you want.\n\nPlugin cache is mounted separately at `./local-cache/opencode` by default so you can keep that cache path on local disk even if your main data path is somewhere else.\n\n| Host Path | Container Path | What's in it |\n|-----------|---------------|-------------|\n| `./data/opencode/.config/opencode`* | `/home/opencode/.config/opencode` | Settings, agents, MCP configs, themes, plugins |\n| `./data/opencode/.local/share/opencode`* | `/home/opencode/.local/share/opencode` | SQLite sessions database, MCP OAuth tokens |\n| `./data/opencode/.local/state/opencode`* | `/home/opencode/.local/state/opencode` | Frecency data, model cache, key-value store |\n| `./local-cache/opencode` | `/home/opencode/.cache/opencode` | Plugin node_modules, auto-installed dependencies |\n\n\\* These `./data/opencode/...` paths are example host paths from the sample compose file. If you bind `/home/opencode` to a different host path, the same subdirectories will appear there instead.\n\nRebuild the container anytime. Run `docker compose pull \u0026\u0026 docker compose up -d` and your sessions, settings, and configs come back automatically.\n\n**SQLite WAL note.** The sessions database uses Write-Ahead Logging. Don't copy the `.db` file while the container is running. Stop the container first if you need to back up or migrate the database file.\n\n**Network storage note.** If `./data/opencode` is on a CIFS/SMB network mount (NAS, Synology, TrueNAS), you need two mount options:\n- `nobrl` — SQLite WAL mode requires this (byte-range locking workaround)\n- `mfsymlinks` — plugin installation requires this (symlink support for node_modules)\n\nKeep `./local-cache/opencode` on local disk. If your whole HolyCode folder lives on network storage, change that cache mount to an absolute local host path such as `/var/lib/holycode-cache/opencode:/home/opencode/.cache/opencode`.\n\nSee the Troubleshooting section below.\n\n\u003cp align=\"right\"\u003e\n  \u003ca href=\"#top\"\u003eback to top\u003c/a\u003e\n\u003c/p\u003e\n\n---\n\n## 🔐 Permissions\n\nHolyCode uses `PUID` and `PGID` to remap the internal container user to match your host user. This means files written to `./workspace` are owned by you, not by root.\n\nFind your IDs on Linux and macOS:\n\n```bash\nid -u   # PUID\nid -g   # PGID\n```\n\nOn most systems this is `1000:1000`. On macOS it's often `501:20`. Set them in your compose file:\n\n```yaml\nenvironment:\n  - PUID=501\n  - PGID=20\n```\n\nIf you skip this, files in your workspace may be owned by root and you'll need sudo to edit them from the host.\n\n\u003cp align=\"right\"\u003e\n  \u003ca href=\"#top\"\u003eback to top\u003c/a\u003e\n\u003c/p\u003e\n\n---\n\n## ⬆️ Upgrading\n\nPull the latest image and recreate the container. Your data stays untouched.\n\n```bash\ndocker compose pull\ndocker compose up -d\n```\n\nThat's it. One command. Your sessions, settings, and configs are in the bind mount so nothing is lost.\n\n\u003cp align=\"right\"\u003e\n  \u003ca href=\"#top\"\u003eback to top\u003c/a\u003e\n\u003c/p\u003e\n\n---\n\n## 🛠 Troubleshooting\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eChromium crashes or browser automation fails\u003c/strong\u003e\u003c/summary\u003e\n\nThe most common cause is not enough shared memory. Chromium needs at least 1-2 GB of `/dev/shm` to run reliably.\n\nMake sure your compose file has `shm_size: 2g`:\n\n```yaml\nservices:\n  holycode:\n    shm_size: 2g\n```\n\nWithout this, Chromium will crash silently or produce broken screenshots.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003ePermission denied on workspace files\u003c/strong\u003e\u003c/summary\u003e\n\nYour `PUID` and `PGID` don't match your host user. Find your IDs:\n\n```bash\nid -u \u0026\u0026 id -g\n```\n\nUpdate your compose environment section to match:\n\n```yaml\nenvironment:\n  - PUID=1001   # replace with your actual UID\n  - PGID=1001   # replace with your actual GID\n```\n\nThen recreate the container: `docker compose up -d --force-recreate`\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003ePort 4096 already in use\u003c/strong\u003e\u003c/summary\u003e\n\nSomething else on your machine is using port 4096. Remap to a different host port:\n\n```yaml\nports:\n  - \"4097:4096\"   # access via http://localhost:4097\n```\n\nOr find and stop the conflicting process:\n\n```bash\n# Linux / macOS\nlsof -i :4096\n\n# Windows\nnetstat -ano | findstr :4096\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eContainer starts but web UI never loads\u003c/strong\u003e\u003c/summary\u003e\n\nCheck the container logs:\n\n```bash\ndocker compose logs -f holycode\n```\n\nOpenCode takes a few seconds to initialize. Give it 10-15 seconds after `docker compose up -d` before opening the browser. If it's still not up, the logs will tell you why.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eWhy doesn't HolyCode need SYS_ADMIN or seccomp=unconfined?\u003c/strong\u003e\u003c/summary\u003e\n\nChromium runs with `--no-sandbox` inside the container, which is standard for containerized browser setups. This eliminates the need for `SYS_ADMIN` capabilities or `seccomp=unconfined` that some other Docker browser setups require. The container itself provides the isolation boundary.\n\nIf you prefer to use Chromium's built-in sandbox instead, add the following to your compose file and remove `--no-sandbox` from the `CHROMIUM_FLAGS` environment variable:\n\n```yaml\ncap_add:\n  - SYS_ADMIN\nsecurity_opt:\n  - seccomp=unconfined\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eSQLite WAL or plugins fail on CIFS/SMB network mounts (NAS)\u003c/strong\u003e\u003c/summary\u003e\n\nIf your `./data/opencode` directory lives on a CIFS/SMB network share (e.g. NAS, Synology, TrueNAS), OpenCode may fail with:\n\n```\nFailed to run the query 'PRAGMA journal_mode = WAL'\n```\n\nOpenCode uses SQLite with Write-Ahead Logging (WAL) for its sessions database. WAL requires byte-range locking, which CIFS/SMB doesn't support by default.\n\nHolyCode detects this at startup and prints a warning with the fix instructions.\n\n**Fix:** Add `nobrl,mfsymlinks` to your CIFS mount options in `/etc/fstab`:\n\n```\n# Before\n//192.168.1.100/share /mnt/share cifs credentials=/etc/smbcreds,uid=1000,gid=1000 0 0\n\n# After — add nobrl and mfsymlinks\n//192.168.1.100/share /mnt/share cifs credentials=/etc/smbcreds,uid=1000,gid=1000,nobrl,mfsymlinks 0 0\n```\n\nThen remount:\n\n```bash\nsudo umount /mnt/share\nsudo mount /mnt/share\n```\n\nRestart HolyCode: `docker compose up -d --force-recreate`\n\nIf you are using the default HolyCode Compose files, the cache mount is `./local-cache/opencode:/home/opencode/.cache/opencode`. Keep that path on local disk. If your entire HolyCode folder lives on network storage, replace it with an absolute local host path.\n\n\u003c/details\u003e\n\n\u003cp align=\"right\"\u003e\n  \u003ca href=\"#top\"\u003eback to top\u003c/a\u003e\n\u003c/p\u003e\n\n---\n\n## 🔨 Building Locally\n\nClone the repo, build the image, swap it into your compose file.\n\n```bash\ngit clone https://github.com/coderluii/holycode.git\ncd holycode\ndocker build -t holycode:local .\n```\n\nThen in your `docker-compose.yaml` swap the image:\n\n```yaml\nimage: holycode:local\n```\n\n\u003cp align=\"right\"\u003e\n  \u003ca href=\"#top\"\u003eback to top\u003c/a\u003e\n\u003c/p\u003e\n\n---\n\n## 🤝 Contributing\n\n1. Fork the repo\n2. Create a branch: `git checkout -b feature/your-feature`\n3. Commit your changes: `git commit -m \"feat: your feature\"`\n4. Push: `git push origin feature/your-feature`\n5. Open a pull request\n\nSee [CONTRIBUTING.md](.github/CONTRIBUTING.md) for full guidelines.\n\n\u003cp align=\"right\"\u003e\n  \u003ca href=\"#top\"\u003eback to top\u003c/a\u003e\n\u003c/p\u003e\n\n---\n\n## ⭐ Support\n\nIf HolyCode saved you from another hour of environment setup, here's how to pay it forward.\n\n- Star the repo on GitHub\n- Share it with someone who'd find it useful\n- [Buy Me A Coffee](https://buymeacoffee.com/CoderLuii)\n- [PayPal](https://www.paypal.com/donate/?hosted_button_id=PM2UXGVSTHDNL)\n- [GitHub Sponsors](https://github.com/sponsors/CoderLuii)\n\n\u003cp align=\"right\"\u003e\n  \u003ca href=\"#top\"\u003eback to top\u003c/a\u003e\n\u003c/p\u003e\n\n---\n\n## 📄 License\n\nMIT License - see [LICENSE](LICENSE).\n\n\u003cp align=\"right\"\u003e\n  \u003ca href=\"#top\"\u003eback to top\u003c/a\u003e\n\u003c/p\u003e\n\n---\n\n\u003cdiv align=\"center\"\u003e\n\nBuilt by [CoderLuii](https://github.com/coderluii) · [coderluii.dev](https://coderluii.dev)\n\n\u003c/div\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcoderluii%2Fholycode","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcoderluii%2Fholycode","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcoderluii%2Fholycode/lists"}