REST API: ScaiCore
Live event stream, checkpoint listing + resolution, and an invoke proxy. All proxied to ScaiGrid using the same auth precedence as the lookups.
GET /v1/scaicore/events#
Paginated event stream from GET /v1/modules/scaicore/events on ScaiGrid. Used by the canvas Live Runs panel.
Query:
core_id— filter to one Core's events.limit— page size, default 50, max 500.cursor— opaque cursor for the next page.
Response:
{
"data": {
"events": [
{ "type": "scaicore.runtime.invocation.started",
"core_id": "core_xxx",
"timestamp": "2026-04-29T12:34:56Z",
"payload": {
"execution_id": "exec_xxx",
"input": { "message": "hello" },
"node_id": null
} },
{ "type": "scaicore.runtime.block.entered",
"core_id": "core_xxx",
"timestamp": "2026-04-29T12:34:57Z",
"payload": {
"execution_id": "exec_xxx",
"node_id": "node_classify",
"block_kind": "flexible"
} }
],
"next_cursor": "..."
}
}
Event payloads pass through verbatim — the proxy doesn't reshape them. New fields the runtime adds (e.g. source_location.node_id when populated) are forwarded as-is.
Built-in runtime events (closed set)#
ScaiCore auto-fires 6 events per invocation (no @emit needed):
scaicore.runtime.invocation.started— carriesinput, optionalinstance_key.scaicore.runtime.invocation.completed— carriesoutput,duration_ms, optionalinstance_key.scaicore.runtime.invocation.failed— carries error info.scaicore.runtime.block.entered— carriesblock_kind(one of 14 IR kinds),node_id.scaicore.runtime.block.exited— carriesresult_binding,result_binding_value(≤4 KB JSON;result_binding_truncated: trueotherwise).scaicore.runtime.block.failed— carries error info,block_kind,node_id.
Flow authors can emit their own @emit events alongside these.
scaicore:view.
GET /v1/scaicore/checkpoints#
List ScaiCore checkpoints. Used by the canvas to surface paused executions (HITL Reviews + debug breakpoints).
Query:
core_id— filter to one Core's checkpoints.status— defaultspending. Other values:resolved,failed.limit— page size, default 50, max 500.
Response:
{
"data": {
"checkpoints": [
{ "id": "ckpt_xxx",
"core_id": "core_xxx",
"checkpoint_type": "hitl_review", // or "debug_breakpoint", "approval", ...
"status": "pending",
"presentation": { "title": "Review needed", "message": "..." },
"options": ["approve", "reject"],
"created_at": "2026-04-29..." }
],
"next_cursor": "..."
}
}
The checkpoint_type discriminator lets the canvas render different CTAs for hitl_review (form-based decision) vs. debug_breakpoint (just a Continue button).
scaicore:view.
POST /v1/scaicore/checkpoints/{checkpoint_id}/resolve#
Resolve a paused checkpoint. Resumes the suspended execution.
Body:
{
"resolution": "approve", // for HITL: one of the decision section's option ids
// for debug_breakpoint: "continue"
"comment": "Within budget." // optional
}
Response: the resolved Checkpoint.
scaicore:manage (resuming has side effects — LLM calls, plugin calls, etc.).
POST /v1/scaicore/cores/{core_id}/invoke#
Invoke a deployed Core directly. Used by the canvas Live Runs panel's "↻ replay" button — extracts the captured input from an invocation.started event payload and fires it again.
Body:
{
"input": { "message": "..." },
"entity_id": "user_xxx" // optional, for entity-mode Cores
}
Response: ScaiCore's InvokeResponse:
{
"output": { /* flow-defined */ },
"request_id": "req_xxx",
"duration_ms": 412
}
scaicore:manage (invocations have side effects).
Notes on the canvas integration#
- The Live Runs panel polls
GET /v1/scaicore/eventsevery 5 s while open, using a monotonicnextFetchto drop out-of-order responses. - Per-event
payload.node_id(top-level) is what the canvas reads to correlate events back to canvas nodes. The runtime populates it from each block'ssource_location.node_id— which the compiler writes for every block we emit. - The visual debugger overlay groups events by
execution_idand computes per-nodeNodeRunInfo(entered → blue, exited → green, failed → red) from the event stream.