Skip to main content
Every run writes its output into a canvas — a directed graph of blocks (documents, spreadsheets, research notes, images, etc.) linked by dependency edges. The SDK exposes three read-only introspection methods so you can audit exactly what a run produced.

The block graph

dag = client.canvas.get_dag(handle.canvas_id)

for node in dag.nodes:
    print(f"{node.type:24} {node.status:10} {node.name}")

for edge in dag.edges:
    print(f"{edge.source_id} -> {edge.target_id}")
Each CanvasNode exposes:
FieldDescription
idUUID of the block.
nameHuman-readable block name.
typeBlock type (e.g. document-block, excel-block).
statusCurrent state (idle, running, completed, error, …).
contentTextual content, when applicable.
urlExternal or pre-signed download URL, when applicable.
sourcesSource attributions (block-type specific).

The task tree

The task tree describes the agent execution that produced the canvas — parent tasks, persona tasks, individual tool calls. It is split into completed and in-progress subtrees:
tree = client.canvas.get_tasks(handle.canvas_id)

def print_tree(tasks, indent=0):
    for t in tasks:
        print("  " * indent + f"- {t.name} ({t.task_type}, {t.status})")
        if t.children:
            print_tree(t.children, indent + 1)

print("Completed:")
print_tree(tree.completed)
print("In progress:")
print_tree(tree.not_completed)

A single task

If you already have a task id (from a progress webhook or a previous tree), fetch just that one with its immediate children:
task = client.canvas.get_task(handle.canvas_id, "task-abc")
print(task.status, task.name)

Async versions

Every method above has an async twin on AsyncSpineClient:
dag = await async_client.canvas.get_dag(canvas_id)
tree = await async_client.canvas.get_tasks(canvas_id)
task = await async_client.canvas.get_task(canvas_id, task_id)