Skip to content

Runtime tree

The left pane of Explorer Mode is <director-tree> (src/components/DirectorTree.ts). It renders a recursive tree of IDirectorTreeNode rows and emits director:node-selected, director:node-expand, and director:refresh events upward.

Anatomy of a row

Each row is a flex container with the following pieces (verified against DirectorTree.ts:83-119):

[toggle] [dot] [node-name] [badges...]
   ▶/▼   color  mount.last  P P π canonical compat
  • Toggle collapsed, expanded. Click to expand/collapse. Toggling a node that hasn't loaded children dispatches director:node-expand { mount } so DirectorApp can lazy-fetch via DirectorRuntimeAdapter.introspectActorCached.
  • Dot — color-coded by component class:
ColorMeaningSource class regex
Blue (#42a5f5)Legacy daemon-named mountmatches daemon/Daemon (v1 holdover; new substrate code uses runtime vocabulary, not "daemon")
Green (#66bb6a)System actormatches system/System (or system.* mount)
Yellow (#ffee58)Package rootdot-package set on canonical package roots (system.agents, system.observability, system.sqlite)
Purple (#ab47bc)Promptableintrospect returned promptable: true
Grey (#78909c)Default fallbacknone of the above
  • Node name — the last segment of the canonical mount (system.observability.tracingtracing).
  • Badges — small chips:
    • P (purple) — promptable.
    • regime — text badge (explore, execute, etc.) when introspect returned a regime.
    • canonical/compat — set by inferPackageFamily + isCompatPackageMount so an operator can see at a glance whether they are looking at, e.g., system.agents.memory (canonical) or system.memory (compat alias).

Toolbar

Above the rows, a small toolbar:

  • Title — fixed text "ACTORS".
  • Refresh button — dispatches director:refresh, which DirectorApp reroutes to director.refresh-surface { surface: 'explorer' }.

Selection and expand contracts

Inbound opEffect
tree.set-data { roots }Replace the entire roots array.
tree.set-selected { mount }Highlight that mount.
tree.set-status { status }Update the small status string ("Loading…", "Ready", "Stale").
tree.set-children { mount, children }Replace one node's children (lazy-load result).
tree.set-runtime-inventory { children }Splice runtime-only inventory into the runtime branch.
tree.set-root { root }Update the implicit authority root used for display.
Outbound eventCarriesWhen
director:node-selected{ mount, componentClass }Click on a row
director:node-expand{ mount }Click toggle on a node with childrenLoaded === false
director:refresh{}Click refresh in the toolbar

DirectorExplorerShell rebroadcasts these as director:explorer-actor-selected, director:explorer-actor-expand-requested, and director:explorer-refresh-requested to DirectorApp.

Live presence

DirectorApp.subscribes includes system.runtimes/$events filtered to runtimes.added, runtimes.removed, and runtimes.inventory.changed. When events arrive, DirectorApp rebuilds its catalog and pushes the new tree via tree.set-data. There is no per-row websocket; the tree is fully redrawn on each catalog refresh.

Limits and known issues

  • Single root only. The tree is rendered for one authority root at a time (the runtime root resolved by DirectorTopology). Multi-root composition (browser realm + runtime realm side by side) is documented in DESIGN.md §2.1 as a future direction.
  • Lazy loading is best-effort. If $introspect.children is missing or shaped differently on a custom actor, the node will appear leaf-like.
  • Synthetic prefix nodes have no actor. system.observability may be a tree branch even though no actor mounts there directly. Clicking it selects the prefix; the detail panel will show the package status row from loadPackageStatuses.

See also

Source: projects/matrix-3/packages/director/src/components/DirectorTree.ts (full component), src/services/DirectorRuntimeAdapter.ts:758-1028 (tree construction).