aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.ai/notes.org2
-rw-r--r--.ai/protocols.org2
-rw-r--r--.ai/workflows/journal-entry.org4
-rw-r--r--claude-templates/.ai/notes.org2
-rw-r--r--claude-templates/.ai/protocols.org2
-rw-r--r--claude-templates/.ai/workflows/journal-entry.org4
-rwxr-xr-xscripts/roam-sync.sh38
-rw-r--r--scripts/systemd/roam-sync.service9
-rw-r--r--scripts/systemd/roam-sync.timer10
-rw-r--r--scripts/tests/roam-sync.bats71
-rw-r--r--todo.org2
11 files changed, 137 insertions, 9 deletions
diff --git a/.ai/notes.org b/.ai/notes.org
index 2c09ac5..a41e6e4 100644
--- a/.ai/notes.org
+++ b/.ai/notes.org
@@ -67,7 +67,7 @@ This section tracks decisions that need Craig's input before work can proceed.
When Craig says "remind me" about something:
1. Add it here with timestamp and description
-2. If it's a TODO, also add to =/home/cjennings/sync/org/roam/inbox.org= scheduled for today
+2. If it's a TODO, also add to =/home/cjennings/org/roam/inbox.org= scheduled for today
3. Check this section at start of every session
4. Remove reminders once addressed
diff --git a/.ai/protocols.org b/.ai/protocols.org
index 15d1476..3fc7104 100644
--- a/.ai/protocols.org
+++ b/.ai/protocols.org
@@ -306,7 +306,7 @@ cmail-action send --to addr@example.com --subject "Re: ..." --body-file /tmp/dra
=cmail-action= handles the receive/triage side too (=list-unread=, =read=, =mark-read=, =star=, =trash=). For the full guided flow (validate the recipient against =contacts.org=, confirm before sending, verify delivery), run the =send-email= workflow; for a known recipient, the one-liner above is enough.
** Task List Location
-Craig's global task list is available at: =/home/cjennings/sync/org/roam/inbox.org=
+Craig's global task list is available at: =/home/cjennings/org/roam/inbox.org=
Use this to:
- See all the tasks that he's working on outside of projects like this one
diff --git a/.ai/workflows/journal-entry.org b/.ai/workflows/journal-entry.org
index 6fc5a73..3f476a7 100644
--- a/.ai/workflows/journal-entry.org
+++ b/.ai/workflows/journal-entry.org
@@ -36,7 +36,7 @@ We know a journal entry is complete when:
1. **Draft has been created** - Claude writes initial first-person draft based on today's session record (=.ai/session-context.org= if session is live, or today's file in =.ai/sessions/= if already wrapped up)
2. **Revisions are complete** - Craig provides corrections and context until satisfied
-3. **Entry is added to journal file** - Text is added to the org-roam daily journal at ~/sync/org/roam/journal/YYYY-MM-DD.org
+3. **Entry is added to journal file** - Text is added to the org-roam daily journal at ~/org/roam/journal/YYYY-MM-DD.org
4. **Craig approves** - Craig explicitly approves or indicates no more revisions needed
*Measurable validation:*
@@ -115,7 +115,7 @@ During revisions:
Once approved:
-1. Find the org-roam daily journal file at ~/sync/org/roam/journal/YYYY-MM-DD.org
+1. Find the org-roam daily journal file at ~/org/roam/journal/YYYY-MM-DD.org
2. If it doesn't exist, create it with this header:
```
:PROPERTIES:
diff --git a/claude-templates/.ai/notes.org b/claude-templates/.ai/notes.org
index 5f1860e..42ea8df 100644
--- a/claude-templates/.ai/notes.org
+++ b/claude-templates/.ai/notes.org
@@ -77,7 +77,7 @@ Implementation is ready - just need Craig's preference.
When Craig says "remind me" about something:
1. Add it here with timestamp and description
-2. If it's a TODO, also add to =/home/cjennings/sync/org/roam/inbox.org= scheduled for today
+2. If it's a TODO, also add to =/home/cjennings/org/roam/inbox.org= scheduled for today
3. Check this section at start of every session
4. Remove reminders once addressed
diff --git a/claude-templates/.ai/protocols.org b/claude-templates/.ai/protocols.org
index 15d1476..3fc7104 100644
--- a/claude-templates/.ai/protocols.org
+++ b/claude-templates/.ai/protocols.org
@@ -306,7 +306,7 @@ cmail-action send --to addr@example.com --subject "Re: ..." --body-file /tmp/dra
=cmail-action= handles the receive/triage side too (=list-unread=, =read=, =mark-read=, =star=, =trash=). For the full guided flow (validate the recipient against =contacts.org=, confirm before sending, verify delivery), run the =send-email= workflow; for a known recipient, the one-liner above is enough.
** Task List Location
-Craig's global task list is available at: =/home/cjennings/sync/org/roam/inbox.org=
+Craig's global task list is available at: =/home/cjennings/org/roam/inbox.org=
Use this to:
- See all the tasks that he's working on outside of projects like this one
diff --git a/claude-templates/.ai/workflows/journal-entry.org b/claude-templates/.ai/workflows/journal-entry.org
index 6fc5a73..3f476a7 100644
--- a/claude-templates/.ai/workflows/journal-entry.org
+++ b/claude-templates/.ai/workflows/journal-entry.org
@@ -36,7 +36,7 @@ We know a journal entry is complete when:
1. **Draft has been created** - Claude writes initial first-person draft based on today's session record (=.ai/session-context.org= if session is live, or today's file in =.ai/sessions/= if already wrapped up)
2. **Revisions are complete** - Craig provides corrections and context until satisfied
-3. **Entry is added to journal file** - Text is added to the org-roam daily journal at ~/sync/org/roam/journal/YYYY-MM-DD.org
+3. **Entry is added to journal file** - Text is added to the org-roam daily journal at ~/org/roam/journal/YYYY-MM-DD.org
4. **Craig approves** - Craig explicitly approves or indicates no more revisions needed
*Measurable validation:*
@@ -115,7 +115,7 @@ During revisions:
Once approved:
-1. Find the org-roam daily journal file at ~/sync/org/roam/journal/YYYY-MM-DD.org
+1. Find the org-roam daily journal file at ~/org/roam/journal/YYYY-MM-DD.org
2. If it doesn't exist, create it with this header:
```
:PROPERTIES:
diff --git a/scripts/roam-sync.sh b/scripts/roam-sync.sh
new file mode 100755
index 0000000..55422ec
--- /dev/null
+++ b/scripts/roam-sync.sh
@@ -0,0 +1,38 @@
+#!/usr/bin/env bash
+# roam-sync.sh — git auto-sync for the org-roam knowledge base (spec D8).
+#
+# Commit any local changes, rebase onto the remote, push. Run by the
+# roam-sync systemd user timer (scripts/systemd/) every 15 minutes so
+# Craig's hand edits travel without a manual git step. Agents don't need
+# this — they pull/commit/push inline per claude-rules/knowledge-base.md.
+#
+# On a rebase conflict: abort the rebase (never leave the repo mid-rebase
+# for a timer to mangle), keep the local commit, exit 1 so the failure is
+# visible in `systemctl --user status roam-sync`.
+#
+# Usage: roam-sync.sh [repo-path] (default ~/org/roam)
+
+set -euo pipefail
+
+repo="${1:-$HOME/org/roam}"
+
+if ! git -C "$repo" rev-parse --git-dir >/dev/null 2>&1; then
+ echo "roam-sync: $repo is not a git repo" >&2
+ exit 1
+fi
+
+cd "$repo"
+
+# Commit local changes first so the rebase replays them.
+if [ -n "$(git status --porcelain)" ]; then
+ git add -A
+ git commit -qm "chore: auto-sync $(date '+%Y-%m-%d %H:%M %z')"
+fi
+
+if ! git pull --rebase -q 2>&1; then
+ git rebase --abort 2>/dev/null || true
+ echo "roam-sync: rebase conflict in $repo — local commit kept, resolve by hand" >&2
+ exit 1
+fi
+
+git push -q
diff --git a/scripts/systemd/roam-sync.service b/scripts/systemd/roam-sync.service
new file mode 100644
index 0000000..e4ad502
--- /dev/null
+++ b/scripts/systemd/roam-sync.service
@@ -0,0 +1,9 @@
+# org-roam KB auto-sync (spec D8). Install:
+# cp scripts/systemd/roam-sync.* ~/.config/systemd/user/
+# systemctl --user daemon-reload && systemctl --user enable --now roam-sync.timer
+[Unit]
+Description=Auto-sync the org-roam knowledge base repo
+
+[Service]
+Type=oneshot
+ExecStart=%h/code/rulesets/scripts/roam-sync.sh %h/org/roam
diff --git a/scripts/systemd/roam-sync.timer b/scripts/systemd/roam-sync.timer
new file mode 100644
index 0000000..3d65be0
--- /dev/null
+++ b/scripts/systemd/roam-sync.timer
@@ -0,0 +1,10 @@
+[Unit]
+Description=Auto-sync the org-roam knowledge base every 15 minutes
+
+[Timer]
+OnBootSec=2min
+OnUnitActiveSec=15min
+RandomizedDelaySec=60
+
+[Install]
+WantedBy=timers.target
diff --git a/scripts/tests/roam-sync.bats b/scripts/tests/roam-sync.bats
new file mode 100644
index 0000000..017a92c
--- /dev/null
+++ b/scripts/tests/roam-sync.bats
@@ -0,0 +1,71 @@
+#!/usr/bin/env bats
+# Tests for scripts/roam-sync.sh — the git auto-sync loop the roam KB timer runs.
+# Each test builds a throwaway clone + bare remote pair under $BATS_TEST_TMPDIR.
+
+setup() {
+ SCRIPT="$BATS_TEST_DIRNAME/../roam-sync.sh"
+ export GIT_CONFIG_GLOBAL=/dev/null GIT_CONFIG_SYSTEM=/dev/null
+ export GIT_AUTHOR_NAME=test GIT_AUTHOR_EMAIL=t@t GIT_COMMITTER_NAME=test GIT_COMMITTER_EMAIL=t@t
+ REMOTE="$BATS_TEST_TMPDIR/remote.git"
+ REPO="$BATS_TEST_TMPDIR/repo"
+ OTHER="$BATS_TEST_TMPDIR/other"
+ git init -q --bare -b main "$REMOTE"
+ git init -q -b main "$REPO"
+ (cd "$REPO" && echo seed > seed.org && git add -A && git commit -qm seed \
+ && git remote add origin "$REMOTE" && git push -qu origin main)
+}
+
+clone_other() {
+ git clone -q "$REMOTE" "$OTHER" 2>/dev/null
+}
+
+@test "clean tree, current remote: exits 0 with no new commit" {
+ before=$(git -C "$REPO" rev-parse HEAD)
+ run "$SCRIPT" "$REPO"
+ [ "$status" -eq 0 ]
+ [ "$(git -C "$REPO" rev-parse HEAD)" = "$before" ]
+}
+
+@test "dirty tree: commits and pushes to the remote" {
+ echo "new fact" > "$REPO/fact.org"
+ run "$SCRIPT" "$REPO"
+ [ "$status" -eq 0 ]
+ [ -z "$(git -C "$REPO" status --porcelain)" ]
+ git -C "$REMOTE" log --format=%s main | grep -q "auto-sync"
+}
+
+@test "remote ahead: pulls the remote commit" {
+ clone_other
+ (cd "$OTHER" && echo upstream > up.org && git add -A && git commit -qm upstream && git push -q)
+ run "$SCRIPT" "$REPO"
+ [ "$status" -eq 0 ]
+ [ -f "$REPO/up.org" ]
+}
+
+@test "local dirty and remote ahead, disjoint files: both land" {
+ clone_other
+ (cd "$OTHER" && echo upstream > up.org && git add -A && git commit -qm upstream && git push -q)
+ echo "local fact" > "$REPO/local.org"
+ run "$SCRIPT" "$REPO"
+ [ "$status" -eq 0 ]
+ [ -f "$REPO/up.org" ]
+ git -C "$REMOTE" log --format=%s main | grep -q "auto-sync"
+}
+
+@test "conflicting rebase: exits nonzero and leaves no rebase in progress" {
+ clone_other
+ (cd "$OTHER" && echo theirs > seed.org && git add -A && git commit -qm theirs && git push -q)
+ echo mine > "$REPO/seed.org"
+ run "$SCRIPT" "$REPO"
+ [ "$status" -ne 0 ]
+ [ ! -d "$REPO/.git/rebase-merge" ]
+ [ ! -d "$REPO/.git/rebase-apply" ]
+ # the local change survives as a commit for the human to resolve later
+ git -C "$REPO" log --format=%s | grep -q "auto-sync"
+}
+
+@test "missing repo path: exits nonzero with a message" {
+ run "$SCRIPT" "$BATS_TEST_TMPDIR/nonexistent"
+ [ "$status" -ne 0 ]
+ [[ "$output" == *"not a git repo"* ]]
+}
diff --git a/todo.org b/todo.org
index d049c5b..fc36528 100644
--- a/todo.org
+++ b/todo.org
@@ -3,7 +3,7 @@
#+DATE: 2026-04-19
Tracking TODOs for the rulesets repo that span more than one commit.
-Project-scoped (not the global =~/sync/org/roam/inbox.org= list).
+Project-scoped (not the global =~/org/roam/inbox.org= list).
* Priority and Tag Scheme