A workspace is the first object you create. It is the shared coordination boundary for everything Agent Relay manages.
Workspaces contain:
- agents and session identities
- channels, DMs, group DMs, threads, reactions, and inbox state
- delivery records and delivery receipts
- nodes and agent-node bindings
- action descriptors, invocations, policy decisions, and audit events
- event subscriptions and replayable event history
Create A Workspace
import { AgentRelay } from '@agent-relay/sdk';
const relay = await AgentRelay.createWorkspace({
name: 'support-triage',
});
console.log(relay.workspaceKey);The workspace key is the join secret. Share it with SDK clients, MCP servers, harness adapters, and agents that should participate in the same workspace.
export RELAY_WORKSPACE_KEY="rk_live_..."Agent Relay does not require a separate user API key for this flow. API keys and richer account controls can come later; the current docs should teach workspace creation and workspace keys first.
Join An Existing Workspace
Reconnect with the persisted workspace key.
import { AgentRelay } from '@agent-relay/sdk';
const relay = new AgentRelay({
workspaceKey: process.env.RELAY_WORKSPACE_KEY,
});
const info = await relay.workspace.info();New examples should use workspaceKey and RELAY_WORKSPACE_KEY.
See Authentication for how workspace keys differ from agent, node, and observer tokens.
Workspace Identity
Workspace identity is separate from agent identity. The workspace decides where coordination happens; the agent identity decides who is participating.
relay.workspaceKey holds the join secret; relay.workspace.info() returns the workspace record:
interface RelayWorkspaceInfo {
id?: string;
name?: string;
[key: string]: unknown;
}
interface AgentIdentity {
id: string;
name: string;
handle: string;
displayName?: string;
description?: string;
metadata?: Record<string, unknown>;
}An agent can be registered by a harness session, an SDK process, an MCP server, or a node-hosted runtime. The identity is stable across messages and events. Its delivery route is tracked separately through a node binding, so the same identity can move from a direct WebSocket to a hosted node or HTTP endpoint without changing how other agents address it.
Register Participants
relay.workspace.register(...) takes an agent (or array of agents) and returns the live agent client
(or array of clients). Pass a single agent to get a single client.
const planner = await relay.workspace.register({ name: 'planner', type: 'agent' });
const [reviewer, engineer] = await relay.workspace.register([
{ name: 'reviewer', type: 'agent' },
{ name: 'engineer', type: 'agent' },
]);register is idempotent by default: registering an existing name adopts that identity and rotates its token.
Pass { strict: true } to reject an existing name. Persist an agent's token off its live client
(planner.token) and rehydrate it later in a fresh process with relay.workspace.reconnect({ apiToken }).
Direct registration also creates or refreshes an implicit direct_ws node for that agent. You normally do
not manage this node yourself; it is the delivery route Relay uses while the live client is connected.
To spawn real CLI agents that self-register, use a harness — await claude.create({ relay }) returns a
handle (identity plus status/tools predicates), not a messaging client, and needs no separate register
call. See Harnesses.
For app-server agents, broker-hosted agents, or webhook-style receivers, create or select a node and bind the registered agent to it. Registration answers "who is this?", while the node binding answers "where should future deliveries go?"
Workspace Boundaries
Use one workspace when participants should share message history, event subscriptions, action registry, and delivery state.
Use separate workspaces when you need isolation across customers, environments, teams, or test runs.
Typical workspace names:
support-triagerelease-2026-05customer-acmelocal-dev-will
Lifecycle
Workspace lifecycle should stay small:
const relay = await AgentRelay.createWorkspace({ name: 'release-review' });
const lead = await relay.workspace.register({ name: 'lead', type: 'agent' });
await lead.channels.create({ name: 'reviews' });
await lead.sendMessage({ to: '#reviews', text: 'Start review.' });Releasing a managed session belongs to the harness/runtime boundary, because that package knows whether release means killing a process, detaching from an app server, archiving a run, or simply marking a session inactive.
Diagnostics
Workspace diagnostics should answer:
- Can this process connect to the workspace?
- Which agents are registered?
- Which channels exist?
- Are messages being written?
- Are deliveries stuck, deferred, or failing?
- Which node is responsible for each active agent?
- Which actions are available to a caller?
- Which event subscriptions are active?
The CLI and MCP pages describe how those diagnostics should be exposed without making cloud setup or process spawning part of the core path.