Skip to content

cmux-imessage: read-only Messages database reader for the opt-in Messages mirror - #32891

Merged
teamleaderleo merged 2 commits into
feat-cmux-nextfrom
feat/imessage-mirror-reader
Nov 3, 2026
Merged

teamleaderleo merged 2 commits into
feat-cmux-nextfrom
feat/imessage-mirror-reader

Conversation

@teamleaderleo

@teamleaderleo teamleaderleo commented Nov 3, 2026 •

Copy link
Copy Markdown
Collaborator

Leo's ask: "i mean like obviously we already are in an imessage type zone im saying like actual imessage chats with contacts/group chats" ... "hm. could we mirror it?"

This is the first step of an opt-in, off-by-default Messages mirror in cmux NEXT: a read-only reader of the macOS Messages database. It adds no UI and nothing calls it yet. The daemon ops and the page come in the next PR.

What it does

New crate cmux-tui/crates/cmux-imessage:

  • Reader::open(path) opens ~/Library/Messages/chat.db with SQLITE_OPEN_READ_ONLY. It never writes. A TCC denial (no Full Disk Access) returns NotPermitted, a missing file Missing, and a database without the Messages tables Schema.
  • threads(limit): 1:1 and group chats, newest activity first. Each one carries its title (the group name, else the participants), is_group, its participants and a last-message preview.
  • messages(chat_id, before_rowid, limit): one thread's messages, oldest first, paged back by rowid. Text comes from message.text, or is decoded from the attributedBody typedstream that recent macOS versions use instead. Attachment names and MIME types are included; tapbacks and group events are left out.
  • since(rowid, limit) and latest_rowid(): the watermark that live updates will use.

Nothing leaves the Mac. The crate has no network code, and attachment files are never copied.

Tests

Two commits: the failing tests against stubs (9 of 10 red), then the reader (10 of 10 green, clippy -D warnings clean). The fixture databases are built from the Messages schema: group naming and fallback, preview skipping tapbacks, attributedBody short/long/unicode/garbage, paging, the watermark across chats, and the missing/schema/not-permitted errors.

Follow-ups (next PRs): the daemon resource messages.mirror.* with a file-watch change event, the webview page and the off-by-default setting; then sending through Messages.app. Contact names are a follow-up too.

Agent session: agent session

🤖 Generated with Claude Code


Autofix with [code]smith
Open in [code]smith · Need help on this PR? Tag @codesmith-bot with what you need.


Summary by cubic

Adds the cmux-imessage crate: a read-only reader of the macOS Messages database (~/Library/Messages/chat.db) that backs an opt-in, off-by-default Messages mirror in cmux NEXT. Nothing calls it yet; the daemon resource, live-update file watcher, and UI come in the next PRs.

New Features

  • Opens with SQLITE_OPEN_READ_ONLY, never writes, never copies attachment files, and has no network code.
  • Maps a TCC denial to NotPermitted so the UI can ask for Full Disk Access, a missing file to Missing, and an unfamiliar schema to Schema.
  • Lists 1:1 and group threads newest-first with participants, group names, and a last-message preview; skips tapbacks and group events.
  • Pages a thread's messages oldest-first by rowid, decoding text from the attributedBody typedstream when message.text is empty; includes attachment names and MIME types.
  • Provides since() and latest_rowid() as the watermark live updates will use.
  • Tested against fixture databases built from the Messages schema, covering group naming, attributedBody variants, paging, the watermark, and all three open errors.

Written for commit 3fc8115. Summary will update on new commits.

View guided diff Turn on auto-fix

teamleaderleo and others added 2 commits November 2, 2026 18:47
Adds the cmux-imessage crate with its API stubbed and the fixture-database
tests that the reader must pass: threads (1:1 and group chats), messages
with attributedBody text and attachments, live-update watermark, and the
missing/not-permitted/schema errors.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-9bf3963ac29d9d619047
Co-authored-by: Codex <199175422+chatgpt-codex-connector[bot]@users.noreply.github.com>
Opens ~/Library/Messages/chat.db read-only and lists threads (1:1 and
group chats, newest first, with participants and a last-message preview),
pages a thread's messages (text from message.text or decoded from the
attributedBody typedstream, attachment metadata; tapbacks and group events
left out) and returns messages past a rowid watermark for live updates.
A TCC denial maps to NotPermitted so the UI can ask for Full Disk Access.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-9bf3963ac29d9d619047
Co-authored-by: Codex <199175422+chatgpt-codex-connector[bot]@users.noreply.github.com>
@cursor

cursor Bot commented Nov 3, 2026

Copy link
Copy Markdown

Bugbot needs on-demand usage enabled

Bugbot uses usage-based billing for this team and requires on-demand usage to be enabled.

A team admin can enable on-demand usage in the Cursor dashboard.

@github-actions

github-actions Bot commented Nov 3, 2026 •

Copy link
Copy Markdown
Contributor

cmux status (one comment, edited in place; each line is updated by the job that owns it)

Review 3fc8115: HQ feed card · gallery before/after runs · checks

App of this head (app.zip, kept 1 day)

gh workflow run reload-build.yml -R manaflow-ai/cmux --ref feat-cmux-next -f tag=pr32891 -f ref=feat/imessage-mirror-reader -f platform=macos -f backend_mode=local

Shipped in:

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Review (subagent claude-opus-5-5 medium): SHIP at 3fc8115

Checked the schema assumptions (style 43 group, ns-since-2001 dates with seconds fallback, typedstream + / 0x81 / 0x82 length decode, tapback and group-event filtering), the read-only open (SQLITE_OPEN_READ_ONLY, no writes or checkpoints, WAL readers don't block Messages), panic safety of the decoder (all slicing is via get, no overflow), EPERM/EACCES to NotPermitted (std maps both to PermissionDenied), and query cost (one full scan per threads() plus at most 500 N+1 PK lookups; nothing quadratic). Nothing calls the new crate yet, so it can't break base.

Follow-ups:

  • [follow-up] threads() picks the last message by MAX(message_id), and messages() pages by ROWID. When iCloud Messages backfills older history it gives old messages higher ROWIDs, so thread order and conversation order can disagree with date. Consider ordering and choosing the last message by date (or message_date) with ROWID as the tiebreak.
  • [follow-up] VISIBLE uses associated_message_type = 0 AND item_type = 0. That also drops rows where either column is NULL (use IFNULL), and hides non-tapback associated types: stickers (1000) and app or balloon messages (2/3). The doc comment says tapbacks are 2000-3005, but iOS 18 added 2006/2007 and 3006/3007. The filter already excludes those; the comment should list them or describe the filter as "all non-zero".
  • [follow-up] The NotPermitted test skips itself when run as root, so it may pass without checking anything in containerised CI. Also, I/O errors other than NotFound or PermissionDenied are reported as Schema; a separate Io variant would be more accurate.
  • [follow-up] since() only shows new rows. Edits, unsends and tapbacks on existing messages never reach live updates. A message joined to more than one chat would also come back twice.
  • [follow-up] Use prepare_cached for the per-row participants, preview and attachments statements.

This branch was previously deployed

3 inactive deployments
artifacts — 3fc81153 Deployed Nov 3, 2026 by teamleaderleo via publish tree-addressed cmux-tui #103595
sentry-dsyms — 3fc81153 Deployed Nov 3, 2026 by teamleaderleo via upload cmux-tui dSYMs to Sentry #103595
ci-routing-agent — 3fc81153 Deployed Nov 3, 2026 by teamleaderleo via cmux-tui tree preflight #103595
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-to-land Reviewed at this head; next-autoland merges it into feat-cmux-next when its only reds are base reds risk:normal Risk tier (docs/ci/risk-tiers.md)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant