Repository navigation
Expose the lineage tree (siblings, children, live roots) to routes, not only the request's own chain #457
Description
Problem
Since #421/#444, (await agent()).lineage answers "who is my parent, what is my root, am I a subagent" for the current request. It does not answer the other half of "where am I in the agent topology": who else is alive under my root (siblings), what did I spawn (children), and which other root conversations are live in this workspace.
A plugin that coordinates agent threads (the examples/worktree-proximity pattern: one root, several subagents in linked worktrees, warn/notify the other actor) therefore still has to hand-roll a topology state definition and feed it from session/start + agent/start + stop itself, even though the warm runtime already keeps exactly that tree in the agent lineage registry. The example does not use request.lineage at all (zero references under examples/worktree-proximity/src), because the axis cannot tell it who its peers are.
Evidence (main @ 284141958)
packages/rsc-runtime/src/agent-request.ts:113-123—AgentLineageis{ conversation, depth, generation?, parent?, resolution, root, subagent? }: the request's own chain only.packages/rsc-runtime/src/lineage/state.ts:10-32, 49-66— the registry already journals every node (id,parent,root,depth,startedAt,stoppedAt,type,isParallelWorker) inLineageState.nodes.packages/rsc-runtime/src/lineage/registry.ts:48-60—AgentLineageRegistry.snapshot()is documented as "for dumps and the Workbench";packages/agent-bundle/src/build/entry-shell.ts:1028-1041hands the registry only tocreateGeneratedRouteMcpServer. No route surface (agent(), providers, services) can reach it.examples/worktree-proximity/src/state.ts:93-165— the hand-rolledtopologyStateDefinition(actors withkind: root|child,parentSessionId,status), fed bysrc/events/session/start.tsx,src/events/agent/start.tsx,src/events/stop.tsx.examples/worktree-proximity/README.md:47-49: "one workspace-durable topology definition and the framework notice definition share the generated runtime's SQLite driver";README.md:70-81documents the per-app actor bookkeeping this forces (native vs derived provenance,worktree:<root>fallback identity).- Add typed Agent request context and pluggable context providers #95 listed "a built-in thread-topology algorithm" as a non-goal; feat(lineage): host-test probe, live host lineage matrix, and runtime-held request.lineage #421 then built the registry anyway to serve
request.lineage. This issue asks only to read what that registry already holds — no new inference.
Proposed shape (small)
Extend the axis rather than adding a new one, so unavailability semantics stay identical:
interface AgentLineage {
// …existing fields…
/** Live nodes the registry currently holds under the same root, excluding this conversation. */
readonly siblings?: readonly AgentLineagePeer[];
/** Live nodes whose parent is this conversation. */
readonly children?: readonly AgentLineagePeer[];
/** Other live depth-0 conversations the registry holds (same workspace digest on Cursor). */
readonly roots?: readonly AgentLineagePeer[];
}
interface AgentLineagePeer {
readonly conversation: string;
readonly depth: number;
readonly parent?: string;
readonly startedAt: string;
readonly type?: string;
}Fed from LineageState.nodes at resolve time (registry.ts resolve() / resolveToolCall()), pruned to stoppedAt === undefined. Alternative: a separate (await agent()).lineageTree() read so the per-request axis stays small; either is fine, the point is that routes can read the tree the runtime already keeps.
Design question: should roots be exposed at all (it crosses conversations that share nothing but an install), or only siblings/children under the caller's own root?
Out of scope / related
- Host-side gaps in building the tree stay on Claude Code 2.1.257 lineage gaps: SubagentStart names no parent; a subagent's hooks name no parent #422 / Codex 0.147.0 lineage gaps: SubagentStart names no parent thread; hooks lag the MCP _meta lineage #423 / Cursor 3.18.25 lineage gaps: subagentStart omits the child conversation id; child hooks carry no parent/root; MCP _meta carries no conversation; sessionStart not dispatched to plugin hooks on desktop #424.
- Addressing a notice at one of these peers is a separate issue (see "Related" comment below); this one is read-only.
- No operator/user identity (Actor principal for generated event scopes: typed unavailable reasons and the one derivable host field (parked from #233/#223) #391 decision, feat(lineage): request.lineage is the only identity-adjacent surface; scoped, self-correcting Cursor child binding #444).
Acceptance
In examples/worktree-proximity: delete src/state.ts's actor bookkeeping (keep activities/intent), and have src/events/tool/before.tsx find the other actor's conversation through lineage.siblings instead of topology.actors; the existing route-unit journeys 1–6 in tests/route-unit/routes.test.ts and the cross-process suite packages/agent-bundle/tests/worktree-proximity-journeys.test.ts still pass, and a new test proves a child sees its sibling after two agent/start events and stops seeing it after the sibling's agent/stop.
Activity
ScriptedAlchemy commentedon Sep 3, 2026
Related (lineage/proximity batch from
examples/worktree-proximityREADME limitations): #458 (address a notice at a lineage conversation), #459 (providers see lineage/state), #460 (publisher-scoped notice visibility). Superseded/covered elsewhere: actor principal for event scopes → #391 (not planned) / #444;useWorktree()→useAgent()since #402.chore(examples): use built-in framework surface over hand-rolled setup (
feat(lineage): expose the live agent tree (siblings, children, roots)…
feat(lineage): expose the live agent tree (siblings, children, roots)…
feat(lineage): expose the live agent tree (siblings, children, roots)…