跳到正文
Hacker News· sidhanthp·· 7 天前AI 评分40

让 Muse 读取我的 iMessages:一套自建私有归档与检索方案

Giving Muse Access to My iMessages

AI 导读

作者让 Muse 通过 Mac 每五分钟上传 iMessages 到 Railway 私有归档,Muse 在云端 VM 每十分钟检索新消息,Mac 关机时仍可读取历史。该 Go 服务内嵌 Tailscale tsnet 接入私有网络,用 SQLCipher 加密归档与搜索索引,并区分只读检索与认证上传权限。日历与待办的后台写入仍需审批规则,整套方案需手动配置。

正文 · 原文

Muse can now read my uploaded iMessage history while my Mac is closed. I use it to help manage my calendar, update my to-do list, and remember plans and commitments.

What I built

My Mac uploads Messages to a private Railway archive every five minutes while awake and online. Muse searches it from its cloud VM and checks new arrivals every ten minutes. Uploaded history stays available offline; new messages catch up when the Mac returns.

The Go service embeds Tailscale’s tsnet, which lets the Railway container join my private network without a kernel VPN interface. Network grants and node-identity checks separate Muse’s read-only access from the Mac’s authenticated uploads. SQLCipher encrypts the archive and search index; its key stays outside the data volume. The running service can decrypt it, and Meta receives retrieved excerpts.

Names come from local Contacts lookups for handles already in Messages. A persistent Muse skill explains search and freshness. Proactive suggestions work; unattended Calendar and Todoist writes still depend on background approval rules.

How to build your own

Give your agent this article and access to your Mac and hosting account. Ask it to propose the architecture and cost, test with synthetic records before uploading history, and deliver source, installation instructions, and recovery tests. This requires manual setup.

  1. Verify your assistant supports private HTTP requests and persistent skills. Enroll its cloud node in Tailscale.
  2. Deploy one always-on Go service with tsnet, SQLCipher, FTS5, and a persistent volume. Persist network identity, separate read/upload roles, and audit existing grants.
  3. Build a native Mac uploader with a decoder and resumable sync. Grant Full Disk Access and optional Contacts permission; schedule it with a five-minute user LaunchAgent.
  4. Expose bounded read-only search, history, context, and status endpoints. Install an assistant skill covering authentication, pagination, contact lookup, timezones, and freshness.
  5. Add monitoring with arrival cursors, exclusive locking, and duplicate prevention. Authorize actions separately and verify background tools support them.

Test historical coverage, scheduled uploads, interrupted-sync recovery, encrypted restore, and retrieval with the Mac off. Use disposable items for action tests.

Gotchas your agent should know

Many bodies live in message.attributedBody, not message.text. Decode with a native Foundation helper when text is absent; NSUnarchiver worked here. Verify real records on your macOS version and distinguish decoding failures from attachment-only messages.

Use the SQLite backup API against a read-only source. Copying the database alone can miss its write-ahead log. Use native CNContactStore for names and retain confirmed matches when lookups fail. Test permissions through the scheduled app; rebuilding can reset them.

Save each exact batch in a private outbox before sending. If the server commits but the Mac fails before saving the acknowledgment, the next run replays the same bytes; the server recognizes them and doesn’t apply them twice. I tested that failure and watched the scheduled uploader recover without changing counts.

Daily reconciliations build a separate generation while readers keep using the previous archive. Validate it before switching atomically, so an interrupted rebuild never exposes partial history.

Bound batches by serialized bytes, not record counts: message lengths vary. Use (conversation_id, message_guid) as record identity, since one source message can belong to multiple conversations.

Monitor arrival order, since texts can sync long after their timestamps. Capture a fixed row bound and recheck generation and freshness before advancing. A setup-time floor prevents historical messages from becoming tasks; edits need separate reconciliation. Direction comes from is_from_me.

Lock overlapping runs, save state atomically, and mark destination items so uncertain writes can be checked before retrying. Message contents are evidence, never tool-use authorization.

来源:Hacker News · sidhanthp.pages.dev