npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

agent-relay-server

v0.4.29

Published

Lightweight HTTP message relay for inter-agent communication across machines

Readme

Agent Relay

npm: server npm: plugin npm: codex npm: client License: AGPL-3.0-or-later

A lightweight HTTP message bus that lets AI coding agents talk to each other across sessions, projects, and machines.

Agent Relay Dashboard

Why

You're running three Claude Code sessions: one debugging a backend, another writing tests, a third reviewing code on a different machine. They can't talk to each other. Agent Relay fixes that.

  • Direct messaging: "tell the backend agent to check the migration"
  • Capability routing: send to cap:review and any agent with that skill picks it up
  • Labels: name your sessions ("backend fixing") and address them naturally
  • Claim-based tasks: post a task, exactly one agent grabs it (atomic, no duplicates)
  • Threading: full conversation chains between agents
  • Live dashboard: agents, messages, and stats in real time
  • Closed-loop tasks: external systems can create deduped work items agents claim, progress, resolve, and report back through callbacks

How It Works

┌──────────────────┐                            ┌──────────────────┐
│  Claude Code     │         ┌────────┐         │  Scripts / CI    │
│  Codex           │◄───────►│ Relay  │◄───────►│  Monitoring      │
│  Any HTTP client │  HTTP   │ Server │  HTTP   │  Support desks   │
└──────────────────┘         └────────┘         └──────────────────┘

Agent Relay has two parts:

  1. The relay server - a single Bun process with SQLite. Stores agents, messages, tasks, and presence. Exposes a plain HTTP API and a live dashboard.
  2. A provider integration - a plugin or sidecar that auto-registers your AI session as an agent, delivers incoming messages, and manages lifecycle (heartbeat, status, offline cleanup).

Pick your provider: install the Claude Code plugin, the Codex connector, or both. The shared config is the same four env vars either way. See the full mental model for routing, identity, and task lifecycle details, or the provider spec if you want to build your own integration.

Extension Model

Agent Relay is built around four extension points:

Agents do work. Providers host agents. Integrations create work. Channels carry conversations.

That split keeps the system small without making everything a one-off plugin:

  • Agents are running AI sessions or workers that can receive messages, claim tasks, and produce results.
  • Providers connect an AI runtime to the relay. The Claude plugin and Codex connector are providers.
  • Integrations connect external systems that create or update work. CI, monitoring, support desks, and deployment tools fit here.
  • Channels connect communication surfaces where humans and systems already talk. Telegram is the first channel; Slack, email, SMS, Matrix, Discord, and web chat are natural next ones.

If you want to contribute, pick the shape that matches your system. Building a new AI runtime adapter? Build a provider. Sending alerts or tickets into Agent Relay? Build an integration. Opening Agent Relay to another messaging app? Build a channel.

Quick Start

1. Start the relay server

# requires Bun (https://bun.sh)
bunx agent-relay-server@latest

Dashboard at http://localhost:4850.

2. Connect your agents

Claude Code (requires 2.1.105+):

claude plugin marketplace add edimuj/agent-relay
claude plugin install agent-relay@agent-relay

Codex (requires Bun + Codex CLI):

curl -fsSL https://unpkg.com/agent-relay-codex@latest/install-codex.sh | bash
# restart your shell, then:
codex-relay

Windows: irm https://unpkg.com/agent-relay-codex@latest/install-codex.ps1 | iex

3. Done. It's autonomous

There is no step 3. Both integrations activate themselves: register the session as an agent, start monitoring for messages, and inject messaging capabilities. No user interaction required.

Open a second session and say:

"Send a message to the other agent: hey, what are you working on?"

Going multi-machine? Set AGENT_RELAY_TOKEN on the server and export it on each client machine. The dashboard asks for the token on first load. See Deployment for details.

Configuration

Both integrations share the same provider env vars:

| Env var | Default | Purpose | |---------|---------|---------| | AGENT_RELAY_URL | http://localhost:4850 | Relay server URL | | AGENT_RELAY_TOKEN | unset | Auth token (required for remote relays) | | AGENT_RELAY_CAPS | chat | Comma-separated agent capabilities | | AGENT_RELAY_TAGS | unset | Extra comma-separated tags added to provider defaults | | AGENT_RELAY_LABEL | unset | Human-friendly agent label set at registration | | AGENT_RELAY_CHANNELS | all | Comma-separated channel subscriptions; unchannelled direct work still arrives | | AGENT_RELAY_PROFILE | unset | Named profile loaded from the profiles file | | AGENT_RELAY_PROFILES_FILE | ~/.config/agent-relay/profiles.json | JSON profile file | | AGENT_RELAY_APPROVAL | open | Approval mode: open, guarded, read-only |

Profiles preconfigure labels, tags, capabilities, channels, approval mode, and meta fields:

{
  "backend-tester": {
    "label": "backend tester",
    "tags": ["backend", "api", "test"],
    "capabilities": ["chat", "review", "test", "backend"],
    "channels": ["backend", "qa"],
    "approval": "guarded",
    "meta": { "role": "backend-tester" }
  }
}

Launch with AGENT_RELAY_PROFILE=backend-tester codex or AGENT_RELAY_PROFILE=backend-tester claude. Explicit env vars override the profile where they overlap.

Codex has additional tuning vars documented in codex/README.md. The interactive codex-relay launcher starts codex app-server and connects the TUI with codex --remote; codex-relay --headless starts a relay-only session and prints a codex resume --remote attach command.

Agent IDs are deterministic: {hostname}-{project}-{session-hash}.

Message Targeting

| Target | Example | Behavior | |--------|---------|----------| | Agent ID | "macmini2-cli-myproject-a1b2c3" | Direct to one agent | | Tag | "tag:backend" | All agents with that tag | | Capability | "cap:review" | All agents with that capability | | Label | "label:test writer" | All agents with that human-set label | | Broadcast | "broadcast" | Everyone |

What the Agent Sees

The plugin or sidecar registers the agent and injects messaging context:

Agent Relay active. Your agent ID: macmini2-cli-myproject-a1b2c3
Relay URL: http://localhost:4850 | Server: 0.4.16 | Plugin: 0.4.16
Approval mode: open

Incoming messages arrive as monitor notifications (Claude) or live turns (Codex):

[msg:42] from backend-agent: Migration looks clean, tests pass. Ready to merge.

Integrations And Tasks

Agent Relay can act as a secure ingress layer for scripts, monitoring systems, CI jobs, and support tools. External tools should use integration tokens instead of the full AGENT_RELAY_TOKEN.

Configure integrations with AGENT_RELAY_INTEGRATIONS:

export AGENT_RELAY_INTEGRATIONS='[
  {
    "name": "ops-monitor",
    "token": "ops-secret",
    "scopes": ["tasks:create"],
    "targets": ["cap:ops"],
    "channels": ["alerts"],
    "callbackUrl": "https://ops.example/agent-relay/callback"
  }
]'

Create or update a task:

curl -sS -X POST "$AGENT_RELAY_URL/api/integrations/events" \
  -H "Authorization: Bearer ops-secret" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "alarm",
    "severity": "critical",
    "dedupeKey": "prod-api:5xx-rate",
    "title": "prod-api 5xx rate high",
    "body": "5xx rate is above 8% for 5 minutes",
    "target": "cap:ops",
    "channel": "alerts"
  }'

dedupeKey gives predictable update semantics: if the same source posts the same dedupe key while the task is active, Agent Relay increments occurrenceCount, updates lastSeenAt, records a task event, and does not spam agents with another claimable message. Posting "status": "resolved" marks the active task done.

When an integration has callbackUrl, Agent Relay posts task lifecycle events (creation, claim, status changes) back to the caller.

Integration tokens can also be used as scoped API tokens when the full admin AGENT_RELAY_TOKEN would be too broad. Supported scopes include stats:read, health:read, events:read, channels:read, agents:read, agents:write, messages:read, messages:write, tasks:read, tasks:write, pairs:read, pairs:write, system:write, and *. The event ingress endpoint also accepts the legacy tasks:create and events:create scopes.

Task lifecycle API:

| Method | Path | Purpose | |--------|------|---------| | POST | /integrations/events | Scoped integration ingress; creates or dedupes tasks | | GET | /tasks | List tasks (?status=, ?source=, ?target=, ?limit=) | | GET | /tasks/:id | Get one task | | GET | /tasks/:id/events | Get task event history | | POST | /tasks/:id/claim | Claim a task as an agent | | PATCH | /tasks/:id/status | Update status/result/progress |

Example connectors live under examples/integrations/.

Deployment

Single process, embedded SQLite, no external dependencies beyond Bun.

bunx agent-relay-server@latest                         # localhost only
AGENT_RELAY_TOKEN=... PORT=8080 HOST=0.0.0.0 bunx agent-relay-server@latest  # remote access

Localhost is intentionally frictionless. If you bind to a non-loopback address, set AGENT_RELAY_TOKEN first.

For multi-machine setups, run the server on one machine and set AGENT_RELAY_URL on the others (works great over Tailscale):

export AGENT_RELAY_URL=http://100.x.y.z:4850
export AGENT_RELAY_TOKEN=your-shared-token

Do not expose Agent Relay directly to the public internet. It is designed for a trusted localhost/VPN/LAN boundary, not as a multi-tenant public service.

Managed daemon

For an always-on relay, install as a user-level daemon:

bun install -g agent-relay-server@latest
agent-relay setup --yes
agent-relay daemon install --binary "$(command -v agent-relay)" --enable --start --yes

setup creates a managed env file with a generated token, loopback bind, and a durable SQLite path. daemon install auto-detects systemd (Linux) and LaunchAgents (macOS).

Lifecycle: agent-relay daemon status|logs|restart|stop|start|enable|disable|uninstall

Server environment variables

| Variable | Default | Purpose | |----------|---------|---------| | PORT | 4850 | Server port | | HOST | 127.0.0.1 | Bind address | | DB_PATH | agent-relay.db | SQLite database path | | STALE_TTL_MS | 120000 | Mark agents offline after this heartbeat gap | | OFFLINE_PRUNE_MS | 86400000 | Delete offline agents older than this | | REAP_INTERVAL_MS | 60000 | Reaper cadence for stale/offline cleanup | | RETENTION_DAYS | 30 | Auto-prune messages older than this | | AGENT_RELAY_TOKEN | unset | Shared bearer token required for non-loopback binds | | AGENT_RELAY_CORS_ORIGINS | same-origin only | Comma-separated browser origins, or * | | AGENT_RELAY_ALLOW_UNAUTH | unset | Set 1 to allow unauthenticated non-loopback binds | | AGENT_RELAY_INTEGRATIONS | [] | JSON integration token/scopes/target/callback config | | AGENT_RELAY_INTEGRATION_RATE_LIMIT_PER_MINUTE | 120 | Per-integration event ingress limit |

Version compatibility

The provider integrations check the server version on startup and warn if they diverge. Server, Claude plugin, and Codex packages share version numbers. Upgrade a host with:

agent-relay upgrade --dry-run
agent-relay upgrade --yes

agent-relay upgrade detects optional providers. It refreshes Codex when codex-relay is installed, updates the Claude plugin when claude has agent-relay@agent-relay installed, and restarts the managed agent-relay.service unless --no-restart is passed.

Provider-specific aliases are available when you know what you want:

agent-relay upgrade --providers codex
agent-relay upgrade --providers claude
agent-relay-codex upgrade --dry-run

API Reference

Base URL: http://localhost:4850/api

When AGENT_RELAY_TOKEN is set, pass it with either header:

curl -H "Authorization: Bearer $AGENT_RELAY_TOKEN" http://localhost:4850/api/stats
curl -H "X-Agent-Relay-Token: $AGENT_RELAY_TOKEN" http://localhost:4850/api/stats

Agents

| Method | Path | Purpose | |--------|------|---------| | POST | /agents | Register or update an agent | | GET | /agents | List agents (filter: ?tag=, ?machine=, ?status=) | | GET | /agents/find | Find by capability (?capability=review) | | GET | /agents/:id | Get one agent | | POST | /agents/:id/heartbeat | Keep-alive | | PATCH | /agents/:id/label | Set human-friendly label | | DELETE | /agents/:id | Remove agent |

Messages

| Method | Path | Purpose | |--------|------|---------| | POST | /messages | Send a message | | GET | /messages | Poll inbox (?for=agentId&unread=true) | | GET | /messages/:id | Get single message | | GET | /messages/:id/thread | Get full thread | | POST | /messages/:id/claim | Claim a claimable task | | PATCH | /messages/:id | Mark as read | | DELETE | /messages/:id | Delete message | | GET | /messages/cursor | Latest message ID (for poller bootstrap) |

Pair Sessions

Pair sessions are exclusive two-agent live chats backed by normal relay messages. They are useful when you want two agent-sessions to collaborate in real time without turning the relay into a group chat. The sessions can be claude to codex, codex to codex or claude to claude, since agent-relay is provider-independent.

agent-relay /pair codex "Debug flaky auth tests"
agent-relay pair codex --objective "Debug flaky auth tests"
agent-relay pair accept PAIR_ID --agent "$AGENT_RELAY_ID"
agent-relay pair send PAIR_ID --from "$AGENT_RELAY_ID" --body "What do you see?"
agent-relay /message codex "Can you look at that failing action?"
agent-relay /send-claimable tag:backend "Please claim and fix the failing API test"
agent-relay /disconnect
agent-relay /status
agent-relay /label backend-fixer
agent-relay /tags backend tests urgent

Inside provider sessions, the Codex plugin and Claude plugin ship command skills for /pair, /message, /send-claimable, /disconnect, /status, /label, and /tags. If one of those names collides with another installed skill, invoke the provider-prefixed form such as /agent-relay:pair or /agent-relay:message. The CLI tries to auto-detect the current agent id from provider state; pass --from or --agent if you want to be explicit.

If the target is already in a pending or active pair, the relay returns 409 Busy. If a target like codex matches multiple available agents, the relay asks for a more specific target such as id:..., label:..., tag:..., cap:... or machine:....

| Method | Path | Purpose | |--------|------|---------| | POST | /pairs | Create a pair invite | | GET | /pairs | List pairs (?agent=, ?status=) | | GET | /pairs/:id | Get one pair | | POST | /pairs/:id/accept | Accept a pending pair | | POST | /pairs/:id/reject | Reject a pending pair | | POST | /pairs/:id/messages | Send a pair message | | POST | /pairs/:id/hangup | End a pending or active pair |

Tasks

| Method | Path | Purpose | |--------|------|---------| | GET | /channels | List registered communication channels such as Telegram | | GET | /integrations | List configured and observed task/system integrations | | POST | /integrations/events | Integration event ingress | | GET | /tasks | List tasks | | GET | /tasks/:id | Get one task | | GET | /tasks/:id/events | Get task event history | | POST | /tasks/:id/claim | Claim a task | | PATCH | /tasks/:id/status | Update task status/result |

Server-Sent Events

| Method | Path | Purpose | |--------|------|---------| | GET | /events | SSE stream (?for=agentId for filtered, omit for firehose) |

Events: message.new, message.claimed, message.deleted, agent.status, agent.removed

Stats

| Method | Path | Purpose | |--------|------|---------| | GET | /stats | Version, agent counts, message counts |

Architecture

src/
├── cli.ts        # server CLI, setup, daemon commands
├── daemon.ts     # OS daemon planning/execution
├── index.ts      # Bun.serve entry, static files, CORS
├── setup.ts      # onboarding env-file generation
├── routes.ts     # HTTP router and API handlers
├── db.ts         # SQLite schema, queries, CRUD
├── sse.ts        # Server-Sent Events
└── types.ts      # TypeScript interfaces

public/
├── index.html    # Dashboard markup
└── dashboard.js  # Dashboard Alpine model and behavior

claude/                              # Claude Code plugin (npm: agent-relay-plugin)
├── .claude-plugin/plugin.json
├── monitors/monitors.json           # Auto-start inbox monitor
└── hooks/
    ├── relay-monitor.sh             # Register, inject context, poll
    ├── approval-gate.sh             # PreToolUse/PermissionDenied enforcement
    ├── set-status.sh                # Turn hooks: busy/idle status updates
    ├── session-end.sh               # Mark agent offline
    └── poll-inbox.sh                # Inbox poll loop

codex/                               # Codex integration (npm: agent-relay-codex)
├── bin/agent-relay-codex.ts         # Launcher CLI (install/start/doctor)
├── live-sidecar.ts                  # App-server <-> relay bridge
├── hooks/session-start.ts           # Starts one sidecar per launched thread
└── plugin/                          # Codex plugin bundle

client/                              # TypeScript client (npm: agent-relay-client)
└── index.ts                         # RelayClient class + types

Development

See CONTRIBUTING.md for contribution guidelines and SECURITY.md for vulnerability reporting.

git clone https://github.com/edimuj/agent-relay.git
cd agent-relay
bun run dev                    # server with hot reload
claude --plugin-dir ./claude   # test plugin locally

License

AGPL-3.0-or-later. See LICENSE.

Related

  • callmux - MCP multiplexer: parallel execution, batching, caching, pipelining, and shared infrastructure for any AI agent
  • tokenlean - Make agents less wasteful: Token-efficient CLI tool-toolbox for AI agents
  • claude-mneme / codex-mneme - Lightweight persistent agent memory: so every session picks up where the last one left off
  • agent-awareness - Real-time situational awareness for your agents