You have a plan file open in a preview window. Your agent works for a minute, says it updated the plan, and the window still shows the old text. You switch to another app and back. Nothing. You close the file and reopen it, and there is the new version — exactly what the preview should have shown you a minute ago.
This is not a rendering bug and it is not the agent lying to you. It is a consequence of how the file was written, and once you know the mechanism it is obvious which tools will get it right.
Agents do not edit files. They replace them.
When a well-behaved program saves a file, it usually does not write into the existing one. Writing in place means that if the process is killed halfway through, you are left with a truncated document and no way back. Instead it writes the new contents to a temporary file alongside the original, then renames the temp file over the target.
# roughly what your agent does
write plan.md.tmp7f2a <- full new contents
rename plan.md.tmp7f2a -> plan.mdThe rename is atomic. At no point does anything reading plan.md see a half-written document — it sees either the entire old version or the entire new one. This is the correct way to save a file, and Claude Code, Cursor, Codex, and most editors all do some version of it.
The part that breaks previews
A file on disk has two identities. There is the path, plan.md, which is just a name in a directory. And there is the inode, the actual object holding the bytes. Opening a file gives you a handle on the inode. The path is only how you found it.
An atomic save puts a different inode at the same path. The old one still exists for as long as something holds it open, but nothing will ever write to it again. A preview window that opened plan.md and asked the system to notify it of changes is now holding a handle on an object that has been unlinked from the directory. It is still watching, faithfully, forever. It is watching a ghost.
This is why the failure looks so strange. The preview is not frozen or crashed — it is working perfectly, on a file you can no longer reach. Reopening the document fixes it because that resolves the path again and finds the new inode.
Why it sometimes works once, then never again
Filesystem event APIs report renames and deletes as their own kind of event, separate from writes. A watcher that only subscribes to write events sees nothing at all when the rename lands. A watcher that subscribes to delete and rename but treats them as “the document is gone” will tear itself down after the first agent write and stay dead.
Both produce the same symptom for you: live updates worked while you were typing by hand, and stopped the moment an agent touched the file. Hand-typing in an editor often does write in place, which is exactly why the problem only shows up once you put an agent in the loop.
Test your own tools in ten seconds
You do not have to guess. Create a file, open it in whatever you use to read Markdown, and then replace it the way an agent would.
printf '# One\n' > note.md
# now open note.md in your previewer and leave it open
printf '# Two\n' > note.tmp && mv note.tmp note.mdIf the window flips to Two, the tool follows the path and you are fine. If it still says One, it is holding the old inode and it will go stale every time your agent writes. Compare that against a plain in-place write, which most tools handle:
printf '# Three\n' > note.mdA tool that updates on the second command but not the first is the common case, and it is the one that will quietly mislead you during an agent session.
What a correct watcher does
There are only four things to get right, and they are not difficult:
- Subscribe to renames and deletes, not just writes. The rename is the event that matters.
- Re-resolve the path rather than giving up. A delete or rename on a watched file means “look again”, not “the document is gone”.
- Retry for a moment. Between the unlink and the rename there is a brief window where the path genuinely does not exist. A watcher that checks once and quits will lose the race some fraction of the time, which is how you get a tool that works nine times out of ten.
- Debounce. One logical save can emit several events. Re-rendering on each one makes the window flicker and wastes work.
Polling the modification time every second is not a real substitute. It catches the change eventually, but it adds latency to every update and keeps the machine busy while you are reading, which on a laptop you notice.
How nicemd handles it
nicemd watches for writes, extends, deletes, renames and attribute changes. When a delete or rename arrives it treats that as a signal to reopen the path, retrying briefly while the new file appears, and debounces the result so a single save renders once. The file your agent just wrote is the file on your screen.
That matters most for the documents agents actually produce — plan files, CLAUDE.md, AGENTS.md, generated READMEs — which are written and rewritten repeatedly while you watch. If you want the wider picture of reading those documents, see reading the Markdown your agent writes.
