diff options
Diffstat (limited to 'claude-templates')
48 files changed, 176 insertions, 68 deletions
diff --git a/claude-templates/.ai/notes.org b/claude-templates/.ai/notes.org index 42ea8df..c16863b 100644 --- a/claude-templates/.ai/notes.org +++ b/claude-templates/.ai/notes.org @@ -1,5 +1,5 @@ #+TITLE: Claude Code Notes - [Project Name] -#+AUTHOR: Craig Jennings & Claude +#+AUTHOR: Craig Jennings #+DATE: [Date] * About This File diff --git a/claude-templates/.ai/protocols.org b/claude-templates/.ai/protocols.org index 5e18ab9..1b41989 100644 --- a/claude-templates/.ai/protocols.org +++ b/claude-templates/.ai/protocols.org @@ -1,5 +1,5 @@ #+TITLE: Claude Code Protocols -#+AUTHOR: Craig Jennings & Claude +#+AUTHOR: Craig Jennings #+DATE: 2025-11-05 * About This File diff --git a/claude-templates/.ai/references/calendar-reference.org b/claude-templates/.ai/references/calendar-reference.org index b44c0f1..5791b08 100644 --- a/claude-templates/.ai/references/calendar-reference.org +++ b/claude-templates/.ai/references/calendar-reference.org @@ -1,5 +1,5 @@ #+TITLE: Calendar Reference -#+AUTHOR: Craig Jennings & Claude +#+AUTHOR: Craig Jennings Tool recipes, authentication, and credentials for Craig's calendar setup. Three access methods, in order of preference. diff --git a/claude-templates/.ai/scripts/inbox-send.py b/claude-templates/.ai/scripts/inbox-send.py index 1362a1f..1ebb636 100755 --- a/claude-templates/.ai/scripts/inbox-send.py +++ b/claude-templates/.ai/scripts/inbox-send.py @@ -177,6 +177,23 @@ def build_text_org(message: str, source_name: str, timestamp: str) -> str: ) +def uniquify(dest: Path) -> Path: + """Return dest, or dest with a -2/-3/... stem suffix when it already exists. + + Two sends in the same minute whose text starts with the same phrase + derive identical filenames, and the second silently overwrote the + first (a message was lost this way, 2026-07-02). Never overwrite. + """ + if not dest.exists(): + return dest + n = 2 + while True: + candidate = dest.with_name(f"{dest.stem}-{n}{dest.suffix}") + if not candidate.exists(): + return candidate + n += 1 + + def send_text( target_inbox: Path, message: str, @@ -191,7 +208,7 @@ def send_text( if not slug: raise ValueError(f"could not derive a slug from text: {message!r}") filename = f"{now.strftime(TS_FILENAME_FMT)}-from-{source_name}-{slug}.org" - dest = target_inbox / filename + dest = uniquify(target_inbox / filename) dest.write_text(build_text_org(message, source_name, now.strftime(TS_DOC_FMT))) return dest @@ -211,7 +228,7 @@ def send_file( raise ValueError(f"could not derive a slug from file: {src_path}") ext = src_path.suffix filename = f"{now.strftime(TS_FILENAME_FMT)}-from-{source_name}-{slug}{ext}" - dest = target_inbox / filename + dest = uniquify(target_inbox / filename) shutil.copy2(src_path, dest) return dest diff --git a/claude-templates/.ai/scripts/tests/test_inbox_send.py b/claude-templates/.ai/scripts/tests/test_inbox_send.py index cb60e63..f75d7a1 100644 --- a/claude-templates/.ai/scripts/tests/test_inbox_send.py +++ b/claude-templates/.ai/scripts/tests/test_inbox_send.py @@ -401,3 +401,78 @@ class TestInboxSendErrors: assert result.returncode != 0 files = list((tmp_path / "projects" / "target" / "inbox").iterdir()) assert files == [] + + +# ---------------------------------------------------------------------- +# Filename collisions (two sends deriving the same name must not overwrite) +# ---------------------------------------------------------------------- + +def _load_module(): + import importlib.util + spec = importlib.util.spec_from_file_location("inbox_send", SCRIPT) + mod = importlib.util.module_from_spec(spec) + spec.loader.exec_module(mod) + return mod + + +class TestFilenameCollisions: + """Two sends in the same minute with the same leading phrase derived + identical filenames and the second silently overwrote the first + (a message was lost this way, 2026-07-02).""" + + def test_send_text_same_minute_same_phrase_keeps_both(self, tmp_path): + from datetime import datetime + mod = _load_module() + inbox = tmp_path / "inbox" + inbox.mkdir() + now = datetime(2026, 7, 2, 5, 42, 0) + prefix = "identical leading phrase long enough to fill the whole slug budget entirely" + first = mod.send_text(inbox, prefix + " tail one", "archsetup", None, now) + second = mod.send_text(inbox, prefix + " tail two", "archsetup", None, now) + assert first != second + assert first.exists() and second.exists() + assert first.name != second.name + assert "tail one" in first.read_text() + assert "tail two" in second.read_text() + + def test_send_text_collision_suffix_increments(self, tmp_path): + from datetime import datetime + mod = _load_module() + inbox = tmp_path / "inbox" + inbox.mkdir() + now = datetime(2026, 7, 2, 5, 42, 0) + paths = [mod.send_text(inbox, "same lead phrase differs later A", "src", "fixed-slug", now) + for _ in range(3)] + names = [p.name for p in paths] + assert names[0].endswith("fixed-slug.org") + assert names[1].endswith("fixed-slug-2.org") + assert names[2].endswith("fixed-slug-3.org") + + def test_send_file_collision_preserves_extension(self, tmp_path): + from datetime import datetime + mod = _load_module() + inbox = tmp_path / "inbox" + inbox.mkdir() + src = tmp_path / "note.org" + src.write_text("body one") + now = datetime(2026, 7, 2, 5, 42, 0) + first = mod.send_file(inbox, src, "src", None, now) + src.write_text("body two") + second = mod.send_file(inbox, src, "src", None, now) + assert second.name.endswith("note-2.org") + assert first.read_text() == "body one" + assert second.read_text() == "body two" + + def test_cli_two_rapid_sends_lose_nothing(self, project_root, run_script, tmp_path): + project_root("sender") + target = project_root("receiver") + roots = [tmp_path / "projects"] + prefix = "identical leading phrase long enough to fill the whole slug budget entirely" + run_script(["receiver", "--text", prefix + " message one"], + cwd=tmp_path / "projects" / "sender", roots=roots) + run_script(["receiver", "--text", prefix + " message two"], + cwd=tmp_path / "projects" / "sender", roots=roots) + files = list((target / "inbox").iterdir()) + assert len(files) == 2 + bodies = "".join(f.read_text() for f in files) + assert "message one" in bodies and "message two" in bodies diff --git a/claude-templates/.ai/workflows/INDEX.org b/claude-templates/.ai/workflows/INDEX.org index 88721ed..c62c296 100644 --- a/claude-templates/.ai/workflows/INDEX.org +++ b/claude-templates/.ai/workflows/INDEX.org @@ -1,5 +1,5 @@ #+TITLE: Workflow Index -#+AUTHOR: Craig Jennings & Claude +#+AUTHOR: Craig Jennings #+DATE: 2026-04-25 * Purpose diff --git a/claude-templates/.ai/workflows/add-calendar-event.org b/claude-templates/.ai/workflows/add-calendar-event.org index 2650fb7..5dd6c42 100644 --- a/claude-templates/.ai/workflows/add-calendar-event.org +++ b/claude-templates/.ai/workflows/add-calendar-event.org @@ -1,5 +1,5 @@ #+TITLE: Add Calendar Event Workflow -#+AUTHOR: Craig Jennings & Claude +#+AUTHOR: Craig Jennings #+DATE: 2026-02-01 * Overview diff --git a/claude-templates/.ai/workflows/broadcast.org b/claude-templates/.ai/workflows/broadcast.org index 60e9ed1..cc14f00 100644 --- a/claude-templates/.ai/workflows/broadcast.org +++ b/claude-templates/.ai/workflows/broadcast.org @@ -1,5 +1,5 @@ #+TITLE: Broadcast Workflow -#+AUTHOR: Craig Jennings & Claude +#+AUTHOR: Craig Jennings #+DATE: 2026-05-29 * Overview diff --git a/claude-templates/.ai/workflows/clean-todo.org b/claude-templates/.ai/workflows/clean-todo.org index a1b2af5..48d3084 100644 --- a/claude-templates/.ai/workflows/clean-todo.org +++ b/claude-templates/.ai/workflows/clean-todo.org @@ -1,5 +1,5 @@ #+TITLE: Clean-Todo Workflow -#+AUTHOR: Craig Jennings & Claude +#+AUTHOR: Craig Jennings #+DATE: 2026-05-11 * Overview diff --git a/claude-templates/.ai/workflows/code-quality.org b/claude-templates/.ai/workflows/code-quality.org index 2406f4c..3ac3e9d 100644 --- a/claude-templates/.ai/workflows/code-quality.org +++ b/claude-templates/.ai/workflows/code-quality.org @@ -1,5 +1,5 @@ #+TITLE: Code-Quality Sweep Workflow -#+AUTHOR: Craig Jennings & Claude +#+AUTHOR: Craig Jennings #+DATE: 2026-06-28 * Overview diff --git a/claude-templates/.ai/workflows/daily-prep.org b/claude-templates/.ai/workflows/daily-prep.org index b6989e7..3103bc7 100644 --- a/claude-templates/.ai/workflows/daily-prep.org +++ b/claude-templates/.ai/workflows/daily-prep.org @@ -1,5 +1,5 @@ #+TITLE: Daily Prep Workflow -#+AUTHOR: Craig Jennings & Claude +#+AUTHOR: Craig Jennings #+DATE: 2026-06-11 * Overview diff --git a/claude-templates/.ai/workflows/delete-calendar-event.org b/claude-templates/.ai/workflows/delete-calendar-event.org index 5bb92a1..7de0086 100644 --- a/claude-templates/.ai/workflows/delete-calendar-event.org +++ b/claude-templates/.ai/workflows/delete-calendar-event.org @@ -1,5 +1,5 @@ #+TITLE: Delete Calendar Event Workflow -#+AUTHOR: Craig Jennings & Claude +#+AUTHOR: Craig Jennings #+DATE: 2026-02-01 * Overview diff --git a/claude-templates/.ai/workflows/edit-calendar-event.org b/claude-templates/.ai/workflows/edit-calendar-event.org index 662f0b4..27a9dd3 100644 --- a/claude-templates/.ai/workflows/edit-calendar-event.org +++ b/claude-templates/.ai/workflows/edit-calendar-event.org @@ -1,5 +1,5 @@ #+TITLE: Edit Calendar Event Workflow -#+AUTHOR: Craig Jennings & Claude +#+AUTHOR: Craig Jennings #+DATE: 2026-02-01 * Overview diff --git a/claude-templates/.ai/workflows/email-assembly.org b/claude-templates/.ai/workflows/email-assembly.org index 003459c..699dbc0 100644 --- a/claude-templates/.ai/workflows/email-assembly.org +++ b/claude-templates/.ai/workflows/email-assembly.org @@ -1,5 +1,5 @@ #+TITLE: Email Assembly Workflow -#+AUTHOR: Craig Jennings & Claude +#+AUTHOR: Craig Jennings #+DATE: 2026-01-29 * Overview diff --git a/claude-templates/.ai/workflows/extract-email.org b/claude-templates/.ai/workflows/extract-email.org index 3a70bea..c68bafe 100644 --- a/claude-templates/.ai/workflows/extract-email.org +++ b/claude-templates/.ai/workflows/extract-email.org @@ -1,5 +1,5 @@ #+TITLE: Extract Email Workflow -#+AUTHOR: Craig Jennings & Claude +#+AUTHOR: Craig Jennings #+DATE: 2026-02-06 * Overview diff --git a/claude-templates/.ai/workflows/find-email.org b/claude-templates/.ai/workflows/find-email.org index 0ef9615..d71ed3e 100644 --- a/claude-templates/.ai/workflows/find-email.org +++ b/claude-templates/.ai/workflows/find-email.org @@ -1,5 +1,5 @@ #+TITLE: Find Email Workflow -#+AUTHOR: Craig Jennings & Claude +#+AUTHOR: Craig Jennings #+DATE: 2026-02-01 * Overview diff --git a/claude-templates/.ai/workflows/first-session.org b/claude-templates/.ai/workflows/first-session.org index 60118a2..147026f 100644 --- a/claude-templates/.ai/workflows/first-session.org +++ b/claude-templates/.ai/workflows/first-session.org @@ -1,5 +1,5 @@ #+TITLE: First Session Workflow -#+AUTHOR: Craig Jennings & Claude +#+AUTHOR: Craig Jennings Run this workflow on the first Claude Code session for a new project. It establishes the git/.ai policy, orients Claude to the diff --git a/claude-templates/.ai/workflows/flashcard-review.org b/claude-templates/.ai/workflows/flashcard-review.org index 31027b3..09af348 100644 --- a/claude-templates/.ai/workflows/flashcard-review.org +++ b/claude-templates/.ai/workflows/flashcard-review.org @@ -1,5 +1,5 @@ #+TITLE: Drill Deck Review Workflow -#+AUTHOR: Craig Jennings & Claude +#+AUTHOR: Craig Jennings #+DATE: 2026-05-30 * Overview diff --git a/claude-templates/.ai/workflows/helper-mode.org b/claude-templates/.ai/workflows/helper-mode.org index cdec200..a6acfa7 100644 --- a/claude-templates/.ai/workflows/helper-mode.org +++ b/claude-templates/.ai/workflows/helper-mode.org @@ -1,5 +1,5 @@ #+TITLE: Helper Mode Workflow -#+AUTHOR: Craig Jennings & Claude +#+AUTHOR: Craig Jennings #+DATE: 2026-06-15 * Overview diff --git a/claude-templates/.ai/workflows/inbox.org b/claude-templates/.ai/workflows/inbox.org index acfd11d..3bd9335 100644 --- a/claude-templates/.ai/workflows/inbox.org +++ b/claude-templates/.ai/workflows/inbox.org @@ -1,5 +1,5 @@ #+TITLE: Inbox Workflow (Engine) -#+AUTHOR: Craig Jennings & Claude +#+AUTHOR: Craig Jennings #+DATE: 2026-06-23 * Overview diff --git a/claude-templates/.ai/workflows/journal-entry.org b/claude-templates/.ai/workflows/journal-entry.org index 3f476a7..c70dfe8 100644 --- a/claude-templates/.ai/workflows/journal-entry.org +++ b/claude-templates/.ai/workflows/journal-entry.org @@ -1,5 +1,5 @@ #+TITLE: Journal Entry Workflow -#+AUTHOR: Craig Jennings & Claude +#+AUTHOR: Craig Jennings #+DATE: 2025-11-07 * Overview diff --git a/claude-templates/.ai/workflows/meeting-prep.org b/claude-templates/.ai/workflows/meeting-prep.org index 162ae30..563328b 100644 --- a/claude-templates/.ai/workflows/meeting-prep.org +++ b/claude-templates/.ai/workflows/meeting-prep.org @@ -1,5 +1,5 @@ #+TITLE: Meeting-Prep Workflow -#+AUTHOR: Craig Jennings & Claude +#+AUTHOR: Craig Jennings #+DATE: 2026-06-10 * Overview diff --git a/claude-templates/.ai/workflows/meeting-prep.pre-wire.org b/claude-templates/.ai/workflows/meeting-prep.pre-wire.org index 6a156c0..3e27c2a 100644 --- a/claude-templates/.ai/workflows/meeting-prep.pre-wire.org +++ b/claude-templates/.ai/workflows/meeting-prep.pre-wire.org @@ -1,5 +1,5 @@ #+TITLE: Meeting-Prep — Pre-Wire Method (supporting doc) -#+AUTHOR: Craig Jennings & Claude +#+AUTHOR: Craig Jennings #+DATE: 2026-06-10 Supporting document for the [[file:meeting-prep.org][meeting-prep workflow]]'s Phase 3.5. The workflow carries the condensed, in-flow version of pre-wiring; this file is the full Manager Tools method, kept beside the workflow (same name + =.pre-wire= suffix) so it travels with the workflow. Source casts: "How to Prewire a Meeting" (2007) and "Peer Prewire" (2015). diff --git a/claude-templates/.ai/workflows/no-approvals.org b/claude-templates/.ai/workflows/no-approvals.org index 9e1c894..5f54b96 100644 --- a/claude-templates/.ai/workflows/no-approvals.org +++ b/claude-templates/.ai/workflows/no-approvals.org @@ -1,5 +1,5 @@ #+TITLE: No-Approvals Mode -#+AUTHOR: Craig Jennings & Claude +#+AUTHOR: Craig Jennings #+DATE: 2026-05-28 * Overview diff --git a/claude-templates/.ai/workflows/open-tasks.org b/claude-templates/.ai/workflows/open-tasks.org index 02a0847..205d95c 100644 --- a/claude-templates/.ai/workflows/open-tasks.org +++ b/claude-templates/.ai/workflows/open-tasks.org @@ -1,5 +1,5 @@ #+TITLE: Open Tasks Workflow -#+AUTHOR: Craig Jennings & Claude +#+AUTHOR: Craig Jennings #+DATE: 2026-04-25 * Overview diff --git a/claude-templates/.ai/workflows/page-me.org b/claude-templates/.ai/workflows/page-me.org index 607ed51..dad5da6 100644 --- a/claude-templates/.ai/workflows/page-me.org +++ b/claude-templates/.ai/workflows/page-me.org @@ -1,13 +1,13 @@ #+TITLE: Page Me Workflow -#+AUTHOR: Craig Jennings & Claude +#+AUTHOR: Craig Jennings #+DATE: 2026-01-31 #+UPDATED: 2026-02-27 * Overview -This workflow enables Claude to set timers and alarms that reliably notify Craig, even if the terminal session ends or is accidentally closed. Notifications are distinctive (audible + visual with alarm icon) and persist until manually dismissed. +This workflow enables Claude to set timers and alarms that reliably notify Craig, even if the terminal session ends or is accidentally closed. Notifications are distinctive (audible + visual with the blue info icon) and persist until manually dismissed. -Uses the =notify= command (alarm type) for consistent notifications across all AI workflows. +Uses the =notify= command (info type) for consistent notifications across all AI workflows. Info-level on purpose: the earlier alarm styling read as all-red urgency, and Craig's verdict was that a page "should be a persistent info notification" — noticeable, never crash-scary (2026-07-02). * Trigger Phrase @@ -63,8 +63,8 @@ Craig tells Claude when and why: Claude schedules the alarm using the =at= daemon with =notify=: #+begin_src bash -echo "notify alarm 'Page' 'Time to call the dentist' --persist" | at 3:30pm -echo "notify alarm 'Page' 'Meeting starts' --persist" | at now + 45 minutes +echo "notify info 'Page' 'Time to call the dentist' --persist" | at 3:30pm +echo "notify info 'Page' 'Meeting starts' --persist" | at now + 45 minutes #+end_src The =at= daemon: @@ -89,26 +89,26 @@ Craig dismisses the notification and acts on it. ** Setting Alarms -Use the =at= daemon to schedule a =notify alarm= command: +Use the =at= daemon to schedule a =notify info= command: #+begin_src bash # Schedule for specific time -echo "notify alarm 'Page' 'Meeting starts' --persist" | at 3:30pm +echo "notify info 'Page' 'Meeting starts' --persist" | at 3:30pm # Schedule for relative time -echo "notify alarm 'Page' 'Check the build' --persist" | at now + 30 minutes +echo "notify info 'Page' 'Check the build' --persist" | at now + 30 minutes # Schedule for tomorrow -echo "notify alarm 'Page' 'Call the dentist' --persist" | at 3:30pm tomorrow +echo "notify info 'Page' 'Call the dentist' --persist" | at 3:30pm tomorrow #+end_src ** Notification System -Uses the =notify= command with the =alarm= type. The =notify= command provides 8 notification types with matching icons and sounds. +Uses the =notify= command with the =info= type. The =notify= command provides 8 notification types with matching icons and sounds. #+begin_src bash -# Immediate alarm notification (for testing) -notify alarm "Page" "Your message here" --persist +# Immediate page notification (for testing) +notify info "Page" "Your message here" --persist #+end_src The =--persist= flag keeps the notification on screen until manually dismissed. All page-me notifications should use =--persist= by default. @@ -139,10 +139,10 @@ The alarm must fire. Use the =at= daemon which is designed for exactly this purp Simple invocation - Claude runs one command. No complex setup required per alarm. ** Fail Audibly -If the alarm fails to schedule, report the error clearly. Don't fail silently. +If the page fails to schedule, report the error clearly. Don't fail silently. ** Testable -The =notify alarm= command can be called directly to verify notifications work without waiting for a timer. +The =notify info= command can be called directly to verify notifications work without waiting for a timer. ** Non-Alarming Use normal urgency, not critical. The notification should be noticeable but not imply something has gone horribly wrong. diff --git a/claude-templates/.ai/workflows/process-meeting-transcript.org b/claude-templates/.ai/workflows/process-meeting-transcript.org index 4dd340f..322bcd9 100644 --- a/claude-templates/.ai/workflows/process-meeting-transcript.org +++ b/claude-templates/.ai/workflows/process-meeting-transcript.org @@ -1,5 +1,5 @@ #+TITLE: Process Meeting Transcript Workflow -#+AUTHOR: Craig Jennings & Claude +#+AUTHOR: Craig Jennings #+DATE: 2026-02-03 * Overview diff --git a/claude-templates/.ai/workflows/read-calendar-events.org b/claude-templates/.ai/workflows/read-calendar-events.org index be66bf4..5eac529 100644 --- a/claude-templates/.ai/workflows/read-calendar-events.org +++ b/claude-templates/.ai/workflows/read-calendar-events.org @@ -1,5 +1,5 @@ #+TITLE: Read Calendar Events Workflow -#+AUTHOR: Craig Jennings & Claude +#+AUTHOR: Craig Jennings #+DATE: 2026-02-01 * Overview diff --git a/claude-templates/.ai/workflows/readability-audit.org b/claude-templates/.ai/workflows/readability-audit.org index 8223a03..90ad366 100644 --- a/claude-templates/.ai/workflows/readability-audit.org +++ b/claude-templates/.ai/workflows/readability-audit.org @@ -1,5 +1,5 @@ #+TITLE: Readability Audit Workflow -#+AUTHOR: Craig Jennings & Claude +#+AUTHOR: Craig Jennings #+DATE: 2026-06-28 * Overview diff --git a/claude-templates/.ai/workflows/rename-artifact.org b/claude-templates/.ai/workflows/rename-artifact.org index 7b9f15b..a8d1246 100644 --- a/claude-templates/.ai/workflows/rename-artifact.org +++ b/claude-templates/.ai/workflows/rename-artifact.org @@ -1,5 +1,5 @@ #+TITLE: Rename an .ai Artifact -#+AUTHOR: Craig Jennings & Claude +#+AUTHOR: Craig Jennings #+DATE: 2026-05-31 * Summary diff --git a/claude-templates/.ai/workflows/send-email.org b/claude-templates/.ai/workflows/send-email.org index 065f925..82d2286 100644 --- a/claude-templates/.ai/workflows/send-email.org +++ b/claude-templates/.ai/workflows/send-email.org @@ -1,5 +1,5 @@ #+TITLE: Email Workflow -#+AUTHOR: Craig Jennings & Claude +#+AUTHOR: Craig Jennings #+DATE: 2026-01-26 * Overview diff --git a/claude-templates/.ai/workflows/session-harvest.org b/claude-templates/.ai/workflows/session-harvest.org index c48d689..54a7c09 100644 --- a/claude-templates/.ai/workflows/session-harvest.org +++ b/claude-templates/.ai/workflows/session-harvest.org @@ -1,5 +1,5 @@ #+TITLE: Session-Harvest Workflow -#+AUTHOR: Craig Jennings & Claude +#+AUTHOR: Craig Jennings #+DATE: 2026-06-11 * Overview diff --git a/claude-templates/.ai/workflows/spec-create.org b/claude-templates/.ai/workflows/spec-create.org index 1249181..e590540 100644 --- a/claude-templates/.ai/workflows/spec-create.org +++ b/claude-templates/.ai/workflows/spec-create.org @@ -1,5 +1,5 @@ #+TITLE: Spec-Create Workflow -#+AUTHOR: Craig Jennings & Claude +#+AUTHOR: Craig Jennings #+DATE: 2026-06-09 * Overview diff --git a/claude-templates/.ai/workflows/startup.org b/claude-templates/.ai/workflows/startup.org index 47a77c8..929d482 100644 --- a/claude-templates/.ai/workflows/startup.org +++ b/claude-templates/.ai/workflows/startup.org @@ -1,5 +1,5 @@ #+TITLE: Startup Workflow -#+AUTHOR: Craig Jennings & Claude +#+AUTHOR: Craig Jennings #+DATE: 2026-04-25 * Summary @@ -126,7 +126,7 @@ These calls have no dependencies on each other. Issue them all together in one m sc=$(.ai/scripts/session-context-path 2>/dev/null || echo .ai/session-context.org) [ -e "$sc" ] && echo "present: $sc" || echo "absent: $sc" #+end_src -3. *Sync =.ai/= from templates — but only when the synced source paths in rulesets are clean.* Guard the three rsyncs behind a check that =claude-templates/.ai/{protocols.org,workflows/,scripts/}= have no uncommitted changes. Otherwise Phase A copies in-flight rulesets WIP (tracked edits or new untracked files) into this project's =.ai/workflows/= and =.ai/scripts/=, where it shows up as drift the user didn't author. Skipping once is cheap — the next session with rulesets clean catches up. The check is scoped to the synced paths, so unrelated rulesets dirt (a stray =session-context.org=, scratch files) doesn't needlessly block the sync. +3. *Sync =.ai/= from templates — but only when the synced source paths in rulesets are clean.* Guard the three rsyncs behind a check that =claude-templates/.ai/{protocols.org,workflows/,scripts/}= have no uncommitted changes. Otherwise Phase A copies in-flight rulesets WIP (tracked edits or new untracked files) into this project's =.ai/workflows/= and =.ai/scripts/=, where it shows up as drift the user didn't author. Skipping once is cheap — the next session with rulesets clean catches up. The check is scoped to the synced paths, so unrelated rulesets dirt (a stray =session-context.org=, scratch files) doesn't needlessly block the sync. A second guard skips the same rsyncs when the *project* branch is behind its upstream (=git rev-list --left-right --count @{u}...HEAD= with =behind > 0=): syncing templates onto a stale committed =.ai/= baseline measures the diff against old content, so it comes out huge and conflicts when the branch later reconciles to upstream, whose history already carries the newer templates. It composes with the rulesets-clean guard — a stable rulesets source and a current project branch are both required before the sync runs. #+begin_src bash rs="$HOME/code/rulesets" @@ -134,15 +134,30 @@ These calls have no dependencies on each other. Issue them all together in one m claude-templates/.ai/protocols.org \ claude-templates/.ai/workflows/ \ claude-templates/.ai/scripts/ 2>/dev/null) - if [ -z "$synced_dirty" ]; then + # Skip the sync when the project branch hasn't reached its upstream. Syncing + # templates onto a behind baseline measures the diff against stale committed + # .ai/, producing confusing drift that conflicts when the branch reconciles — + # the newer .ai/ is already in upstream. behind==0 (up-to-date or ahead-only) + # means HEAD contains all of upstream, so the baseline is current. No upstream + # (new/unpushed branch) → rev-list fails → proj_behind stays 0, sync runs. + proj_behind=0 + if [ -d .git ]; then + counts=$(git rev-list --left-right --count '@{u}...HEAD' 2>/dev/null) \ + && [ "$(printf '%s' "$counts" | cut -f1)" -gt 0 ] 2>/dev/null \ + && proj_behind=1 + fi + + if [ -n "$synced_dirty" ]; then + echo "rulesets has uncommitted changes under the synced template paths — skipping .ai/ sync this session (catches up when rulesets is clean):" + echo "$synced_dirty" | sed 's/^/ /' + elif [ "$proj_behind" -eq 1 ]; then + echo "project branch is behind upstream — skipping .ai/ sync this session (templates never land on a stale baseline; the sync runs once the branch is current)" + else rsync -a "$rs/claude-templates/.ai/protocols.org" .ai/protocols.org rsync -a --delete "$rs/claude-templates/.ai/workflows/" .ai/workflows/ rsync -a --delete --exclude='__pycache__' --exclude='.pytest_cache' --exclude='*.pyc' \ "$rs/claude-templates/.ai/scripts/" .ai/scripts/ echo ".ai/ synced from templates" - else - echo "rulesets has uncommitted changes under the synced template paths — skipping .ai/ sync this session (catches up when rulesets is clean):" - echo "$synced_dirty" | sed 's/^/ /' fi #+end_src @@ -193,6 +208,7 @@ Notes on the rsync commands: - protocols.org is a single file, no =--delete= needed. - The =scripts/= sync excludes Python build artifacts (=__pycache__/=, =.pytest_cache/=, =*.pyc=). Running rulesets' own pytest leaves these in =claude-templates/.ai/scripts/tests/=, and =rsync -a= copies by disk presence regardless of =.gitignore=, so without the excludes every consuming project's tree gets polluted with machine-specific cache files. The excludes also protect existing dest copies from =--delete= cleanup, so a project that already received the cache must remove it once by hand. - The sync is guarded to skip when rulesets has uncommitted changes under the synced source paths. =rsync -a --delete= copies the working tree by disk presence, so without the guard a downstream session started while rulesets had in-flight WIP would pull that WIP into its =.ai/workflows/= and =.ai/scripts/=, surfacing as drift the user never authored (and tempting a fake "chore: sync .ai tooling" commit). The guard is scoped to the synced paths, not the whole repo, so unrelated rulesets dirt doesn't block the sync. From the jr-estate handoff 2026-05-29. +- The sync is also guarded to skip when the *project* branch is behind its upstream (=proj_behind=). Phase A.0 correctly declines to fast-forward a diverged or behind-and-dirty branch, but the rsync would then land templates on the stale committed =.ai/= baseline — a huge diff measured against old content that conflicts once the branch reconciles to upstream's newer templates. Skipping is safe: the sync runs next session once the branch is current. Not an auto-discard — startup never =git checkout=s drift away, because a legitimate local stopgap in a synced file is indistinguishable from accidental drift by content alone (home reverted an intentional =flashcard-to-anki.py= fix this way on 2026-06-22). Prevention is safe; blind cleanup-after is not. Phase C's template-sync-churn safety net still surfaces any pre-existing dirt for a human decision. From the home handoff 2026-07-04. - The sync touches only =protocols.org=, =workflows/=, and =scripts/=. The project-owned dirs =project-workflows/= and =project-scripts/= are deliberately *outside* the synced set, so a project's own workflows and scripts survive startup. This is why a project script that a workflow imports must live in =.ai/project-scripts/=, never =.ai/scripts/= — the latter is wiped to match the template by =--delete= on every startup. Naming: a script imported as a Python module needs an importable name (underscores, e.g. =zlibrary_api.py=); a CLI-invoked script can stay kebab-case like the template tooling (=cmail-action.py=). Rationale: Every call in Phase A is read-only or writes to a distinct path. Running them sequentially wastes round-trips; running them in parallel gives Claude the complete starting picture in one round-trip. diff --git a/claude-templates/.ai/workflows/status-check.org b/claude-templates/.ai/workflows/status-check.org index efff16d..4a9972c 100644 --- a/claude-templates/.ai/workflows/status-check.org +++ b/claude-templates/.ai/workflows/status-check.org @@ -1,5 +1,5 @@ #+TITLE: Status Check Workflow -#+AUTHOR: Craig Jennings & Claude +#+AUTHOR: Craig Jennings #+DATE: 2026-02-02 * Overview diff --git a/claude-templates/.ai/workflows/summarize-emails.org b/claude-templates/.ai/workflows/summarize-emails.org index 6ac5e6f..c9c7001 100644 --- a/claude-templates/.ai/workflows/summarize-emails.org +++ b/claude-templates/.ai/workflows/summarize-emails.org @@ -1,5 +1,5 @@ #+TITLE: Summarize Emails Workflow -#+AUTHOR: Craig Jennings & Claude +#+AUTHOR: Craig Jennings #+DATE: 2026-02-14 * Overview diff --git a/claude-templates/.ai/workflows/suspend.org b/claude-templates/.ai/workflows/suspend.org index 1c16bb9..3691f60 100644 --- a/claude-templates/.ai/workflows/suspend.org +++ b/claude-templates/.ai/workflows/suspend.org @@ -1,5 +1,5 @@ #+TITLE: Session Suspend Workflow -#+AUTHOR: Craig Jennings & Claude +#+AUTHOR: Craig Jennings #+DATE: 2026-06-28 * Overview diff --git a/claude-templates/.ai/workflows/sync-email.org b/claude-templates/.ai/workflows/sync-email.org index 52a7caf..863b400 100644 --- a/claude-templates/.ai/workflows/sync-email.org +++ b/claude-templates/.ai/workflows/sync-email.org @@ -1,5 +1,5 @@ #+TITLE: Sync Email Workflow -#+AUTHOR: Craig Jennings & Claude +#+AUTHOR: Craig Jennings #+DATE: 2026-02-01 * Overview diff --git a/claude-templates/.ai/workflows/task-audit.org b/claude-templates/.ai/workflows/task-audit.org index 7d2b758..aa50176 100644 --- a/claude-templates/.ai/workflows/task-audit.org +++ b/claude-templates/.ai/workflows/task-audit.org @@ -1,5 +1,5 @@ #+TITLE: Task Audit Workflow -#+AUTHOR: Craig Jennings & Claude +#+AUTHOR: Craig Jennings #+DATE: 2026-05-22 * Overview diff --git a/claude-templates/.ai/workflows/task-review.org b/claude-templates/.ai/workflows/task-review.org index ba1571a..4a09545 100644 --- a/claude-templates/.ai/workflows/task-review.org +++ b/claude-templates/.ai/workflows/task-review.org @@ -1,5 +1,5 @@ #+TITLE: Task Review Workflow -#+AUTHOR: Craig Jennings & Claude +#+AUTHOR: Craig Jennings #+DATE: 2026-05-20 * Overview diff --git a/claude-templates/.ai/workflows/triage-intake.cmail.org b/claude-templates/.ai/workflows/triage-intake.cmail.org index d818c72..8d8abfb 100644 --- a/claude-templates/.ai/workflows/triage-intake.cmail.org +++ b/claude-templates/.ai/workflows/triage-intake.cmail.org @@ -1,5 +1,5 @@ #+TITLE: Triage Intake — cmail (Proton) Source -#+AUTHOR: Craig Jennings & Claude +#+AUTHOR: Craig Jennings #+DATE: 2026-05-26 # Source plugin for the triage-intake engine. See triage-intake.org for the diff --git a/claude-templates/.ai/workflows/triage-intake.github-prs.org b/claude-templates/.ai/workflows/triage-intake.github-prs.org index c1bc796..644421c 100644 --- a/claude-templates/.ai/workflows/triage-intake.github-prs.org +++ b/claude-templates/.ai/workflows/triage-intake.github-prs.org @@ -1,5 +1,5 @@ #+TITLE: Triage Intake — Personal GitHub PRs Source -#+AUTHOR: Craig Jennings & Claude +#+AUTHOR: Craig Jennings #+DATE: 2026-05-26 # Source plugin for the triage-intake engine. See triage-intake.org for the diff --git a/claude-templates/.ai/workflows/triage-intake.org b/claude-templates/.ai/workflows/triage-intake.org index a5a3bda..66a48d9 100644 --- a/claude-templates/.ai/workflows/triage-intake.org +++ b/claude-templates/.ai/workflows/triage-intake.org @@ -1,5 +1,5 @@ #+TITLE: Triage Intake Workflow (Engine) -#+AUTHOR: Craig Jennings & Claude +#+AUTHOR: Craig Jennings #+DATE: 2026-05-01 * Summary diff --git a/claude-templates/.ai/workflows/triage-intake.personal-calendar.org b/claude-templates/.ai/workflows/triage-intake.personal-calendar.org index bf7d543..b5ee67a 100644 --- a/claude-templates/.ai/workflows/triage-intake.personal-calendar.org +++ b/claude-templates/.ai/workflows/triage-intake.personal-calendar.org @@ -1,5 +1,5 @@ #+TITLE: Triage Intake — Personal Calendar Source -#+AUTHOR: Craig Jennings & Claude +#+AUTHOR: Craig Jennings #+DATE: 2026-05-26 # Source plugin for the triage-intake engine. See triage-intake.org for the diff --git a/claude-templates/.ai/workflows/triage-intake.personal-gmail.org b/claude-templates/.ai/workflows/triage-intake.personal-gmail.org index aa0554d..a7af333 100644 --- a/claude-templates/.ai/workflows/triage-intake.personal-gmail.org +++ b/claude-templates/.ai/workflows/triage-intake.personal-gmail.org @@ -1,5 +1,5 @@ #+TITLE: Triage Intake — Personal Gmail Source -#+AUTHOR: Craig Jennings & Claude +#+AUTHOR: Craig Jennings #+DATE: 2026-05-26 # Source plugin for the triage-intake engine. See triage-intake.org for the diff --git a/claude-templates/.ai/workflows/triage-intake.telegram.org b/claude-templates/.ai/workflows/triage-intake.telegram.org index 9caa4e1..5039a8b 100644 --- a/claude-templates/.ai/workflows/triage-intake.telegram.org +++ b/claude-templates/.ai/workflows/triage-intake.telegram.org @@ -1,5 +1,5 @@ #+TITLE: Triage Intake — Telegram Source -#+AUTHOR: Craig Jennings & Claude +#+AUTHOR: Craig Jennings #+DATE: 2026-06-09 # Source plugin for the triage-intake engine. See triage-intake.org for the diff --git a/claude-templates/.ai/workflows/work-the-backlog.org b/claude-templates/.ai/workflows/work-the-backlog.org index 642162d..462e6b2 100644 --- a/claude-templates/.ai/workflows/work-the-backlog.org +++ b/claude-templates/.ai/workflows/work-the-backlog.org @@ -1,5 +1,5 @@ #+TITLE: Work the Backlog -#+AUTHOR: Craig Jennings & Claude +#+AUTHOR: Craig Jennings #+DATE: 2026-07-02 * Overview @@ -149,10 +149,10 @@ Task boundaries are clean boundaries by construction: the previous task is close With paging on, fire one page when the set is done or the cap is hit — end-of-set only, never per-task: #+begin_src sh -notify alarm "Page" "<project>: <N> done, <M> remaining — <one-line summary>" --persist +notify info "Page" "<project>: <N> done, <M> remaining — <one-line summary>" --persist #+end_src -=--persist= keeps it on screen until dismissed (the page-me convention). The page fires when the set completes *or* the cap stops the run — either way exactly once. The message carries the project name, the completed count, and the remaining count (with skipped tasks noted in the run summary) so Craig can confirm ready and name the next project in one reply. There is no separate page-signal call — =notify= is the paging surface. +=--persist= keeps it on screen until dismissed, and =info= is the page-me urgency convention (persistent but never crash-scary). The page fires when the set completes *or* the cap stops the run — either way exactly once. The message carries the project name, the completed count, and the remaining count (with skipped tasks noted in the run summary) so Craig can confirm ready and name the next project in one reply. There is no separate page-signal call — =notify= is the paging surface. * Metrics diff --git a/claude-templates/.ai/workflows/wrap-it-up.org b/claude-templates/.ai/workflows/wrap-it-up.org index d0c4e75..6b84a02 100644 --- a/claude-templates/.ai/workflows/wrap-it-up.org +++ b/claude-templates/.ai/workflows/wrap-it-up.org @@ -1,5 +1,5 @@ #+TITLE: Session Wrap-Up Workflow -#+AUTHOR: Craig Jennings & Claude +#+AUTHOR: Craig Jennings #+DATE: 2026-04-20 * Overview |
