docs/00-shared-contract.md
Shared Contract (Build Alignment)
Use this as the single source of truth for runtime ↔ provider ↔ UI integration.
Versioning
contractVersion = "1"(required in run state).- Breaking changes require a new version and a migration note.
Identifiers & time
runId,nodeId,edgeId,payloadId,artifactId: UUID strings.- All timestamps are ISO-8601 UTC.
Event envelope (shared)
Every event must include these fields:
{
"id": "event-uuid",
"runId": "run-uuid",
"ts": "2026-01-01T00:00:00Z",
"type": "event.type",
"nodeId": "optional-node-uuid"
}
Event logs are append-only JSONL files at dataDir/runs/<runId>/events.jsonl.
Run state (minimum fields)
{
"id": "run-uuid",
"contractVersion": "1",
"status": "queued | running | paused | stopped | completed | failed",
"mode": "AUTO | INTERACTIVE",
"globalMode": "PLANNING | IMPLEMENTATION",
"createdAt": "2026-01-01T00:00:00Z",
"updatedAt": "2026-01-01T00:00:00Z",
"nodes": { "nodeId": { "...": "..." } },
"nodeConfigs": { "nodeId": { "...": "..." } },
"edges": { "edgeId": { "...": "..." } },
"artifacts": { "artifactId": { "...": "..." } }
}
Run snapshots are stored at dataDir/runs/<runId>/state.json.
Node state
{
"id": "node-uuid",
"runId": "run-uuid",
"label": "Implementer A",
"roleTemplate": "implementer",
"provider": "codex | claude | gemini | custom",
"status": "idle | running | blocked | failed",
"summary": "short live status",
"lastActivityAt": "2026-01-01T00:00:00Z",
"capabilities": {
"edgeManagement": "none",
"writeCode": true,
"writeDocs": true,
"runCommands": true,
"delegateOnly": false
},
"permissions": {
"cliPermissionsMode": "skip | gated",
"agentManagementRequiresApproval": true
},
"session": {
"sessionId": "provider-session-id",
"resetCommands": ["/new", "/clear"]
}
}
Edge state
{
"id": "edge-uuid",
"from": "node-a",
"to": "node-b",
"bidirectional": true,
"type": "handoff | report",
"label": "task | report | custom"
}
Defaults:
- Orchestrator -> node:
type = handoff,label = "task". - Node -> orchestrator:
type = report,label = "report".
Envelope (handoff payload)
{
"kind": "handoff",
"id": "payload-uuid",
"fromNodeId": "node-a",
"toNodeId": "node-b",
"createdAt": "2026-01-01T00:00:00Z",
"payload": {
"message": "short summary",
"structured": { "key": "value" },
"artifacts": [
{ "type": "diff", "ref": "artifact://diff/123" }
],
"status": { "ok": true, "reason": "tests-pass" },
"response": { "expectation": "optional", "replyTo": "node-a" }
}
}
Artifacts
{
"id": "artifact-uuid",
"runId": "run-uuid",
"nodeId": "node-uuid",
"kind": "diff | prompt | log | transcript | contextpack | report",
"name": "diff.patch",
"path": "/abs/path/to/file",
"createdAt": "2026-01-01T00:00:00Z"
}
Prompt artifacts are required per turn:
prompt.full.txtprompt.blocks.json
Diff artifacts are emitted when available.
Tool event payloads (minimum)
{
"type": "tool.proposed",
"nodeId": "node-uuid",
"tool": { "id": "tool-uuid", "name": "command", "args": { "cmd": "..." } }
}
{
"type": "tool.completed",
"nodeId": "node-uuid",
"toolId": "tool-uuid",
"result": { "ok": true },
"error": { "message": "optional" }
}
Approval contract
cliPermissionsMode = skip | gatedagentManagementRequiresApprovalapplies tospawn_nodeandcreate_edge.
Approval event payloads (minimum)
{
"type": "approval.requested",
"approvalId": "approval-uuid",
"nodeId": "node-uuid",
"tool": { "id": "tool-uuid", "name": "command", "args": { "cmd": "..." } },
"context": "optional"
}
{
"type": "approval.resolved",
"approvalId": "approval-uuid",
"resolution": { "status": "approved | denied | modified", "modifiedArgs": { } }
}
Loop safety contract
- Stall detection on repeated output/diff/verification signals.
- On stall: pause run and emit
run.stalledwith evidence.
Event stream (WS)
Consumers must support:
run.patch,run.mode,run.stallednode.patch,node.progress,node.heartbeat,node.log,node.deleted,turn.statusedge.created,edge.deletedhandoff.sentmessage.user,message.assistant.delta,message.assistant.finalmessage.assistant.thinking.delta,message.assistant.thinking.finaltool.proposed,tool.started,tool.completedapproval.requested,approval.resolvedartifact.createdtelemetry.usage
Minimal REST endpoints
POST /api/runsGET /api/runs/GET /api/runs/:idPATCH /api/runs/:id/DELETE /api/runs/:idGET /api/runs/:id/events(paged; supportslimitandbefore, returnspage.nextCursor+page.hasMore)POST /api/runs/:id/nodesPATCH /api/runs/:id/nodes/:nodeIdDELETE /api/runs/:id/nodes/:nodeIdPOST /api/runs/:id/edgesDELETE /api/runs/:id/edges/:edgeIdPOST /api/runs/:id/chatGET /api/approvals/POST /api/approvals/:id/resolve
