ZotFlow 1.7.0
This release rebuilds sync on the same model Zotero itself uses. Edits made in Obsidian and in Zotero now merge field by field, so far fewer changes turn into conflicts. The conflicts that remain show why ZotFlow stopped, what changed on each side and what each choice will do. Around that, 1.7.0 makes note editing safer, keeps source notes in step with annotations and child items, adds customizable display titles, and turns the template tester into a full editing tool.
On first launch, ZotFlow upgrades its local database to a new format. This happens automatically and keeps changes you haven't synced yet. To be safe, sync once on 1.6.x before updating (recommended, but not required). After the upgrade, older versions of ZotFlow can't open the database, so going back to 1.6.x would mean clearing the local cache and syncing again.
Highlights
- Sync merges instead of colliding. If you change a note's tags in Obsidian and its text in Zotero, both changes are kept. The same goes for any two different fields, and tags added on both sides combine.
- A new Conflicts tab in the Activity Center shows each conflict with a word-level diff, a preview of what Keep Local and Accept Remote will do, and a "?" button that explains why ZotFlow asked.
- Your typing is never lost. Edits in source notes and the note editor are saved before any re-render or sync. If a note was deleted in Zotero while you were editing it, ZotFlow offers to save your text as a new note.
- Source notes refresh when annotations or child items change, not only when the parent item changes.
- Safe across devices. A device whose library is out of date no longer overwrites a source note that a more up-to-date device rendered.
- Customizable display titles for the library tree and item search.
- Template tester upgrade: a variables panel, errors with line positions, and saving straight to your settings or template file.
- Large libraries sync much faster and no longer run phones out of memory on the first sync.
- Phone and tablet layouts for the Activity Center and template tester.
A rebuilt sync engine
ZotFlow's sync now follows Zotero's own approach: it remembers the last version both sides agreed on and compares each side against it (a three-way merge).
- Field-level merging. Changes to different fields merge automatically. Tags and collections merge as sets. A note trashed on one side and edited on the other keeps both changes.
- Real conflicts only. ZotFlow stops to ask only when the same field changed differently on both sides, or when something was deleted on one side and edited on the other. It never overwrites either side silently.
- Edits stay in conflict until you decide. Editing a note or annotation that's already in conflict no longer pushes your edit over the Zotero copy.
- Reliable on bad connections. If an upload's response is lost, ZotFlow figures out on the next sync whether the write reached the server, so nothing is sent twice or dropped. Rate limits and server errors are retried with backoff.
- Large libraries. Downloads are saved in batches as they arrive, so an interrupted first sync picks up where it stopped. First sync of a 15,000-object library dropped from about 44 s to about 6 s in our tests, and a PDF with thousands of annotations now syncs in seconds instead of minutes.
- One sync per library at a time. Starting "sync all" while one library is syncing no longer runs the two on top of each other.
Fixed in sync
- iPad and iPhone: uploads were sent without Zotero's version check, so an edit from iOS could overwrite a newer change in Zotero, and an item deleted in Zotero could come back. All requests now carry their headers correctly on iOS.
- Group permissions: a group set to None or Read Only on the API key page now correctly falls back to the key's default group access, the way Zotero does it.
- A note trashed on both sides no longer shows as a change.
- Writes that Zotero refused because their parent no longer exists anywhere used to be retried silently on every sync. They now show up as a conflict you can resolve.
Conflicts tab
Conflicts have moved out of the Sync tab into a tab of their own.
- Each conflict shows a summary, a field table with git-style word and line diffs against the last synced value (notes and comments rendered as Markdown), and the result of each choice.
- Accept Remote now takes Zotero's value only for the conflicting fields. Your other, non-overlapping changes are kept and uploaded. To replace the whole item with one side, use Keep Local (all fields) or Accept Remote (all fields) ("Overwrite all fields with the selected side").
- An item deleted in Zotero that had local changes underneath appears as one entry, with its affected notes and annotations as a tree. Resolving it resolves the whole group.
- A choice that isn't available (for example Accept Remote before Zotero's copy could be fetched) is disabled, with the reason shown. A missing Zotero copy is fetched again on the next sync.
- The Sync tab now shows, per library, how many changes are waiting to upload (↑), how many are waiting to download (↓), and how many conflicts there are.
- On a phone the list fills the screen and each conflict opens full screen, with Resolve always in view. On tablets and narrow windows, field tables become one card per field.
- Item types use Zotero's display names.
Safer note editing
- Edits typed into a source note's editable regions (Zotero notes, annotation comments) and into the note editor are queued and written as soon as you pause. A source note re-render, or a sync, writes your pending edits first, so it can no longer overwrite text you just typed. Closing the editor right after typing no longer drops the last change.
- Every sync started from a command or the Activity Center first saves what open editors are still holding, so a sync never uploads an older version than the one on screen.
- Note deleted in Zotero: if you edit a note that was deleted in Zotero, ZotFlow shows its title, parent item and first lines, and offers Save as new note. The text is saved under the same item if it still exists, or as a standalone note otherwise, and you keep editing the new note. The note editor and source notes now use the same prompt.
- Saving text that hasn't changed no longer marks a note for upload.
Source notes
- Child changes trigger a refresh. Zotero doesn't bump an item's version
when its annotations, attachments or child notes change, so ZotFlow used to
skip those notes unless you forced an update. Source notes now record an
item-treefingerprint of the whole item, so any change underneath counts. Notes written before 1.7.0 count as outdated once and refresh on their next update. - Multi-device safety. Source notes also record
library-version. If your vault syncs between devices, a device that hasn't caught up with Zotero yet leaves a newer note alone instead of rewriting it from older data. A forced update still rewrites it. - Fixed frontmatter order. ZotFlow's own keys now always come first, in a
fixed order (
zotflow-locked,zotero-key,library-id,item-version,item-tree,library-version). Your template's keys follow in their own order. Existing notes are reordered the next time they render. - Long titles no longer fail. Each part of a note path is capped at 200
bytes, cut cleanly between characters (never inside a Chinese character or
an emoji), so long titles no longer fail with
ENAMETOOLONG. - Source notes only for top-level items. A
zotero://selectlink to an annotation now opens it in its attachment, a child attachment opens in the reader, and a standalone note opens as a note. ZotFlow no longer creates source notes for notes, annotations or child attachments, or warns "No attachments found" when you open a standalone note from search. - A frontmatter template that renders empty no longer breaks the whole note.
Customizable display titles
Settings → General → Item Display → Display Title Template sets how items
are titled in the library tree and item search, using the same item.
variables as citation templates. For example:
{{ item.creatorSummary }} ({{ item.year }}) {{ item.title }}
- Leave it empty to keep the Zotero title. If the template fails or renders empty for an item, that item falls back to its Zotero title.
- Sorting by title follows the display title. Search matches both the display title and the Zotero title.
- Attachments keep their file names unless your template handles them
(checks
item.itemType == "attachment"). Attachments also getitem.filename,item.contentTypeanditem.linkMode. - The file tag next to an attachment now comes from its content type, so a name without an extension isn't shown as the tag, and standalone attachments get their file icon back.
Templates
Every Zotero field, under its proper name
- Templates now see every field in Zotero's schema. Fields an item doesn't
have exist as empty values, which
{% if %},defaultand the other filters treat as missing. - Base fields resolve the way Zotero does: a book section's
publicationTitleis itsbookTitle, a patent'sdateis itsissueDate, and a case'stitleis itscaseName. Previously these came out empty, and cases, statutes and emails had no title in the tree or search. item.creatorsnow has the full creator data (creatorType, first and last name), anditem.creatorSummarygives Zotero's own author summary ("Smith and Jones", "Smith et al.").- Note path templates also accept the
item.prefix, e.g.{{ item.title }}, matching the other templates.
Template tester (Activity Center → Template)
- Variables panel: every variable the template sees for the picked item
or file, with its current value. Click a variable to insert it at the
cursor. Missing values show as
undefined,nullor"", because templates treat them differently. Arrays with no elements still show their structure (attachments[0].annotations[0].text, …). - Errors you can find: a failed render shows its phase, message and
position. Clicking the position selects the line, and a frontmatter error
shows the YAML it produced. Unknown filters (a typo like
| titel) are reported as errors in the tester. Real renders still let them pass through. - Hints explain what the output alone doesn't show: a built-in default was used, a required frontmatter key can't be set, a value was cleaned up for a file name, and so on.
- Save where it's used. A template that renders without errors can be saved to the setting it belongs to (citation, note path and display title templates) or to your source note template file (created and set up if you don't have one yet). The save dialog says whether it will create or overwrite a file. If the output is out of date (you changed the item, file or annotations since the last render), saving waits until you render again.
- A new Item Display Title context, and source note frontmatter shown as a properties table in reading view.
- A template path typed without
.mdnow reads and saves the same file real renders use. - On phones, the editor and output panels have fixed heights and scroll inside, with Save and Render kept in view.
Search, tree and reader
- Enter picks the first result. Group labels ("Best Match", "Recent
Viewed", "TYPE", …) are no longer selectable rows, so Enter works right away
in item search, the item picker and
@@citations. - Results match what you typed last. Typing quickly (e.g.
type:jo) no longer lets a slow, outdated search replace the current suggestions. - Collection labels in search results wrap with "…" on narrow screens, so author and year stay readable.
- The library tree updates just the changed item while you type in a note, instead of rebuilding the whole tree every couple of seconds.
- Reader: reopening a reader tab through back/forward navigation, layout restore, or a link opened in the same tab no longer gets stuck on "Loading…".
- The tag editor focuses its input when it opens.
- All ZotFlow dialogs share one title style.
Other changes
- New installs save rendered image and ink annotations to
Source/Imagesinstead of the vault root. Existing settings are unchanged.