# Opendray V1

> [Archived] Superseded by Opendray/opendray_v2 — see https://github.com/Opendray/opendray_v2

- **Type:** MCP server
- **Install:** `agentstack add mcp-opendray-opendray-v1`
- **Verified:** Pending review
- **Seller:** [Opendray](https://agentstack.voostack.com/s/opendray)
- **Installs:** 0
- **Category:** [Developer Tools](https://agentstack.voostack.com/c/developer-tools)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [Opendray](https://github.com/Opendray)
- **Source:** https://github.com/Opendray/opendray-v1

## Install

```sh
agentstack add mcp-opendray-opendray-v1
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

OpenDray

Pilot AI coding agents from your phone. Self-hosted. Multi-agent. Plugin-driven.

Quick Start &middot;
Features &middot;
Architecture &middot;
Plugins &middot;
Discussions

English &middot;
简体中文

---

Start a Claude Code, Codex, or Gemini session on your server from the train. Close the app. Come back an hour later. The session kept running. Review the diff. Approve it from Telegram.

No other tool does this.

## Features

**Mobile-first remote control** &mdash; Launch any AI coding agent from your phone, tablet, or browser. The PTY session runs on your server. Close the app, come back later &mdash; it is still there.

**Multi-agent, side-by-side** &mdash; Run Claude Code, Codex, Gemini CLI, OpenCode, and Qwen in parallel sessions. Each gets its own terminal with independent lifecycle, idle detection, and output buffering.

**Plugin architecture** &mdash; Every agent and panel is a `manifest.json`. Add support for any new AI CLI by dropping one into `plugins/`. No code changes. No rebuilds. Restart and it appears in the launcher.

**Telegram bridge** &mdash; Full bidirectional session control over Telegram. List sessions, tail output, link a chat for two-way relay, answer structured prompts via inline keyboards, send control keys &mdash; all without opening the app.

**LLM provider routing** &mdash; Register Ollama, Groq, Gemini free tier, LM Studio, or any OpenAI-compatible endpoint. Route per-session: same OpenCode binary, different model, different cost.

**MCP injection** &mdash; Register MCP servers once. OpenDray generates per-session config files and injects them via CLI args and env vars. No global config files touched.

**Claude multi-account** &mdash; Register multiple Claude OAuth tokens. Pick which account per session. Hot-swap accounts on a running session without losing context (session resumes under the new account).

**Self-hosted, single binary** &mdash; Go backend with the Flutter web build embedded via `go:embed`. One binary + PostgreSQL. No SaaS dependency. Your code stays on your hardware.

## Quick Start

Pick your path. **Docker** is the shortest route — one image with every
agent CLI bundled. **Native binary** is the right pick when you want
OpenDray on bare metal without Docker in the stack.

### Docker (recommended — all agent CLIs bundled)

```bash
git clone https://github.com/Opendray/opendray.git
cd opendray
cp .env.docker.example .env && $EDITOR .env   # set DB_PASSWORD at minimum
./scripts/opendray-docker up                  # starts opendray + postgres
./scripts/opendray-docker login claude        # one-time OAuth per agent
# open http://localhost:8640
```

The `*-full` image ships Claude Code, Codex, Gemini CLI, and OpenCode
on PATH, so every builtin plugin works with zero host setup. Published
as a multi-arch manifest (`linux/amd64` + `linux/arm64`) — same tag on
x86 servers, Apple Silicon, Raspberry Pi 4+, and AWS Graviton.

Already have Docker running? Skip the clone and pull directly:

```bash
docker pull ghcr.io/Opendray/opendray:latest-full
```

The `opendray-docker` wrapper exposes `up / down / logs / doctor / login
/ update / backup` verbs over the compose stack. Full reference:
[docs/DOCKER.md](docs/DOCKER.md).

### Native binary (macOS / Linux)

OpenDray also ships as a single self-contained binary. Install, run the
terminal wizard, start the server. **Setup is terminal-only** — there
is no web-based first-run wizard, so the install flow works identically
over SSH, in a VPS, or on your laptop.

```bash
curl -fsSL https://raw.githubusercontent.com/Opendray/opendray/main/install.sh | sh
```

The installer:
1. detects your OS (`darwin` / `linux`) and architecture (`amd64` / `arm64`)
2. downloads the matching binary from [Releases](https://github.com/Opendray/opendray/releases)
3. verifies its SHA256 against the signed `SHA256SUMS` file
4. installs it to `~/.local/bin/opendray`
5. hands control to `opendray setup` — an interactive wizard in the same terminal

Override with env vars: `OPENDRAY_VERSION=v0.5.0`, `OPENDRAY_INSTALL_DIR=/usr/local/bin`, `OPENDRAY_NO_SETUP=1` (skip auto-wizard).

> **Windows:** not yet supported. The core feature (spawning agent CLIs
> in a pseudo-terminal) requires UNIX PTY via `creack/pty`; the Windows
> ConPTY equivalent is on the roadmap.

### What the wizard asks

```
1 / 4   DATABASE        bundled PostgreSQL (managed by OpenDray)
                        or external (bring your own PG 14+)
2 / 4   LISTEN ADDRESS  loopback (127.0.0.1:8640, local only)
                        or all interfaces (0.0.0.0:8640, LAN-exposed)
                        or custom host:port
3 / 4   ADMIN ACCOUNT   username + password (min 8 chars)
4 / 4   JWT SECRET      auto-generate or paste your own
```

Config persists to `~/.opendray/config.toml`. Re-running `opendray setup`
resumes with existing values as defaults, so you can rotate any single field
without re-entering the rest.

### Scripted install (CI / cloud-init)

```bash
opendray setup --yes \
    --db=bundled \
    --listen=loopback \
    --admin-user=admin \
    --admin-password-file=/run/secrets/admin_pw
```

All prompts have matching flags: `--db-host`, `--db-port`, `--db-user`,
`--db-name`, `--db-password-file`, `--db-sslmode`, `--jwt-secret-file`.
See `opendray setup --help`.

### Manual download

Grab a binary from the [Releases page](https://github.com/Opendray/opendray/releases):
- `opendray-darwin-arm64` — Apple Silicon Mac
- `opendray-darwin-amd64` — Intel Mac
- `opendray-linux-amd64` / `opendray-linux-arm64`

```bash
chmod +x opendray-darwin-arm64
./opendray-darwin-arm64 setup
./opendray-darwin-arm64
```

### Build from source

Prerequisites: Go 1.25+ and Flutter (stable channel). No `make`
required — the two direct commands are all you need.

```bash
git clone https://github.com/Opendray/opendray.git
cd opendray

# 1. Build the Flutter web bundle (gets embedded into the Go binary)
cd app && flutter pub get && flutter build web --release && cd ..

# 2. Build the Go binary
go build -o bin/opendray ./cmd/opendray

./bin/opendray setup
./bin/opendray
```

If you already have GNU `make` installed, `make build` is a one-liner
shortcut for the two commands above.

Dev mode (hot-reload)

```bash
cp .env.example .env     # point at your own PostgreSQL
make dev                 # Go backend + Flutter web client
```

With `.env` set the wizard is skipped — env vars win over the config file,
which preserves existing LXC/Docker deployments.

Bring your own PostgreSQL

```sql
CREATE DATABASE opendray;
CREATE USER opendray WITH PASSWORD 'changeme';
GRANT ALL PRIVILEGES ON DATABASE opendray TO opendray;
```

Pick `external` in the wizard, or set `DB_HOST` / `DB_USER` / `DB_PASSWORD` /
`DB_NAME` env vars — either path triggers automatic migration (schema is
created in your database on first connection).

Bundled PostgreSQL and root

The `bundled` database mode refuses to run as `root` — upstream PostgreSQL's
`initdb` hard-fails on `uid == 0`. Create an unprivileged user first:

```bash
useradd -r -m -s /bin/bash -d /home/opendray opendray
su - opendray
opendray setup
```

Or pick `external` and connect to an existing PG instance.

Production binary

```bash
make release-linux                    # cross-compile linux/amd64 with embedded web
./bin/opendray-linux-amd64            # single binary, migrations run on startup
```

`JWT_SECRET` is required when binding to a non-loopback address. The wizard auto-generates one; for env-var deploys, set it yourself.

## Run as a background service

The default `opendray` invocation runs in the foreground — great for
testing, not so great for "always-on server tied to a specific user
session". Install the service wrapper so it:

- starts on boot
- restarts on crash
- logs to a sensible place (journald on Linux, `/var/log/opendray/` on macOS)
- runs as your non-root setup user (bundled PG won't start as uid 0)

```bash
sudo opendray service install
```

Auto-detects the target user from `$SUDO_USER` (the account you ran
`sudo` from). Override with `--user` if that's wrong:

```bash
sudo opendray service install --user opendray
```

Other lifecycle commands:

```bash
opendray service status      # current state
opendray service logs        # tail (journalctl -fu on Linux, tail -f on mac)
sudo opendray service start  # / stop / restart
sudo opendray service uninstall
opendray service help        # full reference
```

### What it writes

| Platform | File | What it does |
|---|---|---|
| Linux | `/etc/systemd/system/opendray.service` | systemd unit, `Restart=on-failure`, journald output, `ProtectSystem=full` |
| macOS | `/Library/LaunchDaemons/com.opendray.opendray.plist` | launchd daemon, `KeepAlive=SuccessfulExit:false`, logs to `/var/log/opendray/` |

Both run the binary as the `--user` account (never root) and inherit
`HOME=$user` so the existing config under `~/.opendray/` is loaded as-is.

### Preview without writing

```bash
opendray service install --user linivek --dry-run
```

prints the unit / plist that would be written. No system changes. Good
for reviewing before committing.

## Uninstall

Mirrors the install flow. Two paths depending on whether your `opendray`
binary can still run.

### Built-in command (preferred)

```bash
opendray uninstall               # interactive: show plan, confirm, remove
opendray uninstall --yes         # no prompt
opendray uninstall --dry-run     # preview only
opendray uninstall --keep-data   # binary + config gone, ~/.opendray/ stays
```

Output:
1. stops any running OpenDray server + bundled PostgreSQL
2. removes `~/.opendray/` (PG cluster, plugins, cache, marketplace)
3. removes `~/.config/opendray/config.toml` if present
4. removes the binary itself (self-delete)

### One-line nuclear option (binary can't run)

When the binary is corrupt or the config is so broken the wizard won't
start, use the shell script instead. It knows nothing about config; it
just `rm -rf`s the well-known paths.

```bash
curl -fsSL https://raw.githubusercontent.com/Opendray/opendray/main/uninstall.sh | sh
```

Environment overrides:
- `OPENDRAY_YES=1` — skip confirmation
- `OPENDRAY_DRY_RUN=1` — preview only
- `OPENDRAY_INSTALL_DIR` — non-default binary location

### External PostgreSQL

OpenDray **never drops tables from an external database you provided** —
table names (`sessions`, `plugins`, `admin_auth`, …) are generic enough
to collide with other applications sharing the DB, and automated drops
are unrecoverable.

Instead, `opendray uninstall` writes a `drop_opendray_schema.sql` file
to your current directory with wrapped `DROP TABLE IF EXISTS … CASCADE`
statements. Review it, then apply manually:

```bash
psql -h  -U  -d  -f drop_opendray_schema.sql
```

The nuclear scripts skip this helper; if you went nuclear, you're
expected to know which tables to drop.

### Manual removal (last resort)

If both paths above fail, these are the locations to nuke by hand:

| Platform | Path |
|---|---|
| macOS / Linux | `~/.local/bin/opendray` |
| macOS / Linux | `~/.opendray/` |
| macOS / Linux | `~/.config/opendray/` (XDG fallback) |

## Architecture

```mermaid
graph TB
    subgraph Client["Flutter App (iOS / Android / Web)"]
        Sessions
        Browser["Browser (Files, DB, Logs, Git, MCP, ...)"]
        Settings
    end

    subgraph Backend["Go Backend — single binary"]
        Gateway["gateway/ — HTTP + WebSocket routing"]
        Hub["kernel/hub — multi-session PTY manager"]
        Store["kernel/store — PostgreSQL + migrations"]
        Plugins["plugin/ — manifest scanner + runtime"]
        MCP["gateway/mcp — MCP config injector"]
        TG["gateway/telegram — Telegram bridge"]
        LLM["gateway/llm_proxy — provider router"]
    end

    subgraph Agents["Agent Processes (spawned per session)"]
        Claude["Claude Code"]
        Codex["Codex CLI"]
        Gemini["Gemini CLI"]
        OC["OpenCode"]
        Qwen["Qwen Code"]
    end

    subgraph Providers["LLM Providers"]
        Ollama
        Groq
        GeminiFree["Gemini Free"]
        OpenRouter
        LMStudio["LM Studio"]
    end

    Client -- "REST + WebSocket" --> Gateway
    Telegram -- "Bot API" --> TG
    Gateway --> Hub
    Hub --> Agents
    MCP -. "inject per-session config" .-> Agents
    OC -- "/v1/chat/completions" --> Providers
    Hub --> Store
    Gateway --> Plugins
```

### Source Layout

```
cmd/opendray/       Entry point — setup, service, uninstall, plugin, version subcommands
kernel/
  terminal/         PTY engine: spawn, 4 MB ring buffer, idle detection
  hub/              Multi-session lifecycle: create, attach, resume, stop (max 20)
  store/            PostgreSQL: connection pool, 18 migrations, queries
  auth/             JWT issuing and middleware (HS256, 7-day TTL)
  pg/               Bundled PostgreSQL launcher (embedded PG 15.4 child process)
  config/           config.toml parser + env overlay
gateway/            HTTP + WebSocket handlers
  telegram/         Telegram bot: commands, links, notifications, inline keyboards
  mcp/              MCP server registry, per-session config renderer + cleanup
  llm_proxy/        Anthropic-to-OpenAI request/response translation
  files/            Sandboxed file browser (allowed-roots, symlink resolution)
  pg/               Read-only PostgreSQL browser (DDL/DML blocked, row/time caps)
  forge/            Git-forge clients (Gitea, GitHub, GitLab) for Obsidian reader
  git/              Per-repo status, per-session baseline diffs, branch listing
  logs/             Tail-follow with rotation detection, regex grep, extension filter
  tasks/            Makefile / npm / shell discovery, concurrent runner with timeouts
  docs/             Markdown reader (used by the Obsidian plugin)
plugin/             Manifest scanner, runtime, hook bus, marketplace, consents
plugins/
  builtin/          Built-in plugins (agents + panels, embedded in binary)
app/                Flutter client (iOS, Android, Web) — 19 feature modules
```

## Plugins

Every agent and panel is a plugin. OpenDray ships with 17.

### Agents

| Agent | Icon | Models | Key Capabilities |
|---|---|---|---|
| **Claude Code** | 🟣 | Sonnet, Opus, Haiku | Session resume (`--resume`), MCP injection, image input, multi-account OAuth, bypass-permissions mode |
| **Codex CLI** | 🤖 | o4-mini, o3, GPT-4.1, GPT-4.1-mini | Approval modes (suggest / auto-edit / full-auto), MCP injection |
| **Gemini CLI** | ✨ | Gemini 2.5 Pro, Gemini 2.5 Flash | Sandbox mode, yolo mode, multimodal input |
| **OpenCode** | 🤖 | Dynamic (via LLM Endpoints) | Provider-agnostic routing to any OpenAI-compatible endpoint, session resume, MCP injection |
| **Qwen Code** | 🐉 | Qwen3-Coder Plus/Flash/480B | DashScope, ModelScope, OpenRouter, dynamic model detection, MCP injection |
| **Terminal** | ⬛ | &mdash; | System login shell (zsh/bash/sh), no AI |

### Panels

| Panel | Category | What it does |
|---|---|---|
| **File Browser** | files | Sandboxed directory listing + file viewing with syntax highlighting, binary detection, size caps |
| **PostgreSQL Browser** | database | Read-only schema introspection (databases, schemas, tables, columns) + filtered SELECT execution, query history, 8 SSL modes |
| **Log Viewer** | logs | Tail-follow with backlog, rotation detection, regex grep, extension filtering |
| **Task Runner** | tools | Discover Makefile targets, package.json scripts, shell scripts; concurrent execution with timeouts and live output |
| **Git Viewer** | tools | Per-repo status, per-session baseline (shows only changes made during the session), unified diff, commit log, branch listing |
| **Git Forge** | tools | Gitea / GitHub / GitLab integration — browse repos, clone, inspect PRs/issues |
| **Telegram Bridge** | messaging | Bot token setup, link status, test messages, command reference |
| **MCP Servers** | mcp | CRUD for stdio / SSE / HTTP MCP servers, per-agent filtering, enable/disable toggle |
| **Obsidian Reader** | docs | Browse Obsidian vaults from G

…

## Source & license

This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [Opendray](https://github.com/Opendray)
- **Source:** [Opendray/opendray-v1](https://github.com/Opendray/opendray-v1)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** yes
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** yes
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: flagged — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/mcp-opendray-opendray-v1
- Seller: https://agentstack.voostack.com/s/opendray
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
