Changelog

All notable changes to mdnest are documented here.


v4.5.3 — Install with one compose file

Installing mdnest meant cloning the repo, running a setup script and building both images on your own machine. That's a lot of ceremony for anyone who already runs their own networks, reverse proxy and certificates, and wants a compose file they can read and edit. GitHub issue #112 said so plainly, after 30 minutes in the docs without a running install. There is now one file, nothing to build and nothing to clone.

Added

Fixed

Tests


v4.5.2 — A task board that does what you meant

Dragging a card between columns worked for exactly one gesture: grab the thin title strip, release squarely over another column's cards. Everything else failed quietly or, worse, landed somewhere you didn't aim. The second move from the same note was thrown away with a flash of "Loading tasks…". A refresh on the board dropped you back into the editor, and switching to the List view on a big workspace froze the app for ten seconds. All of that is fixed, along with one byte the CLI added to every note it read.

Fixed

Security

Tests


v4.5.1 — The CLI installer survives GitHub's CDN

curl -fsSL https://raw.githubusercontent.com/.../install-cli.sh | bash was returning 503 and nobody could install the CLI. The repo was fine, GitHub was fine, and the network was fine — the 503 came from Fastly's own edge: Backend.max_conn reached, served by one POP, which takes out every install in that region for as long as it lasts. Both the installer and mdnest update were hardcoded to that single host with no fallback and no retry, and reported the failure as "check your network" — sending people to look at the one thing that was working.

The install command is now:

curl -fsSL https://mdnest.dev/install.sh | bash

The GitHub URL is the same script and keeps working.

Fixed

Security

Notes


v4.5.0 — Stickies

A personal sticky board, kept beside your notes and never mixed in with them. Open it as a drawer on the right to jot something down without leaving the note you are reading, or full screen as a corkboard where cards are dragged and resized freely. Each card is a title, some free text, and a checklist — all optional, so the same card covers a scribbled reminder and a small to-do list.

Stickies are deliberately not notes. They never appear in a namespace and never reach a git remote: they live in mdnest's secrets volume (Postgres in multi mode), which the git-sync sidecar cannot see. That storage location is the privacy guarantee, which is why there is nothing to encrypt and no key to manage. The tradeoff is stated plainly in the app and the docs — a sticky has no git history and no off-server copy, so anything you would be upset to lose belongs in a real note.

Nothing about the default install changes: no new dependency, no new environment variable, no new failure mode for an operator who never opens it.

Added

Notes for operators


v4.4.0 — Edits that don't overwrite someone else

Changing one line in a note used to mean rewriting the whole file. Both surfaces agents reach mdnest through — the MCP server and the CLI — could only replace a note wholesale, so the only way to edit part of one was to read it, rebuild it, and write it back. Anything saved in that window by the web UI, git-sync, or another agent was silently overwritten, and the write reported {"status":"ok"} while doing it.

Both now have an exact-string edit that carries the version it read, so a concurrent save comes back as a 409 with nothing lost. Plus the Preview pane renders images again.

Added

Fixed


v4.3.3 — Instructions that survive a paste

A short one, entirely about the second half of the v4.3.2 report: someone hit a CLI bug, and nothing in the product told them their CLI was stale or how to fix it. v4.3.2 taught the CLI to say so. This does the same for the app.

Fixed

Added

Guarding it

frontend/src/__tests__/pasteable-commands.test.js fails the build on a new bracketed command. Two things it has to get right, both found by testing the guard itself against the pre-fix file rather than trusting it:

Verified both directions: all nine flagged against the old file, and the false positive stays quiet.


v4.3.2 — The CLI stops dying quietly

One bug report, one root cause, five places it was hiding. mdnest servers printed the table header and then nothing at all — no rows, no error — and exited with curl's 28, any time a registered server was unreachable. Since the server list is globbed alphabetically, one dead server also hid every healthy server sorting after it, so a mdnest login that had worked perfectly looked like it had failed.

Nothing was wrong with the networking, and nothing was wrong with the error handling either: the labels, the hint, and the messages had all been written. They were simply unreachable code. The CLI runs under set -e, and in bash a plain assignment from a command substitution takes the substitution's exit status — so cfg=$(curl ...) killed the whole script the moment curl could not connect, mid-loop, before the first row. The leaked exit code was the tell: a command that should always exit 0 was handing back curl's 28.

The same shape turned up in four more places, each one silently killing the CLI in place of an error message that already existed.

Fixed

Testing

Added

Guarding against the next one

The bug above was one root cause in five places, and it had been in the codebase since the first release. Two things now make a sixth harder.

A third bug fell out of building the notice, and it is worth naming because it had been sitting there quietly: mdnest login read the server's version with grep -o '"version":"[^"]*"', and /api/config carries two matches — the top-level version and latestRelease.version, the nested one emitted first. The value was two lines, not one. Nothing noticed, because the only consumer was ${SERVER_VER%%.*}, which still yields 4 from a doubled string. The moment this release started printing and comparing that value, login began reporting is running v4.3.1\n4.3.1. and the comparison read the third field as 14, telling a 4.3.2 CLI to update to a 4.3.1 server. json_top_string is the depth-aware parser written for exactly this — its own header comment names latestRelease.version as the trap — and the login path simply was not using it. Fixed at the source, and version_gt now takes only the first line of each argument so a sloppy caller cannot fabricate an upgrade either way.

Worth recording, because it is the honest result: while writing the update notice, the same class of bug was reintroduced inside the fix for it — a trailing [ -n "$x" ] && … as a function's last statement, where a false test becomes the return value and set -e exits the CLI with 1. The lint did not catch it; a lint cannot see that shape. The unreachable-servers suite added earlier in this release caught it within a minute. Which is the actual lesson: the behavioural test is the guard, and the lint is the cheap second net.

Reported against v4.3.1 on Linux. Not platform-specific — it is shell semantics, and it reproduces anywhere with a server pointed at a blackhole address.


v4.3.1 — Text you can actually read

v4.3.0 added a light theme. Shipping a second theme turns out to reveal every place the first one was getting away with something, and this release is the cleanup: four separate cases where mdnest drew text you could not read, three of them found by simply looking at the app in the other theme.

The Mermaid ones are the worst of them. A diagram with an author's own classDef fill: — the ordinary way anyone colours a flowchart — rendered its labels in the light ink while in dark mode, so the text was near-invisible on its own node. That is not a subtle miscalculation; the brightness maths was right all along, and the walk that fed it was measuring the wrong shape.

Fixed

Documentation

Testing


v4.3.0 — Light mode

mdnest has been dark-only since the first commit. Some people don't want that, and until now the only answer was "use a different app after sunrise".

This release adds a light theme that follows your operating system by default, a toggle that takes one click, and — the part that matters more than it sounds — a choice that is stored against your account rather than your browser. Pick light on your laptop and your phone agrees.

It also takes a pass at the top toolbar, which had quietly become a wall of equally-spaced buttons.

Added

Changed

Fixed

Under the hood

Upgrading: nothing to do. Existing installs keep dark unless a user chooses otherwise or you set DEFAULT_THEME. Multi-user installs pick up one new table (user_preferences) automatically on first start.


v4.2.2 — A board you can actually use

Almost all of this release came out of running the task board on a real project with roughly 12,000 checkboxes, where it went from useful to unusable. None of it was where it looked: the server answered in ~100 ms, and the cost was the browser being handed every card at once.

The rest is the board finally saying what it is. It has been a third button inside the Basic/Live control, then a row in the sidebar, and is now one button that names where it takes you — with no way out of it until this release, which is the part that should not have shipped in the first place.

Fixed


v4.2.1 — Nothing silently disappears

A bug-fix release with one theme: mdnest should never lose your work or hide it somewhere you can't reach. Every fix here is something that failed quietly — no error, no indication anything had gone wrong.

Fixed

Changed

Security

Fixed (continued)

Testing


v4.2.0 — Drawings, access groups, and per-note authorship

The largest release since v4.0.0, and almost all of it is contributed work. Three new opt-in capabilities — Excalidraw drawings, a centralized Marp theme catalog, and role-based access Groups — plus per-note authorship, a task board grown up enough to run a week on, and an MCP server that can now edit slides, tasks and drawings rather than only note bodies.

Every new capability is off by default. An operator who wants none of them carries no new service, no new required env var, and ~1.8 KB more in the frontend entry bundle; the drawing engine and the deck exporter are code-split and download only when something actually needs them.

One fix here matters more than its size suggests: in the git-native HA topology a move could look like data loss. See below.

Added

Fixed

Security


v4.1.3 — comments, Marp safety, and four papercuts that made mdnest look broken

Alongside the comment-editing and Marp work, this release clears a batch of reported bugs that shared a shape: mdnest was working correctly but not saying so, so each one read as a malfunction. A DNS failure blamed the server's config file. A namespace added to mdnest.conf simply never appeared. A file created on disk sat invisible in the sidebar until you clicked Refresh. Diagram text couldn't be copied at all.

Added

Changed

Fixed



v4.1.2 — mdnest list you can actually read

Patch release fixing GitHub issue #87, reported from Fedora 44. Both halves of that report were the CLI's fault, and both are fixed. Nothing outside the mdnest CLI changed.

Fixed

Chores

Tests



v4.1.1 — The conflict banner learns whose save it is

Patch release fixing GitHub issue #82.

Fixed


v4.1.0 — Marp slides, Git Workspaces admin, and the image v4.0.0 forgot

A short cycle on top of v4.0.0, and it starts with an apology: v4.0.0 shipped without its mdnest-mcp-server image, so any Kubernetes install with mcp.enabled=true hit ImagePullBackOff on a tag that was never built. This release publishes it and makes that class of mistake impossible to repeat.

Fixed

Added

Notes for operators

Thanks again to @ecthelion77, who found the missing image, diagnosed it, and sent the fix.


v4.0.0 — Task board, git-native HA, and bring-your-own-repo durability

The first release built substantially with outside contributions, and the largest change to what mdnest can be deployed as since it started. Notes are still plain Markdown files in a git repo you own — that hasn't moved, and most of this release exists to keep it true at scales where it previously wasn't.

A single-box install is unchanged. The generated docker-compose.yml is byte-identical to v3.11.7's, and .env gains exactly one line (ENABLE_TASK_BOARD=false). Everything below is either opt-in or invisible unless you run multi-user mode.

Major version because two changes require operator action on upgrade — see Breaking changes. Huge thanks to @ecthelion77 (Olivier Gintrand), who wrote most of what follows.

Breaking changes

Added

Changed

Fixed

Security


v3.11.7 — XSS hardening, cross-namespace file leak fixed, Helm chart, build CI

First release with outside contributions. Thanks to @ecthelion77 (Olivier Gintrand) for the sanitization hardening, the /api/files/ authorization fix, the Helm chart, and the CI workflows.

Security

Kubernetes

CI

Bug fixes

Testing


v3.11.6 — Clearer pitch, reveal-in-tree, instant cross-tab sync, security gate

Docs

Features

Bug fixes

Security / CI


Features

Thanks to @lglot (Luigi Lotito) for contributing this feature.


v3.11.4 — git-sync self-healing, fresh-machine CLI, tree memory + local test gate

Bug fixes

Testing


v3.11.2 — CLI list/move fixes + prettier update indicator

Bug fixes


v3.11.1 — Live editor mermaid sizing + contrast

Bug fixes


v3.11.0 — CLI stdin fixes + smoke-test harness

Added

Bug fixes

Testing

Security / CI


v3.10.2 — Live editor list alignment + "Refresh Now" feedback

Security

Bug fixes


v3.10.1 — Login form: proper password-manager hints + per-server scoping + "Keep me signed in"

New features

Bug fixes


v3.10.0 — Live editor migrated to Crepe + per-workspace last-file memory

The big one: the Live editor is now built on @milkdown/crepe — the same component the Milkdown playground uses. The pre-v3.10 hand-rolled @milkdown/core + commonmark + GFM stack is gone. Crepe brings a block-edit handle (drag + + button + slash menu), native SVG task-list checkboxes, KaTeX math, polished tables with column / row controls, link tooltip, and an image-block upload affordance. All four custom plugins from v3.9 (mermaid live edit, comments, in-cell [ ]/[x] checkboxes, clear-empty-block) port forward; the Catppuccin Mocha look is preserved.

This release also rolls up the v3.9.1 changes (paste-handler priority, browser tab title, Vitest scaffolding) — they shipped on the migration branch as the first commit and never got their own tag.

New features

Mermaid rendering preserved

The legacy MermaidBlock React component (Preview / Source toggle, zoom, Fit, Copy, fullscreen viewer, "click any label to edit") stays. Crepe's code-mirror feature is kept enabled (its LaTeX feature depends on it) and a composing plugin wraps the code_block nodeView so language=mermaid blocks render via the React component while everything else falls through to Crepe's CodeMirror block. The fallback was important: without it disabling code-mirror crashed the editor on any $…$ math because LaTeX's editor uses CodeMirror internally.

Paste-fidelity contracts (v3.9.1 priority + new ProseMirror bypass)

Table-editing polish

From v3.9.1 (subsumed into this release)

Bug fixes

Internal cleanup

Notes


v3.9.1 — Paste-handler priority + browser tab title + test scaffolding

Bug fixes

New features

Tests

Notes


v3.9.0 — Tree auto-refresh in single mode + host-side token CLI + path-confusion guard

New features

Bug fixes

Notes


v3.8.0 — Update notifications, version compare, and multi-IP bind

New features

Bug fixes

Mobile UX

Notes


v3.7.0 — In-app version history with restore (single + multi mode)

New features

Notes


v3.6.1 — Stop the Live editor's undo from erasing your notes

New (small UX add)

Bug fixes (critical — data-loss prevention)


v3.6.0 — Admin password reset (UI + host CLI)

New features

Notes


v3.5.4 — Fix renamed file vanishing from the sidebar when extension is dropped

Bug fixes


v3.5.3 — Fix bogus 409 "modified by another user" on first save of new notes

Bug fixes


v3.5.2 — Fix empty tree for superadmin in multi mode

Bug fixes


v3.5.1 — Go 1.26 bump for stdlib CVEs

Security


v3.5.0 — Namespace-scoped Admin role + SuperAdmin + token access scoping

Breaking changes

Features

Configurable grant depth

Dev-only

Internal


v3.4.0 — Corporate SSO + Federated Identity

Features

Internal


v3.3.1 — Preview crash hotfix + CLI server-alias cleanup

Breaking (CLI)

Server

Fixes

Robustness


v3.3.0 — Inline Comments

Features

Fixes


v3.2.2 — Responsive Mobile & Stability

Fixes


v3.2.1 — Performance & Stability

Fixes


v3.2.0 — Two-Factor Authentication & Account Security

New Features

Fixes

Config


v3.1.8 — Developer Experience & Security

New Features


v3.1.7 — Mermaid Improvements & UX Polish

New Features

Fixes


v3.1.1 — Critical Save Fix

Fixes


v3.1.0 — Mermaid Zoom & Live Toolbar

New Features

Fixes


v3.0.0 — Live Rich Editor

New Features

Improvements

Dependencies

New Files


v2.1.0 — Multi-Server CLI + Git Sync Fix

New Features

Fixes

Configuration


v2.0.1 — Patch Release

Fixes

New Features


v2.0 — Multi-User Collaboration

Powerful, privately-hosted Markdown notes — use it the way you like.

mdnest v2.0 transforms the app from a personal note tool into a collaborative workspace for teams, while keeping the default single-user experience unchanged.

Upgrading from v1

If you're running mdnest v1 (single-user), no changes are required. Your existing setup continues to work exactly as before. Multi-user features are opt-in.

To enable multi-user mode:

  1. Update your code:

    cd mdnest
    git fetch origin
    git checkout v2.0
    
  2. Edit mdnest.conf — add:

    AUTH_MODE=multi
    POSTGRES_PASSWORD=a-secure-password
    
  3. Run setup and migrate:

    ./mdnest-server setup      # regenerates docker-compose.yml with Postgres
    ./mdnest-server migrate    # creates database tables
    ./mdnest-server rebuild    # rebuilds and starts everything
    

Your first user (from MDNEST_USER/MDNEST_PASSWORD) becomes the admin automatically.

To also enable live collaboration:

  1. Add to mdnest.conf:

    ENABLE_LIVE_COLLAB=true
    
  2. Rebuild:

    ./mdnest-server rebuild
    

New Features

Multi-User Mode (E1-E6)

Live Collaboration (E7)

UI Improvements

Bug Fixes

Configuration Reference

New settings in mdnest.conf (all optional, defaults preserve v1 behavior):

Setting Default Description
AUTH_MODE single single (file-based) or multi (PostgreSQL)
POSTGRES_PASSWORD — Required when AUTH_MODE=multi
POSTGRES_HOST postgres PostgreSQL host (use postgres for built-in container)
POSTGRES_PORT 5432 PostgreSQL port
POSTGRES_DB mdnest PostgreSQL database name
POSTGRES_USER mdnest PostgreSQL user
ENABLE_LIVE_COLLAB false Enable WebSocket presence and live editing

Docker Changes

When AUTH_MODE=multi, setup.sh automatically adds a postgres service to docker-compose.yml with:

API Changes

New endpoints (multi-user mode only):

Endpoint Description
GET /api/config Public — returns auth mode and feature flags
GET /api/me Current user profile + grants
POST /api/admin/invite Create a new user (admin only)
GET /api/admin/users List all users (admin only)
PUT /api/admin/users?id= Update user role (admin only)
DELETE /api/admin/users?id= Delete user (admin only)
POST /api/admin/grants Create access grant (admin only)
GET /api/admin/grants List grants (admin only)
PUT /api/admin/grants?id= Update grant permission (admin only)
DELETE /api/admin/grants?id= Revoke grant (admin only)
POST /api/admin/sync?ns= Git pull + cache refresh for a namespace (admin only)
GET /api/ws WebSocket for live collaboration

Changed endpoints:

Endpoint Change
GET /api/note Now returns ETag header
PUT /api/note Accepts If-Match header, returns 409 on conflict. Response includes etag field.
GET /api/namespaces In multi mode, filtered to user's granted namespaces
GET /api/tree In multi mode, filtered to user's granted directories

v1.0 — Self-Hosted Private Knowledge Base

The initial release. A single-user, file-based markdown notes app.

Features