ZenNotes 2.62.0 brings ZenNotes to Finder: press Space on any Markdown file and Quick Look shows it the way ZenNotes renders it, with an Open in ZenNotes button. It also makes Cloud restores and backups behave the way they read, and tidies the rough edges ZenNotes Cloud's launch testing turned up. A restored note no longer leaves a copy behind, a refused backup names the limit it hit, Settings → Cloud opens on what needs you, and an embed whose file is not on this device says so instead of drawing an empty player. It also answers this week's reports: a Kanban board can order its cards by due date, link hints reach the links in the Edit view, ⌘W closes Settings and floating windows, Blinking cursor off holds in every window, and a dated wikilink like [[2024.01.15]] opens its note instead of the browser.
Released from fb3d13f8 through PR #895 on October 5, 2026. All installers are verified.
Features
- Quick Look for Markdown files (macOS). Select a
.mdfile in Finder and press Space: Quick Look shows it rendered by ZenNotes' own Preview, in your theme and fonts, with callouts, tasks, tables, highlighted code, math, Mermaid diagrams and the images the note embeds. Open in ZenNotes opens it in the app (a note inside a vault you use opens there, any other file in its own window); once you click into the preview, Enter does the same, and with Vim mode onoopens it whilej/k, Ctrl+D / Ctrl+U,ggandGmove through the note. The preview is read-only and never goes online: website links open in your browser, and pictures hosted on the web are not loaded. It turns on after you open ZenNotes once, and System Settings → General → Login Items & Extensions → Quick Look turns it off. - Order Kanban cards by due date. The board's toolbar has Order next to Group by: Manual, as before, or Due date. By due date every column on every board, custom status boards included, sorts earliest first with cards without a date last, and a card moved to another column (a drag,
Shift+H/Shift+L) lands in its date slot. Before, the first drag saved a hand-made order for the columns and that order won from then on, so a task whose date moved up stayed where it had been dragged. The dragged arrangement is kept while you order by date, and Manual brings it back exactly. The same switch isson the board in Vim mode,:order due | manualon the Tasks ex line, the palette's "Kanban: Order Cards by Due Date", Settings → Tasks → Card order, andkanban_card_sortunder[view]in config.toml (#889). - Settings → Cloud shows a skipped automatic backup. When the daily backup could not run, the Automatic daily backups row now says why: a plan limit is worded from its numbers ("The automatic backup on 10/5/2026 was skipped. This vault holds 54 MB, and backups on your plan hold up to 52 MB…"), anything else says the backup failed and will be tried again. Before, a skipped backup was silent.
Fixes
- A restored note leaves no copy behind. Restoring a Cloud backup that moved a note back (out of Trash, for example) wrote the note in its old place and left the copy where it had been; the next scan uploaded that copy as a new note to every device. The old copy now goes, but only when this device still holds exactly what it synced there; an edit made here since is kept and reported as a conflict. On the phones, a restore that only changed a note's capitalization could delete the only copy on storage that ignores case (Android's default); it now renames in place, and a phone stopped in the middle of that rename, or a save landing in the middle of it, no longer leaves a hidden copy behind or loses the save.
- A refused backup names the limit it hit. "This backup would exceed your plan limits" now reads, for example, "This vault holds 54 MB, and backups on your plan hold up to 52 MB. Remove large files, or contact support to raise the limit.", and likewise for the file count and the number of backups kept. The restore prompt quotes the backup's label ("Restore “Weekly”?") and the result counts in the singular when it should.
- Settings → Cloud opens on what needs you. The status bar's Review and Set up, and
Space ror the palette after a Cloud vault was removed, open Settings on the Cloud page scrolled to This vault, with the keyboard on the first thing waiting (a removed-vault notice, a settings difference, a sync failure, files needing attention). Before, the page opened at its top with the keyboard in the settings search. - The Cloud usage card stays current. It read usage when Settings opened; it now reads it again a few seconds after a sync run moves files, and waits while the window is hidden.
- The restore result reads plainly. "This vault is synced to cursor 18." is now "This vault now matches the backup."
- An embed whose file is not on this device says so. A file too large for Cloud stays on the device that has it, while its note syncs everywhere; other devices drew
![[clip.mp4]]as an empty player and images or PDFs as broken frames. Edit mode and Preview now show "clip.mp4 isn't on this device." in its place, and the embed turns into the player as soon as the file arrives. A file reached through a symlink is listed as an attachment and plays as before. - Link hints label the links in the Edit view.
Space hlabelled every control on screen and the links in Preview, but none of the links in the Edit view, which draws them as styled text. Hint mode now also labels the visible links of every open editor (bare URLs,[[wikilinks]]with an alias or a heading, Markdown links and images), down the note in reading order and never inside code, and following a label does what clicking the link does (#894). - ⌘W closes Settings and floating windows. With Settings open, ⌘W closed the tab behind it (or the whole window once no tab was left), and in a floating note it did nothing. ⌘W now closes the frontmost window, the macOS rule, and Settings counts as one. Floating notes, the external-file window and Quick Capture close on it like their close button: a pending save is written first, and Quick Capture hides and keeps its draft. A rebind or unbind of Close active tab applies there too. While a dialog, palette or menu is open ⌘W does nothing, so it can never close the tab behind it (#893).
- Blinking cursor off holds in every window. Floating notes, Quick Capture and the external-file window (and the reference pane and the template editor) kept blinking with Blinking cursor turned off. Every editor now follows the setting, and an open window follows a change made in Settings at once (#892).
[[2024.01.15]]opens its note.gd,gD, ⌘-click on a link's source, a link in a table cell, a database relation chip and a missing dated note clicked in Preview sent a wikilink with dots in its name to the browser ashttps://2024.01.15, even with the note right there, andgyoffered to copy that address. A wikilink now reaches the browser only when it is written with a scheme ([[https://…]]); Markdown links keep reading[site](example.com)as a web address.- A card's menu keeps what you type into it. A card's right-click menu on the Kanban board filters as you type, and the manual suggests typing "prio"; the board's own single keys saw the letters first, so that
imarked the card in progress (anxor acwould check it off or cancel it). Behind Settings the Tasks view's keys fired too:1,2and3switched the view andaopened the new-task prompt. Both now wait while a menu, a prompt or a dialog is open. - Setting a value back in config.toml applies. Change a setting in the app, then set it back by hand in
config.toml, and the file is byte for byte what the app had written before; the app took that for a late echo of its own write and ignored it, so it stayed on the newer value while the file said otherwise. A put-back now applies like any other edit: at once, or about a second and a half later when the app has only just written the file. - A right-click on a wikilink stays where you are. In the Edit view a right-click on a rendered wikilink opened the linked note and then drew the menu over it, and on a link to a missing note it asked to create the note. Only the primary button follows a link now.
For contributors
- Quick Look lives in the new
apps/quicklookworkspace: the page (src/, app-core's Preview with a bridge shim, Typst and plot renderers left out, 11 MB), the sandboxedZenNotesQuickLook.appex(Swift, serves the page and embedded files overzenql://behind a no-network CSP; WebKit still needsnetwork.clientto start), andZenNotesQuickLookOpener.xpcinside it (unsandboxed, because Quick Look's sandbox lets a preview launch nothing).apps/desktop/build/after-pack.jsbuilds and signs it per architecture with the app's identity and timestamp server, since electron-builder never signsContents/PlugIns.ZENNOTES_QUICKLOOK_SELFTEST=1compiles a self-test for local validation (never in CI).apps/quicklook/README.mdcovers testing. The typography CSS variables moved fromApp.tsxtolib/typography-variables.ts. - Cloud sync: an upsert with a path change retires the previous path only when this device vouches for it (
retirePreviousPath, inode-checkedsameFile); the coordinator's matching-bytes shortcut no longer skips a move. The portable repository renames case-only through a temporary name, writes a record under.zennotes/zennotes-cloud-sync/respellingsfirst, and skips the second step when a save took the name;CloudSyncRepository.recoverInterruptedWork(optional) settles leftover records at the start of every run and never fails it. cloudBackupLimitMessageandcloudBackupCreateErrorin shared-domain word BACKUP_QUOTA_EXCEEDED details;formatCloudBytesmoved to shared-domain (app-core re-exports it).CloudBackupSchedule.last_failureis declared in bridge-contract.- Browse (
packages/app-core/src/browse.ts) now returnsfilesrows for the phones' folder view, placed as the desktop sidebar places them; additive, unused by desktop and web. - The store records
assetFilesListed, andresolveLocalAsset()reportsmissing;indexImportedAssetsindexes an import before its embed is inserted. DesktoplistAssetsincludes symlinked files; znserver needs ZenNotes/znserver#11 in the release that pins this web artifact. - Phones: ZenNotes/zennotesios#42 and ZenNotes/zennotesandroid#95 carry the shell side (note dates follow renames, folder file rows, iOS folder vault list, Cloud UI tests); the file rows, media notice and Settings fixes reach the phones with a core built from this release. Shell-only fixes from the same issue round: ZenNotes/zennotesandroid#96 and ZenNotes/zennotesios#44 (Edit mode scrolling no longer snaps back to the caret, #891) and ZenNotes/zennotesios#43 (Ubuntu Sans and Ubuntu Sans Mono bundled on iPhone and iPad, #890).
- Links:
linkRangeAtCursorreports the link's kind from the shared shape table (linkRangesInLinereads the same table), andexternalUrlForLink(target, kind)decides what opens in the browser;followLinkTargettakeskind, andextractLinkAtCursor, which dropped it, is gone. Hint mode collects editor links inlib/editor-link-hints.tsand follows a wikilink throughopenWikilink. The rendered-wikilink mousedown handler ignores every button but the primary one. - Every editor builds its cursor layer through
lib/cm-cursor-blink.ts(cursorDrawSelection,storedCursorDrawSelectionfor windows that read the prefs blob and follow itsstorageevent); a test fails if another file callsdrawSelection(). - Kanban (#889):
kanbanCardSort('manual' | 'due') is a portable pref ([view] kanban_card_sort), global only and deliberately not a vault view override, which the Go server's vault.json mirror would have to learn. The board orders cards throughorderCards;compareCardsByDueis the one comparator the column builders share (three copies before);placeTaskInColumnOrderwrites nothing while ordered by date.isOverlayOrDialogOpeninlib/overlay-open.tsadds aria-modal dialogs and Settings toisAppOverlayOpen; the board and the Tasks view use it, the other list views still use the narrower check. apps/desktop/src/main/app-config.ts: an earlier own-write text counts as a stale watcher read only while the module's own writes are landing (in flight, or withinOWN_WRITE_SETTLE_MS, 1.5 s, of the last one), and a read skipped for that reason is re-checked once they settle. Remembering own-write texts with no time bound swallowed any hand edit that put an earlier version back. A read that outlives its watcher is dropped.lib/close-shortcut.ts:resolveCloseShortcutdecides what Mod+W does in the main window (close Settings, keep, Vim prefix, close tab, close window);useCloseWindowShortcutgives the floating, external-file and Quick Capture windows the same binding, rebinds included. Settings marks its paneldata-settings-dialog.
Verification
How to test locally:
- Build and launch with isolated stores:
npm run build --workspace @zennotes/desktop, thenZENNOTES_USER_DATA_PATH=$(mktemp -d) ZENNOTES_CONFIG_DIR=$(mktemp -d) npx electron apps/desktop/out/main/index.js. - Missing media: in a note write
![[assets/nope.mp4]],![[assets/nope.png]]and![[assets/nope.pdf]]. Before: an empty player and broken frames. After: "nope.mp4 isn't on this device." (and so on) in Edit and Preview; copy a realnope.pngintoassets/and the card turns into the picture. - Restore (needs Cloud): move a note to Trash, sync, restore the backup from before. Before: the note in Inbox and a copy in Trash, uploaded to every device. After: only the note in Inbox.
- Backup limits (needs Cloud on a small plan): Create backup on a vault over the limit. Before: "This backup would exceed your plan limits." After: the sentence names the size and the limit.
- Settings → Cloud: with a kept-both conflict copy waiting, press Review on the status bar. Before: Settings at the top of the Cloud page. After: This vault in view, the file list focused.
- Link hints (#894): in the Edit view open a note holding
https://example.net,[[ZenNotes]],[GitHub](https://github.com)and`https://code.test`, then pressSpace h. Before: labels on the toolbar and sidebar only. After: labels on the three links too, none on the code span; typing a label opens that link. - ⌘W (#893): with three tabs open press
⌘,then⌘W. Before: Settings stays and a tab closes. After: Settings closes and the tabs stay. Run Open in Floating Window from the palette, then⌘Win it. Before: nothing. After: the window closes. In Quick Capture type a line and press⌘W: it hides, and the line is still there when it opens again. - Blinking cursor (#892): Settings → Editor, turn Blinking cursor off, then open a note in a floating window and open Quick Capture. Before: both blink. After: both hold still, and turning the setting back on makes both blink without reopening them.
- Dotted wikilinks: make a note named
2024.01.15and, in another note, write[[2024.01.15]]. With Vim on, put the caret in the link and pressgd(or ⌘-click the link while its brackets show). Before: the browser opens https://2024.01.15. After: the note opens. Then right-click the rendered link. Before: the linked note opens under the menu. After: the menu opens where you are. - Quick Look:
cd apps/desktop && npx electron-builder --dir, open the packeddist/mac-arm64/ZenNotes.apponce (orpluginkit -a dist/mac-arm64/ZenNotes.app/Contents/PlugIns/ZenNotesQuickLook.appex), then select a note in Finder and press Space. Before: macOS showed the raw Markdown text. After: the note as ZenNotes renders it, in your theme, with Open in ZenNotes; pressing it opens the note in the app. (Opening a packed build also makes it the handler forzennotes://; seeapps/quicklook/README.mdfor testing on a separate profile.) - Kanban card order (#889): in a scratch vault write
- [ ] Write spec @status:backlog due:2026-10-20,- [ ] Fix login @status:backlog due:2026-10-08,- [ ] Someday idea @status:backlogand- [ ] Ship v1 @status:backlog due:2026-10-12, putkanban_statuses = ["backlog", "doing", "review"]under[view]in config.toml, and open Tasks → Kanban with Group by: Custom status. Drag Someday idea to the top of Backlog, then change Write spec's date to2026-10-06. Before: the column keeps the dragged order and Write spec stays at the bottom, with no way to sort by date. After: set Order to Due date (or pressswith Vim on): Write spec, Fix login, Ship v1, Someday idea;Shift+Lon a card lands it by date in the next column; Order: Manual brings back Someday idea on top. - Menu keys: with Vim on, right-click a card on the board and type
prio. Before: the card turns[/](in progress) and the menu filters on "pro". After: the menu narrows to the priority entries and the card is unchanged. Also press⌘,on the Tasks view and then1: before, the view behind Settings switched to List; after, nothing happens behind Settings. - config.toml put-back: launch as in step 1 but with a fixed config directory (
ZENNOTES_CONFIG_DIR=/tmp/zn-cfg), open Tasks → Kanban, and set Order to Due date, then Manual, then Due date again. Wait two seconds, changekanban_card_sort = "due"back to"manual"in/tmp/zn-cfg/config.tomland save. Before: the board stays on Due date. After: it switches to Manual within half a second.
Distribution channels
- AUR 2.62.0-1:
beeb7d7, mirrored in372a44ba; tarball SHA-256903baa6e...ca69cf4matches GitHub's digest, the bundled CLI folder check passed, and the AUR package checks passed onmainand the release branch. - Homebrew: tap
b28fc38, mirrored in8983e4ae; the arm64 DMG was downloaded and its SHA-256 matches the cask and GitHub's digest, the x64 hash is GitHub's digest;brew styleclean. - Nix: the first hash-generation run failed. The packaged app now carries
@parcel/watcherand its prebuilt musl binary (sass 1.103.1, which this release's braces override gives Excalidraw, depends on it, and nothing loads it), and autoPatchelf could not satisfylibc.musl-x86_64.so.1.93934229drops the musl variants inside the Nix package; the rerun 37382323699 passed,f16bbe0dcarries its values, and the main rebuild 37382901964 passed.desktopHashis the same tarball digest the AUR pins. nixpkgs PR #570652 carries 2.61.0 -> 2.62.0 as one commit on current master and awaits upstream review. Its source hash is the tag tarball's, computed withnix store prefetch-file --unpack; the same command reproduces master's current 2.61.0 hash. nixpkgs' derivation builds from source and has no autoPatchelf step. verify:channels -- 2.62.0passed for Homebrew, AUR, Nix, and all seven website download routes. GitHub latest is v2.62.0. Website PR #62 merged atff57488f. Its main tests and deploy passed (run 37384433044), and zennotes.org/releases serves the 2.62.0 entry; the docs carry the Quick Look section and:order.- Self-hosted server: znserver 2.62.0, released the same day, embeds this release's client code (
web-2.62.0-web.h53c3b6622d59ff2e, published as a pre-release) and lists files reached through a symlink as assets (znserver#11); Dockeradibhanna/zennotes:2.62.0,2.62andlatest(linux/amd64 and linux/arm64, reporting v2.62.0). - Phones: iPhone 1.18.0 (34) and Android 1.1.32 (35) carry this release's app code as core
core-2.62.0-core.hcf81934394c63533, published as a pre-release. Android 1.1.32 is live on Google Play and on GitHub with Play's universal APK; iPhone 1.18.0 is in App Review.
Release validation
- Fresh typechecks passed (no cache); 6,056 unit tests passed, 5 skipped (shared-domain 1,896, app-core 3,096, quicklook 15, desktop 1,049).
- The signed local package (
npm run pack) built and signed the Quick Look extension in afterPack, launched isolated with a CDP page in 1.5 seconds and reported 2.62.0;codesign --verify --deep --strictpassed. Vim editor (12 checks), sidebar navigation (12) and editor improvements (19) smoke suites passed on the first run. - Release PR #895: all 9 checks passed on
fb3d13f8. - Release run 37379286092 passed on every platform on the first attempt, with 25 assets.
- All four update manifests and their 13 referenced files passed size and downloaded SHA-512 verification. The app in the arm64 DMG passed notarization (
Notarized Developer ID), staple and strict deep signature checks, reports 2.62.0, bundlesznv0.6.2, and carriesZenNotesQuickLook.appexwith its opener service: the first CI build of the extension, signed by team WYY7PK57DM with the hardened runtime, a secure timestamp and the sandbox entitlements as designed. Quick Look itself was exercised end to end on a locally packed build during the cycle (Finder Space, Open in ZenNotes, Vim keys); the CI build's extension was checked for presence and signatures, not registered with Quick Look. - Issues #889, #892, #893 and #894 and the dotted-wikilink, menu-key and config.toml fixes were each driven in the built app over CDP on an isolated profile before they were committed.
- Cloud: the restore fix was verified against production in the built app during the October 5 acceptance run (no duplicate, sequence unchanged). Billing was accepted separately in Stripe's sandbox, and publishing earlier the same day.