Changelog
Generated from the project's CHANGELOG.md,
so this page and the repository cannot disagree. Every release lists what it does not do
alongside what it does. A tool you keep documents in for ten years should be honest about
its edges on the way in, not after you have filed something in it.
The connection Monoleaf uses to check for updates uses a patched TLS library. rustls 0.23.46 fixes four advisories (RUSTSEC-2026-0346 to 0349), among them a downgrade of the key exchange to classical cryptography. Updates were already protected by their own signature, so this hardens the connection rather than closing a way to install a tampered update. Tauri moves to 2.12.2.
Double-clicking a Markdown file in the macOS Finder opens it. macOS hands the file to the app differently from Windows and Linux, and Monoleaf ignored it, so the window opened empty.
monoleaf notes.md from a terminal opens the right file. A relative path is now resolved against the folder the command was typed in, also when Monoleaf is already running, and changes to the file on disk are picked up for such launches too. Starting Monoleaf again while only extra windows are open (the first one closed) now brings one of them to the front instead of doing nothing.
Starting Monoleaf no longer flashes a black screen with a white rectangle. Since 1.3.0 the window appeared before it was maximized and before the editor had drawn anything. It now stays hidden until the editor is ready, then appears complete.
Images embedded directly in the Markdown () now appear in exports. The editor showed them, but the PDF, print and HTML exports replaced each one with its alt text.
A table cell containing a backslash right before a pipe (a\|b) no longer splits in two. Editing such a table, or pasting it from Excel, saved the cell in a form Monoleaf read back as two cells the next time the file was opened, which added a column to that row.
Typing while a save is still writing no longer loses those edits. A slow save (OneDrive, a virus scanner, or the network-folder question) marked everything as saved when it finished, including what was typed meanwhile, so closing the window dropped it without asking. Those edits now stay unsaved until the next save.
A failed autosave no longer leaves you without a recovery copy or repeats its error on every pause. When autosave could not write the file (locked, read-only, disk full), no recovery snapshot was kept, and the same error popped up after each pause in typing. The snapshot is now kept until a save succeeds, and the error is shown once until saving works again.
Files with Windows (CRLF) or classic Mac (CR) line endings keep them when you paste, drop images or edit Document Properties. Pasted text, dropped image links and the metadata block were inserted with Unix line breaks, which showed several lines as one (Document Properties could fold the whole file into a single line) and saved stray Unix line endings into the file.
A document can no longer load remote content through an embedded stylesheet, or restyle Monoleaf itself. A <style> block in a Markdown file could fetch images from the internet even with "Load remote images" off, and could hide or change parts of the app. Such blocks are now removed when the document is rendered.
Clicking an image-map area or an SVG link in print preview opens it in your browser instead of replacing the editor. Previously such a link navigated the whole Monoleaf window away, with no way back to the document. The window now also refuses any navigation away from the app itself.
A save that is interrupted no longer leaves an empty or cut-off file. Monoleaf used to overwrite the document in place, so a crash, a full disk or a dropped network connection partway through could lose it. It now writes the new version beside it first and swaps it in only once it is complete.
Opening or saving a slow file no longer freezes every window. Reading a OneDrive file that is only in the cloud, a file on a slow share, or a large image now happens in the background. Images over 50 MB are no longer loaded into the editor; they show as a broken picture instead.
An image path written in a rarer Windows form (\??\UNC\...) can no longer reach a network share. Such a path slipped past the check that keeps Monoleaf off network paths unless you allow them, so a document could make Windows contact another computer and send it your sign-in details in hashed form.
Unfinished markup no longer freezes the editor. Many tracked-change openers without their closing marks (such as {~~old~> or {++), many unclosed <img tags, or a long line of unclosed review-comment blocks could make Monoleaf hang for seconds on every keystroke or page layout. These are now read in a single pass, however much of the document they fill.
PDF import no longer loses or garbles text that looks like list markup. A line starting 3.5 mg or e.g. was turned into a numbered item and lost its first characters; numbered lists now keep their printed starting number, sub-items under a numbered step stay in the same list, lettered items keep their letter, and text such as __init__ or ~~x~~ no longer turns bold or struck through. A PDF with an enormous grid of drawn lines can no longer crash Monoleaf by exhausting memory.
1.3.0 and 1.3.1 were published briefly and withdrawn, because updating to them from inside Monoleaf failed (first entry under Fixed). Everything they contained is part of this release and listed here.
Local images now render in the editor. A reference to a file on disk, whether relative to the document (, <img src="../x.png">) or an absolute path, shows the picture inline instead of its alt text. Relative references resolve against the saved document's folder, so in a brand-new document that has never been saved they show a quiet placeholder until the first save, then fill in on their own. Network (UNC) paths follow the same opt-in as opening files from them.
A local image that is not at the referenced path is looked up by name. When  does not exist beside the document but a plot.png sits in figures/ or another subfolder (up to four levels down), the editor shows that file, the way Obsidian finds attachments. The reference itself is never rewritten, and the picture carries a tooltip saying where it was found, because the reference as written will not work in other tools. Two files of the same name are reported as a choice rather than guessed between.
Local images are included in print, PDF and HTML export. Every local reference used to become its alt text in exported output; the image bytes are now embedded in the export, and the in-editor page count is measured with them, so a figure that fills most of a page counts as one. An image taller than the page body is scaled down to fit one page, in the editor and in the export alike, instead of being cut off at the page edge. The .md itself is unchanged and still holds only the reference.
Insert Image can browse for a file, and image files can be dropped onto the window. Browse… opens the native file picker; dropping one or more images inserts a reference for each at the drop position. Both write a path relative to the document when the file sits beneath its folder, and an absolute path otherwise.
An open document reloads when another program changes it on disk. Edits made by another editor, a sync client or a tool such as an MCP server adding comments now appear without closing and reopening the file. A document with no unsaved changes reloads on its own, keeping the cursor and scroll position; one with unsaved changes asks whether to reload or keep your version. Monoleaf's own saves are recognised by their content and never trigger a reload. If the file is deleted or renamed away, the document stays open and Monoleaf says so once; the status bar shows "not on disk", autosave holds off, and saving writes the file back. Network paths are only watched when opening them is allowed.
Comment threads can be deleted. Each thread in the comments sidebar has a Delete button, and the Resolved heading has Delete all, so resolved discussions no longer have to stay in the file forever. Deleting removes the thread's hidden comment block, the blank line that set it apart and its anchor markers, but keeps the commented text, so the file reads exactly as it did before the comment was added. Both ask for confirmation, and Ctrl+Z brings the thread back.
Updating from inside Monoleaf no longer stops with "Failed to kill Monoleaf". On a computer with a virus scanner, Install and restart closed Monoleaf and started the installer, which found the scanner briefly checking Monoleaf's program file, could not stop the scanner, and gave up, so the update never happened. The installer now waits for the file to be free first. Updating to this version from 1.2.1 works, since it is the new installer that does the waiting.
Text typed into a table cell is saved again. Since 1.2.1, an edit in a table cell could stay visible in the grid without ever reaching the document, so it was missing from the saved file and from PDF, print and HTML export, which showed the table empty. It happened whenever page breaks were recalculated between the table appearing and the edit, which is almost always. Cell edits, the table toolbar and Delete table all reach the document again.
A right-click submenu closes when the pointer moves on. The Image, Table and Change case submenus stayed open once shown, so moving to another entry stacked a second submenu on top of the first. A submenu now closes when the pointer reaches another entry or the formatting buttons.
The page indicator no longer claims "1" page before the first measurement has succeeded. When the background page measurement failed on a document's very first pass, the indicator fell back to a built-in "1" and showed "p. 1 / 1" for a document of any length. The first measurement is now retried up to three times, and the indicator shows "p. 1 / ?" until one succeeds.
Enter works properly in files with Windows line endings. In a file saved with CRLF line endings (as Notepad and many Windows tools write them), Enter left the cursor two characters too far along, and near the end of the file it failed outright and inserted a stray line break shown as a red "NL". The same applied to Shift+Enter in a heading, page breaks, callouts, the table of contents, new tables and typing with Track changes on. The cursor now lands where the new text ends.
The Dark mode switch works in the installed app. The installed build followed the system's light or dark appearance and ignored the switch, so on a system set to dark the editor stayed dark however it was set. The switch now decides; until it is first used, the system setting still applies.
Spelling mistakes are underlined everywhere, not just while typing. On Windows the underline only ever appeared under words as they were typed: an opened document showed none, however many typos it had, and switching spellcheck off and on again removed every mark for good, while right-click still offered corrections. Monoleaf now draws the underline itself, from the same Windows spell checker the right-click suggestions come from, so opened text, text changed by another program, table cells and both views are all checked; Add to dictionary removes the underline at once. Spellcheck was also only active in the writing view, so switching to the source view silently disabled it. It now applies to both views, and Settings has a Spellcheck switch. Words are checked against the system language and English.
The right-click image menu now handles paths containing a space or parenthesis. Picking a size for .png>) used to cut the reference off at the ) inside the name, and "Original size" on a sized <img> wrote back a bare path that no longer rendered as an image. The menu and the drag-resize handle now share one parser, and the menu writes the <…> form such paths need. It also shows only what applies to the image (sizes and alignment) instead of burying them in a submenu above the text formatting tools.
Image paths containing a space or parenthesis now work. A path such as OneDrive - Some Company\pic.jpg or Screenshot (1).png used to break the image reference entirely, whether typed, browsed or dropped; such paths are now written in the <…> form Markdown requires for them.
Keyboard shortcuts now work and read correctly on macOS. Four bindings collided with keys macOS reserves for itself and never reached the editor: Cmd+Q (quits) now has the writing/source toggle on ⌘/, Cmd+M (minimise) has Insert equation on ⌥⌘E, Cmd+Option+H (hide other apps) has Highlight on ⇧⌘H, and Cmd+` (cycle windows) has Inline code on ⇧⌘C. Headings move from ⇧⌘1–6 (⇧⌘3/4/5/6 are the macOS screenshot keys) to ⌥⌘1–6 with body text on ⌥⌘0, the same keys Word for Mac uses. Every tooltip, menu hint and help text shows ⌘-style shortcuts on a Mac instead of "Ctrl+…", and Cmd+scroll zooms the page like Ctrl+scroll does elsewhere. Windows and Linux bindings are unchanged.
Stray markdown symbols no longer appear after deleting around formatting. Backspace right after a bold or italic word deletes its last letter instead of eating the closing marker; deleting the last letter inside a run removes the whole run rather than leaving ****; Enter inside a run splits it into two runs; a space typed at a run's edge lands outside it; and a Shift+Enter line break is treated as one unit, so Delete, Ctrl+Backspace and selection deletes never leave a lone \ behind. Backspace after an escaped character removes its backslash too.
macOS and Linux now ship alongside Windows. Windows remains the tested, primary build. The macOS .dmg is unsigned and unnotarized (no Apple Developer account, none planned): Gatekeeper refuses a plain double-click as "damaged," so right-click (or Control-click) the app and choose Open, then confirm Open again. The Linux AppImage is community-tested rather than exercised as broadly as Windows.
Page breaks are no longer invisible inside a table that spans multiple pages. A table is rendered in the editor as one interactive grid, so a page-break divider landing inside it had nowhere to draw: the divider now renders as a row inside the table itself, at the same row the real PDF/print output breaks on.
A page break landing inside a single tall cell now shows precisely where the PDF actually breaks, instead of only at row boundaries. A cell long enough to span a page on its own (a <br>-separated list, say) has no row to anchor a divider to; the divider is now rendered inline inside the cell's own content, at the exact character position the real PDF broke at.
The gap between pages, and the divider inside a split table, now match the editor's actual canvas color instead of a similar but slightly different grey that never quite lined up with the background behind the page.
The text cursor no longer renders as tall as an entire table when placed at the edge of a table that spans multiple pages. It's now clamped to the height it would have in ordinary text.
Document fonts. Page Setup now offers a font: Source Serif 4 (the new default), Lora, Source Sans 3, Atkinson Hyperlegible Next or Lexend, plus IBM Plex Mono for code blocks and the raw view. All six are bundled with the app (SIL Open Font License) rather than drawn from whatever is installed on your system, so a document renders and paginates identically everywhere, the same reason page size and margins already travel with the file. The choice is saved in the document itself and carried into PDF and HTML exports; HTML exports embed the font directly so the file looks right even on a machine that doesn't have it installed. - Existing documents have no font set and now render in Source Serif 4 instead of the system font; page breaks may shift slightly as a result. - Lexend has no italic design; italic text in that font is a browser-synthesised slant, the same as most other apps do. - Code blocks switch from Consolas/Cascadia Mono (Windows-only fonts, so they rendered inconsistently on Linux) to the bundled IBM Plex Mono.
PDF and print output now actually uses the page's intended typography. The stylesheet that sets the 11pt body size, heading sizes, line spacing, justified text and code font was scoped to an element ID that Paged.js rewrites internally, so none of those rules ever matched: printed documents silently fell back to a 16px browser default instead. Exports now render at the intended size, so a document has noticeably more text per page and the printed page count may be lower than before.
The in-editor page-break indicator now matches the real PDF/print output exactly, instead of landing on a nearby but different line. A long paragraph that runs across a page boundary now reads Paged.js's own break point for plain-text paragraphs directly, rather than guessing where the cut fell; anything with inline formatting (bold, links, code, …) still falls back to the previous best-effort estimate, which itself no longer collapses onto a single position when a paragraph spans more than two pages.
Bold, italic, strikethrough, inline code, subscript and superscript no longer stack extra markers when toggled twice with nothing typed in between. Clicking the same formatting button again on an empty selection used to wrap the cursor in an ever-growing pile of markers (** → **** → ********…) instead of clearing the empty pair.
Release notes in the update bar. When an update is available, a collapsed "What's new" disclosure under the offer shows the release notes, instead of just a bare version number.
Skip a specific update version. A "Skip this version" button lets you decline one release without turning update checks off entirely. A later "Check for updates" still offers it, and the next release is unaffected.
Periodic update rechecks. Monoleaf now checks for updates roughly once a day while it stays open, not only at startup, so a long-running session doesn't miss a release.
The update offer now reaches every open window, not just the one that happened to check. Dismissing or skipping an update in one window now clears it everywhere, instead of leaving other windows showing a stale offer.
Optional update checks. Monoleaf can ask GitHub once per launch whether a newer version exists, then download and install it on request. Off by default: you are asked once on first run and can change the answer in Settings at any time. The check is a single HTTPS request carrying no identifiers and nothing about your documents. Updates are cryptographically signed and the signature is verified before installation.
Installing an update closes and reopens Monoleaf. Before it does, every open window writes its unsaved work to the crash-recovery snapshot, and the restarted app offers those drafts back.
Recovering an unsaved draft no longer consumes the only copy of it. The snapshot used to be deleted at the moment it was offered back, and the next one was over a second away and waiting on an edit that might never come, so a document recovered and then left untouched existed nowhere but in memory. A crash or a forced close in that window lost it: the exact failure recovery exists to prevent. Each draft is now written straight back, under the key of whichever window ends up holding it.
Dialogs no longer stretch to the width of the window when they hold a long message. Their width is capped at a readable column, for every dialog rather than only the ones where it had been noticed.
Em dashes in labels and messages give way to plainer punctuation: a colon, a comma or parentheses. The window title keeps its dash, which is the conventional form there.
First public release.
Single-file WYSIWYG editing. A silent live preview renders headings, bold, tables, math, callouts and code in place while the file on disk stays pure Markdown. Ctrl+Q shows the raw view, which is exactly what is on disk.
Lossless, byte-for-byte round-trip. Opening a file and saving it untouched reproduces it exactly: line endings (CRLF/CR/LF), BOMs and missing trailing newlines included. Enforced by tests, not hoped for.
Writing. Bold, italic, strikethrough, inline code, underline, highlight, sub/superscript, change case and clear formatting; headings, bullet, numbered and task lists, blockquotes, tables and horizontal rules; GitHub-style admonitions, LaTeX math, fenced code with syntax highlighting, footnotes, and an outline sidebar. Pasting from Word, Excel or the web arrives as clean Markdown, tables included.
Document. Table of contents, in-file document properties, page setup (size, margins, header/footer with field substitution), find & replace, live word count, and a page-accurate layout view with zoom.
Review. Inline threaded comments that resolve, and CriticMarkup tracked changes with accept/reject. Both live in the .md itself with no sidecar files and no character offsets, so both survive editing elsewhere and diff in git.
Export. PDF with true page geometry via CSS Paged Media, and self-contained HTML with styles inlined and no external resources.
PDF import under File ▸ Import from PDF…, a separate command from Open because a PDF is converted rather than opened. The result is a new unsaved document named from the PDF's title metadata; the original is only ever read.
Conversion is pure Rust, using pdf-extract over lopdf, no Poppler, PDFium, Python or ML runtime, so Monoleaf stays a single static binary. Because a PDF contains only glyphs at coordinates (no words, no paragraphs, usually not even spaces), structure is reconstructed from geometry: word spacing from pen advances, headings from relative type size, paragraphs from leading, list items from markers or from the bullet glyph a browser draws as a filled path, tables from ruled cell borders, and columns from a gutter no line crosses.
Imported documents are plain CommonMark + GFM and start completely untracked. Text that would read as markup is escaped rather than deleted, so nothing in a PDF can impersonate Monoleaf's own constructs: an <!-- cannot return as a metadata or comment block, and a {--…--} cannot return as a tracked change that Accept All would then apply.
Remote images are not loaded unless you enable them (Settings ▸ Load remote images). Otherwise opening a document fetches every image it references, which turns  into a tracking pixel telling whoever wrote it your IP address, when you opened the file and, from a unique URL, which file. Blocked images show their alt text. Mail clients block remote images by default for the same reason.
Portability modes. Strict/Enhanced flagging of anything beyond CommonMark + GFM, so you always know how portable a document is. Constructs other viewers do not understand (callouts, comments, page setup) are written as ordinary blockquotes or HTML comments, so the file still reads cleanly on GitHub or in any plain editor.
Light and dark themes, autosave with crash recovery, reopen-last-file, and a Windows installer that installs per-user with no administrator rights.
Rendered document HTML is sanitized with DOMPurify before it reaches the DOM or an exported file, under a restrictive Content-Security-Policy, with withGlobalTauri disabled and file writes constrained to document extensions.
Documents never leave your machine: no account, no cloud, no telemetry. The app window never navigates; external links open in your system browser.
The page-setup block cannot inject CSS. A margin value travels with the document and is interpolated into the printed page's @page rule, so it is validated as plain CSS lengths and nothing else. Without that, a document could close the rule and append styles of its own (applied on open, since page layout is measured when a file loads, not when it is printed).
Remote content is blocked on every attribute that fetches, not just <img src>: srcset, poster and the legacy background attribute on any element, href/xlink:href on the SVG elements that load one, and any inline style that references a remote URL, including through CSS escape sequences and image-set(), neither of which a pattern over url() tokens catches. Inline data: images are unaffected, in either setting.
Exported HTML carries its own Content-Security-Policy. A shared .html opens in an ordinary browser, which applies none of the app's restrictions; scripts are refused outright and images are limited to what the reader's remote content setting allowed at the moment of export. Links that open a new tab now carry rel="noopener noreferrer".
Network paths need your permission (Settings ▸ Allow network paths, off by default). On Windows, merely opening a \\server\share path makes the system sign in to that server and hand it a hash of your credentials, so a path Monoleaf did not choose cannot reach a host you did not choose. Opening a file on a share offers to switch the setting on and then retries, so it is one click rather than a dead end; mapped drives (Z:) never needed it.
A panic while importing a PDF cannot take the app down, and cannot poison the locks that the rest of the session depends on.
Supply chain: CI runs on a least-privilege token with every third-party action pinned to a commit hash, blocking npm and cargo advisory audits on both the build and release paths, CodeQL static analysis, dependency review on incoming changes, and Dependabot across npm, Cargo and Actions. A release tag is checked against the version in all three manifests before anything is published.
PDF import is best-effort by nature. Tables are rebuilt from their ruled borders, so a borderless, whitespace-aligned table arrives as text in reading order, with no cell text lost, and merged cells flatten into the first column they cover. Multi-column layouts are split on a vertical gutter and can still interleave on complex pages. Scanned or image-only PDFs are refused with an explanation rather than opened blank; there is no OCR. Bold-only headings at body size arrive as paragraphs, since relative type size is the only heading signal a PDF reliably carries. Images are dropped. Encrypted, damaged and oversized files each fail with a specific message.
Embedded media is not rendered. Raw <video>, <audio> and <track> elements in a document are removed rather than displayed, in the editor and in both exports. Monoleaf does not emit them, and allowing tags it never produces only widens what an untrusted document can reach for. Images, math and tables are unaffected.
Page margins accept plain CSS lengths only: one to four values in mm, cm, in, pt or px, or a bare 0. Anything else in a document's page setup falls back to the default, because a margin travels with the file straight into the printed page's style rule.
The installer is not code-signed, so Windows SmartScreen may warn about an unknown publisher.
Windows is the tested and distributed platform. macOS and Linux build from the same source but are neither distributed nor currently verified.
Monoleaf was built and tagged in the open before its first public release, so the repository carries earlier tags. They are not listed here because they were never published as releases and were never installed by anyone but the author. Only versions this page can honestly describe as shipped appear above.