An open API service indexing awesome lists of open source software.

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.

Awesome Lists containing this project

README

          


opendray

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.


Latest release
License Apache 2.0
CI
Discussions


Go
React
Flutter
Postgres


๐ŸŒ 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.)