Conversation
The website docs got a full drift-audit pass against the running app (zennotes.org commit 0e325ba); this lands the same corrections in the in-app manual so the two surfaces keep telling the same story: the find-and-replace bar on Mod+F, Mod+O and the editor mode shortcuts, Mod+L, tag rename/delete from the chip context menu, rename-fixes- wikilinks, note list sort/group/reveal, quick capture and template leader bindings, K/J task reordering, database header and row menu keys, sidebar footer degradation, Empty Trash, workflows trigger status, and the home-row-mod leniency in hint mode.
Three users, one gap: a reading list, a movie backlog, and a project note with an embedded checklist all flooded the Tasks view, because one rule decided everything: every - [ ] line in a live note is a task, and an undated task lands in Today, the most prominent bucket in the app. The only escape was splitting vaults. Two mechanisms now separate checklists from tasks, both stored in the vault itself so every runtime agrees (desktop, web, the Go server, the CLI, MCP, and mobile, which imports the same parser): - Frontmatter tasks: false (or off) turns a note into a pure checklist. Checkboxes render and toggle exactly as before; the note just stops feeding every Tasks surface, and it wins over a tags: [task] file task. tasks: note keeps the note's own file task on the board while silencing its inline checkboxes, so a project note is one card instead of twenty. Anything else means today's behavior; there is no YAML typing anywhere, so values are matched as lower-cased strings. - tasks.excludedFolders in vault.json lists on-disk relative folders whose notes are never scanned. Right-click a folder for Exclude from Tasks, or manage the list under Settings, Tasks. The matching helper lives in shared-domain with a byte-compatible Go mirror (tasks_exclude.go), the same discipline as system-folder-paths. Exclusions are total on purpose: no surface shows a different truth. The escape hatches are explicit: zn task list --include-excluded (--all was taken; it means every status), includeExcluded on the MCP list_tasks tool, and ?includeExcluded=1 on the server's /api/tasks and /api/tasks/for. Toggling by task id stays exclusion-blind everywhere, because an explicit id is an explicit ask. Two latent bugs fixed on the way, both found by running the real thing: the Go single-note rescan (ScanTasksForPath) had no folder gate at all, so it would parse a trashed note the full scan skips; and Go cloneSettings rebuilds VaultSettings field by field and silently dropped the new tasks object, which only a curl against the live server caught. A vault-level regression test now goes through New, the settings cache, and the clone. Deliberately not done: the Obsidian-Tasks-style per-line #task opt-in (it would empty every existing Tasks view on upgrade; the vault.json tasks object leaves room for a mode: all | tagged later), and view-side filtering, which is its own feature. How to test locally: npx electron-vite build in apps/desktop, add tasks: false to a checklist note, watch it leave the Tasks view; put tags: [task] plus tasks: note on a project note with checkboxes and see one card; right-click a folder, Exclude from Tasks; compare zn task list with and without --include-excluded.
… view
Reported on X by @BTC_1Ly: a worked answer written as
$$\frac{800}{10000} \times 100\% = 8\%$$ inside a table cell
rendered in the editor's table widget but came out as raw source in the
reading view, so Split showed two different truths for the same cell.
(They later found the single-dollar workaround in the docs; the double-
dollar form is legal and renders everywhere else, so it should just
work.)
The regression was self-inflicted: the currency guard added to keep
lines like 'I paid $5 and got $10 back' from rendering as formulas
re-tests every inline-math node against the editor's strict
single-dollar rule. Display math inside a cell parses as an inline node
whose raw token is $$...$$, and two dollars can never pass a
one-dollar regex, so genuine math was demoted to literal text.
The guard now keeps a $$...$$ token whose immediate parent is a
table cell, swaps its class to math-display (rehype-katex keys
displayMode off it), and flags the node for the Typst placeholder
plugin so both engines render it the same. Cell-scoped on purpose:
mid-line $$ in prose stays literal because the editor rejects it
there, and the #399 parity test enforces that; it caught the first,
too-broad version of this change.
How to test locally: put | 9 | B | $$\frac{800}{10000} \times 100\%
= 8\%$$ | in a table, open Split. Before: the right pane shows the
raw source. After: both panes show the rendered fraction, and $5 in a
cell or prose still stays plain text.
…#547) bert-maes timed it to the millisecond: the official AppImage took 45 seconds to become ready on Arch, and the same image extracted to disk took 0.63 seconds. Their tests did the diagnosis for us. A private fontconfig cache changed nothing, so the bundled-fontconfig rescan theory died. Restarting xdg-desktop-portal changed nothing, and the CPU was busy rather than idle, so the D-Bus timeout theory died with it. What remained was the process running the AppImage itself at 99% CPU for 75 seconds while the Electron main process sat in D state, blocked on reads. That process is squashfuse, and the work it was doing was ours. compression: maximum in the builder config becomes --compression xz for the AppImage target, and the shipped artifact's superblock confirms it: xz, 1 MiB blocks. Electron boots with thousands of small scattered reads across its libraries and the asar, each one forcing single- threaded decompression of up to a full megabyte block, and squashfuse's small cache re-decompresses the same blocks over and over. The extracted app skips all of it, which is the whole 45-vs-0.6 gap. compression is per-platform in electron-builder, so linux gets normal while macOS and Windows keep maximum untouched. The AppImage squashfs becomes gzip with 128 KiB blocks (superblock-verified on a local build), which decompresses an order of magnitude faster and re-reads cheaply. The deb, rpm, and pacman artifacts ride along from xz to their faster defaults. The trade is size: the x86_64 AppImage grows from roughly 200 MB, and that is the right trade; nobody chose this app for a small download, and everybody notices a 45-second boot. What this deliberately does not claim: bert-maes also saw an old 2.8 AppImage turn slow on a second machine where it used to be fast, so something in Arch's FUSE stack amplified the cost recently. That part is theirs to chase; ours was shipping the compression that made the amplification hurt. How to test locally (macOS is enough for the artifact half): cd apps/desktop && npx electron-builder --linux AppImage --publish never, then read the squashfs superblock 2 bytes at offset+20 past the hsqs magic: 1 is gzip, 4 is xz. Runtime timing needs a Linux machine: ZEN_PERF=1 ./ZenNotes.AppImage and compare main.boot.app-ready against the extracted squashfs-root/AppRun.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this brings
Three commits on the v2.23.0 release branch:
Feat(tasks): not every checkbox is a task (#458). Closes #458. Frontmatter
tasks: false/offturns a note into a pure checklist on every surface;tasks: notekeeps a #task note's card on the board while silencing its internal checklist;tasks.excludedFoldersin vault.json retires whole folders (sidebar context menu + Settings > Tasks). Vault-carried, so desktop, web, Go server, CLI, MCP, and mobile all agree. Escape hatches:zn task list --include-excluded,list_tasks.includeExcluded,GET /api/tasks?includeExcluded=1. Includes two latent Go fixes found while verifying against the live server: the single-note rescan had no folder gate, andcloneSettingsdropped newly added settings fields.Fix(preview): display math inside a table cell renders in the reading view. Reported on X by @BTC_1Ly:
$$...$$in a table cell rendered in the editor but showed raw source in the reading view. The currency guard was demoting double-dollar tokens; it now keeps them when the node sits in a table cell, display-mode, for KaTeX and Typst alike. Prose stays strict (#399 parity holds).docs(help): website drift-audit mirrored into the in-app manual.
Verification