# Running Chorus Chorus is a monorepo: a TypeScript daemon (`packages/*`) plus a React/Vite dashboard (`apps/dashboard`). One long-lived daemon owns orchestration, backend CLI runs, git worktrees, GitHub PR creation, and dashboard/API serving. The top-level [README](../README.md) is the platform-by-platform install guide. This document records the runtime details operators usually need after choosing container or bare-metal mode. ## Recommended Runtime Container mode is strongly recommended. Chorus intentionally drives AI CLIs with dangerous approval-bypass modes for unattended engineering work: - Codex: `codex exec --dangerously-bypass-approvals-and-sandbox` - Claude Code: `--permission-mode bypassPermissions` - Gemini CLI: `--approval-mode yolo` Containers keep that process tree away from the host filesystem while mounting only the Chorus data directory and the BYOAI/GitHub credential home you choose. Bare-metal mode is supported, but should be limited to a dedicated machine, VM, or OS account. ## Prerequisites For all modes: - A GitHub account with push + PR access to target repos. - `gh` authenticated for that account. - At least one BYOAI backend account: Codex, Claude Code, or Gemini CLI. For container mode: - macOS: Apple `container`, Docker Desktop, Podman, or OrbStack. - Linux: Docker or Podman. - Windows: Docker Desktop or Podman Desktop with Linux containers enabled. For bare-metal mode: - Node 22+ and npm 10+. - Git and GitHub CLI. - The AI CLI packages you want to use: ```bash npm install -g @openai/codex@latest @anthropic-ai/claude-code@latest @google/gemini-cli@latest ``` ## Container Quick Start ```bash # macOS ./deploy/mac/run-container.sh start # Linux, or macOS with Docker Desktop/Podman/OrbStack ./deploy/linux/run-container.sh start ``` ```powershell # Windows PowerShell .\deploy\windows\run-container.ps1 start ``` Then authenticate inside the container: ```bash gh auth login codex login # Also run claude/gemini once if you want those backends available. ``` The launchers publish the dashboard on . The daemon binds to `0.0.0.0` inside the container, but the host port is loopback-only by default. Useful actions: ```text start Build the image and start a fresh container. restart Same as start. shell Open an interactive shell inside the running container. logs Follow daemon logs. stop Stop the container. rm Remove the container. status Show runtime status. ``` ## Bare-Metal Quick Start ```bash cp chorus.config.example.json chorus.config.json npm install npm run build npm --workspace @chorus/dashboard run build node packages/daemon/dist/main.js ``` Open . Before using agents, authenticate the host tools: ```bash gh auth login codex login # Also run claude/gemini once if you want those backends available. ``` Bare-metal mode runs agent CLIs as your host user. Keep `host` set to `127.0.0.1` unless the dashboard is protected by a trusted private network or authenticated reverse proxy. ## Configuration Copy the example and edit it: ```bash cp chorus.config.example.json chorus.config.json ``` The daemon auto-loads `chorus.config.json` from the repo root on every start. Set `CHORUS_CONFIG=/path/to/file.json` only if you keep config elsewhere. The example omits `dataDir`; leaving it unset uses `~/.chorus` on bare metal, while the container launchers force `/var/lib/chorus` inside the container. Important fields: | field | meaning | |---|---| | `dataDir` | SQLite DB, clones, worktrees, and logs. Bare-metal default is `~/.chorus`; container launchers force `/var/lib/chorus` inside the container. | | `port` / `host` | Dashboard/API bind. Code defaults to `0.0.0.0:7878` when no config/env is present; the example config uses `127.0.0.1`, and container launchers publish only `127.0.0.1:7878` on the host. | | `maxConcurrentAgents` | Parallel agent runs. | | `agent.model` | Default Codex model override. Empty means CLI default. | | `agent.autoUpdateCli` | Self-update Codex/Claude CLIs once per daemon process. | | `quota.exhaustionPatterns` | Regexes that classify quota/rate-limit exhaustion. | | `notifications.imessageTo` | macOS iMessage recipient for PR/merge notifications. | | `terminal.allowRemoteClients` | Allows the dashboard terminal from non-local clients. Enable only on trusted networks because the dashboard is unauthenticated. | Environment overrides: ```text CHORUS_CONFIG CHORUS_DATA_DIR CHORUS_PORT CHORUS_HOST CHORUS_DASHBOARD_DIR CHORUS_ALLOW_REMOTE_TERMINAL ``` ## Backend CLIs Chorus detects installed backend CLIs at startup and exposes them in the dashboard. The implemented adapters are: - `codex` - `claude` - `gemini` Container images install those CLIs unless `CHORUS_INSTALL_AI_CLIS=false` is set for the build. Credentials are stored in the mounted container home, so login survives rebuilds. ## Using Chorus 1. Open . 2. Click **New project**. 3. Paste a GitHub repo URL. 4. Chorus clones the repo and finds or asks for `docs/SPEC.md`. 5. Chorus generates tickets and dispatches role-based agents. 6. Agents work in per-ticket worktrees and branches. 7. Chorus pushes completed ticket branches and opens GitHub PRs. 8. A human reviews and merges on GitHub. Chorus never merges to `main` itself. ## 24/7 macOS Bare-Metal Service Edit `deploy/com.chorus.daemon.plist` paths, then: ```bash cp deploy/com.chorus.daemon.plist ~/Library/LaunchAgents/ launchctl load ~/Library/LaunchAgents/com.chorus.daemon.plist ``` `KeepAlive` restarts the daemon on crash; boot reconciliation resumes interrupted work from SQLite and git state. ## Remote Access The dashboard/API has no built-in authentication. Prefer loopback plus a private overlay or authenticated proxy. For Tailscale: ```bash tailscale serve --bg 7878 ``` If opening the dashboard from another device, set `terminal.allowRemoteClients` only when the network is trusted and you accept exposing the interactive terminal to clients that can reach the dashboard. ## Safety Model - Agent CLIs run with approval bypasses. Container mode limits host exposure; bare-metal mode does not. - Agents work in isolated git worktrees on per-ticket branches cut from `origin/`, never directly on `main`. - A local pre-push hook blocks pushes to `main`/`master`/base. - Chorus, not the agent, pushes ticket branches and opens PRs. - Merging a PR is always a manual human action on GitHub. ## Tests ```bash npm test python3 -m unittest discover -s tests ```