macsync/README.md
Natalie 576496ca3e feat(deploy): video-projects FUSE mount over DO Spaces
Generalize the photos-originals rclone-mount pattern to a video-projects
prefix so the video studio (and imajin ETL, per storage-portability-plan
§2.3) can read/write multi-GB project sources/renders as local files while
only hot data stays resident on plum (bounded VFS LRU cache). Lets a
small-disk laptop work with large footage without filling APFS.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 21:10:13 -04:00

4.4 KiB

@mac-sync

Unified macOS sync agent. One menu-bar app on the Mac, one Bun/Hono server on the LAN, one React SPA in the browser — six personal data domains kept in step: Messages, Photos, Mail, Calendar, Reminders, Notes.

@mac-sync collapses what used to be three separate agents (mac-imessage-sync, mac-iphoto-sync, mac-imail-sync) into a single Swift package with one BaseSyncManager lifecycle, one SendQueueClient outbound poller, one AppleScriptEscape helper, and one Postgres schema (icloud.*).

At a glance

Module Direction OS surface Read interval Outbound interval
iMessage bidirectional ~/Library/Messages/chat.db 30s 30s
iPhoto read-only Photos.framework 300s
iMail read-only (*) Mail.app via AppleScript 300s
iCal bidirectional EventKit 300s 60s
iReminders bidirectional EventKit 300s 60s
iNotes bidirectional Notes.app via AppleScript 600s 60s
iCalls read-only CallHistory.storedata (GRDB) 120s

(*) IMailSync.SyncManager.sendEmail exists but is unwired; see known limitations.

Intervals verified in BaseSyncManager super.init(...) calls and SendQueueClient(label:..., interval:) constructions; see architecture for citations.

Repository layout

@packages/
  shared/       MacSyncShared SwiftPM target
                  Sync/        BaseSyncManager, SendQueueClient, SyncConnectionError
                  Storage/     ActivityLog, ConfigFile
                  Transport/   Shared (server URL resolution), DeviceRegistration
                  Util/        AppleScriptEscape, ContentTypeMapping, PhoneUtils
                  WebServer/   LocalWebServer (localhost:8765, settings + SPA)
  imessage/     IMessageSync   (bidirectional, legacy icloud.send_queue table)
  iphoto/       IPhotoSync     (read-only Mac to server, with binary uploads)
  imail/        IMailSync      (Mail.app AppleScript reader; Sender unwired)
  ical/         ICalSync       (bidirectional, EventKit + calendar_send_queue)
  ireminders/   IReminderSync  (bidirectional, EventKit + reminder_send_queue)
  inotes/       INoteSync      (bidirectional, AppleScript + note_send_queue)
  icalls/       ICallsSync     (read-only, CallHistory.storedata via GRDB)
src/client/     MacSyncApp     (executable menu-bar app)
src/server/     Bun + Hono + PostgreSQL (TypeScript)
web/            React SPA dashboard (Vite, react-query)
deploy/         install.sh, deploy-remote.sh, systemd units, nginx config

(See Package.swift:21-157 for the canonical target list.)

Get started

Per-module deep dives:

Build & test

make build       # swift build --product MacSyncApp  (Makefile:60-61)
make test        # swift test                        (Makefile:71-73)
make run         # build then run .build/debug/MacSyncApp

Server:

cd src/server && bun run dev    # src/server/package.json:7

Web:

cd web && bun run dev           # vite --port 5200  (web/package.json:7)

Safety

  • NEVER commit — an external service handles commits (CLAUDE.md:46).
  • NEVER pkill node / killall node — kills Claude Code sessions.
  • NEVER use file: or link: in package.json — edit source, publish, bump.