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 /.ai/workflows | |
| 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 '.ai/workflows')
| -rw-r--r-- | .ai/workflows/inbox-zero.org | 11 |
1 files changed, 8 insertions, 3 deletions
diff --git a/.ai/workflows/inbox-zero.org b/.ai/workflows/inbox-zero.org index 4da27bd..5979ec0 100644 --- a/.ai/workflows/inbox-zero.org +++ b/.ai/workflows/inbox-zero.org @@ -71,9 +71,14 @@ Apply =process-inbox.org='s discipline against the project's =todo.org=; don't r The roam inbox lives in a git repo (=~/org/roam=, auto-synced by the =roam-sync= timer). Edit it carefully: -1. *Pull first* (=git -C ~/org/roam pull --ff-only=). If it can't fast-forward (dirty tree, divergence), surface and stop. Don't auto-stash, auto-merge, or force. Resolve before removing items. -2. *Remove only the claimed items.* Never touch foreign or unowned items. -3. *Commit the roam repo as its own commit* (separate from any project wrap commit): =chore(inbox): route <project> tasks to <project>/todo.org=. Push, or leave for the =roam-sync= timer. Surface a blocked push; don't force. +1. *Guard against a live org-capture session* — before any read-modify-write of the roam inbox, run =.ai/scripts/capture-guard "$HOME/org/roam/inbox.org"=. This runs first because the pull in step 2 *also* rewrites the file on disk, and a fast-forward landing underneath a live capture wedges it just as a hand edit would. + - *Exit 0* → no live capture (or no reachable Emacs). Proceed. + - *Exit 1* → an indirect org-capture buffer is cloned from the roam inbox (the script prints the offending buffer name). Editing or fast-forwarding the file underneath it would leave the capture pointing at stale state and unable to finalize with =C-c C-c= (see =emacs.md=). Behavior depends on the caller: + - *On-demand / interactive run* → stop and surface: "You have a live org-capture session open against the roam inbox (=<buffer>=) — finalize it (=C-c C-c=) or abort it (=C-c C-k=) and I'll continue." Re-run the guard and resume once it returns clean. + - *Wrap-up sub-step* → don't block the wrap. Skip the roam reconcile for this run and surface one line: "Skipped roam-inbox reconcile — a live org-capture is open against it; claimed items stay and get caught next run." The items were already filed into =todo.org= in Phase C, so the next inbox-zero run's Phase C status-check drops the duplicates and its Phase D removes them from the roam inbox — the skip self-heals, it doesn't lose anything. +2. *Pull first* (=git -C ~/org/roam pull --ff-only=). If it can't fast-forward (dirty tree, divergence), surface and stop. Don't auto-stash, auto-merge, or force. Resolve before removing items. +3. *Remove only the claimed items.* Never touch foreign or unowned items. +4. *Commit the roam repo as its own commit* (separate from any project wrap commit): =chore(inbox): route <project> tasks to <project>/todo.org=. Push, or leave for the =roam-sync= timer. Surface a blocked push; don't force. * Phase E — Surface |
