github ZenNotes/zennotes v2.69.0
ZenNotes v2.69.0

latest releases: core-2.69.0-core.h27a2c5df8414d1dd, viewer-2.69.0-viewer.h5e7ef0f99f145d0a, web-2.69.0-web.h90d11c06b6e3cf34...
3 hours ago

ZenNotes 2.69.0 lets AI assistants reach a ZenNotes Server that needs a token, with one click in Settings instead of a terminal, and makes zn connect work for every MCP install. Setup no longer asks a server vault for a layout, the Claude integrations say which tab of the Claude app they reach, the New note form in search names the keys of the field you are in, and a Cloud vault that another device encrypted reads as encrypted, not deleted. Shortcuts no longer act behind What's New, Settings or a palette, and the phones can now start a note in the folder they are browsing.

Released from d1344076 through #934 on 2026-10-13. All installers are verified.

New

  • Assistants reach your ZenNotes Server without a terminal (#830). When the app is connected to a ZenNotes Server that needs a token, Settings → MCP → Server token now offers Let assistants use it. It saves the token the app connects with where zn connect saves it, so Claude Code, Codex and any other assistant you installed from Settings → MCP reach the server on their next call, with no terminal and no typing the token a second time. It is your choice, and the section says why: the app keeps its own copy in your system's secure storage, which no assistant can read, and sharing puts a copy in a private file that programs running as you can read. Stop sharing takes it out again. The shared copy follows the app: saving a new token for the server replaces it, and forgetting the server in Settings → Vault removes it. A token you saved yourself with zn connect is never touched. Thanks to Kevin (@diazkev314) for the report and for asking for exactly this.
  • Start a note in the folder you are browsing, on the phones (ZenNotes/zennotesandroid#108, #923). Browse on Android and iPhone gains a New note row above New folder, in every folder and at the top level. It opens a new note inside the folder you were looking at, with its title selected so you can type the name. Until now a note could only start at the top and then be moved. The part inside ZenNotes ships here; the row arrives with the next Android and iPhone updates. Thanks to @davi-jorge-art for the request.

Fixes

  • After zn connect, every MCP install reaches the server (#830). With the app connected to a token-protected server, an assistant could keep answering "The MCP server has no valid token for this ZenNotes server" even after zn connect, as the manual says to run. Install registers one of two MCP servers: zn mcp when zn came from Settings → CLI, and otherwise the server bundled with the app (a zn from Homebrew and every Windows install included). Only zn mcp read the token zn connect saves. Both do now, for the server the app is connected to, and the call after zn connect works without restarting the assistant. The error now names the exact zn connect <url> --no-default to run, and the new Server token button first. Thanks to Kevin (@diazkev314).
  • Setup skips the layout step for a server vault. Connecting to a ZenNotes Server in the setup wizard went on to ask how the vault should be organized, a choice the server's vault has already made for every app connected to it. Clicking through it could change the layout for the phones and the web app too. Setup now goes from the vault straight to Done for a server vault; a folder on this machine still gets the layout step. Thanks to Kevin.
  • The Claude integrations say which tab of the Claude app they reach. Settings → MCP read "Claude Code" and "Claude Desktop", which looks like one entry per app. But the Claude desktop app's Code tab runs Claude Code and uses the Claude Code entry, while the Claude Desktop entry reaches only its Chat tab. They now read Claude Code (CLI + Desktop Code tab) and Claude Desktop (Chat). Kevin suggested the names.
  • The New note form in search names the keys of the field you are in (#933, by @uNyanda). The form's footer always offered ↑↓ pick and ↵ create, which was wrong in most fields: arrows only move through the folder and tag lists, and Enter picks the highlighted row when there is one. Now in Name it reads ↵ create note; in Folder ↑↓ pick, and ↵ choose folder once a row is highlighted; in Tags ↵ add tag; and text that is not a valid tag drops the Enter hint, while the line above says why. Thanks to @uNyanda, who also wrote the component's first tests.
  • Cancelled tasks no longer count as open for assistants (#929, by @vishalhabib99). The MCP list_tasks tool's open filter and zn task list listed [-] cancelled tasks next to the ones still to do, although the calendar and Kanban already leave them out. They are left out now; status: all and --all still show them. The Go zn does the same from 0.7.1. Thanks to @vishalhabib99.
  • A Cloud vault that another device encrypted says so. When one device moves a Cloud vault to end-to-end encryption, the other devices linked to the old vault are told it was replaced. The desktop app stopped syncing it but said "Cloud vault deleted", and the phones kept the link and repeated "Update ZenNotes on this device" on every sync, even when up to date. Now every app stops syncing the old vault, the status bar says Cloud vault now encrypted, and Settings says the vault was replaced by an end-to-end encrypted one and how to open it: unlock encryption on this device if needed, then choose the encrypted vault. The phones get this with their next update.
  • The manual shows bold names and paragraphs. Thirteen entries of the in-app manual printed ** around the names of buttons and settings, and longer guides ran their paragraphs together. They now read as intended, and a search phrase that runs through a bold name finds its entry. The end-to-end encryption entry also names the right button (Save archive under Backups, in the desktop app; the phone apps send you there) and says what other devices do when a vault is encrypted.
  • Shortcuts no longer act behind What's New, Settings or a palette. What's New opens by itself on the first launch after an update, so the keys you press out of habit land on it, and none of them knew it was there: Cmd+P opened a note search underneath it that you could not see and took your typing, Cmd+N and Shift+Cmd+N made a note behind it, Shift+Cmd+P opened the command palette and Cmd+, opened Settings under it. Now no shortcut acts behind What's New; its own buttons, Tab and Escape still work, and Cmd+, (or Settings… in the macOS menu) replaces it with Settings. Behind Settings or any palette, Ctrl+Tab (previous note), Alt+Left and Alt+Right (note history) and Shift+Cmd+T (reopen closed tab) switched the note you would come back to, and Shift+Cmd+N made a Quick Note and moved your typing into its hidden title. They wait until the overlay is closed, as tab switching already did. Found while recording this release's demos.
  • The Tasks calendar's keys no longer change tasks behind a dialog. With the calendar open under Settings, What's New or a palette, Space on one of the dialog's buttons marked the selected day's task done (x in Vim mode), Tab moved through the calendar's tasks instead of the dialog's buttons, and in Vim mode dd deleted a task. The calendar now leaves the keyboard to the dialog, as the task list and the board already did.
  • An encrypted vault shows its name as soon as you unlock. Settings → Cloud showed an encrypted vault as "Encrypted vault" until this device unlocked encryption, and kept showing that after unlocking until Settings was opened again. It reads the list again when you unlock or lock. On the phones, an encrypted vault's backups no longer offer Save archive, which could only fail there; they say to use Save archive in the desktop app.
  • Settings on the phones and iPad offers only what the device has. Settings search listed the settings of sections the phones hide, so "review" offered Review agent edits and a tap opened an empty page; and Settings → Keymap on an iPad (and in the web app) listed the keys for reviewing an assistant's edits, which only the desktop app can do, and the grammar keys where grammar checking is not available. With the next phone updates.

For contributors

  • MCP token lookup (#830, ef122a4b): apps/desktop/src/main/remote/zn-credentials.ts reads and writes zn's credentials.toml ([tokens], keyed by the URL trimmed, without trailing slashes, lowercased; 0600; atomic replace; a file not in zn's format is never overwritten, and errors never quote it), in the portable config dir (ZENNOTES_CONFIG_DIR, then XDG_CONFIG_HOME/zennotes, then the platform default). The bundled MCP server (apps/desktop/src/mcp/vault-ops.ts) and the TypeScript zn (apps/desktop/src/cli/vault-target.ts) resolve a server's token as --token, ZENNOTES_REMOTE_TOKEN, a legacy profile token, then the saved one, the Go server's order, for the URL the app already chose, so a saved token never picks a server.
  • Server token (dd0f929b): apps/desktop/src/main/mcp-server-token.ts (states none with a reason, missing, shared, different, unreadable; share, remove only the app's own token, and followAppServerToken on profile save and delete), receipts in userData/mcp/shared-server-tokens.json. The main process picks the server from the persisted workspace, the way both MCP servers do, and reads the token from the secret store; IPC MCP_SERVER_TOKEN_STATE, _SHARE and _REMOVE take no arguments from the renderer, which only ever sees the state. The bridge methods mcpGetServerTokenState, mcpShareServerToken and mcpRemoveServerToken are optional and desktop only (faa8f873): the phone bridges implement ZenBridge too, and a required method broke their typecheck against core 2.69. UI: McpServerTokenSetting in SettingsModal.tsx, Settings search id mcp-server-token.
  • Onboarding (ed6fb808): OnboardingWizard.tsx takes its steps from the workspace mode (visibleSteps, stepAfter); connecting sets the vault and the mode in one store update, so the auto-advance already knows the next step, and goToStep now records the step it lands on (the rail could not move forward to it after Back). The web app reports no remote workspace and keeps the layout step, which is how a new server vault gets made.
  • Create form hints (#933, bcc52592, follow-up fb9c6fcc): SearchCreateForm.tsx derives ↑↓ and the Enter label from the focused field and reads the highlighted row exactly the way the Enter handlers do, so a list that shrinks under the highlight (a sync dropping a tag while the form is open) cannot make the hint lie. SearchCreateForm.test.ts is the component's first test file, .ts because vitest.config.ts only includes src/**/*.test.ts.
  • Cancelled tasks (#929, c0d25dd2): list_tasks in apps/desktop/src/mcp/server.ts and zn task list in apps/desktop/src/cli/commands/tasks.ts; the Go mirror is ZenNotes/tui 91bb33b (zn 0.7.1).
  • Superseded vaults (00c592bb): packages/shared-domain/src/cloud-vault-availability.ts owns the check (isCloudVaultSuperseded: a CloudServiceRequestError with 410 and VAULT_SUPERSEDED) and CLOUD_VAULT_SUPERSEDED_MESSAGE. CloudSyncHostService, the phones' sync host, retires the link on it during a sync and the background remote-changes check, as it does for a 404; the desktop main process uses the same two pieces. app-core's removal notice gains a third reason, encrypted.
  • Manual rendering (a72e97c9): packages/app-core/src/lib/help-rich-text.tsx (renderHelpRichText, helpSearchText): **bold** only outside code spans, a blank line starts a paragraph (block spans, since a section description sits in a <p>). Deliberately not the task cards' inline-markdown renderer: the manual mentions [[ 43 times and shows link syntax as examples to type. help-rich-text.test.ts renders every manual string and fails on any ** left outside code.
  • Browse (f9e219b2): requestCreateBrowseNote(host, directory) in the browse boundary beside requestCreateBrowseFolder, with the same guards, creating through createAndOpen with the title focused. The phone shells add the row: ZenNotes/zennotesandroid 4523a8b (in #111, version 1.1.39) and ZenNotes/zennotesios e5b5928 (in #59, version 1.25.0).
  • MCP integration labels (504c1551): packages/shared-domain/src/mcp-clients.ts; Settings search keyword code tab.
  • Shortcuts behind overlays (12908407): in App.tsx, the capture-phase handler (Mod+P, Mod+N, pane focus and modes) adds whatsNewOpen to the overlays it bails for; the bubble-phase handler returns at once while What's New is open, except global.openSettings, which closes it and opens Settings (the onOpenSettings listener does the same for the macOS menu, which takes Mod+, before the page). The overlay check that guarded tab selection and the template pickers (tabSelectBlocked, now overlayOpen) moves to the top of the handler and also guards global.newQuickNote, global.historyBack, global.historyForward, global.toggleRecentNote and global.reopenClosedTab. View toggles and the command palette's own toggle are unchanged. Harnesses: docs/releases/v2.69.0/whats-new-overlay/ (local).
  • Tasks calendar (6da71c43): TasksCalendar.tsx's capture-phase window handler bails on isOverlayOrDialogOpen(), like TasksView and TasksKanban.
  • Settings per host (803ae295): each Settings search result carries data-settings-result-category (the section id), which the phone shells use to hide the results of the sections they hide; keymapAvailableOnHost in lib/keymaps.ts leaves the editor.review* / vim.review* keys out without supportsAgentEditReview and the vim.harper* keys without supportsHarper.
  • Encrypted vaults in Settings → Cloud (d1344076): CloudSettings reads the vault list again when the encryption status's unlocked changes (not on the first status); the new optional capability supportsEncryptedBackupArchive (set by the desktop preload) decides whether an encrypted vault's backups offer Save archive.
  • Phone shells (on their release branches): Settings search hides the results of hidden sections (Android b6fea3f, iPhone 6fa07b5); an assistant's edit record (.zennotes/agent-edits/<note>.json) is a third sidecar in vault-fs.ts, moving with renames, moves, Trash and folder renames, going with deletes and Empty Trash, and never inherited by a new note (Android dc6cb34, iPhone 329ee69); the shells' own strings drop the long dash (Android d72ec37, iPhone c17556a).
  • Bundled CLI: zn 0.7.1 (69342fa3), its terminal-release.json copied byte for byte after it verified against zn-release-1 (source commit 91bb33b, protocol 1, all four archives matching checksums.txt); the staged darwin-arm64 binary reports zn v0.7.1. It carries #929's task filter and a token message that names the Server token button.
  • What's New: the 2.69.0 entry in packages/app-core/src/lib/whats-new.ts (87c7e216).
  • Docs: the in-app manual's MCP card (which server Install registers when, the Code tab, the Server token paragraph) and CLI card; on the website, the MCP section, the Server token docs, the encryption notice, and the CLI version mentions (website/docs-2.69).

Demos

In docs/releases/v2.69.0/media/ (local), 1080p with captions burned in and a .vtt beside each, recorded on the 2.69.0 build with scratch vaults; the server clips run a real ZenNotes Server with a token and a real MCP client named claude-code driving the app's own MCP server:

  • setup-server-vault.mp4 (12 s): the setup wizard connects to a ZenNotes Server with its token and goes from the vault straight to Done, with no layout step.
  • server-token.mp4 (25 s): Settings → MCP shows the renamed Claude entries; Server token's Let assistants use it saves the token where zn connect would; then Claude Code creates a note on the server through MCP and it shows up in the app.
  • new-note-hints.mp4 (28 s): search for a note that does not exist, open the New note form, and watch the footer follow the field: Name, Folder (pick and choose Inbox › Projects), Tags (add #launch), text that is not a tag, then Create.

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. For the server steps, run a ZenNotes Server with a token, for example ZenNotes/znserver's go run ./cmd/zennotes-server with ZENNOTES_VAULT_PATH=<folder> and ZENNOTES_AUTH_TOKEN=<token> (it listens on 127.0.0.1:7878).

  1. Setup for a server vault. With a fresh profile, the wizard opens. On the Vault step choose Connect to ZenNotes Server, enter http://127.0.0.1:7878 and the token. Before: the next step was "Vault layout". After: "You're ready to write", and the step rail reads Welcome, Vim mode, Theme, Vault, Done. Back returns to Vault; Choose vault folder with a local folder still leads to the layout step.
  2. Server token. Connected to that server, open Settings (Cmd+,) → MCP. The Claude entries read "Claude Code (CLI + Desktop Code tab)" and "Claude Desktop (Chat)". Under Server token, the section says assistants can't reach the server yet. Choose Let assistants use it: credentials.toml in your config dir now holds the server's URL and token (mode 0600), and zn --server http://127.0.0.1:7878 vault info answers without zn connect. Stop sharing removes the line and zn is refused again. A local vault shows a one-line note instead of the button.
  3. zn connect reaches the bundled MCP server (#830). Without sharing, run zn connect http://127.0.0.1:7878 --no-default and enter the token, then call any tool from an MCP client running apps/desktop/out/main/mcp.js with ELECTRON_RUN_AS_NODE=1 and the same ZENNOTES_CONFIG_DIR. Before: "no valid token for this ZenNotes server" in the same session and a fresh one. After: the next call reads the server's vault.
  4. New note form hints (#933). Press Cmd+P, type a name no note has, press Shift+Enter. The footer reads ↵ create note in Name; Tab to Folder: ↑↓ pick, and after ↓ ↵ choose folder; in Tags, ↓ gives ↵ add tag; type !!! and the Enter hint disappears while the line above explains. Before: ↑↓ pick and ↵ create everywhere.
  5. Cancelled tasks (#929). In a vault with - [ ] open and - [-] dropped: zn task list (and the MCP list_tasks with its default open filter) lists only "open"; --all lists both.
  6. The manual. Open Help (or :help) and search "Encrypt a Cloud vault": two paragraphs and bold button names, no **. Search a phrase that runs through a bold name, like "choose encrypt this vault in settings": the entry is found.
  7. Shortcuts behind What's New. Launch with a fresh ZENNOTES_USER_DATA_PATH and an existing config.toml in ZENNOTES_CONFIG_DIR (that marks a returning user, so What's New opens). Press Cmd+P and type: before, a hidden search took the text and Escape revealed it; after, nothing happens behind the window. Cmd+N: before, Untitled.md appeared in the vault; after, nothing. Cmd+,: What's New closes and Settings opens. With What's New closed, open two notes, then Settings, and press Ctrl+Tab: before, the note under Settings changed; after, it stays.
  8. Tasks calendar. Put a task due today in a note, open Tasks → Calendar, open Settings (Cmd+,) and click Appearance, then press Space. Before: the task was marked done on disk. After: unchanged, and Space toggles it again once Settings is closed.
  9. Phones (once the updates are out): Browse, open a folder, New note: the note opens in that folder, title selected. Settings → search "review": no Review agent edits.

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.
  • AUR: zennotes-bin 2.69.0-1 (AUR clone 281358c, repo 97a16340), pinned to ZenNotes-2.69.0-linux-x64.tar.gz SHA-256 4e790b5c…208e (GitHub's own digest for the asset), after the bump script checked the bundled CLI folder is world-readable; aur-check passed.
  • Nix: packaging/nix/release-data.json lifted from the update workflow (run 38431006332, bot PR #935 closed) as e0fd70cf; its desktopHash is the same digest as the AUR pin, and nix-build on main passed.
  • nixpkgs: NixOS/nixpkgs#572180, still waiting for review, now proposes 2.64.0 -> 2.69.0 (b5870af); the source hash comes from the tag tarball, by the same prefetch that reproduces the 2.64.0 hash in nixpkgs today.
  • Homebrew: zennotes 2.69.0 in the tap (e317675), mirrored in 634f67a8; both DMGs were downloaded and their SHA-256 matches the cask and GitHub's digest; brew style clean.
  • Website: ZenNotes/website#77 merged at 18ceb3eb with the releases entry and its three clips, the docs for this release (Settings → MCP → Server token, the Claude tabs' names and the zn token the bundled server reads, both MCP servers following a vault switch, the notice for a vault another device encrypted, and CLI 0.7.1 leaving cancelled tasks out), the dashboard's note that an encrypted vault's archive is saved in the desktop app, and the 2.69.0 share viewer (2.68.0 stays installed for pages cached against it). Laravel Cloud deployed it, and the live check passed: the releases page and docs carry 2.69.0, one clip and its captions match the local files byte for byte, a Range request on another answers 206, and the live 2.69.0 and retained 2.68.0 viewer files match their manifests. npm run verify:channels -- 2.69.0: every applicable channel serves v2.69.0.
  • zn CLI: 0.7.1 (ZenNotes/tui#8, tag v0.7.1, Homebrew formula bac26a2), bundled here: #929's task filter and a token message that names the Server token button.
  • Server: ZenNotes/znserver v2.69.0 pins the published web-2.69.0-web.h90d11c06b6e3cf34 browser artifact (#26); its five binaries match SHA256SUMS, and the released darwin-arm64 binary reports v2.69.0, serves the app and turns away a request without the token. Docker adibhanna/zennotes:2.69.0, 2.69 and latest (linux/amd64 and arm64, one digest 6328d4c9…); README #27.
  • Boundary packages: built by CI from d1344076 and published as pre-releases, never "latest": web-2.69.0-web.h90d11c06b6e3cf34, viewer-2.69.0-viewer.h5e7ef0f99f145d0a and core-2.69.0-core.h27a2c5df8414d1dd, published once both phone apps had shipped on it; publishing the viewer's draft also started a stray desktop Release run onto the viewer pre-release (the workflow's v* trigger matched viewer-...), which was cancelled; v2.69.0's own files were never touched, and 2.69.1 narrows the trigger to v[0-9]*.
  • Phones: iPhone 1.25.0 (41) and Android 1.1.39 (42), both on core-2.69.0-core.h27a2c5df8414d1dd: Browse's New note row (#923, zennotesandroid#108), the notice and the name for a Cloud vault another device encrypted, Settings search that offers only what the device has, and an assistant's pending edits that move with a renamed note. iPhone: zennotesios#59 merged at dfa8128; its UI tests passed on iPhone and iPad simulators, the account-backed Cloud UI tests were not run for this build, and it was submitted to App Review on 2026-10-13. Android: zennotesandroid#111 merged at 1664759 (tag v1.1.39, the same tree as the uploaded bundle) and sent to Google Play review on 2026-10-13 for a full rollout; the GitHub release v1.1.39 carries Play's signed universal APK (31,883,725 bytes, SHA-256 3e2d5f90…7f5d, signer 9f1af3a4…), byte-identical when downloaded again.

Release validation

Cycle checks:

  • #830 end to end with real binaries (docs/releases/v2.69.0/issue-830/): a token-protected ZenNotes Server, the Go zn built at 0.7.0 running zn connect, and mcp.js run exactly as Install registers it. Before: vault_info still failed after zn connect, in the same session and a fresh one. After: the same running session read the server's vault on its next call. Server token over CDP in the dev app, with its safeStorage swapped for an in-memory fake so no Keychain was touched: connected from the wizard, Let assistants use it wrote credentials.toml (0600, the app's token under zn's key), and the real Go zn and mcp.js both reached the server; Stop sharing turned both away; sharing again and saving a new token for the server updated the file; forgetting the server emptied it. Unit tests: zn-credentials.test.ts, mcp-server-token.test.ts and the MCP and resolver tests, five of which fail with the fallback removed.
  • Setup over CDP with throwaway profiles and a loopback server: before, connecting landed on "Vault layout"; after, on Done, with the server's layout untouched; a local folder still lands on the layout step.
  • #933 in the built app over CDP: the footer in Name, Folder (with and without a highlight, and filtered to nothing) and Tags (with a highlight and with invalid text) matches the PR; the form, search-create and palette-nav suites (42 tests; the follow-up's new test fails on the merged code). The PR's first CI failure (a test seeded vaultSettings: null, which vitest does not typecheck) is fixed in fb9c6fcc.
  • Superseded vault: the desktop live test against a local Cloud with CLOUD_E2EE=beta, the second device getting the real 410; the new host tests fail against the old service; the status bar and both Settings states over CDP.
  • Browse New note on an Android emulator with a core built from this tree: Browse, New folder "Projects", into it, New note opened "Untitled" with its title selected and wrote inbox/Projects/Untitled.md; the iPhone shell's row in its browser preview.
  • Manual: help-rich-text.test.ts (8), and Open Help over CDP shows two paragraphs with four bold names in the encryption guide.
  • Found during the release and fixed before it: shortcuts behind What's New and other overlays, reproduced in the built app over CDP with throwaway profiles before the fix (Cmd+P opened a hidden search that took the typed text, Cmd+N wrote inbox/Untitled.md, Shift+Cmd+N a Quick Note, Shift+Cmd+P and Cmd+, opened their dialogs under What's New; behind Settings, Ctrl+Tab, Alt+Left and Shift+Cmd+T changed the active note and Shift+Cmd+N wrote a Quick Note) and after it (none acts, focus stays, Cmd+, replaces What's New, and with nothing open all four note shortcuts still work). The Tasks calendar behind Settings: Space (Vim off) and x (Vim on) wrote - [x] before and nothing after; with nothing open both still toggle. CloudSettings.test.ts gains three tests (unlocking reads the list again; Save archive per host), each failing with its fix removed; keymaps.test.ts three. The phone shells: three new vault tests each, failing on the old vault-fs.ts; Android 278 and iPhone 253 tests pass. With a rehearsal core from d1344076 in the iPhone shell's browser preview: at phone width, Settings search hides every MCP, CLI and Keymap result and nothing else; at iPad width, Keymap lists no review key; Browse's New note row creates the note in the browsed folder with its title focused.

Release-time gates on d1344076: typecheck 8/8 and test:run 6/6 with no turbo cache (shared-domain 1,994, app-core 3,220, quicklook 15, desktop 1,139), npm audit --omit=dev --audit-level=high clean (the same 15 low or moderate as 2.68.0). Pack: Developer ID signed, deep strict codesign OK, bundled zn v0.7.1 in a drwxr-xr-x Resources/zn-cli, the Quick Look extension; packaged launch check: page target and drawn app in 1.5 s, version 2.69.0. Smoke suites: sidebar-vim (12) and editor-improvements (19) pass; vim-editor failed one check on its first run (repeated L read the same scroll position twice, a timing flake) and passed all 12 on the re-run. The commit messages carry no long dash except the merged contributor commit bcc52592, which stays as its author wrote it. Release PR #934: all 11 checks green, including the windows-11-arm package and launch check (CI run 38426359796). Release run 38428914590: all six jobs green in about 45 minutes; verify-installers.py ALL GOOD on the five manifests; both DMGs hash to GitHub's digests and the cask, and the app in each is Notarized Developer ID with a valid stapled ticket. npm run verify:channels -- 2.69.0 passed locally and from a clean runner (run 38437499904). After the cut, CI on main failed twice on Windows: 16 tests timing out at 5 seconds on one slow windows-latest runner, and, on windows-11-arm, one rename test that found a real bug: on Windows, renaming a note onto another note's name could replace that note. It dates from 2.55.0 and is fixed in 2.69.1.

Don't miss a new zennotes release

NewReleases is sending notifications on new releases.