Protocol — frontmatter field-source contract
Parent: obsidian-sync-mechanism · audited against
backend/internal/corpus/obsidian/import.go(the package moved out ofusecases/on 2026-07-29,9f1ffcf13; re-audited 2026-09-07)
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 |
Note
publishis intentionally Obsidian's native keypublishis 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 samepublish: truetriggers both (intended — both mean public; use two keys only if you want them to diverge).
Two counterintuitive traps
cross_refsdoes nothing: you might think listing related articles in frontmatter creates relationships — the importer hardcodes it empty. Relationships come only from[[wikilinks]]in the body.- One key, two audiences:
created/aliasesare useless to the StandMeet import, butaliasesis useful to Obsidian andcreatedis 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.