- Reveal-in-sidebar + residual external-watcher misses:
SPECs/reveal-in-sidebar-and-external-watcher-spec.md— keep the explicit tab-context-menu "Reveal in sidebar" action working, leave ordinary file opens from expanding the Everything tree, and characterize the remaining external-file-watcher miss cases through a logging + manual-repro pass before patching further.
- Keyboard scrolling stalls in long notes (#125) — the
ProseMarkEditormount wash-full, so its content overflowed it and CodeMirror'sscrollRectIntoViewtreated it as a scroller, clipping the caret rect to its (viewport-high) bounds before reachingEditorScrollContainer;scrollTopstuck at 113px after ~27 Down presses. Nowmin-h-full.e2e/specs/keyboard-scroll.spec.jsholds Down and Up through a 114-line note and checks a short note's mount still fills the viewport. Follow-up not done: Up to the first line stops atscrollTop120 (CodeMirror scrolls to the line, not the frontmatter/top padding above it), so the title sits under the top fade — same before this change. - Website download button follows the latest published release —
apps/website/src/latest-release.tsfetches GitHub'sreleases/latest(the release-asset redirect the updater uses has no CORS headers, so the REST API is the only source a browser can read) anduseLatestReleaseswaps the prerendered build-time version/DMG pair for the live one; on a non-2xx (spent rate limit) or an unexpected payload the page keeps the build-time pair and warns in the console. Docs indocs/website-deploy.md("Download link"). - Scroll jumps when the caret's line leaves the viewport:
SPECs/offscreen-selection-line-height-spec.md— CodeMirror keeps the selection's anchor and head lines rendered wherever the viewport is and measures them into the height map, but every plugin decoratingview.visibleRanges(and@codemirror/language's tree highlighter) left them bare, so an H1 holding the caret measured 28.8px instead of 92.1px once it scrolled out and the note above the viewport shifted 63px.renderedRanges(view)/renderedRangesChanged(update)inprosemark-core/utils.tsare now the one definition of what to decorate, used by the heading, wiki-link, code fence, tab width and blockquote plugins;offscreenSelectionHighlightExtensionhighlights those lines since the tree highlighter can't be told about them. Verified in the playground on the same note: no line above the viewport changes height across a full blurred scroll pass with the caret on the H1, in a code block, or on a long list item. - Scroll jumps on long notes —
@codemirror/viewbumped 6.40.0 → 6.43.12 (@codemirror/stateto 6.7.5 alongside, so pnpm keeps one copy). Before 6.42.1 the height oracle treated a >0.1px change in sampled character width as a font change and re-estimated every line outside the viewport, discarding measured heights; Writer's short fenced-code lines sample in the monospace font (9.4px per character vs 6.65px for the prose dummy line), so every pass through a code block reshuffled the heightmap and moved the scroll position by up to ~1000px. Reproduced and verified in the playground on a note mixing a wide table, code blocks and nested lists; the mechanism and what still shifts are indocs/editor.md("Line-height estimates"). - List exit paths and the parse frontier — Backspace at the text start of a top-level item leaves a blank line between the list and the new paragraph (same
listExitSeparatoras Enter on an empty item; nested items keep their one-level-out behaviour).listLineAttrusts the prefix grammar whensyntaxTreeAvailableis false at the line, closing the follow-up where Enter/Backspace/Tab past the committed parse fell through to the generic markdown handlers. Verified in the built app bye2e/specs/list-enter-exit.spec.js: Enter+Enter, Enter+Backspace, and a 3000-item note typed without pauses. - Editor playground —
apps/playground, a plain Vite + React page that mountsprosemark-corewith the app theme beside a live markdown source view (whitespace made visible, caret marked), for QA in a normal browser withagent-browserrecording. Used to confirm in a real browser that ending a list with Enter leaves a blank line, on a short note and a 4000-item one. - Nested list second pass:
SPECs/nested-list-editing-audit-spec.md("Second pass") — a loose item's later paragraphs are padded like wrapped lines (only the marker line was skipped before, so a second paragraph's first line sat at the margin while its wrapped lines were padded); Tab and Shift-Tab move an item's own wrapped lines with its marker line; Backspace at the marker or body start steps back to the parent's whitespace viareindentTarget("outdent")instead of a fixed two characters, so tabs and ordered parents count as one level.itemParagraphLinesis the one source for "the item's lines other than the marker line". Enter on an empty top-level item now leaves a blank line between the list and the caret (unless one is already there), because- a⏎Whatis a lazy continuation ofaper CommonMark and the continuation padding made that visible. - Code blocks scroll instead of wrapping:
SPECs/code-block-horizontal-scroll-spec.md— fenced code and frontmatter lines getwhite-space: pre+overflow-x: clip; a per-block pixel offset incodeBlockScrollFieldrenders as atext-indentline decoration on every line of the block, driven by horizontal wheel gestures, by caret reveal, and by a draggable scrollbar thumb drawn in a CodeMirror layer. Lines are not scroll containers becausedrawSelection's caret/selection layers would not follow them. - Heading line-height —
.cm-heading-lineinherited the body's 1.8 line-height (~46px line box at the 1.6em H1), so wrapped titles looked loosely stacked; setline-height: 1.3on the heading line inprosemark-theme.css. - Gap below headings — the 1.3 line-height also removed the half-leading under a heading, so the first line of a paragraph or list sat tight against it;
.cm-heading-linenow haspadding-bottom: 0.35em(body-relative, since the heading font-size lives on the inner span) inprosemark-theme.css. - View zoom shortcuts:
SPECs/view-zoom-shortcuts-spec.md— Cmd+= / Cmd++ / numpad + zoom the note text in, Cmd+- out, Cmd+0 back to actual size. Persisted as the globaleditor.zoompercent setting (50–300, browser-style stops) bound to--writer-editor-zoom;App.cssmultiplies it into--writer-editor-font-sizeon top ofeditor.font-size(now bound to--writer-editor-base-font-size), so the chrome stays put and the existing cssVar side effect is the only write path. Palette commands Zoom In / Zoom Out / Reset Zoom; JS-only handling (no View menu needed); the Mermaid canvas now ignores Cmd chords. Whole-window webview zoom was tried first and dropped by decision. - List item spacing — items that follow another item at the same level carry
cm-list-item-gapon their marker line, and the theme gives itpadding-top: var(--writer-list-item-gap, 0.4em). Only the first item of a top-level list and continuation lines are excluded (a nested list's first child is gapped from its parent, viahasListItemGap, so spacing inside a list is uniform); fixed value for now, no setting. - Nested list editing audit:
SPECs/nested-list-editing-audit-spec.md— Tab/Shift-Tab take their target from the syntax tree (ordered parents, loose lists, tab indentation, odd indents), a selected parent moves its subtree with it, Enter on an empty nested item outdents instead of wiping, the bullet/task toggles keep indent on nested lines, and hard-wrapped items pad their continuation lines to the body column. The spec holds the full pass/fail matrix; four follow-ups added under Up Next. - Sidebar "Folders first" toggle:
SPECs/sidebar-sort-options-spec.md— the sort submenu is renamed "Sort by" and ends with a "Folders first" check item, persisted asappearance.sidebar-folders-first(default on, the previous behavior). Off sorts folders and files together by the selected mode likels.sortTreeEntriesandflattenTreetake afoldersFirstflag; no backend change since folders already carry both timestamps. - Sidebar sort options:
SPECs/sidebar-sort-options-spec.md— right-click the sidebar for a "Sort files by" submenu with name, modified-time, and created-time modes in both directions, persisted asappearance.sidebar-sort. Folders stay first and alphabetical; "name" is the visible label (title or filename stem). One registry insidebar-sort.tsdrives the comparator and the menu;DirEntrygainscreated_at, and own saves patch the tree's cachedmodified_atsince the watcher suppresses them. - Last Cmd+W hides the window:
SPECs/last-cmd-w-hides-window-spec.md— Cmd+W with no file open requests a window close; the main window's close-requested handler hides it instead of destroying it (so the app keeps running and a Dock click brings it back viaRunEvent::Reopen), while secondary and standalone windows still close. Every focus-existing-window path and in-place runtime open now reveals a hidden main window. - Sidebar sort by visible label — the
Everythingtree re-sorts each folder inflatten-tree.tsby the samefileTreeLabelfunction the rows render with (title or filename stem perappearance.sidebar-file-label), folders first, via a natural-orderIntl.Collator. The Rust listing keeps its filename sort as the baseline for other consumers. - Website mobile hero overlap — drop the desktop-only sticky positioning from
.heroin the stacked (<900px) layout and usemin-height: 100svhinstead of a fixed100vh, so the demo-video strip no longer scrolls over the feature list. - Website PostHog analytics:
SPECs/website-posthog-analytics-spec.md— replace the marketing site's self-hosted Umami script anddata-umami-*attributes withposthog-jsbehind the officialPostHogProvider, capturing$pageviewplusupdates_opened,github_opened, anddownload_started(carryingapp_version). Configuration is build-time only and shares the desktop app's project:VITE_POSTHOG_KEYfirst, thenWRITER_POSTHOG_KEYfrom the repo-root.env(bridged by name invite.config.ts, never by wideningenvDir, so the signing secrets beside it cannot reach the bundle); host likewise. With no key nothing is initialized and nothing is sent, mirroringtelemetry.rs. Full disclosure indocs/website-analytics.md. - Opt-in telemetry:
SPECs/opt-in-telemetry-spec.md— off-by-default PostHog reporting behind a one-time first-run consent dialog, with a self-declared email the prompt asks for by name, aPrivacysettings section, and four fixed events (app_opened,workspace_opened,file_created,folder_created) carrying no paths or content. The client is Rust-side socommands/fs.rsstays the single write path andposthog-jsautocapture can never reach the editor DOM; the project key is build-time only, so clone-and-build binaries are inert. Review follow-ups not yet done: promotetrack(&str)to anEventenum with a unit test that parses the event table out ofdocs/telemetry.md; factor the enable/once-per-session state machine off theOnceLockstatic soapply_settingsand the consent-timeapp_openedpath get unit coverage; give the e2e harness a keyed build sotelemetry-consent.spec.jsactually runs in CI. - Editor audit fixes:
SPECs/editor-audit-spec.md— five commits: stale-decoration and titled-link bugs plus helper dedupe; keystroke-path performance (deferred stats/headings, indexed fold specs, line-scoped heading guard, cached HTML sanitising, facet-based image src); tree-gated single list-prefix grammar; trimmed basic setup, Escape-closes-find, paste notice, one command registry; hook split into focused modules. - Editor content width slider:
SPECs/editor-content-width-spec.md— replace the two-stateappearance.editor-widthenum with a 480–1600pxeditor.content-widthrange under Preferences → Editor, bound directly to--writer-editor-max-widthso the frontmatter panel and text column share one width; oldnarrow/fullvalues migrate to 720/1600. - Table column sizing (Phase A, CSS-only):
SPECs/table-column-sizing-spec.md— folded table cells inheritedoverflow-wrap: anywherefromEditorView.lineWrapping, which feeds min-content sizing and let the auto table layout starve columns until words broke mid-word. Reset tooverflow-wrap: break-word+word-break: normal, replaced the blanketmin-width: 6emwith amax-width: 48chper-cell demand cap, top-aligned cells, and left-aligned headers while keeping explicit:---:/---:alignment. Phase B (wide tables breaking out of the editor measure) and Phase C (JS column-width computation) remain open. - PR #111 review fixes:
SPECs/Agent/worksheet-pr111-review-fixes.md— guard creation and external launches against workspace switches, closes, and replaced roots; preserve cross-window global settings writes; and route the sidebar background menu through the full surface and rootless shell. - Folder-row Open in Terminal:
SPECs/sidebar-empty-area-context-menu-spec.md— add an Open in Terminal action to folder row context menus, launching the selected in-workspace directory with the configured terminal. - Configurable default terminal:
SPECs/configurable-default-terminal-spec.md— add a global Workspace preference for the terminal app/executable used by the sidebar's Open in Terminal action, preserving the platform default when unset. - Sidebar empty-area workspace actions:
SPECs/sidebar-empty-area-context-menu-spec.md— right-click sidebar gaps and section headers to create a root file/folder, open the workspace in Terminal or Finder, and retain the existing Search/Recents visibility toggles. - Status bar + sidebar visibility toggles:
SPECs/statusbar-sidebar-visibility-spec.md— hide/show each footer metric (words, characters, paragraphs) and the sidebar Search button and Recents section, via five new boolean settings and native right-click check-item menus on the footer and sidebar surface. - Select-only Typography font controls:
SPECs/font-select-spec.md— replace the AppKit Font panel and editable stack field with a standard installed-family<select>matching the other settings controls; default UI/editor to SF Pro and the renamed Code font setting to SF Mono. - Native macOS font picker + Typography settings:
SPECs/native-font-picker-spec.md— replace the custom installed-font combobox with AppKit's system Font panel, route selections back to the originating settings row/window, preserve editable CSS fallback stacks, and rename the settings section from Fonts to Typography. - Global font settings:
SPECs/global-font-settings-spec.md— the six per-modetheme.{mode}.{ui,editor,mono}-fontsettings become three globalfonts.{ui,editor,mono}settings in a Typography section above the theme cards (fonts are typographic, not chromatic); startup migration adopts existing per-mode values (light wins, dark fallback) and drops the old keys. The font control is a single select-style pill (stack input + chevron in one surface). - Obsidian image embeds:
SPECs/obsidian-image-embed-spec.md—![[image.png]]renders inline via the wiki-link decorator; path targets resolve workspace- then note-relative, bare basenames fall back to an on-demand case-insensitive basename walk (find_file_by_name, shortest path wins), unresolved embeds show the raw source as a muted placeholder. - Editor bug sweep — image widget scroll-height stability (per-URL measured-height cache + re-measure on decode), viewport force-parse on scroll so tree-derived decorations (list hanging indent, hide, fold) stop rendering stale in unparsed regions, and compact recents picker fixes (loading state before empty state, non-destructive prune, atomic saves, recording/display extension mismatch).
- LaTeX math rendering:
SPECs/latex-math-spec.md— KaTeX-render$...$inline and$$...$$display math through the fold-widget pattern (rendered when the selection is outside, raw source when touched), with Pandoc-style inline-$guards so currency amounts stay prose. Verified at runtime via a browser-driven editor harness (widgets render, currency stays literal, click-to-edit unfolds, refolds on caret move);e2e/specs/latex-math.spec.jscovers the same flow for macOS harness runs. - Font picker for theme font settings — new
fontsetting type on the sixtheme.{mode}.{ui,editor,mono}-fontentries: stack input plus a searchable popover of installed system fonts (Rustlist_system_fontsviafontdb, cached, hidden dot-prefixed families filtered), previewed in each face; picking swaps the stack's primary family over the schema-default tail. Verified end-to-end via a newe2e/specs/font-picker.spec.js(seeapps/desktop/.claude/skills/verify/SKILL.md). - Configurable monospace code font — add a per-mode
theme.{mode}.mono-fontsetting bound to a new--mono-fontCSS variable;--pm-code-fontand the remaining hardcoded code-font stacks (HTML block widgets, Mermaid source editor and error display) now resolve through it. Ported from upstream commit6bb56f5. - Sidebar drag-and-drop move:
SPECs/sidebar-drag-and-drop-move-spec.md— drag files/folders in theEverythingtree to re-parent them (drop on folder → inside, on file → its folder, on empty space → workspace root), with multi-select batches, open-tab/pin/expanded-state rewrites, and collision reporting. Pointer-event based so it coexists with the existing Finder-drop-to-open; inline rename and drag-move now share one write path (use-move-entry). - Compact picker recents polish — add a plain non-hovering Recents label using sidebar section styling, remove the search field, per-row opened time, Open other file row, and active file entry, then keep the row remove affordance small so the picker is a direct global recents list.
- Global-scoped compact mode:
SPECs/global-compact-mode-spec.md— compact windows are fully workspace-free (no root, no indexing, parent-dir single-file watcher), the picker shows a persisted global recent-files list, and the workspace-scoped compact setting is replaced by an "Open File in Compact Window" command. - Compact picker trigger hit area — scope the closed trigger surface hover/focus state to the pill instead of the full picker-width wrapper.
- Compact picker trigger close hold — keep the closed trigger surface visible for 300ms after the picker close morph, then fade it with the picker opacity curve.
- Compact picker shadow fade — move the light-mode popover shadow to an opacity-animated layer so it fades out on close.
- Compact picker light trigger fill — make the light-mode compact trigger use a subtle gray tint instead of a near-white fill.
- Compact picker light shadow — add a subtle floating-card-style shadow to the compact picker popover in light mode.
- Compact picker timing — slow the picker morph and related content fades to 260ms while keeping the previous easing curve.
- Compact picker height cap — raise the compact navigator popover max height to 420px while keeping content-sized wrapping below the cap.
- Compact picker center anchoring — counter-scale the picker content from the horizontal center so the navigator stays centered while the popover expands.
- Compact footer polish — hide the document stats footer in compact chrome while leaving the normal workspace footer unchanged.
- Compact mode setting:
SPECs/compact-mode-setting-spec.md— make compact chrome a persisted appearance setting with a command-palette toggle, while removing the debug-only compact launch environment variable. - Compact single-file window:
SPECs/compact-window-spec.md— use compact chrome for explicit single-file opens with no sidebar, no sidebar toggle, no tab strip, and a top dropdown that reuses Pinned, Recents, and Everything navigation. - Website TanStack Start refactor:
SPECs/website-tanstack-start-refactor-spec.md— move the marketing website from a plain Vite SPA to TanStack Start routing/document/build structure while preserving the static Cloudflare deployment path. - Floating card shadow polish — add a large subtle shadow to the shared command-palette/popover card surface.
- Sidebar sections redesign:
SPECs/sidebar-sections-spec.md— split the sidebar into collapsible Pinned, Recents, and Everything sections; keep the existing file tree under Everything; add per-workspace pinned files and compact metadata-backed recent files with Show More pagination. - Table virtualization scroll stability:
SPECs/table-virtualization-scroll-stability-spec.md— give folded markdown table widgets stable CodeMirror height estimates so scrolling through virtualized documents with tables does not suddenly resize the document or scrollbar. - Sidebar file label setting — add an
appearance.sidebar-file-labelenum (title|filename, defaulttitle) and have the sidebar file tree render the filename stem or the title-fallback chain accordingly. Also expose a "Rename..." action in the file context menu (files reuse the inline-rename flow folders already had). - Desktop dev script — make the root
devscript delegate to the desktop package's Tauri dev workflow and keep desktop build/preview scripts on Vite+ commands. - Dependency lock refresh:
SPECs/Agent/worksheet-dependency-lock-refresh.md— refresh compatible Rust and JavaScript dependency lockfiles, including thevite-plustoolchain update, root TypeScript config alignment, and package-audit fixes. - Default paragraph line height — make new and reset editor line-height settings use 1.8 instead of 1.6.
- List prefix interaction zones:
SPECs/list-prefix-interaction-zones-spec.md— constrain pre-body caret positions to line start, marker start, and body start, then make Backspace and multi-line Tab/Shift-Tab operate from those source zones. - List selection geometry revamp:
SPECs/list-selection-geometry-revamp-spec.md— replace bullet/task point widgets plus zero-width hidden prefixes with measurable source-backed prefix marks so horizontal drag selection has stable hit-test geometry. - Table cell link regressions:
SPECs/table-cell-link-regressions-spec.md— keep rendered table-cell links clickable without unfolding the table, and render Obsidian wiki links with table-escaped aliases correctly. - Table cell markdown preview:
SPECs/table-cell-markdown-preview-spec.md— render inline markdown inside folded table preview cells instead of showing the raw markdown delimiters. - Table unfold codeblock display:
SPECs/table-unfold-codeblock-spec.md— render touched table markdown as codeblock-styled source lines in the main editor instead of plain prose. - Markdown heading top padding:
SPECs/heading-top-padding-spec.md— inject a shared editor heading class and use it to add 1rem top padding to Markdown headings. - Sidebar hover and active foreground polish — make sidebar icons and labels use full foreground color on hover, selection, and active states.
- Code block editor font size — make fenced Markdown code blocks and inline code follow the editor font-size setting.
- Link and image paths with spaces:
SPECs/link-paths-with-spaces-spec.md— make Markdown links/images and existing wiki-style link resolution work when labels, aliases, folders, filenames, or generated asset paths contain spaces. - Empty list caret visibility:
SPECs/empty-list-caret-spec.md— keep the caret visible at the body column on empty bullet and task-list items whose source marker is hidden by the list-prefix renderer. - List selection and TODO checkbox regression:
SPECs/list-selection-todo-checkbox-regression-spec.md— replace list-prefix replace widgets with point widgets to stop selection/caret snaps, and render TODO checkboxes as a single non-native span so drag-selection and nested alignment work. - Mermaid canvas widget:
SPECs/mermaid-canvas-widget-spec.md— render mermaid blocks in a fixed-height canvas-style frame with pan, zoom, reset-to-fit, and an edit-code toggle. - Mermaid fullscreen diagram:
SPECs/mermaid-fullscreen-diagram-spec.md— expand button on the canvas opens the diagram in a viewport-sized<dialog>with reused pan/zoom controls. - Heading anchor links:
SPECs/heading-anchor-links-spec.md— GFM slugger, same-doc smooth scroll, cross-doc navigate+scroll, inline warning on unresolved anchors. - Section indicators:
SPECs/section-indicators-spec.md— left-edge rail of heading ticks with active-heading tracking, hover outline popover, click-to-scroll, and right-clickCopy heading link. - Mermaid drag-selection edit-mode flip:
SPECs/mermaid-drag-selection-edit-mode-flip-spec.md— freezeeditModefor the duration of a pointer drag-selection so the widget doesn't flip into source view mid-drag.
- Backspace on an empty nested item at depth 2 or deeper leaves a whitespace-only line (
····-→··), per the literal "marker plus one indent level" rule inSPECs/list-prefix-interaction-zones-spec.md. Consider outdenting to the parent's indent instead, matching Enter on an empty nested item. - Nested ordered items (now reachable with Tab) render with the fixed 3ch ordered hanging indent, so their leading source spaces stay visible; give ordered lines the same depth-aware indent as bullets.
- Cmd+Shift+8 on a task line strips
-and leaves[ ] text; it should probably strip the whole task prefix or leave the line alone.
Previously-triaged work organized by phase. Pull into Up Next as capacity opens.
- Fuzzy content search and grep:
SPECs/fuzzy-search-grep-spec.md - Tags:
SPECs/tags-spec.md - New tab recent files:
SPECs/new-tab-recent-files-spec.md - Document date display:
SPECs/document-date-display-spec.md
- Inline media preview:
SPECs/inline-media-preview-spec.md
- Archive files:
SPECs/archive-files-spec.md— medium risk. Adds a parallel storage area and a purge job. - Multi window (v1 shipped — single-process multi-window):
SPECs/multi-window-spec.md. Future work: macOS Window menu listing open workspaces, session restore of all open windows at quit, tab tear-off across windows. - Custom MCP:
SPECs/custom-mcp-spec.md— high risk. New protocol client, trust model, and tool invocation surface. - Writer CLI:
SPECs/writer-cli-spec.md— standalone second binary; can slot in whenever convenient.
- Slow storage resilience:
SPECs/slow-storage-resilience-spec.md— async title extraction + bounded timeout so iCloud / Dropbox / network-mount workspaces stay responsive. Storage-agnostic, no provider-specific path lists. - Workspace snapshot:
SPECs/workspace-snapshot-spec.md— architectural cleanup ofAppStateinto a single versionedArc<Snapshot>with inode-keyed entries and watcher-maintained titles. Follow-up to the workspace-switch-hang fix; pull in only if the current epoch/cancel primitives prove insufficient or if tags / new-tab-recents want the richer metadata.
See CHANGELOG.md and git log for shipped work. Notable items:
- External file watcher: external file changes (Finder, git, vim, scripts) reach the sidebar and reload-from-disk reliably; dotdir workspace roots,
/varaliases, and self-write echoes all fixed (SPECs/external-file-watcher-spec.md) - Cmd+F polish: safe scroll-into-view, Cmd+G / Cmd+Shift+G next/previous, scrollbar match overview (
SPECs/cmd-f-spec.md) - Caret position after history navigation
- Obsidian-style wikilink parsing — aliases, escaped table pipes, note fragments, same-file fragment links
- Sidebar toggle tab chrome shift
- Rename bundled Codex theme preset to Writer
- Recent workspaces Dock menu
- Editor search lifecycle refactor
- Theming system — CSS-var-driven primaries (accent, bg, fg, fonts, translucency, contrast) per light/dark mode
- Multi-window v1 (single-process, per-window state):
SPECs/multi-window-spec.md—WorkspaceStatekeyed by window label isolates watcher, file index, settings, pending-open queue - Tabbed pages (settings in a tab + page-kind registry)
- Frontmatter edit flow
- Editor shortcut clashes + markdown formatting keymap
- Editor context menu (incl. Format/Paragraph/Insert submenus)
- Extensionless markdown links
- Mermaid diagrams
- Editor tab switch performance — tab-keyed panes, watcher/save coordination
- Local-only macOS E2E smoke test via Choochmeque/tauri-webdriver —
apps/desktop/e2e/ - Workspace visual redesign
- Auto update, titlebar double-click zoom, scrollbar layout shift fix, scroll active tab into view, hide sidebar handle, remove saving indicator + tab dirty dot
- Sidebar file/folder context menus, sidebar bulk actions, craft-style sidebar
- Gitignore-aware workspace
- Reduce document open latency
- Cold-start startup performance — bundled
restore_workspaceIPC, pre-resolvedrestore_target, skeleton-shell rendering, dev-only startup telemetry - Keyboard and accessibility pass
- Workspace switch hang fix
- Writer open CLI —
writer-clibinary + sharedopen_targetmodule, macOS PATH-install menu item, bundle-resource staging