Agent Discovery
Before your app sends events to agents, it needs to know which agents exist and which ones it's allowed to reach. The discovery endpoint returns the list of agents available to your app.
Discovery Message
Send a discovery message over your WebSocket connection:
{
"type": "discover"
}
Relay responds with a list of agents you're allowed to reach:
{
"type": "agents",
"agents": [
{
"agent_id": "athena",
"name": "Athena",
"description": "Personal EA, general tasks"
},
{
"agent_id": "klyve",
"name": "Klyve",
"description": "Technical workflows"
}
]
}
The agents array is filtered to your app's allowlist. If you're not allowlisted for an agent, it won't appear in this list.
Response Format
The agents list contains:
| Field | Type | Notes |
|---|---|---|
agent_id | string | Lowercase slug, unique within the organization |
name | string | Display name for the agent |
description | string | What this agent does |
When to Call Discover
On Startup
Call discover after your app first connects to Relay:
import asyncio
import websockets
import json
async def initialize_agents(websocket):
# Send discover message
await websocket.send(json.dumps({"type": "discover"}))
# Receive agents list
response = await websocket.recv()
data = json.loads(response)
if data["type"] == "agents":
print(f"Available agents: {data['agents']}")
return data["agents"]
async def main():
token = "rlk_yourapp_x8k2m9p..."
uri = "wss://api.relay.ckgworks.com/v1/ws/app"
async with websockets.connect(uri, extra_headers={"Authorization": f"Bearer {token}"}) as ws:
agents = await initialize_agents(ws)
# Use agents to populate UI dropdowns, etc.
Periodically (Optional)
Relay may add new agents over time. Refresh your agent list every 6-12 hours or provide a manual "Refresh" button in your app:
async def refresh_agents_periodically(websocket, interval_seconds=3600):
while True:
await asyncio.sleep(interval_seconds)
await websocket.send(json.stringify({"type": "discover"}))
response = await websocket.recv()
data = json.loads(response)
if data["type"] == "agents":
update_agents_in_database(data["agents"])
print(f"Agent list updated: {len(data['agents'])} agents")
On Permission Changes
If an agent operator updates the allowlist to add or remove your app, you won't be notified automatically. For real-time awareness, listen for discover at key moments:
- After a user reports "I can't mention @athena anymore"
- After deploying a new feature that depends on an agent
- During troubleshooting/debugging
Auto-Creating Agent User Profiles
Most apps create local user profiles for each discovered agent. This allows users to @mention agents or assign tasks to them:
Portal Example
When Portal calls discover, it auto-creates agent user profiles in its database:
async def sync_agents_with_portal_db(agents_from_relay):
for agent in agents_from_relay:
# Check if agent user already exists
existing = User.query.filter_by(
account_type="agent",
agent_id=agent["agent_id"]
).first()
if existing:
# Update name/description
existing.name = agent["name"]
existing.description = agent["description"]
else:
# Create new agent user profile
user = User(
account_type="agent",
agent_id=agent["agent_id"],
name=agent["name"],
email=f"{agent['agent_id']}@relay.ckgworks.com", # Dummy email
description=agent["description"],
avatar_url=f"https://api.relay.ckgworks.com/agents/{agent['agent_id']}/avatar"
)
db.session.add(user)
db.session.commit()
print(f"Synced {len(agents_from_relay)} agent profiles")
Then in your app's UI, agent users appear in the @mention autocomplete:
User starts typing: "Due for review: " + "@" + "a"
Autocomplete shows:
- Athena (agent)
- Alice (human user)
- Alex (human user)
Directory/Teams Example
If your app has a team directory, add a separate "AI Agents" section:
agents = discover_agents()
directory = {
"humans": [
{"name": "Christian Garcia", "role": "Product Manager"},
{"name": "John Doe", "role": "Engineer"}
],
"ai_agents": [
{"name": "Athena", "description": "Personal EA", "agent_id": "athena"},
{"name": "Klyve", "description": "Technical workflows", "agent_id": "klyve"}
]
}
Handling Empty Agent Lists
If agents is empty, your app isn't allowlisted for any agents yet. Possible reasons:
- No agents exist in the organization — Admin needs to register agents first
- All agents have restrictive allowlists — Admin needs to allowlist your app
- App token is invalid — Check your Bearer token
When agents list is empty:
agents = discover_agents()
if not agents:
print("No agents available. Check with your Relay admin.")
# Disable AI features in UI
disable_ai_button()
else:
populate_agent_ui(agents)
JavaScript/Node.js Example
async function discoverAgents(ws) {
return new Promise((resolve) => {
const messageHandler = (event) => {
const data = JSON.parse(event.data);
if (data.type === 'agents') {
ws.removeEventListener('message', messageHandler);
resolve(data.agents);
}
};
ws.addEventListener('message', messageHandler);
ws.send(JSON.stringify({ type: 'discover' }));
});
}
// Usage
const agents = await discoverAgents(ws);
console.log(`Available agents: ${agents.map((a) => a.name).join(', ')}`);
// Create UI dropdown
const agentSelect = document.getElementById('agent-select');
agents.forEach((agent) => {
const option = document.createElement('option');
option.value = agent.agent_id;
option.textContent = agent.name;
agentSelect.appendChild(option);
});
Best Practices
Do
- Call discover on app startup
- Store agent list in your database
- Create agent user profiles for @mentions
- Refresh every 6-12 hours
- Use agent_id for event routing
Don't
- Hardcode agent IDs
- Assume agents exist without discovering
- Send events to agents not in the discovered list
- Cache agent list indefinitely
- Ignore description field
Troubleshooting
Empty agents list?
- Verify your app token is valid
- Ask your Relay admin if agents exist
- Check the allowlist in Relay dashboard
Agent appears in discover but events fail with AGENT_NOT_ALLOWED?
- The agent may have been removed from your allowlist after discovery
- Call discover again to get fresh list
- Check Relay logs for details
Agent name/description outdated?
- Refresh by calling discover again
- Relay caches agent metadata, updates take ~5 minutes
Rate Limiting
Discover requests are rate-limited. Don't call discover more than once per second. If you need a real-time agent update, keep a background refresh job on a 6-12 hour timer.