Protocol — frontmatter field-source contract

Updated · View the entry on sijie.xyz ↗

For every field, two questions: where does its value really come from, and who reads it — Obsidian, StandMeet, both, or neither. Anything whose source is more trustworthy than "you typing it" (the filename, system time, the body, the importer) shouldn't be in the template. Checked field-by-field against buildSaveInputFromVault (import.go:286) — this is the writings branch; the wiki/subjectivity branch parses its own smaller set (corpFM, sync_note.go:15), noted per row where it differs.

The matrix

✅ = used / read · ✕ = no native behavior — Obsidian still stores & shows every property (excerpt/status/… appear in the picker only because your own notes use them, not because Obsidian acts on them).

Field Source Obsidian StandMeet Note
publish you (the gate) ✅ Obsidian Publish ✅ import gate (writings) · visibility gate (wiki/subjectivity) writings: true → import; corp notes: always persisted, publish only sets published and an absent key keeps the current value (F-L-8 / F-L-22); renders as a Checkbox
tags you ✅ tag pane / search ✅ shared native key
excerpt you ✕ ✅ summary
cover_headline / cover_sub you ✕ ✅ cover copy
cover_hue you ✕ ✅ amber(def) / violet / acid
cover_image you / a body image ✕ ✅ resolved to an asset
visibility you ✕ ✅ public(def) / private
locked_body special ✕ ✅ not normal authoring
title filename ✅ filename is the title — same as Obsidian ✅ override-only (pickTitle) set only to override the display name
slug filename ✅ filename = the note identity — like Obsidian ✅ reads fm.slug else filename (pickSlug) don't set it; ⚠️ no folder-note collapse yet
aliases you ✅ alt names / [[alias]] / search ✕ writings: parsed, ignored · ✅ wiki/subjectivity: stored in corpus_notes.aliases, resolves [[alias]] links (463411b48, 2026-08-05) shared key for corp notes
cssclasses you ✅ per-note CSS ✕ writings · ✅ wiki/subjectivity: stored as css_classes, added to the note container at render (f147b1e8f, 2026-07-06) shared key for corp notes
lang / lang-labels you ✕ ✅ wiki/subjectivity only: identity language + switcher labels for > [!lang] notes (corpus_notes.lang, lang_labels) not read on the writings branch
created system ✕ (fs time is separate) ✕ DB created_at wins neither needs it typed
cross_refs body [[links]] ✕ ✕ hardcoded empty relationships come from body wikilinks
path / parent_id vault path / folder tree (the file's location) ✅ auto not a frontmatter key
read_minutes computed from body ✕ ✅ computed not a frontmatter key
published_at · obsidian_source_path · obsidian_imported_at · updated_at importer / DB ✕ ✅ auto not frontmatter keys

publish is intentionally Obsidian's native key

publish is one of the property keys Obsidian recognizes natively (it's what Obsidian Publish reads). So StandMeet's import gate and Obsidian share one flag with one meaning — publish: true = "make this public" — instead of inventing a custom field. Upshots: it renders as a real Checkbox in the Properties panel, and if you ever also run Obsidian Publish, the same publish: true triggers both (intended — both mean public; use two keys only if you want them to diverge).

Two counterintuitive traps

  1. cross_refs does nothing: you might think listing related articles in frontmatter creates relationships — the importer hardcodes it empty. Relationships come only from [[wikilinks]] in the body.
  2. One key, two audiences: created/aliases are useless to the StandMeet import, but aliases is useful to Obsidian and created is covered by fs time. Neither needs to be hand-typed.

The slimmed template (i.e. the standmeet-article template)

---
publish: false
excerpt:
tags: []
# add visibility / cover_hue / cover_headline / cover_sub when needed
---

title, slug, created, cross_refs, path are all absent — left to the filename, system time, body wikilinks, and the importer.

Related notes