You’re reading the ZotLit v2 docs. Still on v1? Read the v1 docs

ZotLit

Frontmatter

Field definitions, merge strategies, reserved keys, and update behavior for literature note frontmatter.

This page documents how ZotLit manages YAML frontmatter on literature notes: the fields ZotLit owns, the managed fields a profile declares, merge strategies, and the behavior during note updates.

For step-by-step configuration, see Configure frontmatter properties.

System-managed fields

ZotLit writes these keys itself. Managed frontmatter cannot target them.

FieldSourceDescription
zotero-keyzt.indexedKeyLiterature note identity: KEY for My Library or KEYgGROUPID for group libraries
zotlit-profileThe profile that ran the operationThe profile that produced the note, as its name and 12-character ID. Absent when the Default profile produced it
zotlit-cslThe profile's citation styleCSL ID the note's citations and references render with. Absent when the profile binds no style

User-configured fields

Managed frontmatter is the ordered list of entries under the frontmatter key of a profile document's manifest. Each entry produces one property, or several at once.

Edit the list in the Properties tab of the Template Workbench. On the Templates and properties row at Settings > ZotLit, select Edit profile.

Each entry has an optional key, an optional merge strategy, and exactly one value member. The member name declares the language, so an entry carries no separate language setting:

MemberRequiredDescription
keyNoThe YAML property name written to the note. Omit it for a spread entry
exprOne of the threeA Liquid value expression
valueOne of the threeA JSON-e template
jsOne of the threeA JavaScript expression. Inert while the JavaScript Templates gate is off
mergeNoHow the entry applies when the note is updated. replace (the default), append, or keep

One entry, with key, value, and merge written out:

frontmatter:
  - key: citekey
    value: { "$eval": "zt.citationKey" }
    merge: replace

The Value format control names the value members in the editor: Zotero field · Liquid writes an expr, Rule · JSON-e writes a value, and Fixed text writes a value that holds the text as written. A js entry is edited in the Source view.

A value can be written in any YAML form, such as the block mapping under Spread entries. When you edit a value in the editor, the Workbench saves it as one line of JSON in the profile document. Other entries keep the form they were written in.

Spread entries

An entry with no key is a spread entry. Its value or js member evaluates to a mapping, and every produced key lands as a field at that entry's position, under the entry's one merge strategy.

frontmatter:
  - value:
      title: { "$eval": "zt.title" }
      "zotero/${zt.itemType}": true

Inside a spread mapping, a false $if omits that key and leaves the note's value alone. ${} interpolation builds a key name. A top-level $let shares one calculation across every produced field. A $if that is false at the root of the entry contributes an empty patch, so the entry writes nothing.

expr always produces a single value, so a spread entry cannot use it: a keyless expr entry fails validation. A spread entry whose result is not a mapping, or that produces a reserved or empty key, refuses the whole operation. Diagnostics name the entry by its 1-based position in the list.

In the editor, Add several properties from one rule adds a spread entry. Its row reads Several properties and lists the properties it produced.

Default fields

Out of the box, the Default profile declares four entries. Its document reads:

frontmatter:
  - key: title
    expr: zt.title
    merge: replace
  - key: related
    expr: zt.relatedItems | note_links
    merge: replace
  - key: collections
    expr: zt.collections | collection_paths
    merge: replace
  - key: citekey
    value: { "$eval": "zt.citationKey" }
    merge: replace

The citekey entry writes citekey: null when the Zotero item has no citation key. All four are ordinary managed frontmatter. You can edit or remove them like any other entry.

Liquid expressions

An expr member is one value expression, not a template block. It uses the same filter vocabulary as templates (see Template syntax) and returns typed values (arrays, numbers, strings), not rendered text.

zt.title                              -> "My Paper Title"
zt.authors | join: ", "               -> "Jane Smith, Bob Jones"
zt.tags | map: "name"                 -> ["methodology", "open access"]
zt.tags | obsidian_tag                -> ["methodology", "open_access"]
zt.collections | collection_paths     -> ["Project/Reading", "Research"]
zt.date.year                          -> 2023

JavaScript expressions

A js member holds a JavaScript expression. It requires the JavaScript Templates gate. Any valid JavaScript expression works, with the full note context available as zt:

zt.authors.map(c => c.fullName)   -> ["Jane Smith", "Bob Jones"]
zt.tags.map(t => t.name)          -> ["methodology", "review"]
zt.date?.year                     -> 2023

The return value is serialized to YAML automatically.

Merge strategies

Each entry selects one merge strategy, set with When the note is updated in the editor:

StrategyEditor optionBehavior
replaceReplace the existing valueWrites the generated value unconditionally. The existing value is overwritten
appendAdd to the existing listAppends new generated values not already present to the existing array. Manual additions remain. If existing is blank, writes the generated value. Both the existing and generated values must be arrays; when either side is not an array (and existing is not blank), the field is left unchanged
keepKeep the existing valueWrites the generated value only when the existing field is blank. Once the field has a value, it is never overwritten

Absent values

Only a value entry can produce absence. A JSON-e template that renders nothing at its root, such as one whose top-level $if is false, contributes no value at all.

Absence is the one way to delete a managed key. Under Replace the existing value an absent value deletes the existing key; under Add to the existing list and Keep the existing value it leaves the key as it stands.

What counts as blank

A value is blank (and treated as absent by Add to the existing list and Keep the existing value) when it is:

  • null or undefined
  • An empty string ("")
  • An empty array ([])
  • An empty plain object ({})

Undefined expressions

When a Liquid or JavaScript expression returns undefined, the field is untouched regardless of the merge strategy. Only defined values (including explicit null) reach the merge logic.

Append arrays detail

The Add to the existing list strategy preserves existing items verbatim (including any duplicates already present) and appends only generated items not already in the array.

Reserved keys

ZotLit refuses a static key, or a key a spread entry produces, from this set:

KeyWhat it protects
zotero-keyLiterature note identity. The item key, with the group library ID appended for group libraries
zotlit-profileThe profile stamp that records which profile produced the note. Absence selects the Default profile
zotero-note-keyIdentity of an imported child note. Kept apart from zotero-key so the note never registers as a literature note
zotero-lastmodThe source child note's dateModified, which batch re-import reads to skip unchanged notes
zotlit-cslThe CSL style ID one note's citations and references render with, set from the profile's citation style

A profile document that declares a reserved or duplicate static key fails to load, and ZotLit excludes it from the profiles it offers instead of repairing it. See Profiles.

Validation

The Properties tab marks the row that failed with Problem, and the row shows what went wrong in place of a value. The full explanation, which names the failing key and the entry's position, is in the Problems area of the editor.

Validation has three stages:

  1. The document. A reserved static key, a duplicate static key, or a keyless expr entry stops the document from loading.
  2. The expression. An expr or js member that fails to compile, or a value that cannot evaluate, is a problem the editor names by key and entry position.
  3. The write. A value or js entry whose result falls outside the frontmatter value domain, a spread entry that produces no mapping, or a produced key that is reserved or empty refuses the whole operation.

A refused operation writes nothing. ZotLit never applies a partial patch to a note. A js entry that is inert while the gate is off refuses by key, or by entry position when the entry is keyless.

Merge on update

When you run ZotLit: Update literature note or ZotLit: Update literature note metadata, ZotLit refreshes frontmatter:

  1. Managed entries are re-evaluated in the order they appear in the frontmatter list of the profile document and applied with their merge strategy.
  2. System identity (zotero-key) is refreshed.
  3. Unmanaged keys: any frontmatter key not in the managed set (e.g. aliases, tags, cssclasses) is preserved. ZotLit never touches keys it does not own.

ZotLit: Overwrite literature note replaces the note body but applies the same frontmatter behavior: managed keys are refreshed and unmanaged keys are kept.

ZotLit writes frontmatter through Obsidian's processFrontMatter API, which preserves key ordering and formatting for unmanaged keys. On a newly created note, managed fields are written in the order they appear in the profile document's frontmatter list, followed by system fields. An entry later in the list wins the value, because each entry is applied over the value the entries before it produced.

Removing citekey or another entry from the frontmatter list does not delete existing values. Those values become unmanaged and remain in the note.

JavaScript Templates gate

The JavaScript Templates gate controls whether js entries run:

  • Gate off: js entries are inert. They are not evaluated. Any operation that depends on an inert entry surfaces an error naming those keys. expr and value entries are unaffected.
  • Gate on: expr, value, and js entries evaluate normally.

The gate never reinterprets a member. An expr entry always evaluates as Liquid, and a js entry always evaluates as JavaScript.

A spread entry that uses js is refused by its entry position while the gate is off, because its keys cannot be known until it runs.

Inert entries block note operations

When any frontmatter entry uses the js member and the gate is off, literature note creation and update fail with an error listing the inert keys. Either enable the gate or rewrite those entries as expr or value. See Enable JavaScript templates.

See also

Last updated on

On this page