Skip to content

ZenNotes v2.80.0

Choose a tag to compare

@github-actions github-actions released this 30 Oct 20:34
· 9 commits to main since this release

ZenNotes 2.80.0 turns the Kanban board into a real planning board: swimlanes, subtasks folded into their card with a progress bar, and WIP limits, in a quieter Tasks header. Templates can live in a folder of your vault, an assistant can be given only part of a vault, and large vaults open on macOS without freezing.

Released from 31520814 through #1019 on 2026-10-30. All installers are verified. 2.80.1 followed the same day with one fix (the scrollbar corner below).

Features

  • Swimlanes on the Kanban board (#1027, asked for by williamcheuk03). Pick Lanes: Priority, Folder, Tag or any @field in the board's View menu, and the board splits into rows across the same columns, each with its own count. Drag a card into another lane to change that field on its task line (!high, @sprint:24, or a tag lane's tag); folder lanes are read-only, like folder columns. Click a lane's header to collapse it. In Vim mode S steps through the lane fields, { / } hop between lanes, Shift+J / Shift+K move a card a lane down or up, and za / zM / zR collapse lanes; :lanes tag works on the ex line.
  • Subtasks fold into their card (#1028, asked for by williamcheuk03). A task's indented subtasks now sit inside its Kanban card, with a progress bar such as 3/5 · 60%, counted like the 3/5 chip in the note (direct subtasks, cancelled ones left out). Click the bar to show them and check them off from the card; Tab steps onto them, Space checks one, Enter opens the note at its line. A task note's checkboxes count the same way.
  • WIP limits (#1025, asked for by williamcheuk03). Right-click a column header (or Shift+F10 on it) and choose Set WIP limit…; W or :wip 3 in Vim mode. The header reads 2 / 3, and past the limit the column turns red. Limits count the whole column, across lanes.
  • Quieter Tasks views (#1026, asked for by williamcheuk03). Empty - [ ] placeholders, like the ones daily-note templates leave, stay out of the Tasks list, calendar and board, the Calendar and Timeline panels and the home view, so yesterday's placeholder no longer turns up overdue; in Tasks, a quiet "3 hidden" says how many. Board options live in one View menu, and a Keys button (? in Vim mode) lists each view's shortcuts in place of the two lines of key hints the header and footer used to carry.
  • A template folder (#1024, asked for by williamcheuk03). Keep templates as ordinary notes in a folder of your vault, the way Obsidian does: Settings, Templates, Template folder, or Use as Template Folder from a folder's menu in the sidebar. Every note in it shows in the template picker; its checkboxes stay out of Tasks, its tags out of the tag list, and its notes out of search (zn 0.13.1 and its MCP server follow the same rules). A self-hosted vault needs server 2.80.
  • Share part of a vault with an assistant (ZenNotes/tui#21, asked for by lewxdev). The MCP server bundled with the app and zn mcp take --allow-path, --deny-path, --read-only and --access, enforced on every tool: a hidden note answers exactly like a missing one, and the vault's location never shows. The bundled zn is 0.13.1.
  • Delete rows from the keyboard. In a database grid, Delete or Backspace deletes the selected rows, or the row at the cursor, after asking; the question opens on Cancel.
  • Numbered lists that line up past 9 (asked for by Julie). A list padded so 9. sits above 10. stays lined up as it grows, through Enter, o / O and renumbering. The demo tour's Start Here list is padded that way.
  • Phones: a folder's menu opens its Gallery.

Fixes

  • Large vaults no longer freeze on macOS (#999, thanks to MDerman). The file watcher used one handle per folder and ran out on a large vault; it now watches the vault as a whole. A folder the app cannot read (such as lost+found on Linux) no longer stops live updates, a watcher that runs out of handles restarts on its own, and the themes, CSS snippets, language packs and config.toml watchers keep working past an unreadable folder too.
  • A duplicate daily note (reported by yeminn). With rollover on, a daily-note template and a Cloud-synced vault, opening today's note could make 2026-10-30 2.md with the rolled tasks and open an empty 2026-10-30.md. The rollover now uses the note it just opened, and a rolled task no longer stays behind in yesterday's note as well.
  • One file Cloud won't take no longer stops the sync (#1004). It stays on this device while the rest syncs, and Settings, Cloud says what to do with it. A note moved or renamed to such a path stays in Cloud under its old name until then, so other devices keep it; a path longer than Cloud takes is held before it is sent; and a held note of yours keeps the status bar on "1 file stays on this device" until you rename it.
  • Enter in a confirmation presses the focused button. A question that deletes or discards opens on Cancel, so Enter alone keeps everything; Tab to the button that goes ahead.
  • A tooltip cut off at the window's edge (#1020, thanks to williamcheuk03). The note header's last button (Move to trash) now shows its whole tooltip.
  • Shift+F10 with Vim off on macOS opens the editor's right-click menu at the cursor.
  • Databases: Backspace while editing a view's picks no longer offers to delete them; after dd, the next key still moves in the grid; a row deleted while its confirm was open no longer blames the linked pages.
  • Kanban: a card moved into In progress keeps the cursor, so the next move acts on it.
  • Tasks calendar: Esc puts back a task picked up with m (it stayed held, and the toolbar kept saying Moving), and other keys wait until the task is placed. With daily notes on, a there always adds a task to the selected day, as its key sheet says; which of that and New task it did used to depend on the order the view had opened in.
  • MCP: assistants stay inside the note folders: moves, renames and paths can no longer reach .zennotes or the attachments folder, or follow a link out of the vault.
  • zn base add puts a new row into the picked rows of the view the database opens on, as + Row does.
  • Phones: closing the sidebar leaves its keys with the editor, and the keyboard stays down where the app moved focus out of habit.

For contributors

  • Swimlanes (7a6e3d36, 70189664, f3ad9a3c, merge a069a4bb): lane building and drops reuse lib/task-column-mutations.ts; kanban_lanes is a portable pref, collapsed lanes are machine-local.
  • Subtasks (aebdeab5, 44a9946e, c71a7dcc, merge de8a419d): an optional parentId computed once in shared-domain/task-nesting.ts, mirrored in znserver (ZenNotes/znserver#55) and held to the shared fixture bridge-contract/fixtures/task-subtasks.json. The nesting walk reads lazy continuation lines the way Lezer does, so a card and the note's chip always agree (0e8a921a).
  • Empty tasks, View menu and Keys (3b48e94f; the panels and home view 94a527b2), WIP limits (fa5ba5a6): TasksToolbar.tsx; hide_empty_tasks under [view], [kanban_wip_limits] in config.toml.
  • Template folder (8b42b542, tags and local search 38a20451): vault.json templates.folder, loaded in app-core for every host; tasksFolderListsForSettings keeps it out of Tasks and outsideTemplateFolder out of the tag surfaces; znserver #54 adds supportsTemplateFolder, zn follows in ZenNotes/tui#25.
  • MCP scopes (969f50e3, df340cb5, d0fe299f): rules in shared-domain/mcp-scope.ts, contract fixture bridge-contract/fixtures/mcp-scope.json shared with zn; path hardening 228a1d9e. zn pins 6a07ef89 (0.13.0) and 31520814 (0.13.1).
  • Watchers (383a2e9a by MDerman, 9c27db1b, 6bf2604e): chokidar 6 bundled into main; ignorePermissionErrors, restart on handle exhaustion.
  • Daily notes and buffers (f6413063, 156269b6); Cloud refused paths (3c8fb850, 5587a42d, c8493d03, 66af53e9, eaab18c4, 1b49dcda, dd513589); dialogs 695a9237; tooltip 0cfcb3a8; menu 4bed24c6; calendar Esc eca34b23 and a 4fcf9196.

Demos

Clips and screenshots of this release on the release build, attached to this release:

Swimlanes: View, Lanes: Priority splits the board into a lane per priority; a card dragged into High gets !high, Shift+J moves it a lane down, za folds a lane, and Enter shows the line it wrote. Watch the clip (29 seconds, captioned).

The Kanban board split into priority lanes

Subtasks on the card: a card reading 3/5 · 60% opens its subtasks, one is checked from the card, Tab steps through the rest and x takes it to 5/5 · 100%; Enter opens the note at that line. Watch the clip (23 seconds, captioned).

A Kanban card with its subtasks and progress bar

WIP limits: Set WIP limit… on In progress, a limit of 3 against 4 cards turns it red, :wip 4 sits at the limit and a bare :wip clears it. Watch the clip (21 seconds, captioned).

Empty tasks and Keys: daily notes' blank - [ ] lines stay off the board behind "3 hidden", the View menu shows them, E hides them again, and ? opens the board's keys. Watch the clip (23 seconds, captioned).

The board's Keys sheet

A template folder: a Templates folder's checkboxes leave Tasks once it is picked in Settings, Templates; Space t makes a new note from its Meeting note, and only the new note's checkboxes reach Tasks. Watch the clip (35 seconds, captioned).

Settings, Templates with the template folder picked

Deleting rows from the keyboard, with Vim mode off: Space selects two rows, Backspace asks with Cancel focused so Enter keeps them, then Tab and Enter delete both. Watch the clip (18 seconds, captioned).

Padded numbered lists: Enter after 9. writes 10. and keeps the text in one column, and the Start Here tour lines its list up the same way. Watch the clip (20 seconds, captioned).

The daily note fix: Space d makes today's note from its template with yesterday's open tasks rolled in, one note for today, and yesterday keeps only what it finished. Watch the clip (18 seconds, captioned).

Verification

How to test locally. Build once with npm run build --workspace @zennotes/desktop and launch with isolated stores: ZENNOTES_USER_DATA_PATH=$(mktemp -d) ZENNOTES_CONFIG_DIR=$(mktemp -d) npx electron apps/desktop/out/main/index.js. Turn Vim mode on in Settings for the letter keys.

  1. Swimlanes. Open Tasks, Kanban. Write a few tasks with !high, !low and none. View, Lanes: Priority: three lanes plus No priority. Drag a card from Low into High: its line now reads !high. Press za on a lane: it folds.
  2. Subtasks. In a note, write - [ ] Launch with three indented - [ ] lines, one checked. On the board the card reads 1/3 · 33%. Click the bar, tick one: 2/3 · 66% and the note's line reads - [x].
  3. WIP limits. Right-click a column header, Set WIP limit…, 1: with two cards the column turns red and reads 2 / 1. :wip clears it.
  4. Empty tasks. Add a line - [ ] with no text: no empty card shows, and "1 hidden" sits beside View. Click it: the card shows. Press ?: the Keys sheet opens. Open the Timeline (Mod+7): no "(empty task)" there either while Hide empty tasks is on.
  5. Template folder. Make a folder Templates with a note Meeting.md. Settings, Templates, Template folder: Templates. Space t, pick Meeting (marked with its folder), then a folder: a new note from it. Its - [ ] lines are not in Tasks, and its tags are not in the sidebar's tag list.
  6. MCP scopes. Run zn mcp --allow-path Projects --read-only from an MCP client (or point a client at it): list_notes lists only Projects, and no write tools are offered.
  7. Large vault (macOS). Open a vault with tens of thousands of notes: it lists without a freeze.
  8. Daily note. Turn on Daily notes, rollover and a daily template; with an open task in yesterday's note, open today's: one note, holding the task, and yesterday no longer has it.
  9. Confirmations. In a database, select a row, press Delete: the question opens on Cancel, so Enter keeps the row; Tab, then Enter, deletes it.
  10. Numbered lists. Write 1. to 9. padded with a space, press Enter after 9.: the new item reads 10. and lines up.

Distribution channels

  • GitHub release: installers for macOS (Apple silicon and Intel DMG and zip), Windows (x64 and ARM64 installer and zip) and Linux (x64 and arm64 AppImage, deb, rpm, pacman, tar.gz), with five update manifests; promote-latest marked it latest once the last feed was up (release run 41124241181).
  • AUR: zennotes-bin 2.80.0-1 (AUR clone 627c759, repo 1b5201d9), pinned to ZenNotes-2.80.0-linux-x64.tar.gz SHA-256 a3acecae…59d8 after the bump script checked the bundled CLI folder.
  • Nix: packaging/nix/release-data.json from the update workflow (run 41127543084, bot PR #1030 closed) as d4de4f0a; nix-build passed on main (run 41128267693).
  • nixpkgs: NixOS/nixpkgs#579420, still waiting for review; the source hash is the tag tarball's, by the same prefetch that reproduces master's 2.74.0 hash.
  • Homebrew: zennotes 2.80.0 in the tap (ab330cc), mirrored in 999eeefc; DMG SHA-256 arm64 f20e9b55…, x64 5688d421….
  • Website: ZenNotes/website#100 (docs, the release entry with eight clips, zn 0.13.0 and 0.13.1, server 2.80.0, iPhone 1.34.0, the 2.80.0 share viewer) and #99 merged at 95bc1a7; deployed by hand on Laravel Cloud while GitHub Actions is billing-blocked; the live check passed (clips byte-identical, range requests, docs, viewer files).
  • zn CLI: 0.13.1 (ZenNotes/tui#25, tag v0.13.1, Homebrew formula 8104e41, tap 7550560) is bundled (31520814, signed manifest verified against zn-release-1).
  • Server: ZenNotes/znserver v2.80.0 (#53, #54, #55 through #57) pins web-2.80.0-web.hc6427fa53ec1c133; Docker adibhanna/zennotes:2.80.0, 2.80, latest at sha256:6b41ba7f… (amd64, arm64).
  • Boundary packages: core-2.80.0-core.hc5a4589d040cd0da, web-2.80.0-web.hc6427fa53ec1c133 and viewer-2.80.0-viewer.hf5ba15d44219af5b, published as pre-releases after their provenance checked out.
  • Phones: iPhone 1.35.0 (build 54) Waiting for Review; Android 1.1.51 (versionCode 54) in Play review, with its GitHub release carrying Play's universal APK.

Release validation

  • Local gates on the release commit: npm ci, typecheck, every test suite uncached (shared-domain 2298, app-core 4618, desktop 1351, Quick Look 18), build:prod, the three smoke suites, npm run pack and the packaged launch check (page target, rendered, 2.80.0), hazard scan and dash lint. One editor-improvements run read an extra s at the caret after a Preview round trip: nothing in the suite types it, and three runs alone on the same build passed; recorded as a physical keystroke reaching the focused test window.
  • #1019: all ten checks green on every platform; CI on main passed on the release commit before the tag (run 41121541361, CodeQL included).
  • verify-installers.py: every file the five feeds name is present at its size; both DMGs are Notarized Developer ID and stapled, reporting 2.80.0; npm run verify:channels -- 2.80.0 reported every channel serving 2.80.0.
  • Found after the tag: the phone walk for iPhone 1.35.0 and Android 1.1.51 found a white square where a view's two scrollbars meet, on the new swimlanes board and wide database grids, in desktop, the web app and the share viewer too. It shipped as 2.80.1 the same day. The phones' walk now runs on a candidate core before the desktop is tagged.