macsync/CLAUDE.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

3.7 KiB

@mac-sync

Unified macOS sync agent — Messages, Photos, Mail, Calendar (2-way), Reminders (2-way), Notes (2-way via AppleScript), Calls (read-only), Contacts, plus message search/embeddings — in one menu-bar app + one server.

Latest plan: ~/.claude/plans/magical-tumbling-peach.md.

Structure

@packages/
  shared/                MacSyncShared SwiftPM target
                           • Sync/        BaseSyncManager, BlobSyncManager,
                                          SendQueueClient, SyncConnectionError
                           • Storage/     ActivityLog, ConfigFile
                           • Transport/   Shared, DeviceRegistration
                           • Util/        ContentTypeMapping, PhoneUtils,
                                          AppleScriptEscape
                           • WebServer/   LocalWebServer
  imessage/              IMessageSync SwiftPM target  (bidirectional via
                                                       SendQueueClient,
                                                       wrapping the legacy
                                                       server-side
                                                       icloud.send_queue table;
                                                       attachment blob upload)
  iphoto/                IPhotoSync SwiftPM target    (read-only Mac → server,
                                                       photo blob upload)
  imail/                 IMailSync SwiftPM target     (bidirectional via AppleScript)
  ical/                  ICalSync SwiftPM target      (bidirectional via SendQueueClient)
  ireminders/            IReminderSync SwiftPM target (bidirectional via SendQueueClient)
  inotes/                INoteSync SwiftPM target     (bidirectional via AppleScript)
  icalls/                ICallsSync SwiftPM target    (read-only Mac → server)
  contacts-sync-core/    ContactsSyncCore SwiftPM target (Contacts.framework
                                                          → server)
src/client/              MacSyncApp executable (menu bar app)
src/server/              Hono + Bun + PostgreSQL server (TypeScript)
                           • features/embedding   — message embedding pipeline
                           • features/search      — semantic + keyword search with cache
                           • features/imessage    — iMessage ingestion / send queue
                           • features/prospect    — outreach prospect graph
deploy/                  install.sh, LaunchAgent template, systemd units
web/                     React SPA dashboard

Architecture invariants

  • One sync manager per module, all extending BaseSyncManager<Stats, SyncError>. Blob-uploading modules (iMessage attachments, iPhoto) additionally use BlobSyncManager for the blob upload pipeline.
  • One send queue contract. Per-module Postgres tables (icloud.<module>_send_queue) use the shared createSendQueueRepo factory. iMessage's legacy icloud.send_queue table predates the factory and stays on its own bespoke schema, but the Mac client polls all of them via the same generic SendQueueClient<Transport> (60s for calendar/reminders/notes, 30s for iMessage).
  • Single AppleScript escape helperMacSyncShared/Util/AppleScriptEscape.swift.
  • Embedding/search pipeline is server-side only. The Mac client ingests messages; embedding generation, search caching, and sync-history bookkeeping all live on the server.

Dev

make build       # swift build --product MacSyncApp
make test        # swift test

Safety

  • NEVER commit — external service handles commits
  • NEVER pkill node
  • NEVER use file: or link: in package.json