Files
clawmates/infrastructurehandoff/realtime/events.schema.json
T
Omar SobhandClaude Opus 4.8 fb59378aa2
ci / gates (push) Failing after 5s
ci / rust (push) Has been skipped
ci / sandbox-k8s (push) Has been skipped
ci / frontend (push) Has been skipped
ci / e2e (push) Has been skipped
Fleet P2b: run agent sandboxes on connected nodes (RemoteDriver + placement)
Agents can now provision their sandbox on a connected fleet node instead of the
gateway host. Local stays the strict default, so existing agents are byte-for-
byte unaffected until explicitly placed elsewhere.

Security parity: the daemon links the REAL cm-sandbox DockerDriver and runs the
typed container ops (sb_provision/sb_exec/sb_destroy/sb_health/sb_list) through
it — identical hardening (cap-drop ALL, seccomp, no-net, read-only, non-root) to
local sandboxes. cm-sandbox spec types are now Serialize/Deserialize so the spec
crosses the channel.

- cm-api: RemoteDriver (impl SandboxDriver over the node channel) + HubDriverProvider
  (impl cm_runtime::NodeDriverProvider, hands out a driver only for connected
  nodes via a sync online set) + NodeHub.call/is_connected. AppState.with_node_hub
  so the hub is shared with the placement provider.
- cm-runtime SandboxManager: driver_for(node_id) routes by the recorded
  agent_containers.node_id (local default = existing driver, identical path);
  placement_node() reads the workspace setting and falls back to local if the
  node is offline; exec/release route accordingly. NodeDriverProvider trait.
- DB: 0020_workspace_placement + repo (for_agent/get/set/clear).
- main.rs: build the NodeHub first; inject HubDriverProvider into the agent
  manager + share the hub with AppState.
- API+UI: GET/PUT /api/fleet/placement + a "Run agents on: Local / <node>"
  selector in the Fleet overview.

Note: a node must be able to pull the agent image (the daemon docker-pulls it);
interactive PTY for agent containers on remote nodes is not wired (Terminal app
stays local) — the in-dashboard node shell already covers host access.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-24 12:48:50 -07:00

200 lines
6.7 KiB
JSON

{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://clawmates.work/schemas/events.schema.json",
"title": "Clawmates Event Taxonomy",
"description": "Normalized real-time events emitted by the live bridge and consumed by the visualizations. Each SSE frame is `event: <type>` + `data: <object matching the matching definition>`.",
"type": "object",
"oneOf": [
{ "$ref": "#/definitions/agent.status" },
{ "$ref": "#/definitions/agent.task.update" },
{ "$ref": "#/definitions/agent.reasoning.delta" },
{ "$ref": "#/definitions/agent.computer.frame" },
{ "$ref": "#/definitions/agent.tool.call" },
{ "$ref": "#/definitions/door.request" },
{ "$ref": "#/definitions/door.resolve" },
{ "$ref": "#/definitions/agent.message" },
{ "$ref": "#/definitions/world.touch" },
{ "$ref": "#/definitions/node.activity" },
{ "$ref": "#/definitions/topology.update" },
{ "$ref": "#/definitions/telemetry" },
{ "$ref": "#/definitions/routine.update" }
],
"definitions": {
"agent.status": {
"type": "object",
"required": ["agentId", "status"],
"properties": {
"agentId": { "type": "string" },
"status": { "enum": ["online", "working", "idle", "offline"] },
"role": { "type": "string" }
}
},
"agent.task.update": {
"type": "object",
"required": ["agentId", "taskId", "title"],
"properties": {
"agentId": { "type": "string" },
"taskId": { "type": "string" },
"title": { "type": "string" },
"elapsedMs": { "type": "integer", "minimum": 0 },
"steps": {
"type": "array",
"items": {
"type": "object",
"required": ["label", "state"],
"properties": {
"label": { "type": "string" },
"state": { "enum": ["done", "active", "pending"] }
}
}
}
}
},
"agent.reasoning.delta": {
"type": "object",
"required": ["agentId", "text"],
"properties": {
"agentId": { "type": "string" },
"text": { "type": "string", "description": "Token chunk to APPEND to the reasoning stream." },
"channel": { "enum": ["think", "say", "tool"], "default": "think" }
}
},
"agent.computer.frame": {
"type": "object",
"required": ["agentId", "app"],
"properties": {
"agentId": { "type": "string" },
"app": { "enum": ["browser", "terminal", "slack", "claw-chat"] },
"url": { "type": "string" },
"lines": {
"type": "array",
"items": {
"type": "object",
"required": ["text"],
"properties": {
"text": { "type": "string" },
"kind": { "enum": ["plain", "add", "del", "ok", "warn", "cursor"], "default": "plain" }
}
}
}
}
},
"agent.tool.call": {
"type": "object",
"required": ["agentId", "tool"],
"properties": {
"agentId": { "type": "string" },
"tool": { "type": "string" },
"target": { "type": "string" },
"doorRequired": { "type": "boolean", "default": false }
}
},
"door.request": {
"type": "object",
"required": ["doorId", "agentId", "action"],
"properties": {
"doorId": { "type": "string" },
"agentId": { "type": "string" },
"action": { "type": "string", "description": "e.g. github.review.comment" },
"target": { "type": "string" },
"summary": { "type": "string" }
}
},
"door.resolve": {
"type": "object",
"required": ["doorId", "decision"],
"properties": {
"doorId": { "type": "string" },
"decision": { "enum": ["approve", "deny"] },
"by": { "type": "string" }
}
},
"agent.message": {
"type": "object",
"required": ["fromAgentId", "toAgentId", "text"],
"properties": {
"fromAgentId": { "type": "string" },
"toAgentId": { "type": "string" },
"text": { "type": "string" },
"ts": { "type": "string", "format": "date-time" }
}
},
"world.touch": {
"type": "object",
"description": "An agent is converging on a project/service/event node (Gource). Drives the Live canvas retarget + beam.",
"required": ["agentId", "nodeId"],
"properties": {
"agentId": { "type": "string" },
"nodeId": { "type": "string" },
"kind": { "enum": ["service", "event"], "default": "service" },
"weight": { "type": "number", "minimum": 0, "maximum": 1, "default": 1 }
}
},
"node.activity": {
"type": "object",
"required": ["nodeId"],
"properties": {
"nodeId": { "type": "string" },
"label": { "type": "string" },
"kind": { "enum": ["service", "event"] },
"heat": { "type": "number", "minimum": 0, "maximum": 1 }
}
},
"topology.update": {
"type": "object",
"description": "Full or partial re-layout of the world graph.",
"required": ["formation"],
"properties": {
"formation": { "enum": ["hierarchy", "flat", "live"] },
"nodes": {
"type": "array",
"items": {
"type": "object",
"required": ["id", "tier"],
"properties": {
"id": { "type": "string" },
"tier": { "enum": ["org", "company", "team", "agent", "service", "event"] },
"label": { "type": "string" },
"parentId": { "type": "string" }
}
}
},
"edges": {
"type": "array",
"items": {
"type": "object",
"required": ["from", "to"],
"properties": {
"from": { "type": "string" },
"to": { "type": "string" },
"kind": { "enum": ["parent", "peer", "flow"], "default": "parent" }
}
}
}
}
},
"telemetry": {
"type": "object",
"properties": {
"tokensPerMin": { "type": "number" },
"costPerHr": { "type": "number" },
"loops": { "type": "integer" },
"doorsPending": { "type": "integer" }
}
},
"routine.update": {
"type": "object",
"required": ["routineId", "name", "kind"],
"properties": {
"routineId": { "type": "string" },
"name": { "type": "string" },
"kind": { "enum": ["cron", "loop"] },
"owner": { "type": "string" },
"schedule": { "type": "string", "description": "cron expr or next-run hint" },
"progress": { "type": "number", "minimum": 0, "maximum": 1 },
"state": { "enum": ["running", "scheduled", "done", "failed", "door"] }
}
}
}
}