Skip to content

Tree and clusters

The memory dashboard renders the same set of entries two ways. The tree shows structural lineage — who is whose parent, which phase a decision belongs to. The cluster view shows semantic proximity — which entries are about the same thing, regardless of where they sit in the hierarchy. Neither replaces the other; they answer different questions about one body of knowledge. (The animation of one morphing into the other lives on the Memory hub.)

The memory dashboard's Cluster view: entries laid out by semantic proximity into labeled topic clusters, with granularity and spread controls

The Cluster view — the same entries regrouped by meaning into auto-labeled topic clusters, with a granularity slider that sets how many clusters form.

Why both views exist

A research tree is authored: an agent records a decision under a phase, under a subproject. That hierarchy encodes provenance and intent — the chain of reasoning that led here. It is precise but rigid: an entry lives where it was filed, and a theme that recurs across three different phases is scattered across three different branches.

Semantic clustering is emergent: it ignores where entries were filed and groups them by what their text means. It surfaces the cross-cutting themes the hierarchy hides, and the surprising adjacencies — two entries that turned out to be about the same problem even though nobody filed them together.

Why not pick one?

Lineage and meaning are orthogonal. You cannot recover "this decision belongs to Phase 2" from an embedding, and you cannot recover "these five entries are all about cycle detection" from parent_id. Each projection discards exactly what the other preserves, so the dashboard keeps both and lets you switch.

How it works

Both views read one shared KGLite graph rebuilt from the .memory/ markdown files by graph_loader.py. The same nodes then flow down two independent projections:

.memory/ entries one node set KGLite graph graph_loader.py /graph parent_id + contains /cluster entry embeddings TreeView ELK layered · lineage ClusterView t-SNE · agglomerative
The same node set flows down two independent projections: /graph for structural lineage (the tree), /cluster for semantic proximity (the clusters).

Structural lineage — the tree

The /graph route walks each entry's parent_id to build primary has_child edges, then adds secondary parents from explicit contains edges so an entry can belong to more than one branch — a multi-parent DAG rather than a strict tree (Multi-parent DAG: contains edges, ELK layered layout, cycle-safe add_parent API). Each entry carries a parent_ids array; secondary edges are deduplicated and resolve_parent collapses links through hidden nodes so the visible graph stays connected.

The frontend lays this out with ELK's layered algorithm (direction RIGHT, falling back to mrtree if layout fails) — chosen over a pure tree layout precisely because the topology is a DAG. Primary edges render solid; secondary parent edges render dashed, and multi-parent nodes get a DAG badge. The layout is deterministic: the same entries always produce the same shape.

The research tree: a project fans out into subprojects, phases, and entries with solid parent→child edges and one dashed multi-parent edge

Structural lineage: solid has_child edges trace the authored hierarchy; the dashed edge marks a multi-parent entry that belongs to two branches.

Semantic proximity — the clusters

The /cluster route pulls each entry's search_text embedding (model2vec static vectors, from the graph or the .memory/ sidecar), projects the high-dimensional vectors to 2D with t-SNE, and normalizes the result into a fixed viewport. It then runs agglomerative clustering whose target cluster count is mapped monotonically from the granularity slider — "Few" yields 2 clusters, "Many" up to a ceiling of 30 (Cluster view: semantic embedding layout with auto-detected clusters). Clusters are auto-labeled from their members' most common content tags (structural tags like phase/decision are skipped), falling back to a member title.

Position here means meaning, not lineage. Parent/child edges are still drawn, but faintly; related cross-references become first-class. Entries with no embedding land in cluster -1 ("other") near their parent, and federated repos' embeddings are merged in so cross-repo entries cluster together too.

The same entries regrouped into labeled semantic clusters, positioned by embedding similarity

The same node set re-projected: entries pull together by meaning into auto-labeled clusters, regardless of which branch they were filed under.

What's available

Tree view (/graph) Cluster view (/cluster)
Question it answers Where does this sit? What's the lineage? What else is about this?
Position encodes parent → child hierarchy semantic similarity
Layout ELK layered (deterministic) t-SNE + agglomerative (computed)
Edges shown has_child (solid/dashed), invalidated_by, related related (primary), parent/child (faint)
Best for provenance, navigation, active-phase tracking, multi-parent reuse thematic discovery, spotting duplication, cross-cutting structure

Reach for the tree when you are navigating a workstream, tracing why a decision was made, or checking which phase is still open. Reach for the cluster view when you want the shape of the whole knowledge base — to find entries related to a topic that were filed in different branches, or to notice that two efforts converged on the same idea.

Design notes

The decisions behind this, drawn as a slice of the memory tree.

Semantically related entries from the memory graph.