A minimalist yet powerful markdown editor your agent can drive.
$ brew tap malinborn/mdmini && brew trust malinborn/mdmini && brew install --cask mdmini
Everything a markdown file needs, nothing else.
Markdown renders inline as you type. No split pane, no preview toggle.
**fast**
fast
Create, edit, reorder, and delete table rows and columns. Drag to reorder.
Click any heading to fold the section below it. Keeps long docs navigable.
Fenced code blocks render with language-aware syntax highlighting.
Flowcharts, sequence, class, Gantt, ER, pie, mindmap — all render inline as SVG. Pinch to zoom, swipe to pan around the big ones.
Secret values in .env and shell configs (.zshrc, .bashrc) are masked by default. Cursor or Cmd+E to reveal.
External changes to open files are detected and reloaded automatically.
Open files instantly from the terminal with mdmini file.md.
Drag any file onto the Dock icon to open it. Works with multiple files at once.
Reopen the windows you had last time with ⇧⌘T — files, positions, scroll, and unsaved drafts.
Four themes: Rosé Pine dark and Rosé Pine Dawn, plus an Aurora light/dark pair that matches the app icon. Switch with a single keypress.
Changes are saved continuously. Crash recovery restores your last session.
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.
After an upgrade, macOS asks for folder access again. mdmini 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.
**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 diskEsc 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 seeTab / ⇧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 usesindexOf(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%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 foldersJSON.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 markdownTab 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⇧⌘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 itAI → 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 workmdmini 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.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 herebrew 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 othermdmini show file.md --line 42 scrolls a window to a spot and pulses it; cat new.md | mdmini edit file.md pushes content straight into the live buffer and highlights exactly what changed. No writing to disk and praying the watcher noticesmdmini 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 fitmdmini mcp runs a stdio MCP server exposing the same three verbs as tools, so agents that prefer MCP need no shell glue. mdmini agent prints a ready-to-paste block for your CLAUDE.mdView → Editor Engine → (beta) Live Rendermd-mini.com; the old GitHub Pages address redirects⇧⌘T brings them back, or use File → Reopen Windows from Last Sessionbrew upgrade --cask mdmini closes every window, and now you can get them backCmd+scroll does the same for a mouse⤢ button or a double-click refits; drag the bottom edge to resize the frame[text](url) inside a cell now renders as a clickable link instead of raw brackets and parens[Back to top](#heading) jumps within the document; re-clicking the same anchor no longer leaks out to the system browser.zshrc, .bashrc, .bash_profile, .profile and friends now render as Shell code instead of plain textexport API_KEY=…, TOKEN=… are masked to a sk-…jkl pill with a Copy button, while the key and the rest of the line stay highlightedCmd+E, to see the raw value; shell expansions ($VAR, $(…)) are left untouched[Section](#section) now scrolls to the matching heading instead of doing nothing#section-2)1.| and line breaks inside cells survive a save/reload via \| and <br># H1–###### H6```mermaid blocks render as inline SVG diagramsbrew update prefix.env values blurred by defaultmdmini file.md via Homebrew tap