https://github.com/opendray/opendray
Self-hosted terminal cockpit for piloting AI coding agents (Claude Code, Codex, Gemini, OpenCode, Qwen) from mobile, web, or Telegram. Go backend, Flutter app, plugin architecture.
https://github.com/opendray/opendray
ai-coding claude-code cli codex developer-tools flutter gemini golang homelab llm mcp multi-agent open-source plugin-architecture self-hosted telegram-bot terminal
Last synced: 26 days ago
JSON representation
Self-hosted terminal cockpit for piloting AI coding agents (Claude Code, Codex, Gemini, OpenCode, Qwen) from mobile, web, or Telegram. Go backend, Flutter app, plugin architecture.
- Host: GitHub
- URL: https://github.com/opendray/opendray
- Owner: Opendray
- License: mit
- Created: 2026-04-17T10:00:39.000Z (2 months ago)
- Default Branch: main
- Last Pushed: 2026-04-22T08:38:36.000Z (about 2 months ago)
- Last Synced: 2026-04-22T09:15:49.690Z (about 2 months ago)
- Topics: ai-coding, claude-code, cli, codex, developer-tools, flutter, gemini, golang, homelab, llm, mcp, multi-agent, open-source, plugin-architecture, self-hosted, telegram-bot, terminal
- Language: Go
- Homepage:
- Size: 2.54 MB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 2
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Contributing: CONTRIBUTING.md
- Funding: .github/FUNDING.yml
- License: LICENSE
- Code of conduct: CODE_OF_CONDUCT.md
- Codeowners: .github/CODEOWNERS
- Security: SECURITY.md
Awesome Lists containing this project
README
opendray
Self-hosted multi-CLI control gateway for AI coding agents.
Remote-control Claude Code ยท Codex ยท Gemini ยท shell from web, mobile, or your favourite messaging app.
๐ English ยท ็ฎไฝไธญๆ
---
## What is opendray?
**opendray** wraps the AI coding CLIs you already use โ Claude Code, Codex, Gemini, plus any shell โ and turns them into something you can drive from anywhere. Run sessions on your home server / NAS / VPS, get notified on Telegram when one goes idle, reply from your phone to feed the next prompt back in, all over a self-hosted gateway you control end to end.
- ๐ฐ **One backend, three surfaces** โ single Go binary serving a React web admin and a Flutter mobile app, with every action also exposed over a REST + WebSocket API for third-party integrations.
- ๐ฌ **Six bidirectional channels, no walled gardens** โ Telegram, Slack, Discord, Feishu (้ฃไนฆ), DingTalk (้้), WeCom (ไผไธๅพฎไฟก), plus a Bridge adapter for anything custom. Replies on any channel get routed back into the right session.
- ๐ง **Local-first memory** โ ONNX / Ollama / LM Studio embeddings with three-scope retrieval (user ยท project ยท session), smart ranking, and cross-layer conflict detection. No vector data leaves your network.
- ๐ **Integration-grade API** โ scoped API keys, per-call audit log, reverse-proxy mounts. Treat opendray as the gateway behind your own product or just as a personal command centre.
- ๐ **Self-hosted, license-clear** โ Apache 2.0, one static binary, cosign-signed releases with SPDX SBOM. No telemetry, no cloud account, no subscription.
## Status
**v2.0.5** (latest) โ the v2 generation is feature-complete and shipping
patch releases as operators report polish items. See
[`VERSIONING.md`](VERSIONING.md) for the major-as-generation policy
(major = product generation, not strict SemVer "breaking change") and
[`CHANGELOG.md`](CHANGELOG.md) for the full release history.
This generation ships:
- **One-line installer + uninstaller wizards** (Linux + macOS;
Windows funnels through WSL2). Walks the operator through Postgres
bootstrap, AI-CLI install, admin credentials, listen address,
binary install, schema migration, and service registration.
- **Self-managing binary** โ `opendray update / start / stop /
restart / status / providers list / providers update` so operators
don't touch `systemctl` / `launchctl` for routine ops.
- **Goreleaser release pipeline** โ cross-compiled binaries
(linux/darwin ร amd64/arm64), cosign keyless signing (Sigstore),
SPDX SBOM, atomically verified self-update.
## Install
### One-line installer
**Linux / macOS / WSL2**
```sh
curl -fsSL https://raw.githubusercontent.com/Opendray/opendray/main/scripts/install.sh | bash
```
**Windows** โ sets up WSL2 first, then runs the Linux installer inside it. [details โ](scripts/README.md#windows)
```powershell
irm https://raw.githubusercontent.com/Opendray/opendray/main/scripts/install-windows.ps1 | iex
```
Walks through Postgres setup, AI-CLI install, admin credentials, and service registration โ landing a running gateway in ~5โ10 minutes. See [**`scripts/README.md`**](scripts/README.md) for what the wizard does, the file layout it creates, options, and troubleshooting.
> **Want the manual walkthrough?** Read [**docs/getting-started.md**](docs/getting-started.md) โ a 15-minute end-to-end guide that mirrors what the wizard does so you can verify each step yourself.
### Uninstall (Linux / macOS)
**Default** โ stops the gateway and removes the binary, but **keeps** your `config.toml`, data directory (bcrypt keyfile, sessions, notes, vault), logs, and the PostgreSQL database so a re-install resumes where you left off:
```sh
curl -fsSL https://raw.githubusercontent.com/Opendray/opendray/main/scripts/uninstall.sh | bash
```
**Full purge** โ also drops the PG database + role, deletes config / data / logs, removes the service user. Includes a post-delete verification step that bails loudly if anything survived:
```sh
curl -fsSL https://raw.githubusercontent.com/Opendray/opendray/main/scripts/uninstall.sh | OPENDRAY_PURGE=1 bash
```
### Day-to-day commands
After install, the `opendray` binary handles its own lifecycle โ no need to remember `systemctl` / `launchctl` incantations:
```sh
sudo opendray update --restart # download latest release, verify SHA, atomic replace + restart
```
```sh
sudo opendray providers update # bump installed AI CLIs (claude / codex / gemini) to npm-latest
```
```sh
opendray providers list # see which AI CLIs are installed + their versions
```
```sh
sudo opendray start # start | stop | restart | status โ wraps systemd / launchd
```
`opendray --help` lists the full subcommand set.
### Deploy path picker
Every supported path includes session spawn, AI-CLI access, encrypted backups, and the full integration API. opendray is a host-resident gateway โ it spawns AI CLIs via PTYs and shares process state (`~/.claude`, ssh-agent, project files) with them. That model is incompatible with the container isolation that production Docker would impose, so Docker is not a supported deployment path for v2.x.
| Path | Best for | Jump to |
|---|---|---|
| ๐ฆ **Pre-built binary** | "Just run it" โ Linux / macOS, any supervisor | [Releases page](https://github.com/Opendray/opendray/releases) โ see [Production deploy](#production-deploy) |
| ๐ง **systemd unit** | Bare-metal / VM / LXC Linux box | [Production deploy ยงA](#option-a--systemd-bare-metal--vm--lxc) |
| ๐ **macOS LaunchDaemon** | Mac mini / Mac Studio as home server | [Production deploy ยงB](#option-b--macos-launchd-mac-mini--studio-as-home-server) |
| ๐ **Build from source** | Dev / contributing / custom builds | [Quickstart](#quickstart-5-minute-dev-path) below |
## Quickstart (5-minute dev path)
For a full walkthrough with prereqs and troubleshooting, see [`docs/quickstart.md`](docs/quickstart.md). The condensed dev path:
```bash
# 1. Have a Postgres 15+ running on 127.0.0.1:5432 with pgvector enabled
# (apt install postgresql-16 postgresql-16-pgvector / brew install postgresql@16 pgvector).
# Point [database].url at any other DSN if you'd rather use a remote PG.
# 2. Local config โ already gitignored.
cp config.example.toml config.toml
$EDITOR config.toml # set [database].url, [admin].password
# 3. Build the web bundle into the embed tree.
cd app/web && pnpm install && pnpm build && cd ../..
# 4. Apply schema.
go run ./cmd/opendray migrate -config config.toml
# 5. Run.
go run ./cmd/opendray serve -config config.toml
# โ REST + WS: http://127.0.0.1:8770/api/v1/...
# โ Web admin: http://127.0.0.1:8770/admin/
```
This runs OpenDray in the foreground โ Ctrl-C kills it. For a long-running
daemon, see **Production deploy** below.
## Production deploy
Four supported deploy paths, pick whichever fits your environment.
Each one gives you auto-restart on crash, persistent state, and
separation of secrets from config.
### Option A โ systemd (bare-metal / VM / LXC)
The recommended Linux deploy path. Ships a hardened unit at
[`deploy/systemd/opendray.service`](deploy/systemd/opendray.service)
with sandboxing (`ProtectSystem=strict`, `NoNewPrivileges`,
`MemoryDenyWriteExecute`, capability scrub), `migrate`-then-`serve`
boot, and a 20s graceful-stop window.
**Get a binary first.** Either grab a pre-built archive from the
[Releases page](https://github.com/Opendray/opendray/releases)
(`opendray_*_linux_.tar.gz` โ unpacks to a single `opendray`
binary), or build from source via the [Quickstart](#quickstart-5-minute-dev-path)
above (`go build ./cmd/opendray`).
```bash
# 1. Install the binary you just grabbed (or built).
sudo install -m 0755 /path/to/opendray /usr/local/bin/opendray
# 2. Create the service user + state dir.
sudo useradd -r -s /usr/sbin/nologin -d /var/lib/opendray opendray
sudo install -d -o opendray -g opendray -m 0700 /var/lib/opendray
# 3. Drop config + secrets (root-owned; mode 0640).
sudo install -D -m 0640 config.example.toml /etc/opendray/config.toml
sudo $EDITOR /etc/opendray/config.toml # set [database].url etc.
sudo install -D -m 0640 -o root -g opendray /dev/null /etc/opendray/env.d/secrets
sudo $EDITOR /etc/opendray/env.d/secrets # OPENDRAY_ADMIN_PASSWORD=โฆ
# 4. Install + enable the unit.
sudo cp deploy/systemd/opendray.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now opendray
# 5. Verify.
sudo systemctl status opendray
sudo journalctl -u opendray -f --no-pager
```
The unit runs `opendray migrate` as `ExecStartPre`, so the first boot
applies all migrations before `serve` ever starts. Restarts are
`on-failure` with a 5s back-off and a 5-burst limit per minute.
### Option B โ Direct binary + your own process supervisor
For LXC without systemd, FreeBSD `rc.d`, OpenRC, or anything else.
Build once, run with whatever supervisor you already use:
```bash
# Cross-compile a release archive locally:
goreleaser release --clean --snapshot
ls dist/ # opendray_*_linux_amd64.tar.gz etc.
# Or grab a published release artefact:
# https://github.com/Opendray/opendray/releases
```
Then point your supervisor (s6, runit, supervisord, runwhen) at:
```
/usr/local/bin/opendray serve -config /etc/opendray/config.toml
```
Pre-flight: run `opendray migrate -config /etc/opendray/config.toml`
once before the first `serve`, or as a pre-start hook in your
supervisor of choice.
### Option C โ macOS launchd (Mac mini / Studio as home server)
For Apple Silicon Mac mini / Mac Studio running 24/7. Ships a
LaunchDaemon at
[`deploy/launchd/com.opendray.opendray.plist`](deploy/launchd/com.opendray.opendray.plist)
that starts at boot before any user login, restarts on crash with
a 5s throttle, and logs to `/usr/local/var/log/opendray/`.
```bash
# 1. Install the darwin binary + config + state dirs.
sudo install -m 0755 ./opendray /usr/local/bin/opendray
sudo install -d -m 0755 \
/usr/local/etc/opendray \
/usr/local/var/lib/opendray \
/usr/local/var/log/opendray
sudo install -m 0640 config.example.toml /usr/local/etc/opendray/config.toml
sudo $EDITOR /usr/local/etc/opendray/config.toml # set [database].url etc.
# 2. Apply migrations once.
sudo /usr/local/bin/opendray migrate \
-config /usr/local/etc/opendray/config.toml
# 3. Install + load the LaunchDaemon.
sudo cp deploy/launchd/com.opendray.opendray.plist /Library/LaunchDaemons/
sudo chown root:wheel /Library/LaunchDaemons/com.opendray.opendray.plist
sudo chmod 0644 /Library/LaunchDaemons/com.opendray.opendray.plist
sudo launchctl bootstrap system /Library/LaunchDaemons/com.opendray.opendray.plist
# 4. Verify.
sudo launchctl print system/com.opendray.opendray
tail -f /usr/local/var/log/opendray/opendray.log
```
Restart with `sudo launchctl kickstart -k system/com.opendray.opendray`;
unload entirely with `sudo launchctl bootout system/com.opendray.opendray`.
Postgres on macOS โ install via Homebrew (`brew install postgresql@17 && brew services start postgresql@17`) and point `[database].url` at
`postgres://$USER@127.0.0.1:5432/opendray`. Add `pgvector` with
`brew install pgvector` and `CREATE EXTENSION vector` inside the
opendray database.
---
For Proxmox-specific LXC notes (PTY in unprivileged containers,
networking, cgroup tweaks), see [`deploy/lxc/proxmox-pty-notes.md`](deploy/lxc/proxmox-pty-notes.md).
For reverse-proxy / TLS termination (nginx, Caddy, Traefik, Cloudflare
Tunnel), see [`docs/operator-guide.md`](docs/operator-guide.md) ยงTopology.
### Optional: enable encrypted DB backups + data exports
```bash
# Master passphrase (env-only โ never write into config.toml).
export OPENDRAY_BACKUP_KEY="$(openssl rand -base64 32)"
export OPENDRAY_BACKUP_ENABLED=1
# pg_dump / pg_restore must match the server's major version. On
# Apple Silicon dev machines pointing at a PG17 server:
export OPENDRAY_BACKUP_PG_DUMP_PATH=/opt/homebrew/opt/postgresql@17/bin/pg_dump
export OPENDRAY_BACKUP_PG_RESTORE_PATH=/opt/homebrew/opt/postgresql@17/bin/pg_restore
```
Restart opendray; the sidebar grows a Backups page (`/backups`)
for encrypted PostgreSQL dumps + restore, and `/export` for
zip-bundle data exports + import. See [`docs/operator-guide.md`](docs/operator-guide.md) ยงBackup for the full lifecycle.
A single Go binary carries the whole web bundle โ no Node runtime
required at runtime, no separate static-file server, no Caddy/nginx
needed. Cloudflare Tunnel terminates TLS in front of `:8770`.
## Layout
```
cmd/opendray/ binary entry point (โค100 LOC per design ยง14)
internal/
โโโ app/ composition root (wires every subsystem)
โโโ audit/ subscribes to bus topics, persists to audit_log
โโโ auth/ admin bearer tokens (M2.5)
โโโ backup/ encrypted DB dumps + admin export/importโโโ catalog/ CLI provider manifests + per-id user config (M2)
โโโ channel/ channel hub + telegram impl (M4)
โโโ config/ TOML loader with OPENDRAY_* env overrides
โโโ eventbus/ in-process pub/sub
โโโ gateway/ chi HTTP router + middleware + slog
โโโ integration/ external-app registry + reverse proxy + events WS (M3)
โโโ memory/ cross-CLI persistent memoryโโโ session/ PTY lifecycle + ring buffer + WS stream (M1)
โโโ store/ pgx pool + hand-rolled migration runner (M0)
โโโ version/ build-time identification
โโโ web/ go:embed of the web bundle (W5)
app/web/ React 19 + TypeScript + Vite SPA (Phase 2 W0-W5)
app/mobile/ Flutter app (iOS + Android), feature parity with web
docs/
โโโ design.md SSOT north-star
โโโ adr/ architecture decisions, dated
```
## Web frontend
`app/web/` builds a single SPA into `internal/web/dist/`, which the Go
binary embeds and serves at `/admin/*`. The Vite dev server at `:5173`
proxies `/api` to `:8770` for HMR-driven development.
```bash
# dev (hot reload on the React side, separate Go server for the API)
cd app/web && pnpm dev # http://localhost:5173
go run ./cmd/opendray serve -config ../../config.toml # other terminal
# prod (one binary delivers everything)
cd app/web && pnpm build # writes ../../internal/web/dist
cd ../..
go build ./cmd/opendray # bakes dist into the binary
./opendray serve -config config.toml
```
See [`app/web/README.md`](app/web/README.md) for the frontend stack
(React + Vite + Tailwind v4 + shadcn/ui + TanStack Router/Query +
Zustand + xterm.js) and per-W milestone notes.
## Documentation
- [`docs/getting-started.md`](docs/getting-started.md) โ **start here** if you're new: zero to first session in 15 minutes, including installing the wrapped CLIs and bootstrapping Postgres
- [`docs/quickstart.md`](docs/quickstart.md) โ 5-minute dev environment (assumes you already know the moving parts)
- [`docs/operator-guide.md`](docs/operator-guide.md) โ deploy + ops reference for production-ish setups
- [`docs/integration-guide.md`](docs/integration-guide.md) โ how to write an external integration in any language
- [`VERSIONING.md`](VERSIONING.md) โ versioning strategy (major-as-generation)
- [`CHANGELOG.md`](CHANGELOG.md) โ release history
## Tests
```bash
go test -race ./... # backend
cd app/web && pnpm build # web (TS strict + vite production build)
```
End-to-end smoke flows are tracked in commit messages per milestone.
A Playwright harness is a planned follow-up.
## Relationship to v1
v1 (`Opendray/opendray`) is the legacy codebase, now archived. v2 is
the current and active generation โ feature-complete and the only
branch receiving development. Of the 16 v1 builtins, four migrated
into the v2 backend; the rest became client-side features, channel
adapters, or integration-API consumers.
## License
Apache 2.0 โ see [`LICENSE`](LICENSE). (v1 was MIT; v2 is licensed
independently.)