{"id":"a2431994-5df9-4982-8e6d-e44c26f49631","slug":"dvorinka-relay","kind":"mcp","name":"relay","summary":"Relay - open-source agent communication & project hub. Your projects. Your agents. One place.","owner":"Dvorinka","repoUrl":"https://github.com/Dvorinka/relay","license":"Apache-2.0","licenseTier":"permissive","trust":"community","stars":3,"match":null,"fewStars":true,"format":"mcp","createdAt":"2026-10-01T17:28:59.000Z","addedAt":"2026-10-21T06:51:57.623Z","logoUrl":"https://avatars.githubusercontent.com/u/150935816?u=2e3939eea629954c31cc140731f6a4b33fc51085&v=4","linkOnly":false,"collection":null,"skillPath":null,"categories":["databases","developer-tools","communication"],"tags":["ai-agents","golang","issue-tracker","open-source","self-hosted","solidjs","chat","collaboration"],"runtime":"go","local":true,"cloudCapable":false,"cloudCapability":"unknown","cloudReadyOnPlatform":false,"needsApiKey":false,"reviewed":false,"syncedAt":"2026-10-26T01:38:18.212Z","sample":false,"url":"https://conduits.dev/tools/dvorinka-relay","language":"TypeScript","transports":["stdio"],"install":{},"requirements":{"env":[],"upstreamMayCharge":false},"tools":null,"readme":"<p align=\"center\">\n  <img src=\"assets/brand/relay-icon.svg\" alt=\"Relay\" width=\"120\">\n</p>\n\n<h1 align=\"center\">Relay</h1>\n\n<p align=\"center\">\n  Open-source agent communication & project hub.<br>\n  Your projects. Your agents. One place.\n</p>\n\n<p align=\"center\">\n  <a href=\"#quick-start\">Quick Start</a> ·\n  <a href=\"ARCHITECTURE.md\">Documentation</a> ·\n  <a href=\"https://github.com/Dvorinka/relay/releases\">Releases</a> ·\n  <a href=\"CONTRIBUTING.md\">Contributing</a>\n</p>\n\n<p align=\"center\">\n  <a href=\"https://github.com/Dvorinka/relay/actions/workflows/ci.yml\"><img src=\"https://github.com/Dvorinka/relay/actions/workflows/ci.yml/badge.svg\" alt=\"CI\"></a>\n  <a href=\"https://github.com/Dvorinka/relay/releases\"><img src=\"https://img.shields.io/github/v/release/Dvorinka/relay\" alt=\"Release\"></a>\n  <a href=\"LICENSE\"><img src=\"https://img.shields.io/github/license/Dvorinka/relay\" alt=\"License\"></a>\n</p>\n\n## What is Relay?\n\nRelay is a self-hosted workspace where humans and external AI agents share\nproject context: conversations, issues, screenshots, and GitHub activity in\none persistent place. Agents like Devin, Codex, or Claude Code connect\nthrough MCP when they need to - read the thread, pull the attachment, post\nthe answer - then disconnect. No agent runtime, no hosted tier, no lock-in.\n\nThe workflow it replaces - screenshot into Discord, copy-paste context into\nan agent, answer lost in another channel - collapses into one loop:\npaste into a project, agent reads it through MCP, agent replies in the same\nthread, thread becomes an issue, issue tracks GitHub state.\n\n> Agents don't live in Relay. They communicate through it.\n\n<p align=\"center\">\n  <img src=\"docs/shots/chat.png\" alt=\"Project conversation with replies, reactions, and agent replies\" width=\"720\">\n</p>\n\n<table>\n  <tr>\n    <td><img src=\"docs/shots/board.png\" alt=\"Kanban board\"></td>\n    <td><img src=\"docs/shots/reviews.png\" alt=\"Agent work reviews\"></td>\n  </tr>\n</table>\n\n## Features\n\n- **Workspaces** - multiple isolated workspaces (e.g. one per company) with fast switching and creation from the rail header. Projects and issues stay fully separate; messages still forward across workspaces.\n- **Projects** - Linear-style project organization: overview, issues, conversations, activity, members, settings.\n- **Conversations** - persistent per-project threads with Markdown, code blocks, replies, mentions, and read state. `@` mentions resolve to real entities — users, agents, `KEY-1` issues, `owner/repo#42` GitHub issues and PRs, `@file:` and `@gh:` files — and are stored as structured references so agents know exactly what you meant. Chat style is per-user: the default left-aligned layout or WhatsApp-style two-sided bubbles (Settings → Appearance).\n- **Channels** - Discord-style named channels nest under each project in the left rail: create, rename, and delete them inline. A per-channel **Block agents** toggle hides it from every MCP surface — listings, search, unread counts — while humans keep full access.\n- **Message threads** - any message can sprout a dedicated side conversation (hover → thread icon, optional title) so tangents don't drown the channel. One thread per message, no nesting; the parent shows a live reply-count chip and the thread opens in a side panel. Threads **auto-expire after 5 days** by default — the panel clock menu switches a thread to 24h or keeps it permanently (`ttl_hours` over HTTP and MCP). Works in local mode and via MCP (`create_thread`).\n- **Message actions** - hold **Shift** and hover a message for the full quick-action bar: reply, pin, copy link, forward, edit, delete. Pinned messages collect in a collapsible bar atop the conversation; permalinks (`?msg=`) deep-link and flash the target.\n- **Forwarding** - share any message into another project's chat as an attributed copy (`Forwarded from …`); attachments carry over, mention links stay behind, chains credit the original author. Works in local mode and via MCP (`forward_message`).\n- **Icons & avatars** - projects, workspaces, users, and agents all take real image icons: upload a file, paste an image URL (the server downloads, validates and stores it — public hosts only), or pull the linked repo's GitHub org avatar in one click. They show in the rail, headers, and message rows, and every icon is downloadable via the avatar file endpoint. Agents granted on a project appear in the project's member rail.\n- **Screenshot-first** - `Ctrl+V` a screenshot straight into the composer; drag & drop and file picker supported. Attachments stay attached to their message.\n- **Issues** - fast issue tracker with `MYB-142` keys, **custom per-project statuses** (own lanes, colors, closed flags), priorities, labels, assignees, comments, and an activity timeline. Kanban board is a full page, one click from chat — mirrored GitHub PRs show up as cards — with companion **Timeline** and **Calendar** views merging issues, PRs, commits, and reviews chronologically. **Named boards** and **saved filters** persist per project; the view choice persists too.\n- **Overview** - a cross-project page (`/app/overview`) aggregating every open GitHub issue and PR across the active workspace's projects into one feed, with a List/Calendar view toggle.\n- **Conversation ↔ issue loop** - turn any message into an issue; every issue links back to its thread.\n- **Project folder + file mentions** - link a local folder to a project (instead of or alongside GitHub) from project settings, then `@file:path` and `@gh:repo:path` mentions autocomplete in the composer and open a code preview inline. Agents can read linked files through MCP (`file:read` scope). Sensitive files (`.env`, keys, credentials) are never listed or served.\n- **Offline-first local mode** - no server required: first launch asks whether to connect a server or work locally, and the app runs against IndexedDB on-device storage — attachments included as real blobs, far beyond the old ~5 MB localStorage ceiling. Coming from a server, your last-synced workspace comes with you: cached projects, conversations, messages, issues and more hydrate the local store keeping their server ids, so **Sync to server** later pushes only the work you added on top — replies even land under the right remote parent.\n- **Server-outage tolerance** - a dead server doesn't take the app down with it: reads fall back to the last-synced response cache, sends and edits queue in a durable outbox (queued messages render inline with real attachment previews and a discard option; image/file uploads park as blobs and replay through the base64 JSON upload path), and the queue drains automatically the moment `/api/health` answers again. Placeholder attachment ids resolve to real ones mid-replay — a send fired during recovery just works. Only ephemeral writes — typing pings, read receipts — skip the queue.\n- **Any-server clients** - sign in to any reachable Relay server from the login screen; the API accepts bearer tokens cross-origin (CORS `*`), so the web build works hosted anywhere.\n- **Visual briefs** - agents can attach Excalidraw diagrams explaining their work, and you can draw right back: every brief opens in a real embedded Excalidraw editor (full shape/tool vocabulary, images, bindings) while agents read and revise the identical scene JSON through MCP (`create_brief` / `update_brief`). Each brief has its own comment thread so you can iterate on the picture. Per-project policy: never, on request, or expected pre-merge (Settings → Project settings → Visual briefs).\n- **Ideas** - a per-project whiteboard (context rail → Ideas, or `/app/p/<id>/ideas`): a native pan/zoom canvas with sticky notes, shapes, arrows, text, and **issue/PR mention cards** placed from a searchable picker. Changes autosave; agents read and draw the same `scene.relay_board` document over MCP (`create_idea` / `update_idea`). Legacy Excalidraw scenes still open in the embedded editor. When a sketch firms up, convert it into a backlog issue or spin it out as a new project — the idea is kept, marked converted.\n- **GitHub** - connect repositories three ways: a GitHub App (one-click register + install from workspace settings), a `GITHUB_TOKEN`, or the machine's own `gh` CLI login — Relay picks it up automatically when no app is registered. Issues, PRs, and commits mirror into the project with signature-verified webhooks. Open PRs can be merged, closed, reviewed, and commented on in-app (merge/squash/rebase — GitHub still enforces branch protection and required checks), and issues/PRs can be **created on GitHub straight from Relay** — they mirror onto the board instantly. Messages marked as reports file themselves: open a chat line with `bug:` / `enhancement:` (or `/bug`, `/enhancement`) on a repo-linked project and it becomes a GitHub issue — attachments embedded via presigned image links — mirrored back onto the Relay board with a link reply in the channel. Any message can also be filed explicitly via its ⋯ menu → **File on GitHub** (multi-repo projects get a repo picker); projects linking several repos never guess — the auto-file reply points at the manual action instead. A `/app/pulls` page aggregates every open PR across the workspace; Actions runs and `deployment_status`/`release` webhooks repaint CI state live.\n- **Agents** - first-class agent identities with avatars, per-project permissions, and scoped revocable `rly_` MCP tokens. \"Last seen\" is real MCP activity - never fabricated presence.\n- **Work reviews** - agents file a structured review card after finishing a task: plain-language summary, per-file stats and notes, autonomous decisions, required follow-up (env vars, migrations, CI, deploys), and verification steps. Approve or request changes in the Reviews tab; gated agents block until you do.\n- **MCP server** - streamable-HTTP endpoint exposing projects, conversations, messages, attachments, and issues as tools for external agents. Agents get the full GitHub write surface too — create issues/PRs, comment, review, merge, watch CI (`github_create_issue` … `github_rerun`). `get_attachment` returns a token-authenticated `download_url` agents can curl straight to disk, plus a real image content block for inline viewing — no brittle presigned URLs.\n- **Inbound hooks & support intake** - token-authenticated `POST /api/hooks/<token>` drops a message into any channel — CI alerts, deploy bots, and **live support intake** in two modes: *receive only* (reports land, replies stay in Relay) or *receive & send* (live chat — the same token pulls replies via `GET /api/hooks/<token>/messages?key=&after=` so your product's support widget stays in sync). Two switches on the channel header pick the mode; the setup guide walks through hook creation, the payload contract, ready snippets for cURL/JS/Python/Go, and a paste-ready prompt for an AI coding agent to wire the integration into your product. Point your product at the per-customer channel's hook URL and user reports land in Relay as they happen. Beyond `{message}`, the payload accepts `from` (external sender attribution), `subject`, `key` (a stable ticket key — the first post opens a dedicated sub-chat under the channel; same-key posts and staff replies live inside it — one ticket, one sub-chat, listed under the channel in the rail), `kind` (a free-form report type — *bug*, *feature*, whatever your product calls them — rendered as a colored chip and a `kind:<x>` tag for filtering), and up to 5 base64 `attachments` (logs, screenshots) through the normal storage pipeline. Each hook is customizable: a default `kind` and a `header_template` (`{from}`/`{subject}`/`{kind}`/`{key}` placeholders) shape how reports render — or point several hooks at different channels to split types entirely. Pair it with an outbound `message.created` webhook subscription for the reply path back to your app. Managed from project webhooks (rotate, disable, delete); tokens are sha256-stored and rate-limited.\n- **Realtime** - SSE event stream for live messages, project changes, issue changes, CI updates, ephemeral typing indicators, and notifications. Drafts — staged attachments included — survive reloads.\n- **Search** - `Ctrl/Cmd+K` across projects, issues, channels, threads, messages, and mirrored GitHub items, backed by Postgres FTS; PR results deep-link into the in-app PR view.\n- **Notifications** - unread counts, mentions, assignments, agent replies in one inbox. Optional **Web Push** (VAPID) delivers mentions and review requests to the browser even when the tab is closed - enable in Settings → Notifications. **Email alerts** — any channel can mail a list of addresses on every new message (support intake, on-call channels): configure SMTP in Settings → Email (in-app, workspace admins) or via `SMTP_*` env, then set the recipient list from the channel header's mail button. Port 465 uses implicit TLS, other ports STARTTLS; the stored password is AES-256-GCM-encrypted under `AUTH_SECRET`.\n- **Mobile outbox** - the Android app queues messages and images when offline and syncs them automatically on reconnect.\n- **Web first** - dark and light mode, keyboard-first, accessible. Desktop (Wails: Linux/macOS/Windows) and Android (Expo) clients consume the same API - see the [roadmap](ROADMAP.md).\n\n## Architecture\n\n```\nBrowser ──▶ relay (Go + Gin) ──▶ PostgreSQL (sqlc + goose)\n   web           │             ──▶ S3-compatible object storage (MinIO/S3/R2)\n   desktop       ├── SSE /api/events\n   mobile        └── MCP /mcp ◀── external AI agents (Devin, Codex, ...)\n```\n\nOne binary serves REST, SSE, and MCP. Modular domains under `internal/`,\ntyped queries via sqlc, versioned goose migrations, generated TypeScript\nclient shared by web and mobile. Details in [ARCHITECTURE.md](ARCHITECTURE.md).\n\n## Quick Start\n\nPrerequisites: Docker with the Compose plugin.\n\nOne-liner — no checkout needed. Prompts for install dir, public URL and port,\ngenerates secrets, writes `docker-compose.yml`, pulls the images and starts\nthe stack:\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/Dvorinka/relay/main/install.sh | bash\n```\n\nNon-interactive (CI/automation) — set env vars and every prompt is skipped:\n\n```bash\nRELAY_DIR=~/relay RELAY_PUBLIC_URL=https://relay.example.com \\\nRELAY_PORT=8080 RELAY_YES=1 bash <(curl -fsSL https://raw.githubusercontent.com/Dvorinka/relay/main/install.sh)\n```\n\n`RELAY_IMAGE` overrides the image (defaults to `ghcr.io/dvorinka/relay:latest`).\n\nOr the source route:\n\n```bash\ngit clone https://github.com/Dvorinka/relay.git && cd relay\ncp .env.example .env        # set AUTH_SECRET, storage keys\ndocker compose up -d        # relay + postgres + storage (RustFS)\n```\n\nThen open `http://localhost:8080` - the first registered account becomes\nthe workspace owner.\n\nPrebuilt artifacts: `ghcr.io/dvorinka/relay` publishes on every main push\n(`:latest`, `:sha-<short>`) and on release tags. `v*` tags cut a GitHub\nrelease whose filenames carry the version: `relay-<ver>-linux-amd64`\n(server), `relay-cli-<ver>-{linux-amd64,darwin-arm64,windows-amd64.exe}`\n(plus unversioned `relay-cli-*` aliases so `releases/latest/download/…`\nstays scriptable), `relay-desktop-<ver>-linux-amd64`, the per-user\n`Relay-Setup-<ver>.exe` Windows installer (Start Menu/Desktop shortcuts,\nWebView2 bootstrap, `relay://` deep-link registration, relay-cli component\non by default, no admin needed), and a signed `relay-android-<ver>.apk`\n(see [apps/mobile](apps/mobile) for signing setup).\n\nThe desktop app self-updates: **Check for updates** in the rail offers\n\"install now\" — silent NSIS setup on Windows (relaunches itself), in-place\nbinary swap on Linux. `relay://open/<path>` links registered by the\ninstallers deep-link into the desktop app.\n\nFor local development (Go 1.24+, Node 20+, `just`):\n\n```bash\njust dev       # deps + backend + SolidJS frontend with hot reload\njust check     # vet + golangci-lint + tsc\njust test      # all tests\n```\n\n## Configuration\n\nAll configuration lives in `.env` - see [.env.example](.env.example) for the\nannotated list: `DATABASE_URL`, `AUTH_SECRET`, `STORAGE_*` (MinIO, S3, R2),\n`GITHUB_APP_*`, `RESEND_API_KEY` or `SMTP_*` (transactional mail), and\n`RELAY_PUBLIC_URL`.\n\nRunning a **limited free tier** for others? `RELAY_LIMITED=true` turns the\ninstance into a sync/auth/relay host only: file storage is off on every\npath — UI uploads, avatars, inbound-hook payloads, and MCP `upload_attachment`\nall get `403 uploads_disabled`, hook reports still post with dropped files\ncounted in the response, and `/api/health` reports `limits.uploads: false`\nso clients show the \"self-host for the full thing\" notice. Local-to-server\nsync skips file blobs automatically — messages, issues, and boards still\nland.\n\n## MCP integration\n\nAgents register themselves. In workspace settings click **Invite agent**,\nhand the printed bundle to the agent, and it redeems a one-shot `rli_`\ninvite for a live `rly_` token — picking its own name and review mode:\n\n```text\nPOST {RELAY_PUBLIC_URL}/api/agent-invites/redeem   # one-shot, no auth\nPOST {RELAY_PUBLIC_URL}/mcp                        # streamable HTTP transport\nAuthorization: Bearer rly_...\n```\n\nInvites carry the project grants and scopes you chose at creation; they\nexpire (default 72h) and can be revoked from the same section.\n\n### relay-cli\n\n`relay-cli` talks to any Relay server over MCP — agents use it, humans can\ntoo. Grab the binary from the latest release, or `go install` it:\n\n```bash\n# linux (macOS: relay-cli-darwin-arm64, windows: relay-cli-windows-amd64.exe)\ncurl -fsSL -o ~/.local/bin/relay-cli \\\n  https://github.com/Dvorinka/relay/releases/latest/download/relay-cli-linux-amd64\nchmod +x ~/.local/bin/relay-cli\n\n# or from source (module path is the repo)\ngo install github.com/Dvorinka/relay/cmd/relay-cli@latest\n```\n\nPoint it at a server and redeem an invite — the token lands on stdout ready\nto export:\n\n```bash\nexport RELAY_URL=https://relay.example.com\nexport RELAY_TOKEN=$(relay-cli redeem rli_... --name my-agent)\nrelay-cli projects   # you're in\n```\n\nFrom there: `relay-cli --help` lists everything — `say`, `messages`,\n`issues`, `pin`/`pins`/`forward`, `thread`, `reviews`, `todo-*`,\n`completion bash|zsh|fish` for shell completions.\n\n**[internal/agentdoc/guide.md](internal/agentdoc/guide.md)** is the\ncomplete agent manual — onboarding, both transports, the full\ntool↔command map, mentions, workflows, and error handling. The server\nembeds it: agents reach it via the `get_guide` MCP tool,\n`relay-cli guide`, or `GET /api/agent-guide` — the invite prompt already\ntells them to read it.\n\nTools: `get_guide`, `whoami`, `activity`, `list_projects`, `get_project`,\n`list_conversations`, `get_messages`, `get_message`, `get_attachment`,\n`search_messages`, `list_issues`, `get_issue`, `list_unread`, `inbox`,\n`await_message`, `ops_summary`, `send_message` (+ the `reply` alias),\n`edit_message`, `delete_message`, `create_thread`, `forward_message`,\n`pin_message`, `list_pins`, `react_to_message`, `set_avatar`,\n`create_issue`, `update_issue`, `mark_message_read`, `list_mentionables`,\n`request_input`, `resolve_input`, `work_start`, `work_stop`,\n`todo_list`, `todo_add`, `todo_update`, `todo_delete`, `todo_sync`,\n`list_project_files`, `read_project_file`, `upload_attachment`,\n`github_list_issues`, `github_get_issue`, `github_list_prs`,\n`github_get_pr`, `github_ci_runs`, `github_create_issue`,\n`github_create_pr`, `github_comment`, `github_review_pr`,\n`github_pr_state`, `github_merge_pr`, `github_rerun`,\n`submit_review`, `list_reviews`, `get_review`,\n`await_review`, `get_brief_policy`, `list_briefs`, `get_brief`,\n`create_brief`, `update_brief`, `delete_brief`, `list_ideas`, `get_idea`,\n`create_idea`, `update_idea`, `delete_idea`, `idea_to_issue`.\n\n### Agent work reviews\n\nWhen an agent finishes work it files a review in the project's **Reviews**\ntab — the same card every time: what changed, per-file notes, decisions it\nmade autonomously, what you need to do (new env vars, migrations, deploy\nsteps, CI changes), and how to verify. You approve it or send it back with\na note; the agent sees your verdict over MCP.\n\nPending reviews surface everywhere you'd look: the **Inbox** lists them\nacross all your workspaces, issue pages show linked reviews inline, and the\nrail badge counts what's still awaiting you. Project views are deep links\n(`?view=reviews`, legacy `?tab=` links still resolve), so inbox items land\nexactly where the verdict lives.\n\nEach agent picks a **review mode** at redemption (admins can change it later\nin Settings):\n\n- `notify` (default) - the agent works to completion, then files the review\n  for your records. Change your mind later and request a follow-up.\n- `gate` - `submit_review` returns `must_wait`, and the agent blocks on\n  `await_review` until you approve or request changes. Use for anything\n  that deploys, merges, or otherwise shouldn't land unreviewed.\n\nThe review-card pattern is adapted from\n[devdotfast/whiteboard](https://github.com/devdotfast/whiteboard) (MIT) -\nstructured summaries, decision logs, and required-actions instead of a raw\ndiff. Relay's implementation is native: Postgres rows, REST + MCP surfaces,\nSSE updates, and avatars on both sides of the card.\n\n## Ecosystem\n\n- **[apps/web](apps/web)** - SolidJS + Vite + Tailwind + Ark UI frontend.\n- **[packages/api-client](packages/api-client)** - OpenAPI-generated TS client shared by all clients.\n- **[apps/desktop](apps/desktop)** - Wails shell for Linux/macOS/Windows proxying your Relay server. Optional close-to-tray keeps it connected for alerts while hidden (Windows notification area; Linux StatusNotifierItem on desktops that expose one).\n- **[apps/mobile](apps/mobile)** - React Native + Expo app for Android: login, conversations, issues, work list, attachments (phase 10; push/iOS deferred - see its README).\n- **MCP server** - built into the `relay` binary at `/mcp`.\n\n## Documentation\n\n- [ARCHITECTURE.md](ARCHITECTURE.md) - system design, data model, decisions\n- [ROADMAP.md](ROADMAP.md) - phases from foundation to v1.0\n- [docs/superpowers/specs/](docs/superpowers/specs/) - full design spec\n- [api/openapi.yaml](api/openapi.yaml) - API contract (source of truth)\n- [assets/brand/](assets/brand/) - logo kit and brand guide\n\n## Contributing\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md) for the development workflow. Relay\nis community-driven - self-hosting stays a first-class use case.\n\n## Security\n\nSee [SECURITY.md](SECURITY.md) for reporting vulnerabilities and the\nself-hosting hardening checklist.\n\n## License\n\n[Apache-2.0](LICENSE)\n"}