Files
command-center/omp-docs/tools/live-sync.md
T
Frank e52aa6a4a3 feat: live-sync heartbeat commits machine-written paths
The checkout IS the deployment and symlinks make live state (memories,
auto-learned skills, agent config, desktop settings) dirty tracked files
continuously; no commit law covered machine churn, so it accumulated
unpushed for weeks — one disk held the only copy of ~61 managed skills,
a settings fix stayed local-only, and dirty trees refused merges.

scripts/live-sync.sh (systemd user timer, ~15 min) commits ONLY the
allowlisted machine/desktop-live tiers with hooks armed, merges
origin/main, pushes, and reaps wt/* worktrees older than 7 days. Task
dirt outside the allowlist is never staged; conflicts abort and alert
via ntfy; branch guard refuses off main; never --no-verify, never force.
Black-box contract pinned by tests/live-sync.bats (9 tests, suite 36/36).

Refs #11
2026-10-18 16:13:59 -07:00

3.2 KiB

type, title, description, tags, verified, timestamp
type title description tags verified timestamp
reference live-sync heartbeat Auto-commit daemon for machine-written paths in the command-center checkout — the deployment is live, so symlinks make config churn dirty tracked files continuously.
git
automation
systemd
deployment
fleet
2026-10-18 2026-10-18

live-sync heartbeat

The command-center checkout IS the deployment, and several tracked files are live state: the harness writes memories and managed-skills, the operator edits config.yml/models.yml through the cfg:// surface, and desktop GUIs (Noctalia, niri) rewrite dotfiles through symlinks. Before Refs #11 this machine churn just piled up unpushed — one disk holding the only copy of ~61 auto-learned skills, a settings fix stranded locally, and merge-refusals because the dirty tree collided with incoming work.

scripts/live-sync.sh is the pressure valve: a heartbeat that commits the machine's own writes on a schedule. Tier law (which paths it may touch) lives in AGENTS.md § Live-sync tiers.

Contract (black-box)

Run = one pass: flock → branch guard (main only) → stage allowlisted dirty tiers → commit (hooks armed) → fetch + merge origin/main → push → reap stale wt/* worktrees. Exit 0 = quiet heartbeat (synced/no-op/reaped); exit 1 = an alert was raised. Pinned by tests/live-sync.bats.

Hard properties:

  • Allowlist only. Task dirt (plugins/, omp-docs/, prose) is never staged — merge conflicts with in-flight work become impossible by construction.
  • Hooks stay armed. A secret-gate refusal aborts the commit, leaves changes staged for a human, and alerts. Never --no-verify, never force.
  • Never fights the remote. Merge conflict → merge --abort, local commit kept, alert. Retries are automatic next tick.
  • Branch guard. On a non-main checkout it refuses and alerts — same rule as the doctrine ("never end a session off main").
  • Polite reaper. wt/wt-* worktrees untouched for 7+ days are removed with their wt/* branch; dirty or process-occupied worktrees are skipped.

Alerts

notify() writes stderr always; pushes to ntfy when the topic file ~/.config/ntfy/live-sync (mode 600, topic text only) exists, throttled to one push per hour. Test seams: LIVE_SYNC_REPO, LIVE_SYNC_NOTIFY, LIVE_SYNC_NTFY_TOPIC_FILE, LIVE_SYNC_AGE_DAYS.

Install

Units ship in dotfiles/systemd-user/.config/systemd/user/ and propagate with the usual dotfiles chain:

systemctl --user enable --now live-sync.timer   # after the unit is linked
systemctl --user start live-sync.service        # one manual heartbeat
journalctl --user -u live-sync.service -n 20    # observe

Failure modes

Event Result
Harness mid-write commits a valid snapshot; remainder lands next heartbeat
Gitea down commit safe locally; push retries next tick (≤15 min stale window)
Same file edited on two boxes real merge conflict → ntfy → human resolves (visible, not silent)
Feature branch checked out in main checkout refuses + alerts; protects the never-end-off-main rule
Secret shape in machine-written content hook blocks, changes stay staged, alert