OpenClaw Relay Plugin
The OpenClaw Relay plugin is the easiest way to connect AI agents to Relay. It manages WebSocket connections, session creation, and message routing automatically.
What the Plugin Does
The plugin:
- Maintains persistent WebSocket connections to Relay (one per agent)
- Receives events from apps
- Creates/resumes OpenClaw sessions with the correct session key
- Injects payloads as user messages
- Streams tokens and final replies back to Relay
- Handles reconnection with exponential backoff
- Manages per-agent TTL (time-to-live) for sessions
Think of it as a bridge between Relay and OpenClaw — one connection per agent.
Installation
The plugin is available on npm:
npm install openclaw-relay-plugin
Or with yarn:
yarn add openclaw-relay-plugin
Configuration
Create a openclaw.plugin.json file:
{
"relay": {
"url": "wss://api.relay.ckgworks.com/v1/ws/agent",
"reconnect": {
"enabled": true,
"maxRetries": 5,
"baseDelayMs": 1000,
"maxDelayMs": 60000
}
},
"agents": [
{
"agent_id": "athena",
"token": "rla_athena_k9x2p7m2jq8r5v3n1b9...",
"ttl_days": 14,
"context": {}
},
{
"agent_id": "klyve",
"token": "rla_klyve_k9x2p7m2jq8r5v3n1b9...",
"ttl_days": 30,
"context": {}
}
]
}
Config Schema
| Field | Type | Required | Notes |
|---|---|---|---|
relay.url | string | Yes | Relay WebSocket endpoint |
relay.reconnect.enabled | boolean | No | Auto-reconnect on disconnect (default: true) |
relay.reconnect.maxRetries | number | No | Max reconnection attempts (default: 5) |
relay.reconnect.baseDelayMs | number | No | Initial backoff delay in ms (default: 1000) |
relay.reconnect.maxDelayMs | number | No | Max backoff delay in ms (default: 60000) |
agents[].agent_id | string | Yes | Agent identifier (matches Relay registration) |
agents[].token | string | Yes | Agent token from Relay dashboard (rla_...) |
agents[].ttl_days | number | No | Session TTL in days (default: 14) |
agents[].context | object | No | Custom context passed to OpenClaw |
Security Note
Never commit the config file with real tokens to version control. Use environment variables:
{
"agents": [
{
"agent_id": "athena",
"token": "${RELAY_ATHENA_TOKEN}",
"ttl_days": 14
}
]
}
Then set the env var:
export RELAY_ATHENA_TOKEN="rla_athena_k9x2p..."
The plugin will interpolate ${VAR} from environment.
Usage
TypeScript/Node.js
import { RelayPlugin } from 'openclaw-relay-plugin';
import OpenClaw from 'openclaw';
const plugin = new RelayPlugin({
configPath: './openclaw.plugin.json'
});
const openClaw = new OpenClaw({
plugins: [plugin]
});
openClaw.on('connected', () => {
console.log('OpenClaw connected to Relay');
});
openClaw.on('error', (error) => {
console.error('Error:', error);
});
// Plugin handles everything automatically
With Environment Config
const plugin = new RelayPlugin({
config: {
relay: {
url: process.env.RELAY_URL || 'wss://api.relay.ckgworks.com/v1/ws/agent'
},
agents: [
{
agent_id: 'athena',
token: process.env.RELAY_ATHENA_TOKEN,
ttl_days: 14
},
{
agent_id: 'klyve',
token: process.env.RELAY_KLYVE_TOKEN,
ttl_days: 30
}
]
}
});
How It Works
Session Key Mapping
When Relay delivers an event with session_key: "relay:portal:task-123", the plugin:
- Strips the prefix:
portal:task-123 - Creates/resumes an OpenClaw session with that key
- Your agent logic processes the request
- The plugin streams tokens back to Relay
Event from Relay:
{
"type": "event",
"event_id": "evt_k9p2m",
"session_key": "relay:portal:task-123", <- Full key
"payload": { ... }
}
Plugin processes:
1. Extract session_key: "relay:portal:task-123"
2. Get OpenClaw session: "relay:portal:task-123"
3. Run agent logic
4. Stream tokens back to Relay
Multi-Agent Connections
With multiple agents configured, the plugin creates one WebSocket per agent:
OpenClaw Plugin (one process)
├── Athena Agent
│ └── WebSocket to Relay (authenticated with rla_athena_...)
├── Klyve Agent
│ └── WebSocket to Relay (authenticated with rla_klyve_...)
└── Future Agent
└── WebSocket to Relay (authenticated with rla_future_...)
Each agent runs independently and can receive events concurrently.
Monitoring
The plugin exposes events you can listen to:
plugin.on('relay:connected', (agentId) => {
console.log(`${agentId} connected to Relay`);
});
plugin.on('relay:disconnected', (agentId) => {
console.log(`${agentId} disconnected from Relay`);
});
plugin.on('relay:reconnecting', (agentId, attempt) => {
console.log(`${agentId} reconnecting (attempt ${attempt})`);
});
plugin.on('event:received', (agentId, eventId, sessionKey) => {
console.log(`${agentId} received event ${eventId} for ${sessionKey}`);
});
plugin.on('event:replied', (agentId, eventId, tokenCount) => {
console.log(`${agentId} sent reply with ${tokenCount} tokens`);
});
plugin.on('event:error', (agentId, eventId, error) => {
console.error(`${agentId} error on ${eventId}: ${error}`);
});
Health Check Endpoint
The plugin can expose a health check HTTP endpoint:
const plugin = new RelayPlugin({
configPath: './openclaw.plugin.json',
healthCheck: {
enabled: true,
port: 3001,
path: '/health'
}
});
// GET http://localhost:3001/health
// Returns:
// {
// "status": "healthy",
// "agents": {
// "athena": { "connected": true, "lastPing": "2026-04-07T14:30:00Z" },
// "klyve": { "connected": false, "lastError": "Network unreachable" }
// }
// }
Per-Agent TTL
Each agent can have a different session TTL (time-to-live):
{
"agents": [
{
"agent_id": "athena",
"token": "...",
"ttl_days": 14
},
{
"agent_id": "klyve",
"token": "...",
"ttl_days": 30
}
]
}
- Athena (14 days): General assistant, shorter memory
- Klyve (30 days): Technical workflows, longer memory for complex projects
Sessions expire after the TTL. When a new event arrives for an expired session, a fresh session is created.
Reconnection Logic
The plugin implements exponential backoff:
Attempt 1: 1 second delay
Attempt 2: 2 seconds
Attempt 3: 4 seconds
Attempt 4: 8 seconds
Attempt 5: 16 seconds
After that: capped at maxDelayMs (60s)
Configure in the config file:
{
"relay": {
"reconnect": {
"baseDelayMs": 1000,
"maxDelayMs": 60000
}
}
}
Logging
The plugin logs to console.log/error by default. Integrate with your logging system:
const plugin = new RelayPlugin({
configPath: './openclaw.plugin.json',
logger: {
log: (message, metadata) => yourLogger.info(message, metadata),
error: (message, metadata) => yourLogger.error(message, metadata),
warn: (message, metadata) => yourLogger.warn(message, metadata)
}
});
Graceful Shutdown
Properly close connections on shutdown:
process.on('SIGTERM', async () => {
console.log('Shutting down...');
await plugin.close(); // Closes all agent connections
process.exit(0);
});
Troubleshooting
Agent appears offline in Relay dashboard?
- Check agent token is correct
- Verify environment variables are set
- Check network connectivity to api.relay.ckgworks.com
- Look at plugin logs for connection errors
"Invalid token" on startup?
- Verify token prefix is
rla_ - Check if token was rotated (old token expired)
- Request a new token from Relay dashboard
Tokens arriving but no replies sent back?
- Check OpenClaw is processing events
- Look for errors in OpenClaw logs
- Verify the agent definition exists in OpenClaw
High reconnection rate?
- Check network stability
- Verify Relay isn't rejecting connections
- Check rate limiting isn't kicking in
Limits and Quotas
- Concurrent connections per agent: 1
- Concurrent events per agent: Limited by OpenClaw concurrency
- Token size: Up to 1KB per token (recommended: 1-5 words)
- Payload size: Up to 64KB per event
- Session key length: Up to 255 characters
Version Compatibility
Check the plugin version matches your OpenClaw version:
npm list openclaw openclaw-relay-plugin
Supported OpenClaw versions: 2.0+
Advanced: Custom Context Injection
Pass custom context to OpenClaw for each agent:
{
"agents": [
{
"agent_id": "athena",
"token": "...",
"context": {
"model": "claude-3-5-sonnet-20241022",
"temperature": 0.7,
"maxTokens": 1024,
"systemPrompt": "You are Athena, a personal AI assistant."
}
}
]
}
This context is passed to OpenClaw when creating agent sessions.
Best Practices
Do
- Use environment variables for tokens
- Monitor connection status
- Set appropriate TTL per agent
- Log events for debugging
- Test token rotation
Don't
- Commit tokens to git
- Hardcode agent IDs
- Use maxRetries < 3
- Ignore reconnection errors
- Skip graceful shutdown