agora-relay
v0.2.1
Published
Local relay for Agora — bridges your machine's CLIs (claude, openclaw, codex, cursor) to the Agora dashboard via Supabase Realtime.
Maintainers
Readme
agora-relay
Local relay for Agora — bridges your machine's CLIs (claude, openclaw, codex, cursor) to the Agora dashboard via Supabase Realtime.
What it does
Agora is a hosted SaaS dashboard, but the agent runtimes (Claude Code, OpenClaw, etc.) live on your laptop. The dashboard can't reach those CLIs directly from a Vercel function — it talks to this relay daemon running on your machine, and the relay invokes the CLIs as subprocesses using the sessions you've already authenticated locally.
agora.app (Vercel)
│
▼ (Supabase Realtime broadcast)
│
agora-relay (your machine)
│
▼ child_process.spawn
│
claude / openclaw / codex / cursorQuick start (paired install)
The fastest path — works for everyone, including users who signed into Agora with GitHub OAuth (no Supabase password):
# 1. Install the daemon (Node 20+ required).
curl -fsSL https://agent-tool-beryl.vercel.app/install.sh | bash
# 2. In the Agora web app, open the onboarding wizard and copy the
# 6-digit code it displays (valid for 120 seconds).
# 3. Redeem the code on this machine.
agora-relay pair-code 123456
# 4. Start the daemon.
agora-relay runThe code-based flow is the only one that works for OAuth users.
Password-based agora-relay pair is still supported as a fallback for
self-hosted setups (see Pair (password) below).
Install
The relay is published on npm — no clone or build needed:
# One-liner installer (curl-pipeable).
curl -fsSL https://agent-tool-beryl.vercel.app/install.sh | bash
# Or, manually:
npm install -g agora-relayYou can also run it without installing:
npx agora-relay pair-code 123456
npx agora-relay runRequires Node ≥ 20.
Building from source (contributors)
git clone https://github.com/RaphaelLi0611/agent-tool
cd agent-tool/cli
npm install && npm run build
npm link # makes `agora-relay` available on your PATHPair (code)
The recommended pairing flow — works regardless of how you signed into Agora (email/password, GitHub, future OAuth providers).
agora-relay pair-code 123456
# ✓ Paired successfully.How it works:
- Sign into Agora and open the onboarding wizard. It displays a 6-digit code with a 120-second TTL.
- Run
agora-relay pair-code <CODE>on the machine you want to pair. - The daemon POSTs the code to the Agora server, gets back a fresh
Supabase session, and writes it to
~/.agora/config.json(chmod 600).
Override the server (for self-hosted Agora or local dev):
agora-relay pair-code 123456 --server https://my-agora.example.comPair (password)
Fallback flow for self-hosted setups where you control the Supabase project and have a password-based account. Most hosted-Agora users should use Pair (code) above instead.
agora-relay pair
# Email: [email protected]
# Password: ******
# ✓ Paired successfully.This signs into the Agora Supabase project, persists the session to ~/.agora/config.json (chmod 600), and binds this machine to your account.
Run
agora-relay runSubscribes to relay:<your-userId> on Supabase Realtime and waits for ops. Press Ctrl-C to stop.
You'll see a "Relay: online" badge in the AccountMenu of agora.app once the daemon is connected.
Status
agora-relay statusWhat ops are supported (v0.2.0)
| Op | Status | Description |
|---------------|--------|--------------------------------------------------------------------------------------------|
| ping | yes | Liveness check, replies with pong |
| version | yes | Returns relay version + Node version + platform |
| exec | yes | Spawns a whitelisted CLI binary, streams stdout/stderr/exit |
| fs.read | yes | Reads a UTF-8 file under the allowlist. Result: { content: string }. 10 MB cap. |
| fs.list | yes | Lists a directory. Result: { entries: [{ name, kind, size?, mtimeMs? }] }. Sorted asc. |
| fs.write | yes* | Writes a UTF-8 file. Result: { ok: true }. Opt-in — disabled by default (see env). |
| fs.watch | yes | Streams file-changed events keyed on the watch's jobId. Debounced 200ms. |
| fs.unwatch | yes | Stops the watcher with the matching jobId. Silent no-op if none matches. |
exec whitelist (binaries you can invoke):
claude— Anthropic's Claude Code CLIopenclaw— OpenClaw runtimecodex— OpenAI'scodexCLIcursor— Cursor's local agent CLI
Allowed-roots policy (fs.* ops)
Every fs.* path is normalised, expanded (leading ~ → os.homedir()), then
checked against an allowlist. Anything outside the allowlist is rejected with a
friendly error.
Default read roots:
~/.claude/~/.claude.json~/.openclaw/- the cwd the relay was launched in (so per-project
CLAUDE.md/AGENTS.mdreads work)
Default write roots: none. Write is disabled until you opt in.
Environment variables
| Var | Effect |
|--------------------------------------|--------------------------------------------------------------------------|
| AGORA_RELAY_ALLOWED_ROOTS | Colon-separated extra roots appended to the read allowlist. |
| AGORA_RELAY_ALLOW_WRITE | Set to 1 to enable fs.write. Off → every write is rejected. |
| AGORA_RELAY_ALLOWED_WRITE_ROOTS | Colon-separated allowed write roots (only checked when ALLOW_WRITE=1). |
Example — allow writing under ~/.openclaw/scratch:
AGORA_RELAY_ALLOW_WRITE=1 \
AGORA_RELAY_ALLOWED_WRITE_ROOTS="$HOME/.openclaw/scratch" \
agora-relay runKnown limitations (v0.2.0)
Token refresh isn't fully automatic. The relay restores its session on startup, but if the access_token expires while the daemon is running for >1 hour, Realtime channels can stop delivering. Workaround: restart the relay (
Ctrl-Cthenagora-relay run). Fixed in v0.2.macOS only tested. Linux should work; Windows untested. Subprocess
spawnis platform-aware but $PATH resolution might differ.No reconnect-aware queue. If the WebSocket drops and a job is in flight, the response events may be lost. Web side timeouts the request after 10s — user can retry. Robust queueing is post-MVP.
What it deliberately does NOT do
- It does NOT collect your API keys for Anthropic / OpenAI / etc. Auth happens locally inside
claude/codex(using the sessions you've already logged in to). Agora never sees your provider credentials. - It does NOT execute arbitrary commands — only the binaries in the whitelist above.
- It does NOT phone home to anyone other than your own Supabase project.
