Skip to content

Spines

A spine is a materialized synthesis tree laid over a zettelkasten corpus — a deliberate arrangement you can switch on, switch off, or swap for another, not a separate copy of the corpus. The corpus has exactly one semantic base (the notes and their authored links); a spine re-projects that same base into a shape you chose. This page explains what a spine actually is underneath, why membership lives on the spine side, and how the dashboard renders it. It also folds in the spine definition — the owner-scoped registry entry that names, stores, and governs a spine's lifecycle (once documented on its own Organizations page) — and how a spine relates to the matrix that compares it.

The zettelkasten dashboard Concepts view organized by a spine: the same notes re-laid as a radial tree around a central apex, with labeled dimension spines radiating out

Selecting a spine under Organize by re-projects the corpus as a radial tree — one central apex with its dimension spines fanning out — without copying a single note.

Why it exists

The base zettelkasten is held together by its intrinsic shape: each note's authored semantic links — defines, depends-on, component-of, contrasts, and friends — plus the organic clusters those links form. That substance of the corpus is always there. But one corpus usefully supports many arrangements: the same papers can be organized by methodology, by claim status, by a PM-decision rubric, by a research question. Materializing each of those as a new copy of the notes would fork the truth; encoding each as a query would make them invisible and unselectable.

Why a spine and not a tag scheme or a copy

A spine is a re-projection layer. The base notes are never mutated to join one, and a spine never removes a note's semantic links. Membership in a spine is derived, correctable, and disposable — the opposite of the authored, permanent links on the note itself. This is the central rule: a spine adds a structural layer on top of the semantic base without ever replacing it (north-star invariant).

The decisive design move (Spines are additive/separate/selectable layers: NOT project sources, spine-side edges, 'Organize by' picker) is that spines are additive, separate, and selectable, and crucially not project sources. A promoted spine lives in its own graph and is registered in a spine catalog (the definition registry), so the base composite graph can never accidentally cluster a spine's apex/dimension nodes in as if they were ordinary notes. The viewer picks which arrangement is active from an "Organize by" selector; selecting one loads it as a non-destructive overlay and hides the others.

How it works

A spine is a tree, not a grid (v2 spine model: structure tree + first-class spine-side membership relation (supersedes grid framing)). It is materialized in its own dedicated graph: an apex node for the spine itself (tagged synthesis + extraction-synthesis), then dimension nodes (tagged extraction-dimension plus a schema dimension tag) and optional row hubs, each component-of its parent, to arbitrary depth. A member note attaches to any node — interior or leaf — through a first-class spine-member relation stored spine-side as an outgoing cross-graph edge (dimension/hub --spine-member--> note@home_graph). Because the edge lives on the spine, the base note stays pristine, two spines can never bleed into each other, and teardown is just deleting the spine's graph folder.

There are therefore two edge classes in two places. Semantic and structural links are substance — authored, permanent, and stored on the base note. Membership is arrangement — derived, rebuildable, and stored on the spine. The default spine is the degenerate case: it has no materialized graph at all, because the intrinsic semantic links already are the organic arrangement.

Semantic base (one corpus) Spine graph (a re-projection layer) spine-member related depends on component of component of note · paper A note · paper B note · paper C apex dimension · methods dimension · results row hub · RCTs Concepts tree Draft Matrix
Two edge classes in two places: authored semantic links live on the pristine base notes, while spine-member edges live on the spine and point back at them. The same spine projects as a Concepts radial tree, a Draft, and a Matrix.

Every dimension node carries a durable id (source['node_id'], derived from its schema path) so a relabel, drift, or re-promote re-titles the same node rather than orphaning it and its spine-member edges. Row hubs are likewise keyed by a stable row_id, not by their label. This durable-identity discipline is what lets human corrections survive a rebuild — the lesson learned the hard way in the membership-loss saga that preceded the current model.

How the dashboard shows a spine

A spine is one tree, but you meet it in a few places in the dashboard, and they are not three equal toggles of a single widget. Keeping the view model straight matters, because the corpus renders differently depending on whether a spine exists at all:

  • Concepts graph — the primary view. With no materialized spine, the Concepts tab draws the semantic base as clustered halos (organic similarity, not a spine). Once a spine is materialized, the same tab can render that spine as a radial tree / radial dendrogram — the apex at the center, dimensions and row hubs fanning outward, member notes at the leaves. A matrix adds a third rendering: the graph colored by matrix cell. Halos are for semantic clustering; the radial tree is for a spine. They are different renderings of different things, not the same picture relabeled.

A materialized spine drawn as a radial tree: a central hub with three topic apexes, each fanning out through dimensions to its member notes

A materialized spine as a radial tree — the hub at the center, topic apexes fanning outward through their dimensions to the member notes at the leaves. - "Organize by" is progressive disclosure. The selector that switches the active arrangement only appears once the owner has at least one materialized spine. Before then there is nothing to organize by but the intrinsic semantic projection, so the control stays hidden rather than offering an empty menu. - Matrix and Draft live in the Workshop. They are review-scoped projections opened under a Review in the Workshop — not peer buttons sitting next to the Concepts graph. The Draft renders the spine tree at full depth; the Matrix flattens it to two axes (which component-of level becomes the column cut, and whether a cell rolls up its subtree). Conceptually all three — radial tree, Draft, Matrix — are projections of the same spine; the invariant that ties them together is that a projection must never show fewer, or more, nodes than the base it projects.

The same spine rendered as an indented draft: the hub, its topic apexes, and their member notes nested by dimension, beside a generated narrative

The Draft projection renders the same spine tree at full depth — the identical node set the radial tree and matrix draw from, here as an indented list a narrative can be written against.

See Dashboard for the surrounding UI and Matrices for the comparison surface.

The spine definition

A spine definition is a named, owner-scoped matrix definition — a row axis plus an ordered set of typed columns — held at the owner level rather than buried inside a single review. If a spine is the materialized tree and a matrix is the comparison surface, a spine definition is the registry entry that names, stores, and governs the lifecycle of one such arrangement. It is the thing a project's "Organize by" selector actually lists, and it lives in organizations.py (the registry file keeps its historical name).

A corpus supports many organizing principles at once — the same papers by methodology, by claim status, by a decision rubric. Historically each of those lived inside one review's .tables.json, which meant an arrangement of the corpus could not be reused across reviews, listed in a switcher, or promoted into a durable spine. Decoupling the definition from the review it was born in fixes all three: the definition becomes a first-class, owner-addressable artifact, while the heavy grid stays a derived cache (Organizations storage + owner-level navigation architecture (Phase 1a–1d)).

Owner scope is deliberately narrow. A spine definition is owned by exactly one project or one graph — the same {project, graph} duality a review's scope uses. That single owner is what makes a definition findable: a project's catalog is precisely the set of ways you can choose to organize that project, and nothing leaks in from a sibling.

A definition is a definition, not a copy

A spine definition never forks the corpus. In its proposed state it writes nothing back at all; even when materialized, the base notes stay pristine and only the spine graph carries the derived arrangement. This is the same north-star invariant that governs spines — additive re-projection, never replacement (Organizing principle: semantic base -> spine -> matrix (two kinds of uniting)).

The two states

Every spine definition occupies one of two lifecycle states, and the distinction is the heart of the model.

A proposed spine is a live, read-only projection. Its grid is derived on demand from the row axis and columns — deterministic routing plus, optionally, the agent-semantic tier — and nothing is written to the corpus. A proposed spine is cheap, disposable, and always reflects the current corpus: change a note and the next build reflects it. (This is the state the code still records as lens.)

Notes grouped into organic semantic clusters — the live base a proposed spine projects over

A proposed spine projects over the live semantic base — the organic clusters the corpus already forms — without writing anything back.

A spine is a materialized arrangement. Promotion builds a real synthesis graph — an apex, one dimension node per materializable column, one hub per row — and the definition's spine_ref names that graph. From then on the spine is durable: dimension nodes carry synthesized bodies, spine-member edges pin membership spine-side, and the same tree can be projected as a Matrix, Draft, or Graph.

The materialized spine as a radial tree — apex, dimensions, and pinned member notes

Promotion materializes that projection into a durable synthesis graph — an apex, dimension nodes, and spine-member edges — shown here as a radial tree.

promote: build skeleton + attach + stash proposed form demote: keep nodes/edges resync: re-attach from current grid Semantic base the notes proposed spine live, read-only projection spine materialized synthesis graph
One lifecycle, two states. A proposed spine is a live read-only projection; promote materializes it into a durable spine graph, and demote/resync move between and refresh the two without forking the base.

What a definition holds

The stored definition is byte-compatible with what the matrix engine consumes, because it reuses the engine's own normalizers. The load-bearing fields:

  • columns — the ordered, typed column definitions (the dimensions).
  • row_axis — how rows are enumerated (source, note, tag, note type, or a group strategy). The selectable row axis is what generalized the matrix from "one row per source" to any pivot (Row axes: drop persona, add greyed-out 'spine' axis; materialize-spine flow surfaced in Preview).
  • overlay — the author's corrections (member adds/removes and cell overrides), stored as id-references and re-applied on each fresh proposed build so human edits survive a rebuild.
  • matrix_view — how the spine tree flattens into the 2-axis grid (which component-of level is the column cut, whether a cell rolls up its subtree). It only takes effect once the definition is materialized as a spine — a proposed spine has no tree to flatten.
  • spine_ref — the apex graph a promoted definition writes into (empty while proposed).
  • lens_definition — the pre-promotion row axis + columns, stashed on promote so demote/delete can restore the proposed form after the live columns have been rewritten to link-form.
  • table_id (and review) — the review-local id that keys the grid cache and cell-note anchors.

Storage

Each spine definition is a single JSON file, keyed by owner:

<base>/_organizations/<owner_type>/<owner_name>/<id>.json   # one definition per file
<base>/_organizations/<owner_type>/<owner_name>/index.json  # derived listing

The per-file layout gives every definition an independent, git-trackable artifact — clean diffs, no whole-store write contention — while index.json is a derived read-accelerator, rebuilt by scanning the directory on every write so it can never drift from the source-of-truth files. All writes go through the same substrate reviews use (review_write_lockatomic_write_text_schedule_zettel_commit), keyed by a per-owner lock, so concurrent edits to two definitions never corrupt each other. A lazy, idempotent migration imports legacy review tables as proposed-state definitions the first time an owner is listed, and records which reviews it has absorbed so a deleted definition is never silently resurrected.

The lifecycle operations

Authoring a spine definition (creating a proposed one, GET/POST on an owner's definitions) is managed through the dashboard's REST surface. The lifecycle transitions below are exposed both there and as the spine(action=…) MCP tool — a single collapsed dispatcher (promote / demote / resync / verify / delete, plus list) so an agent can drive a spine end-to-end. Both call the same functions in organizations.py, which serialize on a per-owner file lock, so the MCP and dashboard paths are safe to interleave:

  • promote (proposed → spine) builds the spine skeleton, bulk-attaches the current cell members onto their dimension and hub nodes, stashes the pre-promotion form in lens_definition, and rewrites the live columns to link-form so future builds route deterministically through the materialized edges. The synthesis graph is not registered as a project source — spines are additive overlays, not corpus members. This same path is what remine reuses when it applies an approved grid.
  • demote (spine → proposed) stops treating the spine as materialized but keeps the graph, its nodes, and the attach edges, and reverts the live columns to the stashed proposed definition. It is non-destructive: a later re-promote or resync still finds the nodes. (Discovery honors this — a demoted definition's apex no longer reports as a live spine, and orphaned non-enforcing keyed meta for demoted spines is pruned; Prune orphaned non-enforcing keyed meta for unused/demoted spines.)
  • resync incrementally re-routes new or unrouted in-scope notes into an existing spine, adding only the missing attach edges (idempotent). Corrections are honored, not undone — a removed member is never re-attached, an added one is attached like any other.
  • verify is a read-only synthesis audit: it checks that every synthesized cell summary stays within the notes routed into that cell (ungrounded summaries, empty-with-members, synthesis over ungrounded members), optionally escalating to a semantic overreach check. It never builds or writes.
  • delete unlinks the definition file, rebuilds the index, and — because a project's default_spine names a definition by id — clears any dangling default_spine pointer so it can never reference a deleted spine.

The default spine

A project's default_spine field names the definition that is its primary "Organize by" principle. Unset means the implicit intrinsic projection — the organic semantic cluster graph, which has no definition record because there is nothing to point at. The pointer is kept honest by the registry: it auto-clears when its definition is deleted and follows one through an id change, so it can never dangle.

Spine vs spine definition vs matrix

These three words name three points on one lifecycle, and they are easy to conflate. Concretely:

Spine definition Spine Matrix
What it is A named, owner-scoped definition of how to arrange the corpus The materialized form of a definition: a real synthesis tree in its own graph A comparison grid formed when spines share a spine-schema
State / where it lives proposed (live projection) or spine (materialized) — _organizations/… A dedicated synthesis graph named by spine_ref Emergent — no separate storage; computed from sibling spines
Writes to the corpus? Proposed: no. Spine: materializes a spine graph (never mutates base notes) Adds spine-member edges spine-side; base notes untouched No — a re-projection of existing spines
Shape Whatever the definition describes Tree: apex → dimensions → row hubs → member notes Rows = topics (spine apexes), columns = shared dimensions
Read more this page this page Matrices

The short version: a spine definition is the intention, a spine is that intention made real and attachable, and a matrix is what several spines become when they agree on their columns.

What's available

  • The shared materializerbuild_spine_skeleton stamps the apex, optional spec, and the dimension tree idempotently, behind one tiny ops protocol. Two backends implement it: ServerSpineGraphOps writes through the MCP server primitives (used by grounded-extraction prep), and SpineGraphOps writes directly through ZettelGraph (used by promotion, the dashboard, and tests with no server process). Both share one tag/relation vocabulary so writers and the reader can never silently drift.
  • The spine-definition catalog — a project's spine definitions are its catalog of candidate arrangements. A definition in the proposed state is a live, read-only projection (derived on demand, nothing written back); a definition in the spine state is a materialized, spine-schema-backed spine whose spine_ref names its apex graph. See organizations.py.
  • The default spine — a project's default_spine field points at the definition that is its primary "Organize by" principle. Unset means the implicit intrinsic projection: the organic semantic cluster graph, which has no definition record because there is nothing to point at. The pointer auto-clears when its definition goes away, so it can never dangle.
  • The embedded extraction schema — a materialized spine carries the full expanded extraction schema inline (generated on promotion from the proposed-state columns plus the synthesis block), so a scribe can re-source extraction from the spine itself rather than a separately-named schema file (Schemas can declare materialized structure (the synthesis spine); added a schema-generation tool). This is the grounded-extraction schema — the extraction rubric — a different layer from the spine-schema fingerprint that groups sibling spines into a matrix; see the caution below.
  • Discovery, not examples — spines are discovered from the live graph universe rather than shipped as domain samples (Don't ship domain spine examples; discover live spines via schema(action="spines")). schema(action="spines") reports each live spine and its incomplete list (skeleton nodes still scaffold, not yet authored to materialized), so "which spines exist and which are unfinished?" is one query.

Two things named 'schema' — keep them apart

A spine touches two distinct schema layers, and conflating them is the classic mistake. The spine-schema is the shared rubric a spine-group is built from — concretely a spine's column_key_fingerprint, its sorted set of column keys — and it is what decides whether sibling spines fold into one matrix. The grounded-extraction schema is the extraction rubric the extraction pipeline reads a source against (create_extraction_graph, the entries in extraction-schemas.yaml). A materialized spine embeds the latter inline so a scribe can re-source from it; the former is derived from that schema's dimension tags but names a different job — grouping, not extraction. The extraction layer keeps the plain word schema; the grouping layer is always spine-schema.

Commands

Natural-language phrasings for working with spines — say the thing, the agent runs it. The lifecycle transitions are exposed as the spine(action=…) MCP tool (one collapsed dispatcher), so the agent can drive a spine end-to-end; the same transitions are also available from the dashboard UI. Authoring a new proposed definition (below) is still dashboard-only. See the full command cheatsheet.

Say this What runs
"what spines exist", "list the spines", "show unfinished spines" spine(action="list") / schema(action="spines")
"suggest a spine", "propose an arrangement", "what dimensions could organize this" Spine suggestion from a frame result (dashboard)
"make a spine", "define an arrangement by methodology" Create a proposed spine definition (dashboard)
"organize by X", "set the default spine" project(action="set_default_spine")
"promote this spine", "materialize it", "build the spine graph" spine(action="promote") (proposed → spine)
"demote the spine", "unmaterialize", "back to a lens" spine(action="demote") (spine → proposed)
"resync the spine", "route the new notes in", "update membership" spine(action="resync")
"verify the spine", "check the synthesis", "audit for overreach" spine(action="verify") (read-only; semantic=true for the over-reach tier)
"delete this spine", "drop the arrangement" spine(action="delete")
"draft against this spine", "walk the spine", "build the outline for this spine" syllabus/outline build with a spine partition
"attach this claim to the spine", "route this into the right dimension" note(action="attach")
"write this dimension's portrait", "mark this node materialized" note(action="update", replace_body=…) + synthesis_statusmaterialized

Design notes

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

  • D v2 spine model: structure tree + first-class spine-side membership relation (supersedes grid framing)active
    Design refinement raised during the Graph C spine-promotion review.
  • D Spines are additive/separate/selectable layers: NOT project sources, spine-side edges, 'Organize by' pickeractive
    User requirement: building a new spine must be ADDITIVE to the cluster graph but SEPARATE, and the viewer must be able to pick which spine / organizational principle is active.
  • D Schemas can declare materialized structure (the synthesis spine); added a schema-generation toolactive
    Extended extraction schemas so a schema can declare its OWN materialized structure instead of producing a hub-and-spokes dandelion.
  • D Don't ship domain spine examples; discover live spines via schema(action="spines")active
    Two follow-ups to the materialized-spine work.
  • D Organizations storage + owner-level navigation architecture (Phase 1a–1d)active
    An Organization is a first-class, owner-scoped (project OR graph) matrix definition — a row axis + ordered typed columns — decoupled from any single review.
  • D Organizing principle: semantic base -> spine -> matrix (two kinds of uniting)active
    The canonical conceptual model for the whole zettelkasten organization layer.
  • D Row axes: drop persona, add greyed-out 'spine' axis; materialize-spine flow surfaced in Previewactive
    Design decisions from user feedback while testing the matrix wizard:
  • D Prune orphaned non-enforcing keyed meta for unused/demoted spinesactive
    Post-1.3.1 follow-up: closed the documented DEFERRED LIMITATION where materialize_structure writes a structure-only (non-enforcing) keyed block onto each source OPTIMISTICALLY, before reconcile decides membership.
  • R Angelo
    • P zettelkastenactive
      • P Phase 2: Literature Review Systemactive
        • P Workshop tab: Reading Syllabus (learn) + claim-centric Review/Outline (write)active
          • P Organizations: project-level lenses + spines (matrix builder redesign)active
            • D Organizations storage + owner-level navigation architecture (Phase 1a–1d)active
              • C Checkpoint: Organizations Phase 1a–1d complete + verified
            • D Row axes: drop persona, add greyed-out 'spine' axis; materialize-spine flow surfaced in Previewactive
            • P Spine promotion: materialize a matrix lens into a graph (cols+rows, bulk-attach)active
            • P Spines as the primary organization mechanism (spine directory + default lens + embedded schema)active
              • P Phase: Graph D-phase3 — spine-sourced extraction (scribe reads embedded schema + spine_ref structure; spine scope; spine-member attach)active
                • P Deferred spine affordances: multi-spine extraction + tag_stamp route + per-doc spine routingactive
                  • D Prune orphaned non-enforcing keyed meta for unused/demoted spinesactive
            • P Schema matrix views (ephemeral hub) + user-facing Spines renameactive
              • D Organizing principle: semantic base -> spine -> matrix (two kinds of uniting)active
      • P Phase: Grounded Extraction Pipeline + Reusable Schemas (coordinator capability)active

Semantically related entries from the memory graph.