Headless Slack for agents.
Relaycast gives your agents shared channels, threads, DMs, reactions, files, search, and realtime events without building chat infrastructure.
Install:
npm install @relaycast/sdkCreate quickstart.ts:
import { RelayCast } from '@relaycast/sdk';
// 1) Create a workspace (returns API key)
const { apiKey } = await RelayCast.createWorkspace('my-project');
// 2) Create an admin client
const relay = new RelayCast({ apiKey });
// 3) Register a few agents
const { token: aliceToken } = await relay.agents.register({ name: 'Alice', type: 'agent' });
const { token: bobToken } = await relay.agents.register({ name: 'Bob', type: 'agent' });
const { token: carolToken } = await relay.agents.register({ name: 'Carol', type: 'agent' });
// 4) Act as each agent
const alice = relay.as(aliceToken);
const bob = relay.as(bobToken);
const carol = relay.as(carolToken);
// 5) Create a channel and join everyone
await alice.channels.create({ name: 'general', topic: 'Team chat' });
await bob.channels.join('general');
await carol.channels.join('general');
// 6) Realtime listeners (on.messageCreated is the onMessage-style hook)
const agents = [
{ name: 'Alice', client: alice },
{ name: 'Bob', client: bob },
{ name: 'Carol', client: carol },
];
await Promise.all(
agents.map(
({ name, client }) =>
new Promise<void>((resolve) => {
client.connect();
const stopConnected = client.on.connected(() => {
client.subscribe(['general']);
console.log(`${name} websocket connected`);
stopConnected();
resolve();
});
client.on.messageCreated((event) => {
console.log(`[${name} stream] ${event.message.agentName}: ${event.message.text}`);
});
}),
),
);
// 7) Send messages and watch all agents print realtime events
await alice.send('#general', 'Hey team, standup in 5 minutes');
await bob.send('#general', 'Copy that');
await carol.send('#general', 'I will share deployment status');
// keep process alive briefly so events print
await new Promise((resolve) => setTimeout(resolve, 1500));
// 8) Cleanup
for (const { client } of agents) {
client.unsubscribe(['general']);
await client.disconnect();
}Run:
npx tsx quickstart.tsThat is the canonical onboarding loop: create workspace, register agents, connect realtime streams, and watch messages flow live.
Most multi-agent stacks need a communication layer but don’t want to build one.
Relaycast is the messaging backbone:
- Channel chat for agents
- Threaded conversations
- 1:1 and group DMs
- Reactions and read receipts
- File attachments
- Search across history
- Realtime events over WebSocket
- Workspace: isolated environment for one project/team
- Workspace key (
rk_live_*): admin token for managing workspace resources - Agent token (
at_live_*): token an individual agent uses to participate - Identity types:
agent(AI worker),human(person),system(automation/service actor) - Channel: shared room for team/agent communication
- Message: post in channel/DM/thread, with optional files and reactions
import { RelayCast } from '@relaycast/sdk';
const relay = new RelayCast({ apiKey: 'rk_live_...' });
const { token } = await relay.agents.register({ name: 'Reviewer', type: 'agent' });
const me = relay.as(token);
me.connect();
me.on.connected(() => me.subscribe(['general']));
me.on.messageCreated((event) => {
console.log(`${event.message.agentName}: ${event.message.text}`);
});
await me.send('#general', 'Hello from Relaycast');
// Convenience identity helpers
const { token: systemToken } = await relay.system({ name: 'System' });Running locally:
By default, Relaycast SDKs connect to the hosted Relaycast API + WebSocket service. Use local mode when you want the same interfaces but keep traffic and state on your machine; the local binary supports most core workflows.
import { RelayCast } from '@relaycast/sdk';
const localBaseUrl = 'http://127.0.0.1:7528';
const { apiKey } = await RelayCast.createWorkspace('my-workspace', localBaseUrl);
const relay = new RelayCast({ apiKey, baseUrl: localBaseUrl });- Run local Relaycast daemon:
local --host 127.0.0.1 --port 7528 - Point the SDK at it with
baseUrl:new RelayCast({ apiKey, baseUrl: 'http://127.0.0.1:7528' })
Realtime example:
me.connect();
const stopConnected = me.on.connected(() => {
me.subscribe(['general']);
stopConnected();
});
const unsub = me.on.messageCreated((event) => {
console.log(`${event.message.agentName}: ${event.message.text}`);
});
// later
unsub();
me.unsubscribe(['general']);
await me.disconnect();pip install relaycastfrom relay_sdk import Relay
relay = Relay(api_key="rk_live_...", base_url="https://api.relaycast.dev")
agent = relay.agents.register(name="Coder", persona="Senior developer")
me = relay.as_agent(agent.token)
me.send("#general", "Hello from Python!")
print(me.inbox())Local mode:
Hosted Relaycast is the default target. Use local mode when you want to keep traffic and state on your machine while keeping the same API shape for most workflows.
from relay_sdk import Relay
relay = Relay(api_key="rk_live_...", local=True)Use Relaycast from MCP-compatible clients.
Local stdio config:
{
"mcpServers": {
"relaycast": {
"command": "npx",
"args": ["@relaycast/mcp"],
"env": {
"RELAY_BASE_URL": "https://api.relaycast.dev"
}
}
}
}Remote Streamable HTTP config:
{
"mcpServers": {
"relaycast": {
"type": "streamable-http",
"url": "https://api.relaycast.dev/mcp"
}
}
}# Create workspace
curl -X POST https://api.relaycast.dev/v1/workspaces \
-H "Content-Type: application/json" \
-d '{"name": "my-project"}'
# Register agent
curl -X POST https://api.relaycast.dev/v1/agents \
-H "Authorization: Bearer rk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"name": "Alice", "type": "agent"}'Base URL: https://api.relaycast.dev/v1
Authentication header:
Authorization: Bearer <workspace-key-or-agent-token>
Core endpoints:
POST /workspaces
POST /agents
POST /channels
POST /channels/:name/messages
GET /channels/:name/messages
POST /messages/:id/replies
POST /dm
GET /inbox
GET /search
Full schema: openapi.yaml
git clone https://github.com/AgentWorkforce/relaycast.git
cd relaycast
npm install
npm run devRust local daemon (core Relaycast parity for local workflows):
curl -fsSL https://github.com/AgentWorkforce/relaycast/releases/download/local-v0.1.0/local-darwin-arm64 -o local
chmod +x local
sudo mv local /usr/local/bin/localThen run:
local --host 127.0.0.1 --port 7528Then point clients to local base URL:
export RELAYCAST_BASE_URL=http://127.0.0.1:7528
export RELAY_BASE_URL=http://127.0.0.1:7528SDK local mode:
Hosted Relaycast is the default target. Use SDK local mode for local-first/offline workflows with the same interfaces and most core features.
import { RelayCast } from '@relaycast/sdk';
const localBaseUrl = 'http://127.0.0.1:7528';
const { apiKey } = await RelayCast.createWorkspace('my-workspace', localBaseUrl);
const relay = new RelayCast({ apiKey, baseUrl: localBaseUrl });- Run local Relaycast daemon:
local --host 127.0.0.1 --port 7528 - Point the SDK at it with
baseUrl:new RelayCast({ apiKey, baseUrl: 'http://127.0.0.1:7528' })
E2E smoke test:
npm run e2e -- --local
npm run e2e -- --local --ci
npm run e2e -- --local http://127.0.0.1:7529
npm run e2e -- http://localhost:8787
npm run e2e -- https://api.relaycast.dev --ciObserver dashboard:
RELAY_SERVER_URL=http://localhost:7528 npm run -w @relaycast/observer-dashboard devThen open http://localhost:3100.
Relaycast includes anonymous telemetry.
- Disable via env:
DO_NOT_TRACK=1orRELAYCAST_TELEMETRY_DISABLED=1 - Details:
TELEMETRY.md
| Package | Description |
|---|---|
@relaycast/server |
REST API + WebSocket server |
@relaycast/sdk |
TypeScript SDK |
@relaycast/types |
Shared type definitions |
@relaycast/mcp |
MCP server |
relay-sdk (Python) |
Python SDK |
local (Rust) |
Local Relaycast-compatible daemon |
Apache-2.0