Files
homehub/README.md
T

5.2 KiB

homehub — operator notes

Operational doc. Why each decision exists is in DESIGN.md; this file is only the operational half.

~/homehub/
  bin/homehub                the tool (~750 lines of bash + one python merge)
  config                     machine-specific settings (per-machine, not synced)
  rules/denylist               DEFAULT DENY, emitted first, wins over everything
  rules/sets.d/*.list          named path-lists ("sets")
  rules/hosts/<hostname>     which sets this machine joins
  lib/merge_bookmarks.py       class C union-merge (jq + python3 only)
  systemd/homehub-*.{service,timer}
  DESIGN.md                  rationale for everything below

Install (per machine)

git clone https://gitea.lue.dk/druppy/homehub.git ~/homehub && cd ~/homehub
cp rules/hosts/_laptop-template rules/hosts/$(hostname -s)   # pick your sets
./bin/homehub setup-key                                      # once, see warning below
ssh-copy-id -i ~/.ssh/homehub_ed25519.pub nas.lue.dk         # YOU run this
./bin/homehub setup
./bin/homehub sync            # DRY: prints what would move, writes nothing
homehub sync --exec                 # first real run
sudo loginctl enable-linger $USER   # headless boxes only
~/homehub/bin/homehub install       # systemd user timers

homehub install copies the units into ~/.config/systemd/user and enables homehub-sync.timer (10 min) and homehub-fresh.timer (30 min).

Commands

Command What
sync [--exec] pull → apply deletions → harvest deletions → push. Dry unless --exec.
status last sync per machine, sets, pending dry-run lists, repo manifest, bookmark exports
fresh [--dry] the 24 h alert check; only printer of alerts
git inventory|list|missing|clone [--exec] [--lazy] class B
bookmarks [--write] class C export + union merge
forget <path> drop tombstones so a deleted path can return
filter dump the generated rsync filter
setup, setup-key, install one-time plumbing

The rules that matter when editing config

  1. Default deny. rules/denylist is emitted first, then the host's set includes, then - *. A path in a set that sits under a deny rule can never sync — the tool warns (shadowed: ...) when you write one.
  2. Set syntax. One home-relative path per line; trailing / = subtree. /Documents/ → - /Documents/***; build/ (no leading slash) matches at any depth.
  3. Never add a git repo path to a set. Repos are class B (homehub git inventory).
  4. ~/.config is unreachable by design (it is denied wholesale). State you want shared goes under ~/.local/state/shared/<app>/, with the real config path symlinked to it. ~/.local/state/homehub/ is homehub's private scratch and is denied too — syncing it would make machines overwrite each other's generated filters forever.
  5. Deletions never propagate as --delete. They become tombstones on the hub, are reaped after GRACE_DAYS, and always lose to a competing edit.

Alerting

homehub fresh alerts only when a machine is on (heartbeat < 3 h) but has not synced for > 24 h, and never for network-class rsync/ssh exit codes — so a laptop away for three weeks is silent indefinitely. Delivery auto-detects msmtp, then sendmail, else appends to ~/.local/state/homehub/alerts.out. To wire it to your own mail server:

# /etc/msmtprc  (or ~/.config/msmtp/config)
defaults
tls on
tls_starttls on
account homehub
host mail.lue.dk
port 587
auth on
user homehub@lue.dk
from homehub@lue.dk
password <app-password>

Then msmtp -a homehub you@lue.dk is picked up automatically. On Debian: apt install msmtp msmtp-mta.

A machine whose own config is broken (ssh key revoked, hub disk full) records a local marker in ~/.local/state/homehub/broken.* and alerts about itself even with the hub unreachable — otherwise a dead key would produce no heartbeat, no marker, and therefore no alert, forever.

Known limits (deliberate, not bugs)

  • mtime is the arbiter. Two machines editing the same file while both offline resolve by mtime, so clocks must be NTP-synced (timedatectl on Debian, ntpd on NixOS). The overwritten copy is kept in <hub>/.hub/prev/YYYY-MM/.
  • rsync 3.1.2 on DSM 6/7 — no --ignore-older; the design uses --update only.
  • --checksum is off, so a file edited to the same size in the same second as a previous sync may be missed. Re-run rsync -mc by hand if you ever suspect it.
  • Unpushed commits are advisory in the manifest and never transferred. A dead laptop disk loses them.
  • Empty bookmark folders do not survive the union merge (there is nothing to key on).
  • Symlinks travel as symlinks (-l, never -L); ones pointing into ~/src, ~/git or /tmp will dangle on a machine that has not cloned the target.

Troubleshooting

~/homehub/bin/homehub status              # ages, sets, manifest
journalctl --user -u homehub-sync.service -n 50
cat ~/.local/state/homehub/{pull,push}.err
cat ~/.local/state/homehub/broken.*       # self-detected breakage
ssh nas.lue.dk 'cat /volume1/homes/bl/homehub/.hub/log.tsv | tail'
~/homehub/bin/homehub filter | grep -n shadowed