From 603abc4cb3129be8bd23c89aa69f4f5522d1e5a3 Mon Sep 17 00:00:00 2001 From: Craig Jennings Date: Tue, 23 Jun 2026 21:00:11 -0400 Subject: feat(inbox-zero): guard roam-inbox writes against live org-capture Editing the roam inbox on disk while Emacs has an indirect org-capture buffer cloned from it reverts the base buffer under the capture: the capture can't finalize with C-c C-c, and a freshly-typed item can be lost. inbox-zero Phase D edits that file, which Craig captures into constantly, so the collision recurs every session. I added a capture-guard helper that asks the running daemon whether any CAPTURE buffer's base buffer visits a given file (file-equal-p, so symlinks and path spelling don't matter), exiting non-zero with the names when so. No reachable Emacs or no capture means exit 0, so it never blocks a write that was safe. Phase D calls it before the pull, not only before the remove, because the ff-only pull also rewrites the file on disk and would wedge a capture the same way. On a collision an on-demand run stops and asks Craig to finalize or abort. The wrap-up sub-step skips the roam reconcile without blocking the wrap, since the items are already filed and the next run reclaims them. emacs.md gains the inverse of the reload rule: don't yank a file out from under the daemon's live buffers. --- claude-rules/emacs.md | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'claude-rules') diff --git a/claude-rules/emacs.md b/claude-rules/emacs.md index 702b40e..907a981 100644 --- a/claude-rules/emacs.md +++ b/claude-rules/emacs.md @@ -27,3 +27,9 @@ This re-evaluates the file and redefines its `defun`s live. For straight functio 3. Verify: for visual changes, screenshot and read it (the `screenshot.py` tool under `.ai/scripts/` can capture an app off-screen on a headless output); for behavior, eval or exercise it. This replaces the quit → relaunch → re-find-and-load-files cycle for most edits. A real restart stays the gold standard for a guaranteed-clean state — anything touching `:config`, load order, or when in doubt. + +## Don't edit on disk a file the daemon is capturing into + +The reload caveats above are about pushing changes *into* the daemon. The inverse hazard: a tool that edits a file *on disk* while the daemon has an indirect buffer cloned from it. org-capture works through such a buffer, and a disk write (a hand edit, a `git pull` that fast-forwards the file, a `sed`/Write) reverts the base buffer underneath the capture. The capture is left on stale state, can no longer finalize with `C-c C-c`, and a freshly-typed item can be lost or written back against post-edit content. Orphaned `CAPTURE-*` buffers piling up as Craig retries is the visible symptom. + +The roam inbox (`~/org/roam/inbox.org`) is the live case — Craig captures into it constantly, and inbox-zero's Phase D edits it. Before a disk write to a file the daemon may be capturing into, check first: `.ai/scripts/capture-guard ` exits non-zero (and names the buffer) when a live capture is cloned from ``, and exits 0 — safe — when there's no capture or no reachable Emacs. Same principle as the reload rule, one layer out: leave the daemon's live buffers authoritative rather than yanking the file from under them. -- cgit v1.2.3