Repository navigation
ZenNotes 2.71.0 draws your Mermaid diagrams with Pele, the same ```mermaid fences about 50 times faster and in your theme's colours, and adds D2 for architecture diagrams with ```d2 fences. Turn on Keep running in the tray and closing the window keeps ZenNotes syncing in the background, finished task notes now stay in the Done column of the Custom status board, Preview takes you back to the list item you were reading, nested lists line up in a proportional font, and the demo tour covers today's app.
Released from 603fc6dc through #955 on 2026-10-18. All installers are verified.
New
- Diagrams draw with Pele: about 50 times faster, and in your theme. ZenNotes drew
```mermaidfences with mermaid.js, the heaviest library in the app. It now draws them with Pele, an MIT-licensed renderer that reads the same Mermaid syntax, so no note needs editing. Every example in Mermaid 11.17's documentation that Mermaid itself accepts, 476 diagrams across 32 pages, draws in Pele: 83 ms for all of them, where Mermaid took 4.2 s, from about a third of the download. Diagrams take their colours from your theme, custom CSS themes included, so switching theme repaints them at once instead of drawing each one again; colours a diagram sets for itself withstyle,classDeforlinkStylestill win. Once Pele has loaded, a diagram you type in Edit mode draws on the spot, without the pending block, and a long label wraps inside its box instead of being cut off. As before, a diagram never loads an image or follows a link, and a note without diagrams never loads Pele at all. - Some diagrams look different. Pele lays diagrams out itself, so nodes sit in different places than on mermaid.live, and a mindmap draws as an outline tree instead of spreading out from its centre. Inside a label,
$$math and HTML other than<br>, bold and italic show as typed: put a formula in a math block beside the diagram. Theme settings in a%%{init}%%line give way to your app theme. ZenUML, which ZenNotes never drew, still does not draw. - D2 diagrams. A
```d2fence now draws as a D2 diagram, the text-to-diagram language built for architecture: boxes inside boxes, labelled connections,shape: sql_tabledata models, sequence diagrams, and sketch mode. Diagrams take their colours from your theme and repaint when you switch themes; a colour you set withstylestays as written, and a diagram that names a D2 theme withtheme-idkeeps it. With live preview on, a d2 fence draws in place in the editor and turns back into source when the cursor enters it, and Preview gives each diagram zoom and Expand. A broken diagram shows D2's message with its line and column. Markdown labels work, while icons, images, and links are not drawn: a diagram never reaches the network and never runs script. The D2 compiler is a large download that loads only when a note holds a d2 fence, so a note without one costs nothing and the first diagram takes a moment. The built-in tour has a new note, 05c D2 Diagrams, to try it. - Keep running in the tray (#947). Turn it on under Settings → Appearance → Window, and closing the last window hides it instead of ending the session: a ZenNotes icon stays in the system tray (the menu bar on macOS), Cloud sync keeps running, and the Quick capture hotkey keeps working. Click the icon, or choose Open ZenNotes in its menu, to bring the window back; the menu also opens Quick capture and quits for real, and while a Cloud vault is linked the tooltip and a menu line show the sync state (syncing, synced at a time, needs attention, failed). On a tiling desktop, where minimise has nowhere to go,
Space b(Hide Window to Tray in the palette) hides the window on purpose. It is off by default, so closing still quits on Linux and Windows until you turn it on. Quit ZenNotes in the command palette quits on any desktop, and if yours shows no tray icon, opening ZenNotes again brings the window back. ZenNotes also checks for updates every six hours while it runs, not only at launch, so a copy left in the tray for days still hears about a new release. Thanks to @uNyanda for a thorough proposal. - A demo tour that covers today's app. Generate Demo Tour Notes in the command palette now writes 22 notes. Four are new: 16 Tasks Calendar and Kanban, 17 Templates, Drawings, and Databases (with a sample Excalidraw drawing and a Reading List database to try them on), 18 Workflows, and 19 Cloud, CLI, and AI Agents. The rest were brought up to date with what shipped since spring: task states, fields and subtask counts, editable tables, block links and embeds, image sizes, numbered equations, Mermaid with Pele and D2, the leader keys added since then, themes and overrides, and
config.toml. Lines that no longer held are fixed: hint mode isSpace h, notf; a dropped file lands inassets/, not the vault root; archived notes' tasks leave the Tasks views. Run Regenerate Demo Tour Notes to get it, and Remove Demo Tour Notes clears the sample files too.
Fixes
- Finished task notes stay in your Done column (#949). On the Kanban board grouped by Custom status, a task note (a note tagged
task) whosestatus:wasdonevanished, even withdonelisted in your Kanban statuses: the board dropped every finished task before reading its status, andstatus: doneis what finishes a task note. It now sits in the Done column, still checked, and a card you tick, drag into Done or mark done in another editor stays on the board instead of disappearing. Only statuses you list count, so finished task notes never add a column of their own, and acancelledcolumn you list holds cancelled task notes the same way. Checkbox tasks are unchanged: a checked box still leaves the boards, since its box and its@status:are separate. Thanks to @mateusmatiazzi for a report that pointed at the exact line. - Preview takes you to the list item, not the start of the list (#953). To Preview a whole list was one block, so in a note that is mostly one long list, double-clicking an item opened the editor on the list's first line, and leaving Preview (the Edit button, Cmd+4 on macOS, Ctrl+4 elsewhere) with the cursor off screen put it there too, often a screen or more above what you were reading. Every list item, nested ones included, now knows its own line: a double-click lands on the item you clicked, and leaving Preview lands on the item at the top of the view. Thanks to @Sullti for a report that named the cause.
- Nested lists line up in a proportional font (#952). With a proportional Text font, the spaces that indent a nested item drew at about half the width the hanging indent and the guide lines measure, so a nested bullet sat left of its guide and of its parent's wrapped text, and each level drifted further. Each indent and marker character now takes at least one column: bullets and numbers sit on their guides four columns apart, and a wrapped line starts under the first word of its item. With a monospace font nothing moves. Thanks to @Sullti.
- Closing the last window quits again after Quick capture was used. On Linux and Windows, closing the last window quits ZenNotes, except once Quick capture had been opened in that run: its panel hides instead of closing, so the app counted it as open and kept every process running with nothing on screen, no taskbar entry and no tray icon, until you launched ZenNotes again. It dates from Quick capture itself, in 1.2.0. A hidden capture panel no longer keeps the app alive. With Keep running in the tray on, closing still hides the window and the hotkey keeps working, and macOS is unchanged.
- A broken diagram shows its error as text. When a fence failed to parse, Preview put the error message into the page as HTML, and that message quotes the line it could not read, so a fence could inject markup into the preview. The message is plain text now, in a box, with the caret under the column that failed.
For contributors
- Pele (
23edf8ee):packages/app-core/src/lib/pele-runtime.tsis the only import ofpele(1.6.0, pinned exactly while Pele moves fast), reached throughimport()frommermaid-render.ts, so its chunk is namedpele-runtime-*.js;perf-desktop-runtime.mjs,perf-web-runtime.mjsandtest-app-core-browser.mjshold that name off the boot path. Colour lives in a.pelerule inindex.cssthat maps--pele-*onto the--z-*tokens with the roles the oldthemeVariableshad (nodes on bg-2 with a bg-3 border, subgraphs on bg-softer, edges grey-1, series in the old pie and git order), replacing that 160-line map. Fonts are the only theme input to a drawing, so the cache key is fonts plus the trimmed source: Preview keeps a fence's trailing newline and the editor trims its body, and split view used to draw every diagram twice under two keys.peekMermaidSvgdraws synchronously once the runtime and the diagram type are loaded; labels are measured on a canvas in the note's text font after loading fonts settle.images: falseandlinks: false, as mermaid's strict mode had them; nomaxWidth, so Pele never turns a wide left-to-right flowchart top-down. The #911getBoundingClientRectpatch and its test are gone: labels are SVG text.Preview.tsxwrites a render error as text into.zen-diagram-error. pelereplacesmermaidin the five workspaces that declared it (app-core, desktop, web, share-viewer, quicklook). mermaid.js stays installed only because@excalidraw/mermaid-to-excalidrawlazy-loads it for Excalidraw's Mermaid dialog; the Vite deferral lists and themermaid.coreperf pattern keep both names. There is no mermaid.js fallback for fences, by decision.- Custom status board (#949,
ab15a36d):fieldColumnsinTasksKanban.tsx(now exported for its tests) skipped every taskisBoardCardrejects before reading the field, and a task note'scheckedcomes fromstatus:itself (DONE_STATUSESinparseTaskFile). It now keeps akind: 'file'task whose value is in the configured order (kanban_statuses, passed only forfield:status). Discovered values do not count, and checkbox tasks keep the live-work rule: theirfields.statuscan be inherited from the note's frontmatter, which would pull every checked subtask into that column. Four tests, two of which fail without the change. The Go TUI's board (internal/tui/views_tasks.goin ZenNotes/tui) had the same filter; its fix is ZenNotes/tui434bc15, on a branch for the next zn release, which is not part of this desktop release. - Tray (#947,
6329c89a):apps/desktop/src/main/tray.tsowns the Tray, held for the life of the app, with its menu and tooltip;shouldHideOnClose,traySyncLineandparseTraySyncStatusare pure and tested. The setting iskeepRunningInTrayinzennotes.config.json, main-owned because main needs it before any window exists, and deliberately not inPORTABLE_PREF_KEYS: whether a tray exists depends on the machine's desktop. A workspace window'sclosehides the last visible one withwin.hide()unlessappQuittingis set, bybefore-quit, the tray's Quit,app:quit, Squirrel.Mac'sbefore-quit-for-update(which closes windows beforebefore-quit) or Windows'query-session-end. The macOSactivatehandler andsecond-instancebring held windows back. Turning the setting off brings back every held window, even with another window open (e902b3a1, found on Linux). Each window reports aTraySyncStatusfromuseCloudSyncStatusStore; main validates it and keeps only the main window's. The new bridge methods (getKeepRunningInTray,setKeepRunningInTray,hideWindowToTray,reportTraySyncStatus,quitApp) are optional, so the web and phone bridges need nothing. Glyphs live inapps/desktop/build/tray(a template ensō for macOS, the app icon's 16 and 32 px tiles elsewhere), packaged asresources/tray. The updater repeats its background check every six hours from a settled phase (canRecheckInBackground), with notices still one per version.vim.leaderHideToTray(b) is in the keymap catalog. Not in this release: an icon that changes with the sync state, an Install update item in the tray, and an update restart that stays in the tray. - Tray follow-ups from the Windows and Linux runs: a cancelled Windows sign-out used to leave
appQuittingset, so closing the window quit for the rest of the run;query-session-endnow holds close-to-tray off for a 10 s grace that lapses, and onlysession-endmakes it final (204ae7b0,tray.ts+ tests, checked on Windows 11 with synthetic session messages). The Quick capture panel hides rather than closes, sowindow-all-closednever fired once it had opened; a pure decision inlast-window.ts(8 tests) quits after any window closes or the panel hides when that panel is all that is left, a pinned panel holding the app until it hides and azennotes://quick-capturelaunch staying resident (dcaa821e, checked on Linux X11 before and after: six processes alive after 45 s, then an exit within 6 s). - D2 (
c4a38631):@terrastruct/d20.1.33 (MPL-2.0, no dependencies), pinned exactly in the five workspaces that declarepele.packages/app-core/src/lib/d2-runtime.tsis its only import, reached throughimport()ind2-render.ts, so its chunk isd2-runtime-*.js(8.2 MB, 6 MB gzipped, the WebAssembly compiler inside); both Vite configs keep it out of the boot preloads, and the perf harnesses andtest-app-core-browser.mjswatch it.d2-render.tsserializes calls through a queue (the wrapper keeps one pending callback per worker, so a second call strands the first), caches by trimmed source, formats D2's JSON error list asline N:M: …, and runs every SVG through a DOMPurify instance of its own: Markdown labels arrive as HTML inside aforeignObject(an<img onerror>in a label came through intact),icon:becomes an<image>that fetches, andlink:an<a>, so images, links,href/srcand handlers are stripped, withHTML_INTEGRATION_POINTS: { foreignobject: true }so labels survive in Chromium (jsdom kept them without it).withUniqueD2Idsrenames ids per insertion: Preview and the hidden editor shared one string, and every arrowhead'surl(#mk-…)resolved into the hidden copy. Preview:language-d2maps to.zen-d2inrehypeMathDiagrams, drawn byrenderDiagramswith pan/zoom and Expand (DiagramTabKindd2). Live preview:cm-mermaid-render.tsnow draws mermaid and d2 fences through one widget. Colour: a.zen-d2-themedblock maps D2'sfill-/stroke-/color-/background-color-N1 to N7, B1 to B6, AA and AB classes onto the--z-*tokens and makes D2's canvas transparent; a source withtheme-id/theme-overridesskips it. The demo tour gainsinbox/demo/05c D2 Diagrams.md, linked from 00, 05, 05b and 07; the server writes the same tour frominternal/vault/demo-tour.jsonin ZenNotes/znserver (b18fd97). The MCP instructions list D2; zn mcp's copy in ZenNotes/tui, which had also lost the Pele label rule, collapsible callouts and the comments section, is resynced verbatim (cc5bdb5). - Preview list lines (#953,
0e61c60a):remarkSourceLinesinmarkdown.tsstampsdata-source-lineon everylistItem, nested ones included, besides the top-level blocks.previewVisibleSourceLines(preview-outline-jump.ts) walks the stamps in document order and lets the innermost one still covering the top edge win, so a long list reads as the item at the top of the view;previewEditRequestForTargetalready tookclosest('[data-source-line]'), which is now theli. Split scroll sync selects only[data-preview-content] > [data-source-line]and is unchanged. Three tests; the reader's fails without the change. - List prefix cells (#952,
f2512e32):listPrefixCellsincm-markdown-list-indent.tsgives each prefix character a width in ch (the indent, then a bullet or ordered marker with its spaces; a tab counts as the Tab size, asmarkdownListHangingIndentChcounts it, so the cells add up to the hanging indent). The plugin marks each character as an inline-block.cm-list-prefix-cellwith thatmin-width, and addscm-list-boxed-markerto the line so the•widget, which replaces-outside any mark, takes 1ch too. One mark per character, because the list fold arrow is a widget inside the indent and a mark over the whole run split around it into pieces that each took the full width;data-list-colkeeps CodeMirror from merging neighbours. A line with a quote or callout prefix is left alone, and a task's marker is not boxed: live preview draws a checkbox narrower than the six columns the hanging indent counts, a gap that predates this and shows in every font. With the default monospace font the editor is pixel-identical before and after. - Demo tour (
776112f8):packages/shared-domain/src/demo-tour-data.tsholds 22 notes and four files. The new files sit inside the tour folder:inbox/demo/Tour Sketch.excalidraw, and aReading List.basedatabase whosedata.csvandschema.jsonwere written byinitialDatabaseContents(the same code New Database uses), then given a Status select and a Board view; opening it rewrites nothing.demo-tour.test.tsnow resolves a wikilink to a shipped file by its name and to a database by its title. Removing the tour has to take the.basefolder down beforeinbox/democan go, sodemoTourNestedDirs(shared-domaindemo-tour.ts, two tests) lists the folders deepest first and desktopremoveDemoTourempties them. The server writes the same tour frominternal/vault/demo-tour.jsonin ZenNotes/znserver, regenerated as compactJSON.stringifyof this file (the method reproduces the previous file byte for byte), and itsRemoveDemoTournow walks up from each removed asset too, with a test that fails without it (ZenNotes/znserver50e4c19ondemo/d2-tour-note). The phone apps write the tour from the same data but remove it with their ownvault-fs.ts, which only checksinbox/demoitself: they need the same nested-folder step when they adopt this core, or Remove leaves an emptyReading List.basebehind. The website's starter-tour card says what the tour now holds (96d4d03on website/docs-2.71). - What's New: the 2.71.0 highlights (
603fc6dc): Pele, D2, the tray, the demo tour. Version bump43bd8228. - Docs: the in-app manual and the MCP server's instructions say a diagram label is plain text plus
<br>, with math in a block beside it. The manual's Kanban card and the website's Custom statuses section say a task note keeps its configured column when its status closes it. On the website, branchwebsite/docs-2.71carries the same changes (67bea75Pele,3fa0bcb#949,cc045eetray,f3c3ef6D2,96d4d03the tour card), with the 2.71.0 release page in ZenNotes/website#84.
Demos
Screenshots of this release on the dev build, in Catppuccin Mocha unless noted, attached to this release:
Mermaid, drawn in the editor. Live preview draws each fence in place; move the cursor in to edit it.
One note, two themes. The same flowchart in Catppuccin Mocha and Latte: a theme switch repaints it, no redraw.
D2. A system map with nested containers and labelled connections, in the theme.
Finished task notes stay in Done (#949). The board grouped by Custom status with kanban_statuses = ["backlog", "in-progress", "review", "done"].
Keep running in the tray (#947), under Settings, Appearance, Window.
Nested lists in a proportional font (#952), before and after, in Gruvbox with Helvetica Neue.
The demo tour: note 17, with its sample drawing.
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.
-
Diagrams draw, in Edit and Preview. In a note, type a fence:
flowchart LR A[Capture] --> B{Has a home?} B -- yes --> C[Folder] B -- no --> D[Inbox]
With live preview on, it draws in place; move the cursor into it to get the source back. Add a fence of another type (
sequenceDiagram,pie,mindmap,gantt): it draws on the spot. Before: a pending block first, then the drawing. Switch to Preview and press Expand on a diagram: it opens in a larger view. -
Theme. With a diagram on screen, switch between a light and a dark theme in Settings ▸ Appearance: the diagram takes the new colours at once. Before: every diagram was drawn again, in Mermaid's palette. Add
style D fill:#879a39to the fence above: Inbox keeps that green in every theme. -
Long labels (#911). Change a node to
A["A label long enough to wrap over several lines inside its box"]and zoom with Cmd+= and Cmd+-: the label wraps inside its box at every zoom, never cut off. -
A broken diagram. In Preview, a fence with:
flowchart LR A["<b>bold</b>"] --> -->
After: a box reads
Mermaid error: Parse error on line 2:, then the line as typed,<b>bold</b>included, a caret under the second arrow, andExpecting 'NODE_STRING', got 'LINK'. Before:boldshowed in bold, because the message went into the page as HTML. -
Finished task notes on the Custom status board (#949). Put
kanban_statuses = ["open", "in-progress", "waiting", "done"]under[view]in theconfig.tomlin your config dir, and make two notes in the vault, each with frontmattertags: [task], one withstatus: doneand one withstatus: open. Open Tasks, switch to Kanban and set Group by to Custom status. After: the done note sits in Done, checked and struck through (before: Done read 0 and the note was gone, though Group by Status showed it). Tick the open note's checkbox on its card, or drag it into Done: it moves to Done and stays, and its file now saysstatus: done. A note withstatus: cancelledstays off the board until you add"cancelled"to the list. -
Keep running in the tray (#947). Turn on Settings → Appearance → Window → Keep running in the tray: a ZenNotes ensō appears in the menu bar (macOS) or the system tray. Close the window: it hides and the app keeps running (before: on Linux and Windows the app quit, on macOS the window was destroyed and sync stopped). Click the icon, or Open ZenNotes in its menu, or on macOS the Dock icon: the window comes back. With Vim on, the leader hints list Hide to tray and
Space bhides the window; Hide Window to Tray in the palette does the same. Launch ZenNotes again while it is hidden: the window comes back. With a Cloud vault linked, the icon's tooltip reads, for example,Cloud: synced at 14:05. Quit ZenNotes in the icon's menu or in the palette exits. Turn the setting off and the icon goes; on Linux and Windows closing quits again. -
D2 diagrams. Open a note without diagrams: no
d2-runtimerequest in DevTools' Network panel. Run Generate Demo Tour Notes (or Regenerate) from the command palette and open 05c D2 Diagrams, or type a fence:direction: right app: Desktop app { ui: Renderer main: Main process ui -> main: IPC } cloud: Cloud {shape: cloud} app.main -> cloud: sync
With live preview on, it draws in place; in Preview it has zoom and Expand, and every arrow has its head. Switch between a light and a dark theme: the diagram repaints. Add
vars: { d2-config: { theme-id: 300 } }at the top: it keeps D2's Terminal theme. Break it (a ->):D2 error: line 1:1: connection missing destination. Give a shape{icon: https://icons.terrastruct.com/essentials/087-display.svg}: no request leaves the app and no icon is drawn. -
Preview lands on the list item (#953). Make a note that is mostly one long list: a dozen top-level tasks with two nested items each, then a few paragraphs after it. In Preview, double-click a nested item halfway down: the editor opens with the caret on that item (before: on the list's first line). Back in Preview, scroll until an item near the end sits at the top of the view and press Edit, or Cmd+4 (Ctrl+4 on Linux and Windows): the caret lands on that item. Before: on the first line of the list, a screen or more up.
-
Nested lists in a proportional font (#952). Put
text_font = "Helvetica Neue"(or any proportional font you have) under[typography]in theconfig.tomlin your config dir, open a note in Edit and type:- Top level item - A nested item long enough to wrap onto a second line in the editor, so you can see where the wrapped text starts - Child item 1. An ordered item long enough to wrap onto a second line in the editor, so you can see where the wrapped text starts 1. Nested ordered item
After: each nested bullet and number sits on its guide line, four columns right of its parent, and each wrapped line starts under the first word of its item. Put the cursor on a nested line: the raw
-shows in the same place, and moving withhandlsteps through the indent one column at a time. Before: nested bullets sat about halfway to their guide, left of the parent's text. Cleartext_fontto go back to the default monospace font: nothing moves. -
The demo tour. In a new vault, run Generate Demo Tour Notes from the command palette. The sidebar's
demofolder holds 22 notes, the Reading List database and Tour Sketch. Open 17 Templates, Drawings, and Databases in Preview: the drawing is embedded, and the Reading List link opens the grid with five books, typed fields, and a Board view grouped by Status. In 07 Wiki Links and Tags, the block embed shows the last paragraph of 00 Start Here; in 04 Math with KaTeX the two equations are numbered (1) and (2); in 03 Tables and Task Lists, Weekly review carries a1/4chip. Every link resolves except the deliberate A Future Note. Run Remove Demo Tour Notes:inbox/demois gone from disk, sample files included.
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; the seven screenshots in Demos are attached too.
- AUR:
zennotes-bin2.71.0-1 (AUR clone0e7cb97, repodefbca67), pinned toZenNotes-2.71.0-linux-x64.tar.gzSHA-256e989f84d…3529(GitHub's own digest for the asset), after the tarball check confirmed the bundled CLI folder is world-readable; aur-check passed. - Nix:
packaging/nix/release-data.jsonlifted from the update workflow (run 39177080496, bot PR #958 closed) as672ff40f, and nix-build on main passed. - nixpkgs: #572180 (2.64.0 -> 2.70.0) merged after the last release, so NixOS/nixpkgs#575797 proposes 2.70.0 -> 2.71.0 (
a4d4d3ac) from a fresh branch; the source hash comes from the tag tarball, by the same prefetch that reproduces the 2.70.0 hash in nixpkgs today. - Homebrew:
zennotes2.71.0 in the tap (d4f5ccb), mirrored in6dabad90; both DMGs' SHA-256 match the cask and GitHub's digests;brew styleclean. - Website: ZenNotes/website#84 merged at
c07006bbwith the 2.71.0 entry and its seven screenshots, and the docs for this release (Pele, D2, the tray, the Custom status Done column, and the starter tour card). Laravel Cloud deployed it, and the live check passed: /releases leads with 2.71.0 and Keep running in the tray, two screenshots match the local files byte for byte, and /docs carries D2 and the tray. - Not in this release: the server (its demo tour sync waits on ZenNotes/znserver branch
demo/d2-tour-note,b18fd97and50e4c19), the zn CLI (the #949 board fix434bc15and the MCP instructions synccc5bdb5wait on their branches in ZenNotes/tui), the boundary packages, and the phones. The bundled CLI stays at 0.8.0, the newest zn release.
Release validation
Every CI failure since 2.70.0 was read before this release: ci-sweep.py v2.70.0 found none. hazard-scan.py --since v2.70.0 has no errors; its two warnings, manualChunks changing in both Vite configs, are comment and deferred-preload changes for the Pele and D2 runtimes, and the built renderer neither preloads nor statically imports any diagram stack.
Release-time gates, in a clean checkout with its own npm ci: typecheck 8/8 with no turbo cache, test:run (app-core 3,266, desktop 1,175, quicklook 15 and the rest), and a fresh build:prod. Pack at 603fc6dc: Developer ID signed; packaged launch check: page target and drawn app in 1.4 s, version 2.71.0. On the packaged app with isolated stores: the demo tour's 22 notes generate, its Mermaid and D2 notes draw with no error, the Excalidraw embed renders, and What's New shows the four 2.71.0 highlights. perf:desktop-runtime on 5,000 notes against the packaged app: workspace ready in 783 ms, note switch p50 24.5 ms, search 15 ms, no long tasks, and no Pele, D2 or mermaid chunk loaded. Smoke suites vim-editor, sidebar-vim and editor-improvements pass on the first run.
Release PR #955: all 10 checks green on 603fc6dc, including the windows-11-arm package and launch check. CI on main for 603fc6dc (run 39174585443) passed all six jobs before the tag. CI on main for the packaging commits: the AUR commit's run was cancelled when the Nix commit superseded it, and 672ff40f's (run 39177201972) passed; and so did 6dabad90's, the Homebrew commit (run 39179310865). Release run 39175854759: all six jobs green; verify-installers.py ALL GOOD on the five manifests by SHA-512; the app in both DMGs is Notarized Developer ID with a valid stapled ticket, signed by the G2 Developer ID certificate (valid to November 2027), the first release signed with it. npm run verify:channels -- 2.71.0: every channel serves v2.71.0 (Homebrew, AUR, Nix and the website's eight download buttons).






