Skip to content

Move iMessage sync into BlackbookServer (un-sandboxed) - #40

Merged
mayeack merged 1 commit into
mainfrom
claude/imessage-sync-in-server
May 30, 2026
Merged

mayeack merged 1 commit into
mainfrom
claude/imessage-sync-in-server

Conversation

@mayeack

@mayeack mayeack commented May 30, 2026

Copy link
Copy Markdown
Owner

Why

iMessage Sync in the sandboxed main macOS app could never read ~/Library/Messages/chat.db:

  • NSHomeDirectory() resolved to the sandbox container, so the path didn't exist → "chat.db not found".
  • The App Sandbox blocks the Messages DB regardless of Full Disk Access (FDA is TCC; the sandbox is a separate kernel layer).

De-sandboxing the main app isn't viable — App Store Connect rejects non-sandboxed macOS builds (ITMS-90296), which would break the macOS TestFlight pipeline.

BlackbookServer is already un-sandboxed, always-running (login item), owns the master SwiftData store, and syncs to all devices — so the iMessage reader belongs there. Interactions it creates reach iOS + macOS via /sync/changes (the pull query serves by updatedAt). Bonus: it now works even when the Mac app is closed.

Changes

Main app

  • Restore sandboxed entitlements / project.yml (revert exploratory de-sandbox). macOS build re-embeds com.apple.security.app-sandbox (verified via codesign -d --entitlements -).
  • Remove the dead main-app IMessageSyncService, its BlackbookApp wiring, the SettingsView "iMessage Sync" section, and the unused AppConstants.IMessageSync enum.
  • User-visible: the iMessage Sync toggle disappears from the macOS app's Settings — it lives in the server menu now.

BlackbookServer

  • New IMessageSyncService: polls chat.db, matches contacts by phone AND email (Apple-ID-email threads now match — the likely reason some contacts never logged), 30-day backfill, (contactId, second, summary) dedup guard, and an unmatched-handles diagnostic. Path uses NSUserName() (sandbox-independent).
  • Wire into ServerStatusModel (starts if enabled) and add controls to the menu-bar popover: Log iMessages toggle, Sync Last 30 Days, Open Full Disk Access, Unmatched handles.

Test plan

  • xcodegen generate; BlackbookServer (Debug + Release), Blackbook iOS + macOS all build clean.
  • 13 Swift Testing tests pass.
  • macOS main app sandbox restored (codesign).
  • Release server rebuilt + reinstalled to /Applications, running on :8765.
  • Grant Full Disk Access to "Blackbook Server" (not "Blackbook"), toggle "Log iMessages", run "Sync Last 30 Days", confirm Nick/Jose interactions log and sync to iPhone. (Full scenarios in docs/test-scenarios/TEST_SCENARIOS.md.)

Deploy note

BlackbookServer is not in the TestFlight pipeline. After merge, rebuild/reinstall locally (commands in docs/test-scenarios/TEST_SCENARIOS.md). The main-app changes deploy via the normal iOS/macOS TestFlight build.

🤖 Generated with Claude Code

iMessage Sync in the sandboxed main macOS app could never read
~/Library/Messages/chat.db: NSHomeDirectory() resolved to the sandbox
container, and the App Sandbox blocks the Messages DB regardless of Full
Disk Access. De-sandboxing the main app isn't an option — App Store
Connect rejects non-sandboxed macOS builds (ITMS-90296), which would
break the TestFlight pipeline.

BlackbookServer is already un-sandboxed, always-running, owns the master
SwiftData store, and syncs to all devices, so the iMessage reader belongs
there. Interactions it creates reach iOS + macOS via /sync/changes (the
pull query serves by updatedAt). It also works when the Mac app is closed.

Main app:
- Restore sandboxed entitlements / project.yml (revert exploratory
  de-sandbox); macOS build re-embeds com.apple.security.app-sandbox.
- Remove the dead main-app IMessageSyncService, its BlackbookApp wiring,
  the SettingsView section, and the unused AppConstants.IMessageSync enum.

BlackbookServer:
- New IMessageSyncService: polls chat.db, matches contacts by phone AND
  email (handles routed to Apple-ID emails now match), 30-day backfill,
  (contactId, second, summary) dedup guard, and an unmatched-handles
  diagnostic. Path uses NSUserName() (sandbox-independent).
- Wire into ServerStatusModel (starts if enabled) and add the controls to
  the menu-bar popover: Log iMessages toggle, Sync Last 30 Days,
  Open Full Disk Access, Unmatched handles.

Requires granting Full Disk Access to "Blackbook Server" (not "Blackbook").
BlackbookServer is not in TestFlight; rebuild/reinstall locally per
docs/test-scenarios/TEST_SCENARIOS.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@mayeack
mayeack merged commit 4098719 into main May 30, 2026
2 checks passed
@mayeack
mayeack deleted the claude/imessage-sync-in-server branch May 30, 2026 02:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant