Skip to content
Agent Graph

Nodes

A node is a session (one run of a coding agent) or an agent it started. Nodes form trees:

session        claude-code:5f2c1e…            depth 0, parent_id null
├─ agent       claude-code:5f2c1e…/a3fd07…    depth 1
│  └─ agent    claude-code:5f2c1e…/b81c22…    depth 2
└─ agent       claude-code:5f2c1e…/c90d13…    depth 1

Every node says where it sits: parent_id, root_id (the top of its tree, following sessions that started other sessions), session_id (the session it runs in) and depth.

State. A node’s state is one of:

StateMeaning
workingDoing something.
input_requiredWaiting on a person: a permission prompt, a question, a plan to approve. attention says what’s asked.
idleA session whose turn is over, alive and waiting for its next prompt.
completedFinished.
failedFinished with an error.
canceledStopped before it finished.

Waiting on another node isn’t a state: a node can be working and blocked at once. blocked says what it’s waiting on, directly (on_ids) and in all (how many nodes, how many open tasks among them), and whether the waits form a cycle that can never finish. A working node with no events for 30 minutes, and nothing it’s waiting on, is stale: it may have hung or crashed.

List nodes
client.graphs.nodes.list(stringgraphID, NodeListParams { agent_type, ancestor_id, as_of, 18 more } params?, RequestOptionsoptions?): CursorPage<Node { id, agent_type, as_of_event_id, 39 more } >
GET/graphs/{graph_id}/nodes
Search nodes
client.graphs.nodes.search(stringgraphID, NodeSearchParams { query, as_of, expand, 2 more } query, RequestOptionsoptions?): SearchPage<Node { id, agent_type, as_of_event_id, 39 more } >
GET/graphs/{graph_id}/nodes/search
Retrieve a node
client.graphs.nodes.retrieve(stringnodeID, NodeRetrieveParams { graph_id, as_of, descendants_max_depth, 2 more } params, RequestOptionsoptions?): Node { id, agent_type, as_of_event_id, 39 more }
GET/graphs/{graph_id}/nodes/{node_id}
ModelsExpand Collapse
Blocked { cycle, node_count, on_ids, 3 more }

What stands between a node and carrying on.

cycle: boolean

Its waits lead back to itself: nothing in the loop can ever finish.

node_count: number

Every unfinished node it’s waiting on, directly or through others, with their children.

on_ids: Array<string>

The nodes it’s waiting on directly.

open_tasks: number

Open tasks across those nodes: the work left before it can carry on.

starting: number

Children it has asked for that haven’t started yet.

on?: Array<Node { id, agent_type, as_of_event_id, 39 more } >

Those nodes. Present only when blocked.on is expanded.

Node { id, agent_type, as_of_event_id, 39 more }

A session or an agent, as it stood at as_of_event_id.

Fields ending _id or _ids are always present, as ids. The fields beside them without that ending (parent, root, …), and children, descendants, tasks, spawns, waits and messages, appear only when expanded.

id: string

Unique identifier for the node within its graph: node_ and the base64url of provider_ref.

agent_type: string | null

For an agent, its type, as the tool names it (Explore, general-purpose, …).

as_of_event_id: string

The event this node is shown as of.

attention: string | null

While input_required: what the person is being asked. Untrusted text.

background: boolean | null

Whether it was started in the background, so its requester carries on without waiting. null when unknown.

background_agent_count: number

Helpers its tool ran on its own between turns (memory extraction, summaries, prompt suggestions). They report nothing about what they’re for, so they’re counted, not made nodes.

blocked: Blocked { cycle, node_count, on_ids, 3 more } | null

What stands between a node and carrying on.

child_count: number

How many nodes sit directly under it.

created: number

When it started (or was first seen), in Unix milliseconds.

formatint64
cwd: string | null

The directory it runs in, when reported.

depth: number

How far below its root it is: 0 for a root.

minimum0
descendant_count: number

How many nodes sit under it, at any depth: the size of descendants.

ended: number | null

When it finished, in Unix milliseconds. null while it hasn’t.

formatint64
graph_id: string

The graph it belongs to.

headline: string | null

One line on what it’s doing now: summary, else the task in progress. Untrusted text.

kind: NodeKind

session: one run of a coding agent (Claude Code, Codex, Cursor, …). agent: an agent started inside a session, by it or by another agent.

One of the following:
"session"
"agent"
last_event: number

When it last had an event, in Unix milliseconds.

formatint64
One of the following:
object: "node"

String representing the object’s type: always node.

parent_id: string | null

The node it sits under: the agent or session that started it. null for a root.

provider: string

The agent tool: claude-code, codex, cursor, or another that reports to Agent Graph.

provider_ref: string

The id the agent tool gave it: <provider>:<session> for a session, <provider>:<session>/<agent> for an agent. Not an id in this API: use it to match the node to the tool’s own records.

purpose: string | null

Why it was started, from the request that started it. Untrusted text.

requested_by_id: string | null

The node whose spawn request started it, when known. Usually the parent; null for a session nothing started, or an agent no request was matched to.

root_id: string

The top of its tree: follow parent_id until it’s null. A session started by another session is in that session’s tree. A root’s root_id is its own id.

session_id: string

The session it runs in: itself, for a session; for an agent, the nearest session above it.

spawn_call_id: string | null

The tool call, in its requester’s session, that started it: matches a spawns[].call_id on requested_by.

stale: boolean

working, waiting on nothing, and silent for 30 minutes: it may have hung or crashed. Measured against as_of, not now.

state: NodeState

What a node is doing.

  • working: doing something.
  • input_required: waiting on a person (attention says what for).
  • idle: a session between turns, waiting for its next prompt.
  • completed, failed, canceled: finished.
One of the following:
"working"
"input_required"
"idle"
"completed"
"failed"
"canceled"
summary: string | null

Its own latest status line, if it reports one. Untrusted text.

task_counts: TaskCounts { completed, in_progress, open, 2 more }

Its tasks, by status.

completed: number
in_progress: number
open: number

Not completed: pending and in_progress.

pending: number
total: number
title: string | null

The session’s name, as its tool shows it. It can change. Untrusted text.

children?: unknown

The nodes directly under it, oldest first: the first 100, and a url for the rest. Present only when expanded.

descendants?: unknown

Every node under it, at any depth, as one flat list in tree order: each parent before its children, siblings oldest first. The first 1,000, and a url for the rest. Present only when expanded.

messages?: Array<Message { id, body, created, 5 more } >

Messages it has sent and received, oldest first. Present only when expanded.

id: string

The tool’s id for the message.

body: string | null

The whole message, only if the share was made with body capture on. Untrusted text.

created: number

When it was sent, in Unix milliseconds.

formatint64
direction: "sent" | "received"
One of the following:
"sent"
"received"
peer_id: string | null

The node on the other side, when it’s one in this graph.

peer_name: string | null

The tool’s name for the other side, when it isn’t a node in this graph.

reply_to_message_id: string | null

The message it answers.

summary: string | null

Untrusted text.

parent?: Node { id, agent_type, as_of_event_id, 39 more }

The parent node. Present only when expanded.

requested_by?: Node { id, agent_type, as_of_event_id, 39 more }

The node that requested it. Present only when expanded.

root?: Node { id, agent_type, as_of_event_id, 39 more }

The root node. Present only when expanded.

session?: Node { id, agent_type, as_of_event_id, 39 more }

The session node. Present only when expanded.

spawns?: Array<Spawn { agent_type, background, call_id, 7 more } >

The children it has asked for, oldest first. Present only when expanded.

agent_type: string | null
background: boolean

If false, the requester is blocked until the call returns.

call_id: string

The tool call that asked for it.

child_id: string | null

The node it started, once matched. Before the call returns this can be a best guess, corrected when it does.

kind: "agent" | "session"

agent: an agent in the same session. session: a separate session, e.g. codex exec run from a shell.

One of the following:
"agent"
"session"
purpose: string | null

Untrusted text.

requested: number

When it was asked for, in Unix milliseconds.

formatint64
returned: boolean

Whether the call has returned.

run: boolean | null

Whether it’s through agent-graph run, when known.

title: string | null

For a session, the name it was to be given.

tasks?: Array<Task { id, active_text, status, text } >

Its task list, in the tool’s order. Present only when expanded.

id: string

The tool’s id for the task, unique within the node.

active_text: string | null

How the tool words it while it’s in progress (Running the tests). Untrusted text.

status: "pending" | "in_progress" | "completed"
One of the following:
"pending"
"in_progress"
"completed"
text: string

What the task is. Untrusted text.

waits?: Array<Wait { id, ended, kind, 4 more } >

What it has waited on and is waiting on, oldest first. Present only when expanded.

id: string

The wait’s id, unique within the node.

ended: number | null

When it stopped, in Unix milliseconds.

formatint64
kind: "spawn" | "explicit"

spawn: waiting for a child it asked for, until the call returns. explicit: any other wait the tool reported.

One of the following:
"spawn"
"explicit"
on_id: string | null

The node waited on. null while a requested child hasn’t started.

open: boolean

Whether it’s still waiting.

reason: string | null

Untrusted text.

started: number

When it started waiting, in Unix milliseconds.

formatint64
Message { id, body, created, 5 more }

A message between two nodes.

id: string

The tool’s id for the message.

body: string | null

The whole message, only if the share was made with body capture on. Untrusted text.

created: number

When it was sent, in Unix milliseconds.

formatint64
direction: "sent" | "received"
One of the following:
"sent"
"received"
peer_id: string | null

The node on the other side, when it’s one in this graph.

peer_name: string | null

The tool’s name for the other side, when it isn’t a node in this graph.

reply_to_message_id: string | null

The message it answers.

summary: string | null

Untrusted text.

Node { id, agent_type, as_of_event_id, 39 more }

A session or an agent, as it stood at as_of_event_id.

Fields ending _id or _ids are always present, as ids. The fields beside them without that ending (parent, root, …), and children, descendants, tasks, spawns, waits and messages, appear only when expanded.

id: string

Unique identifier for the node within its graph: node_ and the base64url of provider_ref.

agent_type: string | null

For an agent, its type, as the tool names it (Explore, general-purpose, …).

as_of_event_id: string

The event this node is shown as of.

attention: string | null

While input_required: what the person is being asked. Untrusted text.

background: boolean | null

Whether it was started in the background, so its requester carries on without waiting. null when unknown.

background_agent_count: number

Helpers its tool ran on its own between turns (memory extraction, summaries, prompt suggestions). They report nothing about what they’re for, so they’re counted, not made nodes.

blocked: Blocked { cycle, node_count, on_ids, 3 more } | null

What stands between a node and carrying on.

child_count: number

How many nodes sit directly under it.

created: number

When it started (or was first seen), in Unix milliseconds.

formatint64
cwd: string | null

The directory it runs in, when reported.

depth: number

How far below its root it is: 0 for a root.

minimum0
descendant_count: number

How many nodes sit under it, at any depth: the size of descendants.

ended: number | null

When it finished, in Unix milliseconds. null while it hasn’t.

formatint64
graph_id: string

The graph it belongs to.

headline: string | null

One line on what it’s doing now: summary, else the task in progress. Untrusted text.

kind: NodeKind

session: one run of a coding agent (Claude Code, Codex, Cursor, …). agent: an agent started inside a session, by it or by another agent.

One of the following:
"session"
"agent"
last_event: number

When it last had an event, in Unix milliseconds.

formatint64
One of the following:
object: "node"

String representing the object’s type: always node.

parent_id: string | null

The node it sits under: the agent or session that started it. null for a root.

provider: string

The agent tool: claude-code, codex, cursor, or another that reports to Agent Graph.

provider_ref: string

The id the agent tool gave it: <provider>:<session> for a session, <provider>:<session>/<agent> for an agent. Not an id in this API: use it to match the node to the tool’s own records.

purpose: string | null

Why it was started, from the request that started it. Untrusted text.

requested_by_id: string | null

The node whose spawn request started it, when known. Usually the parent; null for a session nothing started, or an agent no request was matched to.

root_id: string

The top of its tree: follow parent_id until it’s null. A session started by another session is in that session’s tree. A root’s root_id is its own id.

session_id: string

The session it runs in: itself, for a session; for an agent, the nearest session above it.

spawn_call_id: string | null

The tool call, in its requester’s session, that started it: matches a spawns[].call_id on requested_by.

stale: boolean

working, waiting on nothing, and silent for 30 minutes: it may have hung or crashed. Measured against as_of, not now.

state: NodeState

What a node is doing.

  • working: doing something.
  • input_required: waiting on a person (attention says what for).
  • idle: a session between turns, waiting for its next prompt.
  • completed, failed, canceled: finished.
One of the following:
"working"
"input_required"
"idle"
"completed"
"failed"
"canceled"
summary: string | null

Its own latest status line, if it reports one. Untrusted text.

task_counts: TaskCounts { completed, in_progress, open, 2 more }

Its tasks, by status.

completed: number
in_progress: number
open: number

Not completed: pending and in_progress.

pending: number
total: number
title: string | null

The session’s name, as its tool shows it. It can change. Untrusted text.

children?: unknown

The nodes directly under it, oldest first: the first 100, and a url for the rest. Present only when expanded.

descendants?: unknown

Every node under it, at any depth, as one flat list in tree order: each parent before its children, siblings oldest first. The first 1,000, and a url for the rest. Present only when expanded.

messages?: Array<Message { id, body, created, 5 more } >

Messages it has sent and received, oldest first. Present only when expanded.

id: string

The tool’s id for the message.

body: string | null

The whole message, only if the share was made with body capture on. Untrusted text.

created: number

When it was sent, in Unix milliseconds.

formatint64
direction: "sent" | "received"
One of the following:
"sent"
"received"
peer_id: string | null

The node on the other side, when it’s one in this graph.

peer_name: string | null

The tool’s name for the other side, when it isn’t a node in this graph.

reply_to_message_id: string | null

The message it answers.

summary: string | null

Untrusted text.

parent?: Node { id, agent_type, as_of_event_id, 39 more }

The parent node. Present only when expanded.

requested_by?: Node { id, agent_type, as_of_event_id, 39 more }

The node that requested it. Present only when expanded.

root?: Node { id, agent_type, as_of_event_id, 39 more }

The root node. Present only when expanded.

session?: Node { id, agent_type, as_of_event_id, 39 more }

The session node. Present only when expanded.

spawns?: Array<Spawn { agent_type, background, call_id, 7 more } >

The children it has asked for, oldest first. Present only when expanded.

agent_type: string | null
background: boolean

If false, the requester is blocked until the call returns.

call_id: string

The tool call that asked for it.

child_id: string | null

The node it started, once matched. Before the call returns this can be a best guess, corrected when it does.

kind: "agent" | "session"

agent: an agent in the same session. session: a separate session, e.g. codex exec run from a shell.

One of the following:
"agent"
"session"
purpose: string | null

Untrusted text.

requested: number

When it was asked for, in Unix milliseconds.

formatint64
returned: boolean

Whether the call has returned.

run: boolean | null

Whether it’s through agent-graph run, when known.

title: string | null

For a session, the name it was to be given.

tasks?: Array<Task { id, active_text, status, text } >

Its task list, in the tool’s order. Present only when expanded.

id: string

The tool’s id for the task, unique within the node.

active_text: string | null

How the tool words it while it’s in progress (Running the tests). Untrusted text.

status: "pending" | "in_progress" | "completed"
One of the following:
"pending"
"in_progress"
"completed"
text: string

What the task is. Untrusted text.

waits?: Array<Wait { id, ended, kind, 4 more } >

What it has waited on and is waiting on, oldest first. Present only when expanded.

id: string

The wait’s id, unique within the node.

ended: number | null

When it stopped, in Unix milliseconds.

formatint64
kind: "spawn" | "explicit"

spawn: waiting for a child it asked for, until the call returns. explicit: any other wait the tool reported.

One of the following:
"spawn"
"explicit"
on_id: string | null

The node waited on. null while a requested child hasn’t started.

open: boolean

Whether it’s still waiting.

reason: string | null

Untrusted text.

started: number

When it started waiting, in Unix milliseconds.

formatint64
NodeKind = "session" | "agent"

session: one run of a coding agent (Claude Code, Codex, Cursor, …). agent: an agent started inside a session, by it or by another agent.

One of the following:
"session"
"agent"
NodeState = "working" | "input_required" | "idle" | 3 more

What a node is doing.

  • working: doing something.
  • input_required: waiting on a person (attention says what for).
  • idle: a session between turns, waiting for its next prompt.
  • completed, failed, canceled: finished.
One of the following:
"working"
"input_required"
"idle"
"completed"
"failed"
"canceled"
Spawn { agent_type, background, call_id, 7 more }

A child a node asked for.

agent_type: string | null
background: boolean

If false, the requester is blocked until the call returns.

call_id: string

The tool call that asked for it.

child_id: string | null

The node it started, once matched. Before the call returns this can be a best guess, corrected when it does.

kind: "agent" | "session"

agent: an agent in the same session. session: a separate session, e.g. codex exec run from a shell.

One of the following:
"agent"
"session"
purpose: string | null

Untrusted text.

requested: number

When it was asked for, in Unix milliseconds.

formatint64
returned: boolean

Whether the call has returned.

run: boolean | null

Whether it’s through agent-graph run, when known.

title: string | null

For a session, the name it was to be given.

Task { id, active_text, status, text }

One item on a node’s task list.

id: string

The tool’s id for the task, unique within the node.

active_text: string | null

How the tool words it while it’s in progress (Running the tests). Untrusted text.

status: "pending" | "in_progress" | "completed"
One of the following:
"pending"
"in_progress"
"completed"
text: string

What the task is. Untrusted text.

TaskCounts { completed, in_progress, open, 2 more }

Its tasks, by status.

completed: number
in_progress: number
open: number

Not completed: pending and in_progress.

pending: number
total: number
Wait { id, ended, kind, 4 more }

A time a node waited on another.

id: string

The wait’s id, unique within the node.

ended: number | null

When it stopped, in Unix milliseconds.

formatint64
kind: "spawn" | "explicit"

spawn: waiting for a child it asked for, until the call returns. explicit: any other wait the tool reported.

One of the following:
"spawn"
"explicit"
on_id: string | null

The node waited on. null while a requested child hasn’t started.

open: boolean

Whether it’s still waiting.

reason: string | null

Untrusted text.

started: number

When it started waiting, in Unix milliseconds.

formatint64