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>
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
~templaterelation) 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)
- 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.
- Don't flatten computed metadata. Effective attributes include inherited/templated values; record provenance (own vs inherited vs template), don't collapse (UC-67).
- 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.
- Per-note opacity. Some notes are encrypted; never surface protected-note ciphertext; project them as structure-shell (UC-61).
- 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)
- 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.)
- When projecting inherited attributes (UC-67), does shard-wiki materialize effective values (snapshot) or compute them live from the shard's tree/templates?
- Is HTML↔Markdown round-trip lossless enough for write-back overlays, or are Trilium overlays read-only/native-HTML (cf. UC-42 Q2)?
- 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-67 →
spec/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).