Protocol v3 specification for the GoClaw gateway WebSocket RPC interface.
GoClaw exposes a WebSocket endpoint at /ws. All client-gateway communication uses JSON frames with three types: req (request), res (response), and event (server-push). The first request on any connection must be connect to authenticate and negotiate protocol version.
Connection URL: ws://<host>:<port>/ws
Protocol version: 3
| Parameter | Value | Description |
|---|---|---|
| Read limit | 512 KB | Connection auto-closed if a single message exceeds this |
| Send buffer | 256 messages | Messages dropped when the buffer is full |
| Read deadline | 60 s | Reset on each message or pong; triggers disconnect on timeout |
| Write deadline | 10 s | Per-write timeout for individual frames |
| Ping interval | 30 s | Server-initiated keepalive pings |
| Rate limit | configurable | rate_limit_rpm in gateway config (0 = disabled, >0 = requests per minute, burst size 5) |
allowed_origins— string array in gateway config. Empty = all origins allowed (dev mode). Supports"*"wildcard. Non-browser clients (emptyOriginheader) always allowed.- Desktop mode — set
GOCLAW_DESKTOP=1env var for permissive CORS (Access-Control-Allow-Origin: *). Adds custom headers:X-GoClaw-Tenant-Id,X-GoClaw-User-Id.
Sent by the client to invoke an RPC method.
{
"type": "req",
"id": "unique-client-id",
"method": "chat.send",
"params": { "message": "Hello", "sessionKey": "user:demo" }
}| Field | Type | Description |
|---|---|---|
type |
string | Always "req" |
id |
string | Client-generated unique ID, matched in response |
method |
string | RPC method name |
params |
object | Method parameters (optional) |
Sent by the server in reply to a request.
{
"type": "res",
"id": "unique-client-id",
"ok": true,
"payload": { ... }
}Error response:
{
"type": "res",
"id": "unique-client-id",
"ok": false,
"error": {
"code": "UNAUTHORIZED",
"message": "invalid token",
"retryable": false
}
}Error shape:
| Field | Type | Description |
|---|---|---|
code |
string | Machine-readable error code |
message |
string | Human-readable description |
details |
any | Optional extra context |
retryable |
boolean | Whether retrying may succeed |
retryAfterMs |
integer | Suggested retry delay in milliseconds |
Server-pushed without a preceding request.
{
"type": "event",
"event": "agent",
"payload": { "type": "chunk", "text": "Hello" },
"seq": 42,
"stateVersion": { "presence": 1, "health": 2 }
}| Field | Type | Description |
|---|---|---|
type |
string | Always "event" |
event |
string | Event name |
payload |
any | Event-specific data |
seq |
integer | Monotonically increasing ordering number |
stateVersion |
object | Version counters for optimistic state sync (presence, health) |
The first request must be connect. The gateway rejects any other method until authenticated.
// Request
{
"type": "req",
"id": "init",
"method": "connect",
"params": {
"token": "YOUR_GATEWAY_TOKEN",
"protocol": 3
}
}
// Success response
{
"type": "res",
"id": "init",
"ok": true,
"payload": { "version": "v1.2.0", "protocol": 3 }
}A wrong protocol version or invalid token returns ok: false immediately.
user_id requirement: The user_id parameter in connect is required for per-user session scoping. It is an opaque VARCHAR(255). For multi-tenant deployments, use the compound format tenant.{tenantId}.user.{userId} — GoClaw uses identity propagation and trusts the upstream service to supply the correct identity.
| Method | Params | Description |
|---|---|---|
connect |
{token, user_id, sender_id?, locale?} |
Authenticate. Must be first request |
health |
— | Ping / health check |
status |
— | Gateway status |
agent |
{agentId?} |
Get runtime status of a single agent (defaults to "default") |
send |
{channel, to, message} |
Route an outbound message to an external channel |
Session ownership (v3): All five
chat.*methods enforce session ownership. Non-admin callers can only access sessions they own (matched byuser_id). Attempting to access another user's session returnsUNAUTHORIZED. Admins and gateway-owner connections bypass this check. This is implemented via therequireSessionOwnerhelper ininternal/gateway/methods/access.go.
| Method | Params | Description |
|---|---|---|
chat.send |
{message, sessionKey?, agentId?} |
Send a message; response streams via agent/chat events |
chat.history |
{sessionKey} |
Retrieve message history |
chat.abort |
{sessionKey} |
Abort an in-progress run |
chat.inject |
{sessionKey, content} |
Inject a message without triggering a run |
chat.session.status |
{sessionKey} |
Get live run state + activity phase of a session |
| Method | Params | Description |
|---|---|---|
agents.list |
— | List all agents |
agent.wait |
{agentId} |
Wait for agent to finish current run |
agents.create |
agent object | Create an agent |
agents.update |
{agentId, name?, provider?, model?, model_fallback?, avatar?, status?, workspace?, frontmatter?, context_window?, max_tool_iterations?, is_default?, budget_monthly_cents?, tools_config?, subagents_config?, sandbox_config?, memory_config?, compaction_config?, context_pruning?, other_config?, emoji?, agent_description?, thinking_level?, max_tokens?, self_evolve?, skill_evolve?, skill_nudge_interval?, reasoning_config?, workspace_sharing?, chatgpt_oauth_routing?, shell_deny_groups?, kg_dedup_config?} |
Update an agent |
agents.delete |
{id} |
Delete an agent |
agents.files.list |
{agentId} |
List context files |
agents.files.get |
{agentId, fileName} |
Get a context file |
agents.files.set |
{agentId, fileName, content} |
Create or update a context file |
agent.identity.get |
{agentId} |
Get agent persona info |
agents.links.list |
{agentId, direction?} |
List delegation links ("from", "to", "all") |
agents.links.create |
{sourceAgent, targetAgent, direction?, description?, maxConcurrent?, settings?} |
Create a delegation link between agents |
agents.links.update |
{linkId, direction?, description?, maxConcurrent?, settings?, status?} |
Update a delegation link |
agents.links.delete |
{linkId} |
Delete a delegation link |
| Method | Params | Description |
|---|---|---|
sessions.list |
{agentId?} |
List sessions, optionally filtered by agent |
sessions.preview |
{sessionKey} |
Get session summary |
sessions.patch |
{sessionKey, ...fields} |
Patch session metadata |
sessions.delete |
{key} |
Delete a session |
sessions.reset |
{key} |
Clear session history |
sessions.compact |
{key, keepLast?} |
Truncate history to last N messages (default 4); no-op if history < 6 |
run.timeline.get |
{runId?, sessionKey?, limit?, offset?} |
Fetch display-safe archived run/session timeline items |
Fetch display-safe timeline entries captured during agent runs. Pass runId for a single run, or sessionKey for the session archive panel — at least one is required. limit defaults to 200 and is capped at 500; offset paginates. Viewer role can read this method; non-admin callers only receive entries whose user_id matches their connected user.
Request:
{
"type": "req",
"id": "tl-1",
"method": "run.timeline.get",
"params": { "runId": "run-123", "sessionKey": "agent:demo:direct:user-1", "limit": 100, "offset": 0 }
}Response payload:
{
"runId": "run-123",
"sessionKey": "agent:demo:direct:user-1",
"items": [{
"id": "019e...",
"run_id": "run-123",
"session_key": "agent:demo:direct:user-1",
"seq": 1,
"item_type": "assistant.message",
"status": "completed",
"title": "assistant",
"preview": "I will check that now.",
"created_at": "2026-05-29T10:00:00Z"
}],
"limit": 100,
"offset": 0
}Timeline item_type values include activity, assistant.message, tool.call, tool.result, and run.status. Tool entries store bounded previews only; raw reasoning/thinking is not persisted.
| Method | Description |
|---|---|
config.get |
Get current config (secrets redacted) |
config.apply |
Replace config entirely |
config.patch |
Patch specific config fields |
config.schema |
Get JSON schema for config |
config.defaults |
Get compiled-in defaults + agents.defaults overlay (read-only, master scope) |
config.permissions.list |
{agentId, configType?} |
config.permissions.check |
{agentId, scope, configType, userId} |
config.permissions.grant |
{agentId, scope, configType, userId, permission, grantedBy?, metadata?} |
config.permissions.revoke |
{agentId, scope, configType, userId} |
chat_behavior.preview |
Preview resolved channel delivery behavior without sending a message (owner, master scope) |
This live WebSocket RPC powers the dashboard preview for channel chat behavior. It does not send a message or mutate configuration.
Access: the connection must be the gateway owner and must be in master scope. Otherwise the method returns UNAUTHORIZED.
| Param | Type | Description |
|---|---|---|
channel |
string | Channel name used for override lookup when config is omitted |
content |
string | Sample final content used to preview message splitting |
isStreaming |
boolean | Whether the sample delivery is streaming |
hasToolCalls |
boolean | Whether the sample run contains tool calls |
config |
object | Optional ChatBehaviorConfig to resolve directly |
Resolution order:
- If
configis supplied, GoClaw resolves it directly against built-in chat-behavior defaults; channel lookup and gateway configuration are not applied. - If
configis omitted and a channel manager is available, GoClaw applies the named channel's override on top ofgateway.chat_behaviordefaults. - If no channel manager is available, GoClaw falls back to
gateway.chat_behavioronly.
The response payload always contains resolved, ack, and split. resolved is the effective behavior, ack describes whether and how a quick acknowledgement would be sent, and split.parts contains the resulting final-message parts.
Serialization note:
resolvedcurrently uses exported Go field names such asEnabled,QuickAck, andFinalSplit. ItsTimeoutvalues aretime.Durationintegers serialized in nanoseconds. Theackandsplitfields use the camelCase names shown below.
Request:
{
"type": "req",
"id": "behavior-preview-1",
"method": "chat_behavior.preview",
"params": {
"channel": "telegram",
"content": "First update is ready.\n\nSecond update is ready.",
"isStreaming": false,
"hasToolCalls": true,
"config": {
"enabled": true,
"quick_ack": {
"enabled": true,
"mode": "fixed_template",
"templates": ["Working."]
},
"final_split": {
"enabled": true,
"min_chars": 10,
"max_messages": 3,
"delay_ms": 500
}
}
}
}Success response:
{
"type": "res",
"id": "behavior-preview-1",
"ok": true,
"payload": {
"resolved": {
"Enabled": true,
"IntermediateReplies": {
"Enabled": false,
"Mode": "sidecar_generated",
"Provider": "",
"Model": "",
"Timeout": 2500000000,
"MaxTokens": 60,
"MaxChars": 180
},
"QuickAck": {
"Enabled": true,
"Mode": "fixed_template",
"MinDelayMs": 1000,
"Provider": "",
"Model": "",
"Timeout": 2500000000,
"MaxTokens": 40,
"MaxChars": 120,
"Templates": ["Working."]
},
"FinalSplit": {
"Enabled": true,
"MinChars": 10,
"MaxMessages": 3,
"DelayMs": 500
}
},
"ack": {
"shouldSend": true,
"content": "Working.",
"mode": "fixed_template",
"source": "template"
},
"split": {
"parts": ["First update is ready.", "Second update is ready."]
}
}
}| Method | Params | Description |
|---|---|---|
cron.list |
{includeDisabled?} |
List cron jobs |
cron.create |
cron job object | Create a cron job |
cron.update |
{jobId, ...fields} |
Update a cron job |
cron.delete |
{jobId} |
Delete a cron job |
cron.toggle |
{jobId, enabled} |
Enable or disable a job |
cron.run |
{jobId} |
Trigger immediate run |
cron.runs |
{jobId} |
List run history |
cron.status |
{jobId} |
Get job status |
| Method | Params | Description |
|---|---|---|
skills.list |
— | List skills |
skills.get |
{id} |
Get skill details |
skills.update |
{id, ...fields} |
Update skill metadata |
Manage lifecycle hooks stored in agent_hooks. See Agent Hooks for full concepts and examples.
Required roles: viewer for list/history; operator for test; admin for create/update/delete/toggle.
| Method | Params | Description |
|---|---|---|
hooks.list |
{event?, scope?, agentId?, enabled?} |
List hooks visible to the caller's scope |
hooks.create |
hook config object | Create a hook; returns {hookId} |
hooks.update |
{hookId, updates} |
Patch a hook's fields; re-validates merged config |
hooks.delete |
{hookId} |
Delete a hook (builtin hooks return error) |
hooks.toggle |
{hookId, enabled} |
Enable or disable a hook |
hooks.test |
{config, sampleEvent?} |
Dry-run a hook config; no audit row written |
hooks.history |
— | List hook_executions audit records |
hooks.list — filter params:
| Param | Type | Description |
|---|---|---|
event |
string | Filter by event name (e.g. pre_tool_use) |
scope |
string | Filter by scope: global, tenant, agent |
agentId |
string (UUID) | Filter to a specific agent |
enabled |
boolean | Filter by enabled state |
hooks.list response:
{ "hooks": [ { "id": "uuid", "event": "pre_tool_use", "handler_type": "http",
"scope": "tenant", "enabled": true, "priority": 0, ... } ] }hooks.create request params (all fields are the HookConfig schema):
| Field | Type | Required | Description |
|---|---|---|---|
event |
string | yes | Lifecycle event name |
handler_type |
string | yes | command, http, or prompt |
scope |
string | yes | global, tenant, or agent |
name |
string | no | Human-readable label |
matcher |
string | no | Tool name regex (optional for command/http; required for prompt) |
if_expr |
string | no | CEL expression alternative to matcher |
timeout_ms |
int | no | Per-hook timeout ms (default 5000, max 10000) |
on_timeout |
string | no | block (default) or allow |
priority |
int | no | Higher runs first |
enabled |
bool | no | Default true |
config |
object | yes | Handler-specific sub-config |
agent_ids |
array | no | UUID list for scope=agent |
hooks.test — sampleEvent fields:
| Field | Type | Description |
|---|---|---|
toolName |
string | Tool name for pre/post_tool_use events |
toolInput |
object | Tool arguments map |
rawInput |
string | Raw user message (for user_prompt_submit) |
hooks.test response:
{
"result": {
"decision": "allow",
"reason": "...",
"durationMs": 42,
"stdout": "...",
"stderr": "...",
"statusCode": 200,
"updatedInput": {}
}
}| Method | Description |
|---|---|
channels.list |
List active channels |
channels.status |
Get channel health |
channels.toggle |
Enable/disable a channel |
channels.instances.list |
List DB channel instances |
channels.instances.get |
Get a channel instance |
channels.instances.create |
Create a channel instance |
channels.instances.update |
Update a channel instance |
channels.instances.delete |
Delete a channel instance |
| Method | Params | Description |
|---|---|---|
device.pair.request |
{channel, chatId} |
Request pairing code |
device.pair.approve |
{code, approvedBy} |
Approve a pairing request |
device.pair.deny |
{code} |
Deny a pairing request |
device.pair.list |
— | List pending and approved pairings |
device.pair.revoke |
{channel, senderId} |
Revoke a pairing |
browser.pairing.status |
{sender_id} |
Poll pairing approval status (unauthenticated, rate-limited) |
| Method | Description |
|---|---|
exec.approval.list |
List pending shell command approvals |
exec.approval.approve |
Approve a command |
exec.approval.deny |
Deny a command |
| Method | Description |
|---|---|
teams.list |
List all teams |
teams.create |
Create team (admin only) |
teams.get |
Get team with members |
teams.update |
Update team properties |
teams.delete |
Delete team |
teams.members.add |
Add agent to team |
teams.members.remove |
Remove agent from team |
teams.tasks.list |
List team tasks (filterable) |
teams.tasks.get |
Get task with comments/events |
teams.tasks.create |
Create task |
teams.tasks.assign |
Assign task to member |
teams.tasks.approve |
Approve completed task |
teams.tasks.reject |
Reject task submission |
teams.tasks.comment |
Add comment to task |
teams.tasks.comments |
List task comments |
teams.tasks.events |
List task event history |
teams.tasks.get-light |
Get task without comments/events/attachments |
teams.tasks.delete |
Delete task |
teams.tasks.delete-bulk |
{teamId, taskIds} |
teams.tasks.active-by-session |
Get active tasks for a session (used to restore state on session switch) |
teams.workspace.list |
List team workspace files |
teams.workspace.read |
Read workspace file |
teams.workspace.delete |
Delete workspace file |
teams.events.list |
List team event history (paginated) |
teams.known_users |
Get known user IDs in team |
teams.scopes |
Get channel/chat scopes for task routing |
| Method | Description |
|---|---|
usage.get |
Token usage stats |
usage.summary |
Usage summary cards |
quota.usage |
Quota consumption for current user |
| Method | Params | Description |
|---|---|---|
logs.tail |
{action: "start"|"stop", level?} |
Start or stop live log streaming; log entries arrive as server-push events while active |
| Method | Params | Description |
|---|---|---|
heartbeat.get |
{agentId} |
Get heartbeat config for an agent |
heartbeat.set |
{agentId, enabled?, intervalSec?, prompt?, providerName?, model?, ...} |
Upsert heartbeat config (intervalSec min 300) |
heartbeat.toggle |
{agentId, enabled} |
Enable or disable heartbeat |
heartbeat.test |
{agentId} |
Trigger an immediate heartbeat run |
heartbeat.logs |
{agentId, limit?, offset?} |
List heartbeat execution logs |
heartbeat.checklist.get |
{agentId} |
Read the HEARTBEAT.md context file |
heartbeat.checklist.set |
{agentId, content} |
Write/replace the HEARTBEAT.md context file |
heartbeat.targets |
{agentId} |
List delivery targets for heartbeat notifications |
| Method | Params | Description |
|---|---|---|
api_keys.list |
— | List API keys (non-admin sees own only) |
api_keys.create |
{name, scopes, expires_in?, owner_id?, tenant_id?} |
Create an API key; returns raw key once |
api_keys.revoke |
{id} |
Revoke an API key (non-admin can revoke own only) |
| Method | Params | Description |
|---|---|---|
voices.list |
— | List ElevenLabs voices for current tenant (cached) |
voices.refresh |
— | Invalidate cache and refetch voices from provider |
Standard edition only. Methods are not registered when the gateway runs in Lite edition; calls return
method_not_found. Admin role required for every method.
| Method | Params | Description |
|---|---|---|
workstations.list |
— | List workstations for the current tenant |
workstations.get |
{id} |
Get a workstation |
workstations.create |
{workstationKey, name, backendType, metadata, defaultCwd?, defaultEnv?} |
Create a workstation (backendType is ssh or docker) |
workstations.update |
{id, ...fields} |
Update a workstation |
workstations.delete |
{id} |
Delete a workstation |
workstations.testConnection |
{id} |
Probe backend connectivity without executing commands |
workstations.linkAgent |
{workstationId, agentId, isDefault?} |
Link an agent to a workstation |
workstations.unlinkAgent |
{workstationId, agentId} |
Remove the link |
workstations.permissions.list |
{workstationId} |
List allowlist patterns |
workstations.permissions.add |
{workstationId, pattern, description?, enabled?} |
Append an allowlist pattern |
workstations.permissions.remove |
{workstationId, permissionId} |
Remove a pattern |
workstations.permissions.toggle |
{workstationId, permissionId, enabled} |
Enable/disable a pattern |
workstations.activity.list |
{workstationId, limit?, before?, action?} |
Paginated activity audit log; action filter accepts exec or deny |
| Method | Params | Description |
|---|---|---|
tenants.list |
— | List all tenants (owner only) |
tenants.get |
{id} |
Get a tenant by ID |
tenants.create |
{name, slug, settings?} |
Create a tenant and its workspace |
tenants.update |
{id, name?, status?, settings?} |
Update tenant properties |
tenants.users.list |
{tenant_id} |
List users in a tenant |
tenants.users.add |
{tenant_id, user_id, role?} |
Add user (roles: owner/admin/operator/member/viewer) |
tenants.users.remove |
{tenant_id, user_id} |
Remove user and broadcast access-revoked event |
tenants.mine |
— | Get current user's tenant memberships |
| Method | Params | Description |
|---|---|---|
whatsapp.qr.start |
{instance_id} |
Start WhatsApp QR login flow for direct WhatsApp channel |
zalo.personal.qr.start |
{instance_id} |
Start Zalo Personal QR login flow |
zalo.personal.contacts |
{instance_id} |
Fetch Zalo friends and groups |
Status: Planned —
whatsapp.qr.start,zalo.personal.qr.start, andzalo.personal.contactshave protocol constants defined but handlers are not yet implemented in the gateway.
Self-service management of Bitrix24 portal connections. All methods are tenant-scoped (resolved from the connection, never from caller params). list and get_install_url are open to any authenticated tenant member; create and delete require admin role. Credentials are never returned in any response.
| Method | Params | Description |
|---|---|---|
bitrix.portals.list |
— | List portals for the current tenant (credentials masked) |
bitrix.portals.create |
{name, domain, client_id, client_secret} |
Provision a portal; returns {name, domain, install_url} |
bitrix.portals.get_install_url |
{name} |
Re-build the install URL for an existing portal → {install_url} |
bitrix.portals.delete |
{name} |
Delete a portal → {status: "deleted"} |
bitrix.portals.create params:
| Param | Type | Description |
|---|---|---|
name |
string | Portal slug — lowercase letters, digits, hyphen, underscore (2–64 chars) |
domain |
string | Portal host — *.bitrix24.{com,eu,ru,…} or *.bitrix.info |
client_id |
string | Bitrix OAuth client ID |
client_secret |
string | Bitrix OAuth client secret |
createfails withFAILED_PRECONDITIONif the gateway has not yet observed its public URL — open the UI through the gateway's external URL first so the install URL can be built.deleteis blocked (FAILED_PRECONDITION) while any channel instance still references the portal.
Emitted during agent runs. Check payload.type:
payload.type |
Description |
|---|---|
run.started |
Agent run begins |
run.completed |
Run finished successfully |
run.failed |
Run encountered an error |
run.cancelled |
Run was cancelled before completion |
run.retrying |
Run is being retried |
tool.call |
Tool was invoked |
tool.result |
Tool returned a result |
block.reply |
Reply was blocked by input guard |
activity |
Agent activity update |
payload.type |
Description |
|---|---|
chunk |
Streaming text token |
message |
Full message (non-streaming) |
thinking |
Extended thinking / reasoning output |
| Event | Description |
|---|---|
health |
Periodic gateway health ping |
tick |
Heartbeat tick |
shutdown |
Gateway shutting down |
cron |
Cron job status change |
exec.approval.requested |
Shell command needs user approval |
exec.approval.resolved |
Approval decision made |
device.pair.requested |
New pairing request from channel user |
device.pair.resolved |
Pairing approved or denied |
presence |
User presence change |
agent.summoning |
Predefined agent persona generation in progress |
delegation.started |
Delegation to subagent started |
delegation.completed |
Delegation completed successfully |
delegation.failed |
Delegation failed |
delegation.cancelled |
Delegation was cancelled |
delegation.progress |
Intermediate delegation result |
delegation.announce |
Batched subagent results delivered to parent |
delegation.accumulated |
Accumulated delegation results |
connect.challenge |
Authentication challenge issued |
voicewake.changed |
Voice wake word setting changed |
talk.mode |
Talk mode state change |
node.pair.requested |
Node pairing request received |
node.pair.resolved |
Node pairing resolved |
session.updated |
Chat session metadata updated |
trace.updated |
Agent trace updated |
heartbeat |
Heartbeat execution event |
workspace.file.changed |
Team workspace file changed |
agent_link.created |
Delegation link created |
agent_link.updated |
Delegation link updated |
agent_link.deleted |
Delegation link deleted |
tenant.access.revoked |
Tenant access revoked for a user |
whatsapp.qr.code |
WhatsApp QR code generated |
whatsapp.qr.done |
WhatsApp QR login completed |
zalo.personal.qr.code |
Zalo QR code generated |
zalo.personal.qr.done |
Zalo QR login completed |
| Event | Description |
|---|---|
skill.deps.checked |
Skill dependencies check started |
skill.deps.complete |
All skill dependencies resolved |
skill.deps.installing |
Skill dependency installation started |
skill.deps.installed |
Skill dependency installation completed |
skill.dep.item.installing |
Individual dependency item installing |
skill.dep.item.installed |
Individual dependency item installed |
| Event | Description |
|---|---|
team.created |
Team created |
team.updated |
Team updated |
team.deleted |
Team deleted |
team.member.added |
Member added to team |
team.member.removed |
Member removed from team |
team.message.sent |
Peer-to-peer message in team |
team.leader.processing |
Team leader processing request |
team.task.created |
Task created |
team.task.completed |
Task completed |
team.task.claimed |
Task claimed |
team.task.cancelled |
Task cancelled |
team.task.failed |
Task failed |
team.task.reviewed |
Task reviewed |
team.task.approved |
Task approved |
team.task.rejected |
Task rejected |
team.task.progress |
Task progress update |
team.task.commented |
Comment added to task |
team.task.assigned |
Task assigned to member |
team.task.dispatched |
Task dispatched |
team.task.updated |
Task updated |
team.task.deleted |
Task deleted |
team.task.stale |
Task marked stale |
team.task.attachment_added |
Attachment added to task |
const ws = new WebSocket("ws://localhost:18790/ws");
ws.onopen = () => {
ws.send(JSON.stringify({
type: "req", id: "1", method: "connect",
params: { token: "YOUR_TOKEN", user_id: "user-123", protocol: 3 }
}));
};
ws.onmessage = (e) => {
const frame = JSON.parse(e.data);
// After connect succeeds, send a chat message
if (frame.type === "res" && frame.id === "1" && frame.ok) {
ws.send(JSON.stringify({
type: "req", id: "2", method: "chat.send",
params: { message: "Hello!", sessionKey: "user:demo" }
}));
}
// Stream response tokens
if (frame.type === "event" && frame.event === "chat") {
if (frame.payload?.type === "chunk") {
process.stdout.write(frame.payload.text ?? "");
}
}
};- REST API — HTTP endpoints for agent CRUD, skill uploads, traces
- CLI Commands — pairing and session management from the terminal
- Glossary — Session, Lane, Compaction, and other key terms