diff options
| author | Craig Jennings <c@cjennings.net> | 2026-06-23 21:00:11 -0400 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2026-06-23 21:00:11 -0400 |
| commit | 603abc4cb3129be8bd23c89aa69f4f5522d1e5a3 (patch) | |
| tree | 356c6fc1343e4564d63b91b269aa8f65c1a40236 /claude-rules | |
| parent | d961c783d18c6178751b338ef1d8dd6a72db9f20 (diff) | |
| download | rulesets-603abc4cb3129be8bd23c89aa69f4f5522d1e5a3.tar.gz rulesets-603abc4cb3129be8bd23c89aa69f4f5522d1e5a3.zip | |
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.
Diffstat (limited to 'claude-rules')
| -rw-r--r-- | claude-rules/emacs.md | 6 |
1 files changed, 6 insertions, 0 deletions
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 <file>` exits non-zero (and names the buffer) when a live capture is cloned from `<file>`, 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. |
