{"id":49182310,"url":"https://github.com/opendray/opendray","last_synced_at":"2026-05-22T15:09:22.463Z","repository":{"id":353043556,"uuid":"1213370365","full_name":"Opendray/opendray","owner":"Opendray","description":"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.","archived":false,"fork":false,"pushed_at":"2026-04-22T08:38:36.000Z","size":2663,"stargazers_count":0,"open_issues_count":2,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-04-22T09:15:49.690Z","etag":null,"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"],"latest_commit_sha":null,"homepage":"","language":"Go","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/Opendray.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":"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":["opendray"]}},"created_at":"2026-04-17T10:00:39.000Z","updated_at":"2026-04-22T08:37:36.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/Opendray/opendray","commit_stats":null,"previous_names":["opendray/opendray"],"tags_count":7,"template":false,"template_full_name":null,"purl":"pkg:github/Opendray/opendray","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Opendray%2Fopendray","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Opendray%2Fopendray/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Opendray%2Fopendray/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Opendray%2Fopendray/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Opendray","download_url":"https://codeload.github.com/Opendray/opendray/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Opendray%2Fopendray/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32162611,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-22T17:06:48.269Z","status":"online","status_checked_at":"2026-04-23T02:00:06.710Z","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-coding","claude-code","cli","codex","developer-tools","flutter","gemini","golang","homelab","llm","mcp","multi-agent","open-source","plugin-architecture","self-hosted","telegram-bot","terminal"],"created_at":"2026-04-23T02:01:42.403Z","updated_at":"2026-05-22T15:09:22.456Z","avatar_url":"https://github.com/Opendray.png","language":"Go","funding_links":["https://github.com/sponsors/opendray"],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/assets/logo.png\" alt=\"opendray\" width=\"180\"\u003e\n\u003c/p\u003e\n\n\u003ch1 align=\"center\"\u003eopendray\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cstrong\u003eSelf-hosted multi-CLI control gateway for AI coding agents.\u003c/strong\u003e\n  \u003cbr/\u003e\n  \u003csub\u003eRemote-control Claude Code · Codex · Gemini · shell from web, mobile, or your favourite messaging app.\u003c/sub\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://github.com/Opendray/opendray/releases/latest\"\u003e\u003cimg alt=\"Latest release\" src=\"https://img.shields.io/github/v/release/Opendray/opendray?label=release\u0026color=4f46e5\"\u003e\u003c/a\u003e\n  \u003ca href=\"LICENSE\"\u003e\u003cimg alt=\"License Apache 2.0\" src=\"https://img.shields.io/github/license/Opendray/opendray?color=blue\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/Opendray/opendray/actions/workflows/ci.yml\"\u003e\u003cimg alt=\"CI\" src=\"https://img.shields.io/github/actions/workflow/status/Opendray/opendray/ci.yml?branch=main\u0026label=CI\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/Opendray/opendray/discussions\"\u003e\u003cimg alt=\"Discussions\" src=\"https://img.shields.io/github/discussions/Opendray/opendray?color=ec4899\"\u003e\u003c/a\u003e\n  \u003cbr/\u003e\n  \u003cimg alt=\"Go\" src=\"https://img.shields.io/badge/Go-1.25%2B-00ADD8?logo=go\u0026logoColor=white\"\u003e\n  \u003cimg alt=\"React\" src=\"https://img.shields.io/badge/React-19-61DAFB?logo=react\u0026logoColor=black\"\u003e\n  \u003cimg alt=\"Flutter\" src=\"https://img.shields.io/badge/Flutter-mobile-02569B?logo=flutter\u0026logoColor=white\"\u003e\n  \u003cimg alt=\"Postgres\" src=\"https://img.shields.io/badge/PostgreSQL-15%2F16%2F17-336791?logo=postgresql\u0026logoColor=white\"\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  🌐 \u003cstrong\u003eEnglish\u003c/strong\u003e · \u003ca href=\"README.zh.md\"\u003e简体中文\u003c/a\u003e\n\u003c/p\u003e\n\n---\n\n## What is opendray?\n\n**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.\n\n- 🛰 **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.\n- 💬 **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.\n- 🧠 **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.\n- 🔌 **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.\n- 🔒 **Self-hosted, license-clear** — Apache 2.0, one static binary, cosign-signed releases with SPDX SBOM. No telemetry, no cloud account, no subscription.\n\n## Status\n\n**v2.0.5** (latest) — the v2 generation is feature-complete and shipping\npatch releases as operators report polish items. See\n[`VERSIONING.md`](VERSIONING.md) for the major-as-generation policy\n(major = product generation, not strict SemVer \"breaking change\") and\n[`CHANGELOG.md`](CHANGELOG.md) for the full release history.\n\nThis generation ships:\n\n- **One-line installer + uninstaller wizards** (Linux + macOS;\n  Windows funnels through WSL2). Walks the operator through Postgres\n  bootstrap, AI-CLI install, admin credentials, listen address,\n  binary install, schema migration, and service registration.\n- **Self-managing binary** — `opendray update / start / stop /\n  restart / status / providers list / providers update` so operators\n  don't touch `systemctl` / `launchctl` for routine ops.\n- **Goreleaser release pipeline** — cross-compiled binaries\n  (linux/darwin × amd64/arm64), cosign keyless signing (Sigstore),\n  SPDX SBOM, atomically verified self-update.\n\n## Install\n\n### One-line installer\n\n**Linux / macOS / WSL2**\n\n```sh\ncurl -fsSL https://raw.githubusercontent.com/Opendray/opendray/main/scripts/install.sh | bash\n```\n\n**Windows** — sets up WSL2 first, then runs the Linux installer inside it. [details →](scripts/README.md#windows)\n\n```powershell\nirm https://raw.githubusercontent.com/Opendray/opendray/main/scripts/install-windows.ps1 | iex\n```\n\nWalks 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.\n\n\u003e **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.\n\n### Uninstall (Linux / macOS)\n\n**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:\n\n```sh\ncurl -fsSL https://raw.githubusercontent.com/Opendray/opendray/main/scripts/uninstall.sh | bash\n```\n\n**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:\n\n```sh\ncurl -fsSL https://raw.githubusercontent.com/Opendray/opendray/main/scripts/uninstall.sh | OPENDRAY_PURGE=1 bash\n```\n\n### Day-to-day commands\n\nAfter install, the `opendray` binary handles its own lifecycle — no need to remember `systemctl` / `launchctl` incantations:\n\n```sh\nsudo opendray update --restart   # download latest release, verify SHA, atomic replace + restart\n```\n\n```sh\nsudo opendray providers update   # bump installed AI CLIs (claude / codex / gemini) to npm-latest\n```\n\n```sh\nopendray providers list          # see which AI CLIs are installed + their versions\n```\n\n```sh\nsudo opendray start              # start | stop | restart | status — wraps systemd / launchd\n```\n\n`opendray --help` lists the full subcommand set.\n\n### Deploy path picker\n\nEvery 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.\n\n| Path | Best for | Jump to |\n|---|---|---|\n| 📦 **Pre-built binary** | \"Just run it\" — Linux / macOS, any supervisor | [Releases page](https://github.com/Opendray/opendray/releases) → see [Production deploy](#production-deploy) |\n| 🐧 **systemd unit** | Bare-metal / VM / LXC Linux box | [Production deploy §A](#option-a--systemd-bare-metal--vm--lxc) |\n| 🍎 **macOS LaunchDaemon** | Mac mini / Mac Studio as home server | [Production deploy §B](#option-b--macos-launchd-mac-mini--studio-as-home-server) |\n| 🛠 **Build from source** | Dev / contributing / custom builds | [Quickstart](#quickstart-5-minute-dev-path) below |\n\n## Quickstart (5-minute dev path)\n\nFor a full walkthrough with prereqs and troubleshooting, see [`docs/quickstart.md`](docs/quickstart.md). The condensed dev path:\n\n```bash\n# 1. Have a Postgres 15+ running on 127.0.0.1:5432 with pgvector enabled\n#    (apt install postgresql-16 postgresql-16-pgvector / brew install postgresql@16 pgvector).\n#    Point [database].url at any other DSN if you'd rather use a remote PG.\n\n# 2. Local config — already gitignored.\ncp config.example.toml config.toml\n$EDITOR config.toml          # set [database].url, [admin].password\n\n# 3. Build the web bundle into the embed tree.\ncd app/web \u0026\u0026 pnpm install \u0026\u0026 pnpm build \u0026\u0026 cd ../..\n\n# 4. Apply schema.\ngo run ./cmd/opendray migrate -config config.toml\n\n# 5. Run.\ngo run ./cmd/opendray serve -config config.toml\n# → REST + WS:  http://127.0.0.1:8770/api/v1/...\n# → Web admin:  http://127.0.0.1:8770/admin/\n```\n\nThis runs OpenDray in the foreground — Ctrl-C kills it. For a long-running\ndaemon, see **Production deploy** below.\n\n## Production deploy\n\nFour supported deploy paths, pick whichever fits your environment.\nEach one gives you auto-restart on crash, persistent state, and\nseparation of secrets from config.\n\n### Option A — systemd (bare-metal / VM / LXC)\n\nThe recommended Linux deploy path. Ships a hardened unit at\n[`deploy/systemd/opendray.service`](deploy/systemd/opendray.service)\nwith sandboxing (`ProtectSystem=strict`, `NoNewPrivileges`,\n`MemoryDenyWriteExecute`, capability scrub), `migrate`-then-`serve`\nboot, and a 20s graceful-stop window.\n\n**Get a binary first.** Either grab a pre-built archive from the\n[Releases page](https://github.com/Opendray/opendray/releases)\n(`opendray_*_linux_\u003carch\u003e.tar.gz` — unpacks to a single `opendray`\nbinary), or build from source via the [Quickstart](#quickstart-5-minute-dev-path)\nabove (`go build ./cmd/opendray`).\n\n```bash\n# 1. Install the binary you just grabbed (or built).\nsudo install -m 0755 /path/to/opendray /usr/local/bin/opendray\n\n# 2. Create the service user + state dir.\nsudo useradd -r -s /usr/sbin/nologin -d /var/lib/opendray opendray\nsudo install -d -o opendray -g opendray -m 0700 /var/lib/opendray\n\n# 3. Drop config + secrets (root-owned; mode 0640).\nsudo install -D -m 0640 config.example.toml /etc/opendray/config.toml\nsudo $EDITOR /etc/opendray/config.toml             # set [database].url etc.\nsudo install -D -m 0640 -o root -g opendray /dev/null /etc/opendray/env.d/secrets\nsudo $EDITOR /etc/opendray/env.d/secrets           # OPENDRAY_ADMIN_PASSWORD=…\n\n# 4. Install + enable the unit.\nsudo cp deploy/systemd/opendray.service /etc/systemd/system/\nsudo systemctl daemon-reload\nsudo systemctl enable --now opendray\n\n# 5. Verify.\nsudo systemctl status opendray\nsudo journalctl -u opendray -f --no-pager\n```\n\nThe unit runs `opendray migrate` as `ExecStartPre`, so the first boot\napplies all migrations before `serve` ever starts. Restarts are\n`on-failure` with a 5s back-off and a 5-burst limit per minute.\n\n### Option B — Direct binary + your own process supervisor\n\nFor LXC without systemd, FreeBSD `rc.d`, OpenRC, or anything else.\nBuild once, run with whatever supervisor you already use:\n\n```bash\n# Cross-compile a release archive locally:\ngoreleaser release --clean --snapshot\nls dist/                  # opendray_*_linux_amd64.tar.gz etc.\n\n# Or grab a published release artefact:\n# https://github.com/Opendray/opendray/releases\n```\n\nThen point your supervisor (s6, runit, supervisord, runwhen) at:\n\n```\n/usr/local/bin/opendray serve -config /etc/opendray/config.toml\n```\n\nPre-flight: run `opendray migrate -config /etc/opendray/config.toml`\nonce before the first `serve`, or as a pre-start hook in your\nsupervisor of choice.\n\n### Option C — macOS launchd (Mac mini / Studio as home server)\n\nFor Apple Silicon Mac mini / Mac Studio running 24/7. Ships a\nLaunchDaemon at\n[`deploy/launchd/com.opendray.opendray.plist`](deploy/launchd/com.opendray.opendray.plist)\nthat starts at boot before any user login, restarts on crash with\na 5s throttle, and logs to `/usr/local/var/log/opendray/`.\n\n```bash\n# 1. Install the darwin binary + config + state dirs.\nsudo install -m 0755 ./opendray /usr/local/bin/opendray\nsudo install -d -m 0755 \\\n  /usr/local/etc/opendray \\\n  /usr/local/var/lib/opendray \\\n  /usr/local/var/log/opendray\nsudo install -m 0640 config.example.toml /usr/local/etc/opendray/config.toml\nsudo $EDITOR /usr/local/etc/opendray/config.toml    # set [database].url etc.\n\n# 2. Apply migrations once.\nsudo /usr/local/bin/opendray migrate \\\n  -config /usr/local/etc/opendray/config.toml\n\n# 3. Install + load the LaunchDaemon.\nsudo cp deploy/launchd/com.opendray.opendray.plist /Library/LaunchDaemons/\nsudo chown root:wheel /Library/LaunchDaemons/com.opendray.opendray.plist\nsudo chmod 0644 /Library/LaunchDaemons/com.opendray.opendray.plist\nsudo launchctl bootstrap system /Library/LaunchDaemons/com.opendray.opendray.plist\n\n# 4. Verify.\nsudo launchctl print system/com.opendray.opendray\ntail -f /usr/local/var/log/opendray/opendray.log\n```\n\nRestart with `sudo launchctl kickstart -k system/com.opendray.opendray`;\nunload entirely with `sudo launchctl bootout system/com.opendray.opendray`.\n\nPostgres on macOS — install via Homebrew (`brew install postgresql@17 \u0026\u0026 brew services start postgresql@17`) and point `[database].url` at\n`postgres://$USER@127.0.0.1:5432/opendray`. Add `pgvector` with\n`brew install pgvector` and `CREATE EXTENSION vector` inside the\nopendray database.\n\n---\n\nFor Proxmox-specific LXC notes (PTY in unprivileged containers,\nnetworking, cgroup tweaks), see [`deploy/lxc/proxmox-pty-notes.md`](deploy/lxc/proxmox-pty-notes.md).\n\nFor reverse-proxy / TLS termination (nginx, Caddy, Traefik, Cloudflare\nTunnel), see [`docs/operator-guide.md`](docs/operator-guide.md) §Topology.\n\n### Optional: enable encrypted DB backups + data exports\n\n```bash\n# Master passphrase (env-only — never write into config.toml).\nexport OPENDRAY_BACKUP_KEY=\"$(openssl rand -base64 32)\"\nexport OPENDRAY_BACKUP_ENABLED=1\n\n# pg_dump / pg_restore must match the server's major version. On\n# Apple Silicon dev machines pointing at a PG17 server:\nexport OPENDRAY_BACKUP_PG_DUMP_PATH=/opt/homebrew/opt/postgresql@17/bin/pg_dump\nexport OPENDRAY_BACKUP_PG_RESTORE_PATH=/opt/homebrew/opt/postgresql@17/bin/pg_restore\n```\n\nRestart opendray; the sidebar grows a Backups page (`/backups`)\nfor encrypted PostgreSQL dumps + restore, and `/export` for\nzip-bundle data exports + import. See [`docs/operator-guide.md`](docs/operator-guide.md) §Backup for the full lifecycle.\n\nA single Go binary carries the whole web bundle — no Node runtime\nrequired at runtime, no separate static-file server, no Caddy/nginx\nneeded. Cloudflare Tunnel terminates TLS in front of `:8770`.\n\n## Layout\n\n```\ncmd/opendray/        binary entry point (≤100 LOC per design §14)\ninternal/\n├── app/             composition root (wires every subsystem)\n├── audit/           subscribes to bus topics, persists to audit_log\n├── auth/            admin bearer tokens (M2.5)\n├── backup/          encrypted DB dumps + admin export/import├── catalog/         CLI provider manifests + per-id user config (M2)\n├── channel/         channel hub + telegram impl (M4)\n├── config/          TOML loader with OPENDRAY_* env overrides\n├── eventbus/        in-process pub/sub\n├── gateway/         chi HTTP router + middleware + slog\n├── integration/     external-app registry + reverse proxy + events WS (M3)\n├── memory/          cross-CLI persistent memory├── session/         PTY lifecycle + ring buffer + WS stream (M1)\n├── store/           pgx pool + hand-rolled migration runner (M0)\n├── version/         build-time identification\n└── web/             go:embed of the web bundle (W5)\n\napp/web/             React 19 + TypeScript + Vite SPA (Phase 2 W0-W5)\napp/mobile/          Flutter app (iOS + Android), feature parity with web\ndocs/\n├── design.md        SSOT north-star\n└── adr/             architecture decisions, dated\n```\n\n## Web frontend\n\n`app/web/` builds a single SPA into `internal/web/dist/`, which the Go\nbinary embeds and serves at `/admin/*`. The Vite dev server at `:5173`\nproxies `/api` to `:8770` for HMR-driven development.\n\n```bash\n# dev (hot reload on the React side, separate Go server for the API)\ncd app/web \u0026\u0026 pnpm dev               # http://localhost:5173\ngo run ./cmd/opendray serve -config ../../config.toml   # other terminal\n\n# prod (one binary delivers everything)\ncd app/web \u0026\u0026 pnpm build              # writes ../../internal/web/dist\ncd ../..\ngo build ./cmd/opendray               # bakes dist into the binary\n./opendray serve -config config.toml\n```\n\nSee [`app/web/README.md`](app/web/README.md) for the frontend stack\n(React + Vite + Tailwind v4 + shadcn/ui + TanStack Router/Query +\nZustand + xterm.js) and per-W milestone notes.\n\n## Documentation\n\n- [`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\n- [`docs/quickstart.md`](docs/quickstart.md) — 5-minute dev environment (assumes you already know the moving parts)\n- [`docs/operator-guide.md`](docs/operator-guide.md) — deploy + ops reference for production-ish setups\n- [`docs/integration-guide.md`](docs/integration-guide.md) — how to write an external integration in any language\n- [`VERSIONING.md`](VERSIONING.md) — versioning strategy (major-as-generation)\n- [`CHANGELOG.md`](CHANGELOG.md) — release history\n\n## Tests\n\n```bash\ngo test -race ./...        # backend\ncd app/web \u0026\u0026 pnpm build   # web (TS strict + vite production build)\n```\n\nEnd-to-end smoke flows are tracked in commit messages per milestone.\nA Playwright harness is a planned follow-up.\n\n## Relationship to v1\n\nv1 (`Opendray/opendray`) is the legacy codebase, now archived. v2 is\nthe current and active generation — feature-complete and the only\nbranch receiving development. Of the 16 v1 builtins, four migrated\ninto the v2 backend; the rest became client-side features, channel\nadapters, or integration-API consumers.\n\n## License\n\nApache 2.0 — see [`LICENSE`](LICENSE). (v1 was MIT; v2 is licensed\nindependently.)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fopendray%2Fopendray","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fopendray%2Fopendray","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fopendray%2Fopendray/lists"}