couplet

A minimalist yet powerful markdown editor your agent can drive.

macOS free open source
$ brew tap malinborn/mdmini && brew trust malinborn/mdmini && brew install --cask couplet
Or look at the source on GitHub →

Features

Everything a markdown file needs, nothing else.

Live Preview

Markdown renders inline as you type. No split pane, no preview toggle.

**fast** fast

GFM Tables

Create, edit, reorder, and delete table rows and columns. Drag to reorder.

item
qty
tag
flour
2
⋮⋮
eggs
6

Collapsible Headings

Click any heading to fold the section below it. Keeps long docs navigable.

Setup
Usage

Syntax-Highlighted Code

Fenced code blocks render with language-aware syntax highlighting.

let editor = "minimal";
fn render(md) { … }

Mermaid Diagrams

Flowcharts, sequence, class, Gantt, ER, pie, mindmap — all render inline as SVG. Pinch to zoom, swipe to pan around the big ones.

write md? ship

Secret Masking

Secret values in .env and shell configs (.zshrc, .bashrc) are masked by default. Cursor or Cmd+E to reveal.

API_KEY=•••••••• ⌘E

File Watching

External changes to open files are detected and reloaded automatically.

notes.md reloaded just now

CLI Launcher

Open files instantly from the terminal with couplet file.md — or the short alias, coup file.md.

$ couplet file.md

Dock Drop

Drag any file onto the Dock icon to open it. Works with multiple files at once.

a.md b.md

Session Restore

Reopen the windows you had last time with ⇧⌘T — files, positions, scroll, and unsaved drafts.

⇧⌘T 3 windows restored

Dark & Light Themes

Six theme families, each with a light and a dark half: Classic, Aurora, Blueprint, Phosphor, Paper and Ink. Follow the system or pick a half yourself — and the Dock icon takes on the theme’s colours.

Rosé Pine Dawn Aurora Dark Aurora Light

Auto-Save & Recovery

Changes are saved continuously. Crash recovery restores your last session.

Saved · just now

Quick start

Install with Homebrew, open from anywhere, and register the MCP server once — your agent gets a local socket into the running app. No daemon, no cloud.

zsh — 80×16
$ brew tap malinborn/mdmini && brew trust malinborn/mdmini && brew install --cask couplet
$ couplet README.md # opens in a native macOS window
$ couplet *.md notes/*.md # each file gets its own window
$ claude mcp add --scope user couplet -- couplet mcp # connect your AI agent — or use plain CLI verbs: couplet show / edit / ask
$ brew update && brew upgrade --cask couplet

couplet was called md-mini. Already have it? brew upgrade --cask mdmini moves you over and your data comes along. couplet, coup and the old mdmini all work in the terminal; to switch your agent over, run the prompt from AI → Teach Your AI couplet.

After an upgrade, macOS asks for folder access again. couplet is ad-hoc signed — no Apple Team ID — so macOS identifies it by a code hash that changes with every release, and the permission you granted belongs to what it now considers a different app. Signing and notarizing properly costs $99/year, which a free open-source tool is not going to carry. Grant it again and carry on.

Changelog

v2.3.1 2026-10-06 fix Short rows reach the edge
  • Empty cells are drawn — a table row with fewer cells than the widest one stopped at its last cell, background, border and stripe included, so a sparse table read as a staircase. Short rows are now padded with empty cells to the full width, the way GitHub renders them. Double-click one in a data row and couplet writes the missing cells into the row and opens it for editing. The header’s padding stays read-only: in GFM the header must have as many cells as the |---| line under it
  • Rows without outer pipes keep their text — GFM lets a row leave off its leading or closing |, but couplet’s cell reader ignored whatever sat outside them: | R-091 drew an empty row, and a | b | lost a. Both ends are read now, the same way the markdown parser reads them
v2.3.0 2026-10-05 feature CSV opens as a table
  • .csv and .tsv are tables now — open one and the window holds the same table widget markdown gets: edit cells, add and drag rows and columns, and the file is saved back as CSV. The delimiter (, ; or Tab), a BOM and the line endings are read from the file on every save, so an Excel export stays an Excel export. couplet also shows up in Finder’s “Open With” for both. couplet edit refuses CSV files for now; show works
  • Huge CSVs open as text — above 20,000 rows a CSV opens read-only, with a note saying why. 100,000 rows as a table meant about 1.6 million DOM nodes and a frozen window; a scrolling table that draws only what is on screen is the next step
  • Big tables got fast — the striped rows used :nth-child(even of …), which WebKit recomputes from scratch for every row: quadratic, 4.6 s of style work on 20,000 rows, now 0.5 s. A cell edit rebuilt the whole table; it now patches the cells that changed, and a commit in a 10,000-row table went from 1.7 s to under 0.3 s. Markdown tables render up to 1,000 rows (was 500)
  • The header stays put — scroll down a long table and its header row sticks to the top of the window until the table ends. It never could: the table clipped its rounded corners with overflow: hidden, which quietly made it the box a sticky header sticks to
  • Code files, two fixes — a .py (or any code file) opened inside a grey box that vanished on the first click: its style hung on a class the editor rewrites on every focus change. The box is gone for good. And Enter after def f(): indented by two spaces, because nothing ever set an indent unit. couplet now reads it from the file (four spaces, two, or tabs), or uses the language’s convention when the file has none
  • Smaller table fixes — Enter off the last visible row no longer opens the next cell’s field below the window’s edge, and a markdown table too long to render keeps its caret and its search hits instead of throwing the caret out
v2.2.0 2026-10-03 feature Find shows what it found
  • Matches you can read — a match inside a heading used to be an empty box: heading text is painted through its gradient with a transparent fill, and the match background landed on top of the glyphs. Inside inline code the code’s own background covered the match, and inside a table nothing was highlighted at all. All three now show real text, and the current match, the other matches and the selection are three different colours — one shared !important rule used to paint them identically. A test holds every theme to a 4.5:1 contrast for match text
  • Everything else steps back — while the cursor is in the Find field, the page dims except for the matches, and the current one glows. Click back into the text and the dimming lifts, the highlights stay
  • How many, and which one — the Find panel is new: 3 / 17 right in the field, toggles for case, regexp and whole word, a replace row on demand, and a red field when nothing matches or the pattern is broken
  • ⌘G / ⌘⇧G — Find Next and Find Previous are in the Edit menu and printed next to the arrows in the panel. They always worked; nothing said so. With the tab drawer open, ⌘G is still “To a window…”
  • Stepping through tables — landing on a match in a table row snapped the caret out of the table, so the next step skipped every other match in it. Search steps now stay in the row, and the current match is outlined in its cell
v2.1.1 2026-09-27 fix ⌥⌫ and ⌘⌫ work in the drawer filters
  • ⌥⌫ deletes a word, ⌘⌫ clears the filter — the tab and stash drawers filter as you type, but only a plain ⌫ edited the query. ⌘⌫ fell into the branch that handles ⌘L/⌘R/⌘U, found no sort for it and did nothing; ⌥⌫ was read as a plain ⌫ and took one character. Both now behave as in any macOS text field, in the trash view too; on an empty query they do what ⌫ always did
  • ⌫ takes a whole emoji — it used to remove half of one, leaving a broken character in the filter
v2.1.0 2026-09-27 feature The stash — nothing you type is untitled, and nothing you type gets lost
  • Untitled is gone — a new tab becomes a note the moment you type its first character: a plain .md file in ~/couplet/, named by date, titled by its first line. Close it with ⌘W, the red button or ⌘Q and it is put away in the stash, not thrown away; a tab you never typed in just disappears. Drafts from earlier versions are imported as notes on first launch — read back and compared before the old copy moves aside
  • The stash drawer — ⌃S opens it beside the tab drawer, ⌃T puts the current tab away, and a file you tag or put away is kept as a reference — the file itself stays where it was, untouched. Drag cards between the two drawers, sort by changed, opened or kind, filter by #tag; a project window opens the stash already filtered to its repository. A narrow window widens itself so the drawers never overlap, and shrinks back when the stash closes
  • Search that finds word forms — a trigram index over titles and text, so тайник finds тайнике and мент finds документ, case-insensitive in any alphabet. Titles weigh more than text, the matched spot is highlighted and the card shows the text around it, not the first line
  • A trash that keeps things for 30 days — deleting a note moves its file to ~/couplet/.trash/; Trash at the bottom of the stash restores it with its tags or deletes it for good. A note open in another window is released by that window first, after its last keystroke is on disk, so the next autosave cannot bring it back. Removing a file reference never touches the file
  • Why 2.0.1 lost drafts on upgrade — restoring the previous session is opt-in, and a launch nobody restored rewrote the session file with only the windows it had open. The next launch saw the old drafts as unreferenced and deleted them. The session now keeps every un-restored window that holds a draft, and nothing is ever deleted outright: unreferenced drafts move to a trash for 30 days, and a draft that cannot become a note leaves a rescue copy when it is closed
  • Your agent can use the stash — couplet stash search | list | get | add | tag and the same five MCP tools. The default scope is the repository the agent works in; search returns short snippets and get one note at a time, so an agent never pulls the whole stash into its context. Run AI → Teach Your AI couplet again to tell it
  • ⌘' / ⌘⇧' walk through AI marks — the caret jumps to the next or previous edit your agent highlighted, comment anchor or open question, wrapping around and unfolding whatever hides it. They are menu shortcuts, so they work with focus in a comment box
  • Quotes render what is inside them — bold, links, code, lists, checkboxes, headings and nested > levels, each with its own bar, muted towards the quote grey. Tables and mermaid inside a quote stay source: editing them would rewrite the lines without their >
  • Crossing formatting nests instead of tearing — in Live Render, italicising text that ran past the end of a bold word wrapped the hidden ** along with it, and the repair filter, seeing one marker of a pair touched, added a stray **. The selection is now split at hidden markers it crosses, and spans of the same kind merge
  • Tab cards say when — “just now”, “5 minutes ago”, “yesterday at 23:11” for the last time a tab was viewed or edited; View → Tabs → Show Dates hides it
  • Autumn — cinnamon and pumpkin by day, a violet sunset at night, maple for quotes and falling leaves on finished tasks
v2.0.1 2026-09-26 fix ⌃Tab switches tabs from the keyboard, not just from the menu
  • ⌃Tab works again — in 2.0.0 View → Tabs → Show Next Tab worked when clicked and did nothing when pressed. The culprit was the kind of shortcut, not the key: a Control-only menu shortcut never reaches the menu while the window is active, the page swallows it as an ordinary keypress, and ⌃[ failed the same way in a trial build. ⌃Tab / ⌃⇧Tab are now caught by the page itself, the way ⌃1…⌃9 always were
  • The menu says ⌘⇧] / ⌘⇧[ — the same keys as Safari, Chrome, Terminal and Finder, and a Command shortcut does reach the menu. Both pairs do the same thing; a test now fails the build if a Control-only shortcut ever lands in the native menu again
v2.0.0 2026-09-25 feature md-mini is now couplet — and it brought tabs
  • md-mini is now couplet — there are two apps called mdmini, and the other one has mdmini.com. Two small editors under one name meant confused searches, downloads of the wrong thing and bug reports about someone else’s program, so we stepped aside rather than fight over it. The name also stopped telling the truth: this began as a minimalist markdown editor and became a page you and your agent work on together. A couplet is two lines that read as one
  • Your data moves on first launch — windows and tabs, caret positions, unsaved drafts, crash copies, theme and recent files go from md-mini’s folder into couplet’s, and md-mini’s folder keeps a note saying where they went. If md-mini is still running, couplet asks it to quit first instead of copying data out from under it. brew upgrade --cask mdmini still works and moves you onto the couplet cask
  • The old name keeps working — mdmini is an alias for couplet, and coup is the short one, so scripts, aliases and $EDITOR need no edits. An MCP server registered as mdmini still answers with the same tools. Restart agent sessions opened before the upgrade: they still talk to md-mini’s socket
  • Your agent moves over in one step — AI → Teach Your AI couplet hands over a prompt that now also cleans up the md-mini setup: it registers couplet instead of mdmini, replaces the old skill (and keeps it if you edited it by hand), rewrites the note in CLAUDE.md, and tells you what it changed. Installed from the DMG? Delete md-mini.app — opened by accident, it would start empty
  • Tabs — ⌘T, ⌘W, ⌘1…⌘9, ⌃Tab. A file lives in one tab across the whole app, so opening it again focuses it instead of making a copy. Windows are numbered #N; the notch on the left edge opens the tab drawer with ⌘J and glints while a tab your agent opened is unread. ⌘⇧T brings back the last closed tab, caret included
  • ⌘Z stays in its own document — after ⌘O or a Recent file, undo could write the previous document’s text into the new one: the inverse of a deletion survived the swap. History is rebuilt on every switch now, and the last few hundred milliseconds of typing are saved before it rather than dropped
  • Six languages — English, Spanish, German, French, Russian and Simplified Chinese, taken from your system on first launch, with Language and Check for Updates… in the app menu. Changing the language restarts the app: rebuilding the native menu in place would have meant four new places for a silent mismatch
  • Paper and Ink, and a Dock that follows the theme — Paper is ink on paper, and the same paper at night in sepia, with coral only for what you change. Ink is cream on ink with a coral caret that glows. The Dock icon now takes the colours of whichever of the six families is on screen, both halves; the Finder icon stays the default, because writing into an ad-hoc signed bundle would break its signature. /theme in the slash menu switches themes live as you arrow through the list
  • Zoom scales the whole window — ⌘+/⌘− set a font size the editor overrode, so the only thing that ever grew was the slash-menu tooltip. It is page zoom now: text, tables, diagrams and toasts scale and rewrap
  • Files with Windows line endings open — a CRLF file opened as an empty Untitled window with no error: the caret was placed past the end of a document CodeMirror had already shortened. Line endings are normalised on read and restored on save, a failed open now says so, and your own saves no longer trigger the “External Change” dialog — they were recognised by a 600 ms timer that could lose the race to the file-system event, and are recognised by content now
v1.3.0 2026-09-21 feature Four themes, a renderer out of beta, and a cross for everyone who cannot unsee the tick
  • Live Render is the default, and no longer a beta — the mode that hides markdown syntax outright is what you get on launch, including if you never opted in. The three engines are still there under View → Editor Engine, now spelled Raw, Preview and Live Render: the word “Live” in “Live Preview” only ever existed to contrast with the beta, and there is nothing left to contrast with. Someone sitting in Raw stays in Raw — that is a decision to look at the source, not a rendering preference to overrule
  • ⌘E stopped rotating through renderers — Live Render and Preview are two answers to “how should the markup look”, chosen once in a submenu. ⌘E asks something else entirely — “show me the source” — so it now flips between Raw and whichever renderer you picked, and lands back where you left. The “Include Live Render in ⌘E” switch that used to make it a three-way rotation is gone
  • Two new themes, and neither is a port — Blueprint is a cyanotype: white on deep blue, because white there is not an accent but unexposed paper, with red reserved for what you change — the caret, the checkbox, struck-through text. Phosphor is a terminal from before colour: P1 green on black glass, amber as the only second hue, and monospace in the prose itself. Both come in a light half too — tracing paper and fanfold printout
  • The Theme menu is three groups, not a list — family (Classic, Aurora, Blueprint, Phosphor), half (Light, Dark), and Follow System as a checkbox. “System” was a fifth mutually exclusive option, which is the one thing it is not: it decides the half, and it has nothing to say about which family you like. Tick it and the theme follows your Mac from day into night without leaving the family. “Default” is now called Classic, the name it has had in the code since it was written
  • A ticked task reads as done — greyed and struck through, while bold stays bold, italic stays italic and a link keeps its underline: only the colour is taken over. A wrapped item stays greyed across its continuation lines, and an unfinished child of a finished parent does not — the range follows the item, not the line. In the Aurora themes the grey is a gradient, and in Blueprint the line is drawn in that theme's red pencil while the text stays muted: crossed off, not deleted
  • One menu item where four documents used to be — AI → Teach Your AI mdmini. “Getting Started”, “Connect via CLI”, “Connect via MCP” and “Teach your AI” each explained their own part and left the assembly to you, so you ended up stitching a setup out of four texts. Now the document hands over a prompt: your agent registers md-mini over MCP, writes itself a skill on using it well, and adds a short note to its own config about when to reach for it. A second prompt in the same document does the skill only, if you would rather your main config stayed untouched
  • OCD Alignment — the tick in a checked box sits a hair off centre, and that is not sloppiness: ✓ is not a symmetrical glyph, so it never looks centred anywhere. If that hair is going to follow you around all day, View → OCD Alignment replaces it with a cross drawn as two strokes rotated around one point, symmetrical by construction. We like the tick. We also know how it is
  • The table header stopped ignoring the theme — its gradient was hardcoded in two variants, picked by whether the theme's name ended in “light”, so Phosphor got a lilac header on green paper. It is a theme variable now, with the old values as the default, so the themes that never asked look exactly as they did
  • A checkbox in the menu works with two windows open — a menu event is broadcast to every window, and each applied it to its own copy of the setting. Harmless for a radio item, where N windows set the same value; not for a toggle, where N windows flip it N times — so Follow System visibly did nothing whenever a second window was open. The event now carries the value rather than the instruction to flip
  • Zoom In has a key again — it was declared as ⌘Plus, and accelerators are parsed by key code, where Plus is not one. The item simply had no shortcut, which you could only notice by comparing it with Zoom Out. It is ⌘= now, next to ⌘−. And in Live Render's link inspector, Open on a link that points inside the document jumps to that heading instead of doing nothing at all
v1.2.0 2026-09-12 feature Type in Live Render without breaking it, and edit tables like a grid
  • Live Render survives being typed in — the mode hides the markers, which meant every edit that touched one silently damaged the file. Backspace past a bold word turned **bold word** into **bold word.; Enter inside it left two unpaired ** on separate lines; a space after it produced **bold **, which CommonMark refuses to close, so the asterisks stopped being markup and became four literal characters on screen. A repair layer now sits in front of the document and tells “the user is deleting this whole span” from “the pair just got torn” by the shape of the change, and writes the marker back before it ever reaches disk
  • Typing continues the format — the character after a bold word is bold, the way it is in every editor where you can see what you are doing. Esc or the format shortcut ends it. Option+arrows and Option+Backspace step over the hidden markers instead of stopping on them, so a “word” is a word you can see
  • The caret tells you the format — thicker for bold, slanted for italic, a narrow stem with a crossbar for strikethrough, serifs top and bottom for inline code, and they combine. With the asterisks hidden, the screen had nowhere left to say which format the next character carries, so the signal went to the one place the eye is already looking. It is right before the first character exists, too
  • Tables are editable, not just renderable — a click parks the caret in the cell it landed in. It used to jump to the table's first character, so the next keystroke landed in the wrong cell and wrecked the row. Cell text now selects, copies, takes bold/italic/code from the toolbar, and takes comments; the cell expands while you type instead of sliding under its neighbour
  • And navigable from the keyboard — Tab / ⇧Tab across columns, wrapping within the row; ↵ to the next row, and on the last row it leaves the table rather than dead-ending; ⇧↵ breaks a line inside the cell; ⌘↵ commits; ⌘⇧↵ adds a row. The ⓘ beside the wrap toggle has the whole map, because a keyboard grid nobody is told about is a keyboard grid nobody uses
  • A comment you never have to send — the reply area is always editable and saves itself as you type, so a half-written thought survives a crash, a reload and the agent answering in the middle of it: the incoming answer freezes the previous turn without swallowing the sentence you are still writing. And the agent is no longer woken mid-phrase — 20 seconds of quiet first, with the countdown running inside the send button so you can cut it short
  • A comment lands where it was written — anchoring was indexOf(quote), the first occurrence from the top of the file, so a one-word quote or a heading that also appears in a table of contents put the card on a duplicate, usually far above, and reported a confident match while doing it. Threads are now anchored by the text around them. Measured over 20,962 cases generated from this repo's own markdown and then edited the way an agent edits a file: first occurrence 61.5%, context anchoring 100%
  • Saving stopped damaging the file — an atomic write is a temp file plus a rename, and rename keeps the directory entry while dropping everything that lives on the inode. Mode, owner, group, ACLs and extended attributes — quarantine included — are now copied onto the temp before it moves into place; editing through a symlink writes to what the link points at instead of replacing the link; and a save the filesystem refuses raises a toast rather than failing in silence. The atomicity itself is still there and now proven rather than asserted: a test really does SIGKILL the process mid-write and checks the file came back whole. Comment sidecars go through the same path, since they sit in the same protected, cloud-synced folders
  • JSON formatting stopped corrupting numbers — JSON.stringify(JSON.parse(s)) is not a formatter, it is a re-serializer: every literal was destroyed and rebuilt from a JavaScript double. 12345678901234567890 came back as 12345678901234567000, 1e5 as 100000, 3.0 as 3. It now re-indents the text it was given, so number literals, string escapes, key order and duplicate keys survive byte for byte — and the result lands in a ```json fence when the file is markdown
  • Easier to read, in small places — six heading levels you can tell apart, each theme fading its own gradient down the scale. One indent step per list level whatever the marker: the parser was the culprit, not the CSS — Tab always inserted two spaces, and CommonMark nests a sub-item only once its marker reaches the parent's content column, which is 3 for 1. and 4 for 10., so an ordered sub-list never nested at all. Tab now indents every selected item, not just the first; folded sections stop hiding text in Raw mode; an AI edit highlights the regions that changed rather than everything between them; toolbar buttons name their shortcut; and [1] in prose keeps its brackets instead of being read as a link reference
v1.1.0 2026-08-24 feature Now you can ask it back — comments your agent answers
  • Comment on any text — select a fragment and press ⇧⌘M, or use the 💬 in Live Render's selection toolbar. The quoted words stay highlighted in the document, the card header carries an excerpt of them, and putting the caret in a commented fragment makes its cards shimmer — and the other way around. With several comments stacked under one paragraph, that is the difference between finding the right card and hunting for it
  • Your agent gets woken, not polled — AI → Connect Agent to Doc Questions copies a prompt that arms a watcher over your project. With Claude Code's Monitor tool, a new comment interrupts the session that already has your context, the moment you send it. That is the whole design: nothing here spawns an agent or hands your question to one that knows nothing about the work
  • The answer comes back into the thread — couplet answer plan.md --id c-4f2a1b. If the comment asked for a change rather than an answer, insert into text folds it into the document — highlighted like any other AI edit, Escape to dismiss, ⌘Z to take it back. If it was just a question, resolve closes the thread
  • The comments live next to your file — in .mdmini_comments_<file>.md, plain markdown you can read, edit by hand and diff in git. md-mini never rewrites that file wholesale, only appends to it. So the feature works with the app closed, works for agents with no MCP, and needs no store of its own — md-mini is deliberately not the source of truth here
  • Git worktrees stop being a problem — comments sit beside the copy they were written on, so the agent watching that tree is the one that answers. No routing, no claims, no queue to divide between sessions
v1.0.1 2026-08-23 fix Now it installs on your Intel Mac, and tells you it speaks AI
  • Intel Macs are supported — the build is universal now, one download for both architectures. Previously brew install --cask mdmini simply refused on an Intel machine, and never said why. The culprit was a single arch-dependent type: Objective-C's BOOL is a bool on Apple Silicon and an i8 everywhere else, so one true literal compiled on one machine and broke the other
  • The AI interface is findable — 1.0 shipped it and then hid it. A toast on launch now says the editor can be driven by your agent, and a new Getting Started entry sits at the top of the AI menu. It leads with a map of that menu rather than a wall of setup, because the thing worth remembering is where this lives, not which command to type
  • It knows when to stop — the toast appears at most three times, once a day, never on the launch that already opened the welcome window, and never again once an agent has actually connected. The first time one does, md-mini says so — useful if someone handed you a config and you were wondering what just moved on screen
v1.0.0 2026-08-23 feature One point oh — now your agent can type too
  • An interface for AI agents — couplet show file.md --line 42 scrolls a window to a spot and pulses it; cat new.md | couplet edit file.md pushes content straight into the live buffer and highlights exactly what changed. No writing to disk and praying the watcher notices
  • Your agent can ask you things — couplet ask plants a real question with option buttons inside the document and blocks until you click. Checkboxes for multi-select, a free-text field when none of the options fit
  • Speaks MCP too — couplet mcp runs a stdio MCP server exposing the same three verbs as tools, so agents that prefer MCP need no shell glue. couplet agent prints a ready-to-paste block for your CLAUDE.md
  • Live Render, in beta — an opt-in mode where markdown markers stay hidden even when the caret sits on them, Notion-style. It installs only while selected, so the live-preview mode you already trust is untouched by construction. View → Editor Engine → (beta) Live Render
  • Aurora themes — two new palettes, light and dark, alongside Rosé Pine. Five entries in the theme menu now, System included, and the caret picked up a gradient
  • A new app icon — and, at the last minute, a properly antialiased one: the first cut carried a baked drop shadow that ate a fifth of the canvas at 32px
  • A welcome window, once — on first launch after the upgrade md-mini opens a short document showing how to connect your agent, by CLI or by MCP. Close it and it stays closed
  • Fixed: external edits no longer jump you around — when a watched file is reloaded from disk, your scroll position and caret stay where you left them
  • Fixed: selecting across a diagram — dragging a selection over a mermaid block or a table no longer paints over the widget
  • New home — the site lives at md-mini.com; the old GitHub Pages address redirects
v0.5.1 2026-07-28 fix Close that update notice once
  • One notice, not one per window — dismissing the “new version available” toast now dismisses it everywhere instead of making you close it in every open window
  • It stays dismissed — neither the next hourly check nor a window you open afterwards brings it back. A genuinely newer version still shows up
  • One check per app, not per window — five windows used to mean five requests an hour for the same answer
v0.5.0 2026-07-28 feature Your windows come back
  • Reopen your last session — quitting no longer loses the windows you had open. A toast tells you how many are waiting; ⇧⌘T brings them back, or use File → Reopen Windows from Last Session
  • Everything comes back with them — file, window position and size, where the caret was, and how far you had scrolled
  • Unsaved drafts too — an Untitled window you never saved returns with its text intact, still marked dirty
  • Survives an upgrade — this is the point: brew upgrade --cask mdmini closes every window, and now you can get them back
  • Notifications stack — the update notice and the session offer sit above one another instead of overlapping, and each waits until you dismiss it
  • Fixed: scrolling a diagram-heavy file — reaching the end of a document full of mermaid diagrams and scrolling back up threw you straight down again. Diagrams no longer briefly lay out at full natural size, which was corrupting every scroll position on the page
v0.4.0 2026-07-25 feature Big diagrams, finally navigable
  • Pinch to zoom — two fingers on the trackpad zoom around the cursor; Cmd+scroll does the same for a mouse
  • Swipe to pan — a two-finger swipe moves around a zoomed diagram; at full view it scrolls the document exactly as before
  • Gestures that don’t yank the page — running into an edge mid-swipe springs back instead of throwing you down the document; lift your fingers and swipe again to scroll on
  • Back to full view — the ⤢ button or a double-click refits; drag the bottom edge to resize the frame
  • Zoom sticks around — scrolling a diagram off screen, or editing text above it, no longer resets what you were looking at
v0.3.5 2026-06-16 fix Links that work inside tables
  • Markdown links in table cells — [text](url) inside a cell now renders as a clickable link instead of raw brackets and parens
  • Anchor links scroll, not escape — in-cell [Back to top](#heading) jumps within the document; re-clicking the same anchor no longer leaks out to the system browser
  • Mixed inline formatting — links coexist with bold, italic, code and strikethrough in the same cell
v0.3.4 2026-06-05 feature Shell configs come alive
  • Syntax highlighting for shell configs — .zshrc, .bashrc, .bash_profile, .profile and friends now render as Shell code instead of plain text
  • Inline secret masking — values in export API_KEY=…, TOKEN=… are masked to a sk-…jkl pill with a Copy button, while the key and the rest of the line stay highlighted
  • Reveal on demand — put the cursor on the line, or press Cmd+E, to see the raw value; shell expansions ($VAR, $(…)) are left untouched
v0.3.3 2026-06-04 fix TOC links that actually jump
  • In-document anchor links — clicking [Section](#section) now scrolls to the matching heading instead of doing nothing
  • Cyrillic & duplicates — percent-encoded and non-ASCII fragments resolve; duplicate headings disambiguate (#section-2)
  • Folded sections auto-expand — a collapsed parent heading opens before scrolling to the target
v0.3.2 2026-05-23 fix Ordered lists that count themselves
  • Tab restarts numbering — indenting a numbered item now opens a fresh sub-list starting at 1.
  • Shift-Tab renumbers the parent — outdenting back to the previous level keeps the surrounding numbers sequential
  • Works at any nesting depth — list continuation on Enter no longer breaks at the third level and beyond
v0.3.1 2026-05-23 feature Tables that fit your viewport
  • Auto-wrap by default — cells wrap their text to keep tables inside the editor width, no more sideways spillover
  • Per-table toggle (⇔) — release any single table to its natural width when you want the overflow back
  • Multi-line cells — double-click opens a growing textarea; Cmd+Enter to commit, Enter for a new line
  • Pipe & newline roundtrip — | and line breaks inside cells survive a save/reload via \| and <br>
  • Stable column alignment — switched to native CSS table layout so columns no longer drift on edit
  • Cursor never gets stuck — arrow keys past a table snap to the next or previous visible line
v0.3.0 2026-05-23 fix Inline markdown inside headings
  • Code, bold, italic, strike, links inside headings — formatting now decorates correctly when used inside # H1–###### H6
v0.2.2 2026-04-05 feature Line Glow & heading fold redesign
  • Line Glow — subtle gradient glow on active line, toggle via View menu
  • Fold toggle — ▾/▸ inline after headings with glow when folded
v0.2.1 2026-04-05 feature Heading fold toggle redesign
  • Inline fold toggle — ▾/▸ appears right after heading text, no layout shift
  • Glow indicator — folded sections show ▸ with subtle glow
v0.2.0 2026-04-05 feature Mermaid Diagrams
  • Live diagram preview — ```mermaid blocks render as inline SVG diagrams
  • All diagram types — flowcharts, sequence, class, state, ER, Gantt, pie, gitgraph, mindmap
  • Lazy-loaded — zero overhead for documents without diagrams
  • Hybrid errors — shows last valid diagram + error overlay while editing
  • Theme-aware — diagrams adapt to light/dark theme
v0.1.6 2026-04-03 fix Foreground windows
  • Windows open in foreground — new windows from CLI now appear on top via NSApp activate
v0.1.5 2026-04-02 feature File associations & smart windows
  • Dock file drop — drag files onto the Dock icon to open
  • File associations — macOS registers mdmini for .md, .txt, .json, .py, .rs, .yml, .toml, .sh
  • Smart window reuse — drag-drop and Dock drop open in empty windows
  • No white flash — dark background set before CSS loads
  • Cmd+Z safety — undo no longer clears content after file open
v0.1.4 2026-04-02 fix Text wrapping & table alignment
  • Text wrapping — long text wraps correctly even with wide tables
  • Gutter cleanup — removed gray bar, auto-hides on horizontal scroll
  • Table alignment — consistent column alignment across all rows
v0.1.3 2026-03-30 fix Update checks & theme fixes
  • Update banner — correct brew command with brew update prefix
  • Theme menu — single checkmark radio behavior
  • Hourly update checks while app is open
v0.1.0 2026-03-30 initial Initial release
  • Live preview — inline markdown rendering via CodeMirror 6 decorations
  • GFM tables — create, edit, reorder rows/columns, drag-drop
  • Collapsible headings — click to fold sections
  • Syntax highlighting — fenced code blocks with language detection
  • Secret masking — .env values blurred by default
  • File watching — external edits reload automatically
  • CLI launcher — couplet file.md via Homebrew tap
  • Themes — Rosé Pine dark & dawn
  • Auto-save & crash recovery

Full release history on GitHub →