Short version: if you want to read the Markdown your agent writes, set a dedicated
viewer as the default app for .md and use Quick Look (Space) in Finder. Read.md and
Readdown are free and good. I build MacMD Viewer, which is paid. But if you want a viewer
that updates while the agent is still writing, there is a specific bug you should know
about — because I shipped it, a customer hit it, and the root cause turns out to be
something every "live preview" tool on macOS has to get right.
First, the volume
One solo macOS product. One developer. Claude Code doing a large share of the work since
March 2026. I counted what that actually leaves on disk:
| Markdown files tracked in git | 197 |
| Words inside them | 209,392 |
| Markdown files on disk, including untracked scratch | 427 |
New .md per month, sustained |
~50 |
| Largest single document | 9,567 words |
Markdown stopped being where I take notes. It became the format my tooling thinks in —
plans, specs, audit reports, state files. None of it is code. All of it is prose. And
macOS opens all of it in TextEdit as ## and **.
The bug: one update, then silence
MacMD Viewer's whole reason to exist is live reload — you watch a plan render as the
agent writes it. On 8 July a customer emailed to say auto-preview did not work for them,
that my claims were "fluff", and that it was the worst $20 they had spent. I cannot
confirm their machine hit the bug below. But looking for it, I found one, and it was bad.
A macOS DispatchSource file watcher binds to an inode, not to a path.
Obsidian, VS Code and most editors save atomically: write a temp file, then rename it
over the target. The path now points at a new inode, while your watcher is still
watching the old, unlinked one.
The failure mode is worse than "it stops working", because it does not look broken:
exactly one update gets through — the rename that unlinks your inode — and then the
document freezes in silence. For anyone editing in an external editor, the core feature
of the product dies on the second save, with no error.
Agents do it too — here is the two-command proof
I assumed this was an editor problem. It is not. Claude Code's own file writes are atomic.
Check it yourself on any file your agent touches:
stat -f 'inode=%i' PLAN.md # inode=450655861
# ask your agent to edit PLAN.md
stat -f 'inode=%i' PLAN.md # inode=450655923
Different inode after a single edit. Same path, new file underneath. Any tool that opened
a watch on that path before the edit is now watching a file that no longer exists — and
will keep reporting success while showing you stale content.
If you are building anything that watches agent output — a preview pane, a hot reloader,
a test runner — this is the failure you will ship without noticing, because your manual
test (echo >> file) appends in place and never triggers it.
The fix is a state machine, not a re-open
The naive fix — "just reopen the watcher" — is not enough. What actually shipped:
- Security scope held for the watcher's lifetime, not per source. Re-opening without scope fails silently, which is how you turn one bug into two.
-
On
.rename/.delete: cancel that specific source, close its captured descriptor, then re-arm on whatever now lives at the path. - Bounded retry with backoff (12 × 50 ms). The replacement file is not always visible at the instant the old inode signals. Treating that gap as fatal killed watching permanently — a TOCTOU window on the rename.
-
A generation token, so a late
arm()cannot clobber the source that replaced it. - Delivery deliberately not filtered by generation. A re-arm runs shortly after the event that triggered it; filtering there loses the edit in flight.
One more trap: a DispatchSource is born suspended, and libdispatch traps when you
release a suspended object. The lost-guard branch has to cancel() then resume().
I got a SIGTRAP before fixing that.
This shipped in 1.6.0 on 1 August 2026, with the first regression tests that file
had ever had — neutralise the re-arm and the test fails with "save 2 was never
delivered", content frozen on v1. A further hardening pass (resilient delivery, single
security-scope owner) is in the 1.6.1 beta and not in the production build yet.
I do not know which other Markdown viewers handle this correctly. If you rely on live
preview, the inode test above tells you in ten seconds.
The options, honestly
I build one of these, so read the free ones first.
Free
- Read.md — free on the Mac App Store, updated July 2026. Reading-focused. If you want to stop reading raw Markdown today and spend nothing, start here.
- Readdown — free, direct download, Quick Look support.
- QuickMD — free, App Store, updated July 2026, live reload and editor hand-off.
-
VS Code / Cursor —
⌘⇧V. You already have it. If you never leave the editor, this is genuinely the right answer and no app beats it on friction. -
glow —
glow PLAN.mdrenders in the terminal.
Paid
- Marked 2 — $13.99. The mature option: custom styles, strong export, pairs with any editor. Last App Store update March 2025.
- Kite — $14.99, direct download.
- OpenMark — $9.99, also aimed at AI-generated docs.
- MacMD Viewer — $19.99, mine. Read-only viewer: rendered document, Quick Look extension so Space in Finder renders instead of showing raw text, Mermaid inline, 12 document themes, live reload, and an optional hook for Claude Code, Cursor, Copilot and Windsurf that opens the file as soon as the assistant writes one. It is not an editor and will not become one.
Where mine falls short: it is not on the Mac App Store, so there is no App Store
refund flow and no App Store review count to check — three of the free options above have
both. It is paid, in a category with good free software. And it shipped the watcher bug
above for long enough that a paying customer wrote in angry about it.
It is not only developers
I built this expecting a developer audience. An unprompted five-star review on Trustpilot,
18 July 2026:
"Great software! It's lightweight and makes working with MD files way easier. I am not
a developer and dont have other software on my computer besides textedit to work with
MD files. Diving into the AI vibe coding world though...this app is awesome and a great
addition to my toolset."
— Jed Ivie
Another customer bought a MacBook Air specifically to learn Claude Code, arriving as a C#
developer who had never used macOS. That is what agents changed: they hand long-form
documents to people who never asked for a Markdown workflow and would not think to look
for a viewer.
FAQ
Real questions people type into Google before hitting this problem — from my own Search
Console over 180 days, not invented.
How do I open a .md file on a Mac?
Double-click opens it in TextEdit as raw text. Either set a Markdown viewer as the default
app (right-click → Get Info → Open with → Change All), or press Space in Finder with a
Quick Look Markdown extension installed.
How do I read .md files without installing anything?
Open in VS Code or Cursor and press ⌘⇧V. Otherwise brew install glow and render in the
terminal.
What is an .md file?
A plain-text file using Markdown — # for headings, ** for bold, - for lists. Readable
as-is by design; a viewer renders it as the document it describes.
Why does macOS show ## and ` instead of formatting?**.md` as plain text, and Quick
macOS has no built-in Markdown renderer. TextEdit treats
Look does the same unless you install an extension.
Do I need an editor or a viewer?
If you mostly read what an agent wrote, a viewer. If you write Markdown yourself, an
editor with live preview — Typora, Obsidian, or your code editor.
I build MacMD Viewer, one of the paid apps listed above. Every
figure here is measured from my own repository, my Search Console, a public review, or a
commit you can read. I will correct anything shown to be wrong.
Drafting assistance: drafted with Claude, edited by me.
Top comments (0)