Skip to content

Add subagent tree visualization for agent feed (#3932) - #3964

Closed
austinywang wants to merge 54 commits into
mainfrom
issue-3932-subagent-tree-viz
Closed

austinywang wants to merge 54 commits into
mainfrom
issue-3932-subagent-tree-viz

Conversation

@austinywang

@austinywang austinywang commented May 12, 2026 •

Copy link
Copy Markdown
Contributor

Closes #3932

Proposal

This issue leaves the source of truth and surface open, so this PR takes a first-pass slice through the existing Feed workstream path rather than adding a second live agent store. Agent hook events already carry session, workspace, status, tool-use, and focus metadata; the Feed now derives a tree snapshot from those immutable workstream items.

First-pass change

  • Preserve workspace and extra hook metadata on WorkstreamItem so explicit parent/child IDs can flow through from agents that emit them.
  • Add a WorkstreamAgentGraphBuilder that links explicit parent metadata and represents Task/Agent tool-use events as spawn-request child nodes when no child session ID is known yet.
  • Add a Feed sidebar Tree mode with expandable rows, status/type/model chips, task descriptions, and click-to-focus through the existing FeedJumpResolver.
  • Add CMUXWorkstream coverage for Task tool spawn rows and explicit parent metadata links.

Notes

This intentionally does not introduce a dedicated cross-workspace graph store yet. A later SDK/harness event can feed the same metadata keys (parent_workstream_id, child_workstream_id, subagent_type, model) and the UI will upgrade from spawn requests to concrete child session nodes.


Note

Medium Risk
Medium risk because it introduces a new agent-graph derivation pipeline and persists additional sanitized metadata (workspaceId/extraFieldsJSON) that influences UI linking and spawn pruning logic.

Overview
Adds a new Feed “Tree” mode that renders an expandable agent/subagent hierarchy with status/model/type chips, keyboard navigation, scroll-to-selection, and click-to-jump into the associated workstream.

Plumbs additional metadata through the pipeline: the CLI now copies parent/child/model/subagent fields into feed events, WorkstreamItem persists workspaceId plus a sanitized extraFieldsJSON, and FeedCoordinator includes workspace_id/extra_fields when serializing items.

Introduces WorkstreamAgentGraphBuilder (plus spawn-tool detection) to derive a WorkstreamAgentGraphSnapshot by linking explicit parent/child metadata and representing Task/Agent tool uses as pending spawn nodes, with pruning rules to avoid duplicating resolved children; adds focused unit tests and new EN/JA localization strings for the tree UI.

Reviewed by Cursor Bugbot for commit ab8f6a6. Bugbot is set up for automated code reviews on this repo. Configure here.


Summary by cubic

Adds a Tree view to the Feed to visualize parent/child agent sessions and pending spawns, with keyboard navigation, scroll-to, and click-to-focus. Plumbs workspace and sanitized extra metadata to build a reliable agent graph, adds paging, and includes performance/stability fixes; syncs ghostty and addresses #3932.

  • New Features

    • Agent Tree mode with expand/collapse, status/type/model chips, task snippets, keyboard + click-to-focus, and “Load older items.”
    • CMUXWorkstream agent graph builder links sessions via workstream/session IDs; shows spawn-request nodes for Task/Agent; shared spawn-tool detection; EN/JA strings.
    • Metadata plumbing: WorkstreamItem.workspaceId and sanitized extraFieldsJSON; CLI forwards parent/child/model/subagent fields; feed socket emits workspace_id and parsed extra_fields.
  • Bug Fixes

    • Centralized child linking; honor parent source; spawn reconciliation keeps ambiguous spawns and prunes only uniquely matched ones.
    • Correct metadata scoping/preservation: no parent model bleed; prefer spawn input model; keep session title/model/type/task and prompt metadata.
    • Stability/perf and navigation: idempotent keyboard focus registration with scoped snapshots, coalesced/deferred graph rebuilds, avoid invalidating inactive builds, panel-owned observation snapshot, empty-state fix, cleared stale selection, and retry focus registration if the coordinator isn’t available initially.

Written for commit ab8f6a6. Summary will update on new commits. Review in cubic

Summary by CodeRabbit

  • New Features

    • Agent Tree view to visualize agent/task hierarchies with selectable, collapsible rows, programmatic scrolling and keyboard focus bridge.
    • New Feed filter to toggle Agent Tree mode.
  • Improvements

    • Incremental agent-graph snapshot support with coordinated rebuilds and view-model integration.
    • Feed items now include workspace ID and sanitized extra-field metadata; socket payloads include workspace/extra_fields when present.
    • Public agent-graph types and spawn-tool detection added.
  • Tests

    • Added tests for graph construction, spawn/pruning, and metadata handling.
  • Localization

    • Added localized strings for Agent Tree UI (EN/JA).

Review Change Stack

@vercel

vercel Bot commented May 12, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
cmux Ready Ready Preview, Comment May 22, 2026 8:09pm
cmux-staging Building Building Preview, Comment May 22, 2026 8:09pm

@coderabbitai

coderabbitai Bot commented May 12, 2026 •

Copy link
Copy Markdown

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Builds an agent-tree feature: captures/sanitizes hook metadata, computes WorkstreamAgentGraphSnapshot from items, enriches CLI events with agent-graph fields, renders a collapsible Feed agent-tree, and wires async, cancellable graph builds with tests and localization.

Changes

Agent Tree Visualization

Layer / File(s) Summary
Agent Tree Data Models and Graph Building
Packages/CMUXWorkstream/Sources/CMUXWorkstream/WorkstreamAgentGraph.swift, Packages/CMUXWorkstream/Sources/CMUXWorkstream/WorkstreamAgentSpawnTool.swift
Public APIs define node kinds/status, WorkstreamAgentTreeNode, and WorkstreamAgentGraphSnapshot. WorkstreamAgentGraphBuilder.snapshot(from:) builds deduplicated trees from items, handles spawn-request nodes, prunes resolved spawns, and computes metrics.
Metadata Extraction and Store Sanitization
Packages/CMUXWorkstream/Sources/CMUXWorkstream/WorkstreamItem.swift, Packages/CMUXWorkstream/Sources/CMUXWorkstream/WorkstreamStore.swift, Sources/Feed/FeedCoordinator.swift
WorkstreamItem stores workspaceId and extraFieldsJSON (empty strings normalized to nil). WorkstreamStore sanitizes allowlisted extra fields and encodes a stable JSON string; feed serialization includes workspace_id and parsed extra_fields when available.
CLI Hook Enrichment and Compaction
CLI/cmux.swift
Expands Claude hook compaction aliases/keys and adds copyAgentGraphMetadata(to:rawObject:toolName:). Enrichment call sites updated to use the helper, which trims values, converts numbers to strings, conditionally parses tool_input for spawn tools, and copies prompt/message/agent graph identifiers when missing.
Tree View Rendering and Interaction
Sources/Feed/FeedAgentTreeView.swift
FeedAgentTreeView flattens snapshot roots respecting collapsed state and renders rows via FeedAgentTreeRowView with indentation guides, disclosure controls, status icons, metadata chips, help text, selection styling, and programmatic scroll/select behavior.
Controller and Keyboard Focus Bridge
Sources/Feed/FeedAgentTreeController.swift, Sources/Feed/FeedKeyboardFocusBridge.swift
FeedAgentTreeController manages collapsed state, selection, focus targets, and scroll requests. FeedKeyboardFocusBridge/FeedKeyboardFocusView handle AppKit keyboard events, focus ownership, and focus-snapshot propagation.
Panel Integration and Async Graph Builds
Sources/Feed/FeedPanelView.swift, Sources/Feed/FeedPanelViewModel.swift
Adds agentTree filter, wires agentGraphSnapshot to FeedListView, and implements sequence-based cancellable graph rebuilds in FeedPanelViewModel with scheduling/start/complete logic. Keyboard navigation and focus logic extended to support agent-tree targets.
Tests, Localization, and Project Configuration
Packages/CMUXWorkstream/Tests/CMUXWorkstreamTests/WorkstreamAgentGraphTests.swift, Resources/Localizable.xcstrings, GhosttyTabs.xcodeproj/project.pbxproj
New test suite validates spawn-request creation, parent-child linking, non-spawn behavior, and spawn-pruning rules. Localization keys added for the agent-tree filter, empty state, summary, expand/collapse, and status labels. Xcode project updated to include the tree view and the CMUXWorkstream dependency.

Sequence Diagram(s)

sequenceDiagram
  participant Store as WorkstreamStore
  participant ViewModel as FeedPanelViewModel
  participant Worker as FeedAgentGraphBuildWorker
  participant Builder as WorkstreamAgentGraphBuilder
  participant View as FeedAgentTreeView

  Store->>ViewModel: notify items updated
  ViewModel->>ViewModel: scheduleAgentGraphRebuild
  ViewModel->>Worker: snapshot(from: items)
  Worker->>Builder: compute snapshot(from: items)
  Builder->>Worker: return WorkstreamAgentGraphSnapshot
  Worker->>ViewModel: return snapshot
  ViewModel->>View: publish agentGraphSnapshot
  View->>View: flatten roots respecting collapsedNodeIds
  View->>View: render rows with status icons and chips
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • manaflow-ai/cmux#3057: Both PRs modify WorkstreamItem/WorkstreamStore and feed-hook handling for agent metadata propagation.
  • manaflow-ai/cmux#3252: Overlaps on CLI/cmux.swift event enrichment and tool_input parsing.

Poem

🐰 I nibble lines and stitch a branching tree,
Parents call tasks and children hop free,
Nodes hide, reveal, and carry model and name,
From hook to graph to view — the forest claims,
Hop, click, and follow every little frame.

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 2.38% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive PR description is comprehensive with sections for Proposal, First-pass change, and Notes, but lacks Testing and Demo Video sections required by the template. Add Testing section (how tested locally, what verified manually) and Demo Video URL/attachment. Both sections are part of the template and expected for this UI/behavior change.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Add subagent tree visualization for agent feed (#3932)' clearly and specifically describes the main change: a new Tree visualization feature for agents in the Feed sidebar.
Linked Issues check ✅ Passed The PR fulfills the core coding requirements from #3932: tree visualization with expandable rows, status/model/type chips, click-to-focus, keyboard navigation, and parent→child graph linking via explicit metadata and spawn-request nodes.
Out of Scope Changes check ✅ Passed All code changes are scoped to tree visualization, graph building, metadata preservation, and Feed sidebar updates directly addressing #3932; no unrelated changes detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch issue-3932-subagent-tree-viz

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@greptile-apps

greptile-apps Bot commented May 12, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds a Tree feed mode that derives a subagent hierarchy from existing workstream items, plumbs workspace and sanitized extra metadata through the stack, and introduces a graph builder that reconciles explicit parent/child links with Task/Agent tool-use spawn-request nodes.

  • Graph builder & metadata pipeline (WorkstreamAgentGraph.swift, WorkstreamStore.swift, WorkstreamItem.swift, CLI/cmux.swift): adds workspaceId and allowlisted extraFieldsJSON to WorkstreamItem; CLI forwards parent/child/model/subagent keys through hook compaction; WorkstreamAgentGraphBuilder constructs a scored, pruned tree snapshot off the main actor via FeedAgentGraphBuildWorker.
  • Feed Tree UI (FeedAgentTreeView.swift, FeedAgentTreeController.swift, FeedKeyboardFocusBridge.swift, FeedPanelView.swift, FeedPanelViewModel.swift): adds expandable tree rows with status/type/model chips, keyboard navigation bridged through an idempotent NSView registration, and coalesced background graph builds gated to the active tab; FeedKeyboardFocusBridge extracted to its own file with an idempotent registeredWindow guard.
  • Tests & localization: targeted unit tests for graph construction/pruning/metadata; all new strings have EN and JA entries in Localizable.xcstrings.

Confidence Score: 4/5

Safe to merge; all previously-flagged spawn-pruning, debounce, and allowlist issues are addressed, and no new auth or data-loss paths are introduced.

The metadata pipeline, background graph builder, and keyboard bridge are correctly structured. One structural issue remains: visibleAgentTree.focusTargets is captured by value in NSView keyboard closures at body-render time, so a collapse followed immediately by a keyboard navigation event can leave a phantom selectedNodeId pointing to a hidden node until the next graph rebuild clears it. This is bounded in duration and impact, but it is a present UI correctness defect on the tree keyboard path.

Sources/Feed/FeedPanelView.swift — FeedListView.body computes and captures visibleAgentTree in NSView closures; the collapse-then-keyboard-navigate scenario can leave a stale selection.

Important Files Changed

Filename Overview
Packages/CMUXWorkstream/Sources/CMUXWorkstream/WorkstreamAgentGraph.swift New 777-line file: graph builder, tree node types, and scoring algorithm. Previously flagged spawn-pruning and toolInput scoping issues have been addressed. nonisolated annotations are correctly applied to public value types.
Sources/Feed/FeedPanelViewModel.swift Migrated from ObservableObject to @observable; adds coalesced background graph builds via FeedAgentGraphBuildWorker actor. Previously flagged Task.sleep debounce, stale-snapshot-on-reactivation, and graphBuildSequence over-increment issues have all been fixed.
Sources/Feed/FeedPanelView.swift Adds .agentTree filter case, injects agentGraphSnapshot into FeedListView, and gates setAgentTreeActive via onAppear/onChange. visibleAgentTree is computed inside body on every render—acceptable because agentGraphSnapshot is empty when tab is inactive, but in active tree mode every selection change re-traverses all nodes synchronously on the main actor.
Sources/Feed/FeedAgentTreeView.swift 335-line new file for tree rows and row views. Equatable conformance reduces re-renders. NSLocalizedString used in summaryText (for format arguments) is consistent with the String Catalog; all strings have EN/JA entries.
Sources/Feed/FeedAgentTreeController.swift 190-line @mainactor @observable controller for collapse/selection/scroll state. Clean separation of view model and controller logic.
Sources/Feed/FeedKeyboardFocusBridge.swift Extracted from FeedPanelView.swift; adds idempotent registeredWindow guard preventing duplicate coordinator registration on every layout() and updateNSView call. Correct improvement over the previous version.
Packages/CMUXWorkstream/Sources/CMUXWorkstream/WorkstreamStore.swift Adds sanitizedExtraFieldsJSON with allowlist including prompt and message keys (previously flagged missing). Correctly sanitizes to string/NSNumber only before re-encoding.
CLI/cmux.swift Forwards parent/child/model/subagent metadata keys through hook compaction; adds copyAgentGraphMetadata helper that copies spawn-tool inputs and restricts generic keys (description/title/name) to spawn tools only.
Packages/CMUXWorkstream/Tests/CMUXWorkstreamTests/WorkstreamAgentGraphTests.swift 471-line test suite covering spawn creation, parent linking, model non-inheritance, metadata scoping, spawn pruning, and allowlist sanitization. Directly exercises previously-flagged regression paths.

Sequence Diagram

sequenceDiagram
    participant Store as WorkstreamStore
    participant VM as FeedPanelViewModel
    participant Worker as FeedAgentGraphBuildWorker (actor)
    participant Builder as WorkstreamAgentGraphBuilder
    participant View as FeedListView (body)
    participant Controller as FeedAgentTreeController
    participant Bridge as FeedKeyboardFocusBridge (NSView)

    Store->>VM: onChange (arm/observation)
    VM->>VM: applyStoreObservationSnapshot()
    note over VM: items changed?
    VM->>VM: scheduleAgentGraphRebuildIfNeeded()
    note over VM: isAgentTreeActive? set pendingRequest
    VM->>Worker: await snapshot(from: items)
    Worker->>Builder: snapshot(from:) [cooperative thread]
    Builder-->>Worker: WorkstreamAgentGraphSnapshot
    Worker-->>VM: snapshot (main actor hop)
    VM->>VM: completeAgentGraphBuild()
    VM-->>View: agentGraphSnapshot updated (observed)

    View->>View: body re-render
    View->>Controller: visibleSnapshot(from: agentGraphSnapshot)
    Controller-->>View: FeedAgentTreeVisibleSnapshot (rows + focusTargets)
    View->>Bridge: updateNSView (closures with visibleAgentTree)

    Bridge->>View: onMoveSelection(delta) [keyboard event]
    View->>Controller: move(in: visibleAgentTree.focusTargets, delta:)
    Controller-->>View: FeedAgentTreeSelectionEffect
    View->>View: applyAgentTreeSelectionEffect()
Loading

Reviews (32): Last reviewed commit: "fix: retry feed focus registration when ..." | Re-trigger Greptile

Comment thread Packages/CMUXWorkstream/Sources/CMUXWorkstream/WorkstreamAgentGraph.swift Outdated
Comment thread Packages/CMUXWorkstream/Sources/CMUXWorkstream/WorkstreamAgentGraph.swift Outdated
Comment thread Packages/CMUXWorkstream/Sources/CMUXWorkstream/WorkstreamAgentGraph.swift Outdated
Comment thread CLI/cmux.swift Outdated
Comment thread Sources/Feed/FeedPanelViewModel.swift Outdated
Comment thread Sources/Feed/FeedPanelViewModel.swift Outdated
Comment thread CLI/cmux.swift Outdated
Comment thread CLI/cmux.swift
Comment thread Packages/CMUXWorkstream/Sources/CMUXWorkstream/WorkstreamAgentGraph.swift Outdated
Comment thread Sources/Feed/FeedAgentTreeController.swift
@cubic-dev-ai

cubic-dev-ai Bot commented May 19, 2026

Copy link
Copy Markdown

You're iterating quickly on this pull request. To help protect your rate limits, cubic has paused automatic reviews on new pushes for now—when you're ready for another review, comment @cubic-dev-ai review.

Comment thread Sources/Feed/FeedKeyboardFocusBridge.swift

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit ab8f6a6. Configure here.

Comment thread CLI/cmux.swift
else { return }
for key in graphKeys + genericKeys + ["prompt", "message"] {
copyValue(toolInput[key], key: key)
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CLI copies child model to parent extra fields

Medium Severity

When a spawn tool's raw hook payload lacks a top-level model but the tool input contains one, copyAgentGraphMetadata copies the child's model from tool input into the event dict's top-level model key (since event["model"] is still nil after the first rawObject loop). On the receiver, this becomes part of extraFieldsJSON. The graph builder's sessionModel for spawn tools reads extra["model"], so it incorrectly assigns the child's model to the parent session. The tool input model is already available separately via WorkstreamPayload.toolUse's toolInputJSON, making this copy both redundant and harmful.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit ab8f6a6. Configure here.

This branch was successfully deployed

1 active deployment
Preview – cmux — ab8f6a62 Deployed May 22, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

stale-revisit Closed after 30+ days without activity; preserved for possible revisit or reopening.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Subagent tree visualization: parent → child relationship graph for spawned agents

3 participants