No description
Find a file
Natalie ad8e126dd1 docs(mac-sync): outbox/read architecture, handoffs, module docs
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 11:35:13 -04:00
.claude feat(@mac-sync): update handoff docs with verified paths 2026-05-15 21:17:32 -07:00
.forgejo/workflows merge: restore plum-only additive files atop apricot baseline 2026-05-15 17:06:07 -07:00
.playwright-mcp apricot baseline: contacts-sync-core + BlobSyncManager + embedding/search/sync-history 2026-05-15 17:05:39 -07:00
.project docs(mac-sync): outbox/read architecture, handoffs, module docs 2026-06-29 11:35:13 -04:00
@packages feat(shared): LocalWebServer outbox/read routes 2026-06-29 11:35:13 -04:00
deploy fix(deploy): use official rclone for mount (brew rclone lacks FUSE on macOS) 2026-06-28 21:18:03 -04:00
docs docs(mac-sync): outbox/read architecture, handoffs, module docs 2026-06-29 11:35:13 -04:00
handoffs feat(@mac-sync): update handoff docs with verified paths 2026-05-15 21:17:32 -07:00
mcp feat(mcp): outbox/read client methods + tools + README 2026-06-29 11:35:13 -04:00
scripts fix(@applications/@mac-sync): 🐛 update lan instead of local in all configs 2026-06-10 03:12:06 -07:00
src feat(server): wire outbox + read features into app + my surface 2026-06-29 11:35:13 -04:00
web feat(deploy): video-projects FUSE mount over DO Spaces 2026-06-28 21:10:13 -04:00
.gitignore apricot baseline: contacts-sync-core + BlobSyncManager + embedding/search/sync-history 2026-05-15 17:05:39 -07:00
.infra.yaml chore(infra): add .infra.yaml (convention:infra_manifest) for infra-net reconcile 2026-06-29 10:10:18 -04:00
.mcp.json apricot baseline: contacts-sync-core + BlobSyncManager + embedding/search/sync-history 2026-05-15 17:05:39 -07:00
app.manifest.yaml feat(deploy): video-projects FUSE mount over DO Spaces 2026-06-28 21:10:13 -04:00
CLAUDE.md feat(deploy): video-projects FUSE mount over DO Spaces 2026-06-28 21:10:13 -04:00
deploy-to-plum-dist-from-src apricot baseline: contacts-sync-core + BlobSyncManager + embedding/search/sync-history 2026-05-15 17:05:39 -07:00
docker-compose.dev.yml feat(deploy): video-projects FUSE mount over DO Spaces 2026-06-28 21:10:13 -04:00
m-quinn-messages-after-port.png apricot baseline: contacts-sync-core + BlobSyncManager + embedding/search/sync-history 2026-05-15 17:05:39 -07:00
m-quinn-messages-search-after-load.png apricot baseline: contacts-sync-core + BlobSyncManager + embedding/search/sync-history 2026-05-15 17:05:39 -07:00
m-quinn-messages-search-verify.png apricot baseline: contacts-sync-core + BlobSyncManager + embedding/search/sync-history 2026-05-15 17:05:39 -07:00
m-quinn-thread-focus.png apricot baseline: contacts-sync-core + BlobSyncManager + embedding/search/sync-history 2026-05-15 17:05:39 -07:00
mac-sync-dashboard-deployed.png apricot baseline: contacts-sync-core + BlobSyncManager + embedding/search/sync-history 2026-05-15 17:05:39 -07:00
mac-sync-search-cin-2.png apricot baseline: contacts-sync-core + BlobSyncManager + embedding/search/sync-history 2026-05-15 17:05:39 -07:00
mac-sync-search-cin.png apricot baseline: contacts-sync-core + BlobSyncManager + embedding/search/sync-history 2026-05-15 17:05:39 -07:00
Makefile plum baseline: Phase 1/3/4/5 work (BaseSyncManager, SendQueue layer, ireminders, inotes) 2026-05-15 17:05:13 -07:00
no-params.png apricot baseline: contacts-sync-core + BlobSyncManager + embedding/search/sync-history 2026-05-15 17:05:39 -07:00
Package.resolved merge: restore plum-only additive files atop apricot baseline 2026-05-15 17:06:07 -07:00
Package.swift feat(deploy): video-projects FUSE mount over DO Spaces 2026-06-28 21:10:13 -04:00
README.md docs(mac-sync): outbox/read architecture, handoffs, module docs 2026-06-29 11:35:13 -04:00
run feat(send-queue): burst-friendly outbound send-rate cap (default 10/5min) 2026-06-23 15:35:18 -04:00
search-cin-params.png apricot baseline: contacts-sync-core + BlobSyncManager + embedding/search/sync-history 2026-05-15 17:05:39 -07:00
search-cin.png apricot baseline: contacts-sync-core + BlobSyncManager + embedding/search/sync-history 2026-05-15 17:05:39 -07:00
search-click-result.png apricot baseline: contacts-sync-core + BlobSyncManager + embedding/search/sync-history 2026-05-15 17:05:39 -07:00
search-final.png apricot baseline: contacts-sync-core + BlobSyncManager + embedding/search/sync-history 2026-05-15 17:05:39 -07:00
search-q-param.png apricot baseline: contacts-sync-core + BlobSyncManager + embedding/search/sync-history 2026-05-15 17:05:39 -07:00
search-results-count.png apricot baseline: contacts-sync-core + BlobSyncManager + embedding/search/sync-history 2026-05-15 17:05:39 -07:00
search-settled.png apricot baseline: contacts-sync-core + BlobSyncManager + embedding/search/sync-history 2026-05-15 17:05:39 -07:00
thread-dates-highlight.png apricot baseline: contacts-sync-core + BlobSyncManager + embedding/search/sync-history 2026-05-15 17:05:39 -07:00
thread-focus-message.png apricot baseline: contacts-sync-core + BlobSyncManager + embedding/search/sync-history 2026-05-15 17:05:39 -07:00
VERSION.json plum baseline: Phase 1/3/4/5 work (BaseSyncManager, SendQueue layer, ireminders, inotes) 2026-05-15 17:05:13 -07:00

@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 — seven personal data domains kept in step: Messages, Photos, Mail, Calendar, Reminders, Notes, Calls.

@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.