Files
shard-wiki/research/260614-trilium-deep-dive/findings.md
tegwick 5697669063 research: Trilium (TriliumNext) deep dive (note cloning/DAG hierarchy, attribute inheritance, HTML-native); UC-66/67
SQLite-local PKB whose standout is note cloning — a single note can sit in
multiple tree locations at once via the note (identity) vs branch
(placement) split, so the hierarchy is a DAG, not a tree, with no single
canonical path. The identity-not-equal-placement model is the clean way to
represent a page in multiple locations/shards and the namespace-level form
of the clone/reference primitive. Also: attributes (labels + typed
relations) are inherited + templated, so metadata is computed (own +
inherited + template), not a flat bag; content opacity is per-item
(per-note encryption / protected notes), refining the proposed 12th
spectrum; HTML-native (CKEditor, lossy to Markdown); dual extension
surface (scripting code notes + ETAPI token REST). TriliumNext is the
active community fork of zadam's Trilium (TWiki->Foswiki pattern). Added
UC-66 (DAG hierarchy / note cloning), UC-67 (inherited/templated
attributes, effective vs own); enriched UC-15/22/34/38/42/61. Catalog now
67 UCs. Architecture for SHARD-WP-0002 T11/T12/T14/T15/T16: DAG namespace
+ identity/placement split, computed/inherited metadata, per-item content
opacity, HTML source model, scripting + ETAPI host surfaces.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 16:44:49 +02:00

16 KiB

Findings — Trilium (TriliumNext): note cloning, attribute inheritance, HTML-native

Date: 2026-06-14 Source kind: modern shipped product — an open-source hierarchical PKB; a candidate shard whose distinctive traits are note cloning (a DAG hierarchy), an attribute/relation system with inheritance + templates, and HTML-native content Lens: shard-wiki — the namespace model (identity vs placement), inherited/computed metadata, HTML translation, per-note encryption, and the scripting/ETAPI surfaces

Why Trilium earns a dive. It is another SQLite-local note app, but it brings a structural feature none of the prior twelve systems had: note cloning — a single note can sit in multiple places in the tree at once, so the hierarchy is a DAG, not a tree, and note identity is cleanly separated from placement (a note has many "branches"). That directly challenges shard-wiki's namespace model (UC-22 assumes a path) and is the clone/reference primitive made concrete at the namespace level. Trilium also has an attribute system with inheritance and templates (effective metadata is computed, not just stored), and it is one of the few HTML-native (not Markdown) tools — a useful stress on "Markdown-first must degrade."

Lineage note (like TWiki→Foswiki): TriliumNext is the community fork of the original Trilium (zadam) after it went maintenance-only; the active project is TriliumNext.

Contrast set: Joplin (SQLite-local, files-on-sync, page-level), Logseq (block-graph on files), Notion (hosted DB, schema+relations). Trilium = SQLite-local, DAG hierarchy, inherited attributes, HTML content, self-host sync + ETAPI.


1. Core architecture — one SQLite file, server-syncable

  • Storage: a single SQLite file (document.db, via better-sqlite3) holding notes, attachments, history, and settings. Local DB store (like Joplin; not files).
  • Clients/sync: desktop (Electron) or a self-hosted server; multi-instance sync protocol with conflict resolution + entity change tracking, plus WebSocket realtime updates. Attach via the server, the ETAPI (§5), or the DB.
  • IDs: 12-char IDs — noteId, branchId, attributeId, attachmentId. The note vs branch split is the key idea (§2).
  • Export: to Markdown/HTML (lossy — content is HTML, §4).

2. Note cloning — a DAG hierarchy, identity separated from placement

Notes form an arbitrarily deep tree, but a single note can be placed in multiple locations — "cloning," implemented via the branches model:

  • A note (noteId) is the content + identity. A branch (branchId) is one placement of that note under a parent (with an optional branch prefix giving per-location context). A note with several branches is cloned — it appears in several places at once; editing it anywhere edits the one note.
  • So the hierarchy is a DAG, not a tree, and identity (note) is separated from location (branch). There is no single canonical path for a cloned note.

This is the most shard-wiki-relevant feature in the dive:

  • It breaks the assumption behind UC-22 (resolve a page by a path). shard-wiki's namespace model must allow a page in multiple namespace locations with no single canonical path (UC-66).
  • The note/branch split is a clean model shard-wiki should borrow: page identity ≠ page placement. A page is one entity; its locations are separate placement records — exactly how shard-wiki should treat a page that appears under multiple paths/shards.
  • It is the clone/reference-not-copy primitive (Xanadu clone, ZigZag clone, UC-44/45, T16) realized at the namespace level: same note, many positions, one source of truth.

3. Attributes — labels + relations, with inheritance and templates

Trilium's metadata system is attributes:

  • Labels (#tag, optionally #key=value) — typed metadata on a note.
  • Relations (~relation) — typed links to other notes (a knowledge graph).
  • Inheritance — attributes can be inherited down the subtree (inheritable attributes), and templates (a note whose attributes/structure are applied to instances via a ~template relation) inject attribute sets. So a note's effective metadata = its own attributes + inherited + templated — computed, not just stored.
  • Promoted attributes give a form-like UI; attributes drive search/queries and scripting.

shard-wiki read: this is structured data (UC-34) and typed relations (UC-58), but with a new wrinkle — inheritance/templates make metadata computed. Projecting such a shard must distinguish effective vs own attributes (and record their provenance: own / inherited-from / template), not flatten them (UC-67). Templates also reinforce blueprint pages (UC-15).


4. Content model — HTML-native, many note types

  • Text notes are HTML (WYSIWYG via CKEditor5), not Markdown. Trilium is one of the few HTML-first tools studied. Markdown participation therefore needs HTML↔ Markdown translation — more tractable than Notion's block model but still lossy for some constructs (CKEditor features, includes) → a fidelity-aware case bridging UC-42 (lossless ideal) and UC-59 (lossy-with-report).
  • Note types: text (HTML), code (CodeMirror), canvas (Excalidraw), relation maps, mind maps (Mind Elixir), spreadsheets (Univer), geo maps (Leaflet), render notes, file/image, book — i.e. lots of non-Markdown content (UC-55) and script/render-generated dynamic notes (UC-54).

5. Extension surfaces — scripting (in-app) + ETAPI (external)

Two surfaces, like Joplin:

  • Scripting (in-engine host). Code notes in JS run as frontend (UI widgets, buttons) or backend (server-side automation) scripts against a Script API (create/query notes, attributes, etc.). Executable, in-app — the adapter-host path (UC-38). "Render notes" + scripts produce dynamic, generated content (UC-54).
  • ETAPI (external REST API). Trilium's public REST API (since v0.50), token auth (Bearer ETAPITOKEN), with client libs (trilium-py): CRUD over notes/branches/ attributes/attachments, search, import/export — an external attach surface (UC-57) that, unlike Joplin's localhost-only Data API, is the designed external integration API for a (often self-hosted) server.

6. Security — per-note (partial) encryption

Trilium offers strong per-note encryption ("protected notes") unlocked in a protected session (password; TOTP/OpenID for login). Crucially this is per-note: a shard can hold some encrypted and some plaintext notes at once. This refines the content-opacity dimension (UC-61, proposed twelfth spectrum from Joplin/Anytype): opacity is per-item, not only whole-shard — the adapter must handle a shard where part of the content is opaque without a key (protected notes projectable only as structure-shell; unprotected notes fully).


7. Trilium as a shard — capability profile

Capability Trilium Notes for the adapter contract
Read yes (ETAPI / sync / DB) ETAPI REST (server) is the clean surface
Write yes (ETAPI / script) per-note; via ETAPI or backend code notes
Write granularity per-note (page)
Identity / addressing noteId + branchId (12-char) identity ≠ placement; cloned notes have many branches (UC-51, UC-66)
Hierarchy DAG (cloning) a note in multiple locations; no single canonical path (UC-66)
Structure labels + relations, inherited + templated effective vs own metadata (UC-34, UC-58, UC-67)
Content HTML (CKEditor) + many types HTML↔MD lossy translation (UC-42/59); non-MD types (UC-55)
History internal revisions in the DB not portable git → supplement (UC-36)
Native query attribute search / script queries delegate or build index (UC-52/63)
Subscribe WebSocket + sync protocol push; conflict resolution built in (UC-31)
Content opacity per-note encryption (partial) per-item opacity (UC-61 refined)
Extension scripting (in-app) + ETAPI (external) dual surface (UC-38, UC-57)
Templates yes (~template) blueprint pages (UC-15)

Verdict: a capable SQLite-local, server-syncable shard best attached via ETAPI. Standout demands: the DAG hierarchy / note-branch identity model (UC-66) and inherited/templated attributes (UC-67); plus HTML-native translation, per-note opacity, and the scripting host.


8. Mapping to shard-wiki INTENT (compare, do not equate)

8.1 Reinforcements

  • Identity ≠ placement (note/branch) is a model shard-wiki should adopt for pages that appear under multiple paths or in multiple shards — provenance and union without erasure depend on separating "what a page is" from "where it sits."
  • Typed relations + templates validate the structured/relation demand (UC-58) and blueprints (UC-15) on a local-first, self-hostable backend.
  • ETAPI is a clean example of a designed external REST surface for a self-hosted server (cf. Notion external API, but self-hosted/trust-boundary friendly).

8.2 Deliberate divergences (design bugs if conflated)

  1. Don't force a single canonical path. A cloned note has many placements; modeling it with one path loses information (UC-66). Use the note/branch separation.
  2. Don't flatten computed metadata. Effective attributes include inherited/templated values; record provenance (own vs inherited vs template), don't collapse (UC-67).
  3. HTML-native, not Markdown. Translate HTML↔Markdown with a fidelity report; degrade to read-only where lossy (UC-42/59/03). Markdown-first must degrade gracefully.
  4. Per-note opacity. Some notes are encrypted; never surface protected-note ciphertext; project them as structure-shell (UC-61).
  5. One Trilium instance = one shard, not the federation layer; its sync protocol is its own — attach via ETAPI/replica, don't re-drive it (not-a-sync-daemon).

8.3 What Trilium teaches that shard-wiki should keep

  • Separate page identity from placement (note vs branch) — the cleanest model for multi-location / multi-shard pages and for the clone/reference primitive (T16).
  • Model metadata as computed (own + inherited + templated) with per-attribute provenance (UC-67) — not a flat key/value bag.
  • Content opacity is per-item, not only whole-shard (UC-61 refinement).

9. Use-case seeds → catalog (promoted 2026-06-14)

Last existing UC is UC-65. New UCs UC-66, UC-67 added; existing UCs enriched.

Seed Catalog action
Attach a shard with a DAG hierarchy / note cloning — a page may occupy multiple namespace locations at once (note identity separated from placement via branches); no single canonical path UC-66 (new)
Preserve inherited / templated attributes — project a structured shard whose metadata is computed (own + inherited + template), distinguishing effective vs own with per-attribute provenance UC-67 (new)
DAG/multi-parent vs tree; note/branch (identity vs placement) enriches UC-22
Labels (#tag) + typed relations (~relation); HTML-native enriches UC-34
Templates (~template) inject attribute sets enriches UC-15
HTML (CKEditor) content → HTML↔Markdown lossy translation enriches UC-42 (links UC-59)
Per-note encryption (protected notes) = partial content opacity enriches UC-61
Scripting (frontend/backend code notes, Script API) = in-app host enriches UC-38
ETAPI (token REST) = designed external surface for a self-host server links UC-57
Render/script notes + attribute queries = dynamic content links UC-54; typed relations link UC-58
noteId/branchId 12-char IDs links UC-51

10. Architecture notes for SHARD-WP-0002 (no UC)

  • Namespace model must support a DAG and separate page identity from placement (note/branch). A page is one entity with N placements (paths/shards). Feeds the page/ namespace model and the clone/reference primitive. (T12, T16.)
  • Computed/inherited metadata (UC-67): the page model's structured-data representation must carry effective vs own with per-attribute provenance (own/inherited/template), not a flat bag. (T12.)
  • Content opacity is per-item (UC-61 refinement): the content-opacity capability (proposed twelfth spectrum) should be granular (per-note), not only whole-shard. (T11.)
  • HTML as a source content model joins TML/Notion-blocks in the translation capability (HTML↔Markdown, lossy-aware). (T15.)
  • Scripting as an in-engine host + ETAPI external REST are two more adapter-host exemplars (with Roam/Obsidian/Joplin). (T14.)

11. Open questions (for spec / workplans)

  1. How does shard-wiki represent a cloned note in the union — one page with multiple path placements, or a page transcluded into multiple locations? (UC-66 vs UC-44/45.)
  2. When projecting inherited attributes (UC-67), does shard-wiki materialize effective values (snapshot) or compute them live from the shard's tree/templates?
  3. Is HTML↔Markdown round-trip lossless enough for write-back overlays, or are Trilium overlays read-only/native-HTML (cf. UC-42 Q2)?
  4. For per-note encryption (UC-61), is a partially-opaque shard projected with protected notes as visible-but-opaque placeholders, or hidden entirely?

12. Sources

Source Used for
TriliumNext/Trilium — DeepWiki (https://deepwiki.com/TriliumNext/Trilium) SQLite document.db/better-sqlite3; tree + cloning via branches; note types; sync
Cloning notes — TriliumNext wiki (https://github.com/TriliumNext/Trilium/wiki/Cloning-notes) Note in multiple locations; branches; branch prefixes
TriliumNext — DeepWiki API & Synchronization (https://deepwiki.com/TriliumNext/Trilium/4.3-api-and-synchronization) WebSocket + sync protocol w/ conflict resolution; 12-char IDs (note/branch/attribute/attachment)
ETAPI (REST API) — Trilium docs (https://docs.triliumnotes.org/User%20Guide/User%20Guide/Advanced%20Usage/ETAPI%20(REST%20API)/) Public REST API since v0.50; token/Bearer auth; trilium-py
Script API — TriliumNext wiki (https://github.com/TriliumNext/Trilium/wiki/Script-API) Frontend/backend code notes; Script API
BrightCoding — TriliumNext overview (https://www.blog.brightcoding.dev/2025/09/20/triliumnext-notes...) Attributes (labels/relations), inheritance, templates, per-note encryption, note types

Cross-references: research/260614-joplin-deep-dive/findings.md (SQLite-local, dual surface, content opacity), research/260614-notion-deep-dive/findings.md (typed relations, external API), research/260614-zigzag-deep-dive/findings.md (clone / dimensions), research/260614-shard-spectrum-synthesis/findings.md (spectra this refines), spec/UseCaseCatalog.md (UC-15, UC-22, UC-34, UC-38, UC-42, UC-51, UC-54, UC-57, UC-58, UC-61), workplans/SHARD-WP-0002-federation-architecture.md (T11, T12, T14, T15, T16).


13. Traceability

  • New UCs: UC-66, UC-67spec/UseCaseCatalog.md.
  • Enriched UCs: UC-15, UC-22, UC-34, UC-38, UC-42, UC-61 (links UC-51, UC-54, UC-57, UC-58, UC-59).
  • Architecture (no UC): DAG namespace + identity/placement (note/branch) split; computed/inherited metadata; per-item content opacity; HTML source model; scripting + ETAPI host surfaces → SHARD-WP-0002 (T11, T12, T14, T15, T16).
  • Boundary recorded: Trilium (TriliumNext) is one SQLite-local candidate shard with a DAG hierarchy and computed metadata, best attached via ETAPI; HTML-native (lossy to Markdown), per-note opacity; not a substrate, not the federation layer (INTENT graceful-degradation, no-silent-mutation, not-a-sync-daemon).