Files
claudetools/.claude/commands/sync.md
Mike Swanson 6b0ce9aa04 feat(sync): serialize sync.sh with a per-machine lock; per-session log filenames
Multiple concurrent Claude sessions (and the scheduled-task sync) were
stepping on each other's git state. sync.sh now takes an atomic mkdir
lock in .git/ around the whole run (stage/commit/fetch/rebase/push +
vault), exits 75 (EX_TEMPFAIL = deferred) on contention instead of
racing, and reclaims stale/dead-owner locks with a re-verify-before-clear
guard (closes two TOCTOU races caught in review). /save now mandates
per-session-unique log filenames (never the bare YYYY-MM-DD-session.md).
Docs updated for the lock + deferred-exit semantics.

Note: git add -A is still the catch-all sweep; full per-session commit
isolation and routing /scc + /checkpoint through the lock are follow-ups.
2026-06-05 18:50:52 -07:00

3.8 KiB

Sync the ClaudeTools and vault repos with Gitea.

Phase 0 — Uncommitted Session Log Check

Run this before invoking sync.sh.

git status --porcelain | grep -E '\bsession-logs/.*\.md$' | grep -v '^\s*D '

This finds any untracked (??) or modified ( M, M , AM) session log files across all locations:

  • session-logs/*.md (root general logs)
  • clients/*/session-logs/*.md
  • projects/*/session-logs/*.md

If count == 0: proceed with sync normally (invoke sync.sh).

If count > 0:

Emit:

[WARNING] Found <N> uncommitted session log(s):
  - <path/to/file.md>
  - ...

These contain work context that will be auto-committed with a generic
"sync: auto-sync" message if you proceed. Run /save instead to capture
a proper narrative summary before syncing.

Then ask: "Run /save now, or proceed with plain sync anyway?"

  • If user says save (or doesn't respond / says yes): execute the full /save flow (write session log → sync.sh). Do NOT call sync.sh separately after — /save already calls it.
  • If user says proceed / skip: invoke sync.sh directly and note that the session logs will be auto-committed with generic messages.

The intent: a /sync that finds unsaved work should default toward /save. Auto-committing session logs with "sync: auto-sync" loses the narrative context that makes logs searchable.


What this does

Invokes bash .claude/scripts/sync.sh, which:

  1. Detects local changes (including untracked-only files) via git status --porcelain; stages with git add -A and auto-commits with sync: auto-sync from <hostname> at <timestamp>
  2. Fetches from origin, rebases local commits onto remote
  3. Pushes to origin
  4. Copies .claude/commands/*.md~/.claude/commands/ so the global Claude CLI commands stay current without a manual copy
  5. Repeats steps 1-3 for the vault repo (path read from .claude/identity.json vault_path field)
  6. Surfaces any ## Note for <user> / ## Message for <user> blocks from incoming session logs

The script is the single source of truth for git operations. Both /sync and /save invoke it.

Concurrency: the run is serialized by a per-machine lock (.git/claudetools-sync.lock) so two syncs (e.g. interactive + the scheduled-task sync, or two Claude sessions) can't interleave staging/commit/rebase/push. If another sync is already running, this run waits up to ~120s then exits 75 (EX_TEMPFAIL = deferred, not a failure) — report it as deferred, not synced; the next run catches up. Stale locks (owner process dead, or older than 10 min) are auto-reclaimed.


Cross-user note handling (CRITICAL)

If sync surfaces a note from another user, display it prominently at the top of the response, before the sync summary, formatted as:

============================================================
MESSAGE FROM <author> (<date>)
============================================================
<full note content>
============================================================

Address each action item or question explicitly before moving on. Do not bury cross-user notes in the sync summary or skip them because other work is in progress.


Output format

Report:

  • Pulled commits — count + authors + one-line summaries
  • Wiki updates — categorized by clients/projects/systems/patterns/meta with status (added/modified/deleted)
  • Pushed commits — count + your commits + outgoing SHAs
  • Vault sync status — pulled/pushed/clean
  • Cross-user notes addressed (if any)
  • Final HEAD + status

Companion: /save

/save writes a comprehensive session log first, then invokes the same sync.sh. Use /save after substantive work to capture context for future sessions. Use /sync for routine repo sync without writing a log (start of day, switching machines, mid-session check-in).