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

(*) `IMailSync.SyncManager.sendEmail` exists but is unwired; see
[known limitations](./docs/known-limitations.md).

Intervals verified in `BaseSyncManager` `super.init(...)` calls and
`SendQueueClient(label:..., interval:)` constructions; see
[architecture](./docs/architecture.md) 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)
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

- Set up a dev environment: [docs/dev-setup.md](./docs/dev-setup.md)
- Tour the system: [docs/architecture.md](./docs/architecture.md)
- Trace a sync end-to-end: [docs/data-flow.md](./docs/data-flow.md)
- Add a 7th module: [docs/adding-a-module.md](./docs/adding-a-module.md)
- Ship a release: [docs/release.md](./docs/release.md)
- Known gotchas: [docs/known-limitations.md](./docs/known-limitations.md)

Per-module deep dives:

- [Messages (iMessage)](./docs/modules/imessage.md)
- [Photos (iPhoto)](./docs/modules/iphoto.md)
- [Mail (iMail)](./docs/modules/imail.md)
- [Calendar (iCal)](./docs/modules/ical.md)
- [Reminders (iReminders)](./docs/modules/ireminders.md)
- [Notes (iNotes)](./docs/modules/inotes.md)

## Build & test

```sh
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:

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

Web:

```sh
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.
