Skip to content

cmux-imessage: send to a chat through Messages.app (opt-in mirror, library step) - #32919

Merged
cmux-bot[bot] merged 2 commits into
feat-cmux-nextfrom
feat/imessage-mirror-send
Nov 3, 2026
Merged

cmux-bot[bot] merged 2 commits into
feat-cmux-nextfrom
feat/imessage-mirror-send

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 sending half of the opt-in Messages mirror, at the library level. It adds cmux_imessage::send to the crate from #32891. Nothing calls it yet: the daemon op and the composer come in a follow-up, behind the same off-by-default imessage.enabled setting, and every send needs a user gesture.

What it does

  • send(&SendRequest { chat_guid, text }, &SystemRunner) runs osascript with a fixed script: tell application "Messages" to send messageText to chat id chatGuid.
  • The chat guid and the text reach the script only as argv items and are never spliced into its source, so a message can't change what the script does. A test sends a hostile string and checks that it arrives verbatim.
  • Validation: refuses empty text, text over 20,000 bytes and NUL bytes. A chat guid must be service;-;id or service;+;id, with no control characters and no leading -, so osascript never reads it as an option.
  • Errors map to stable codes:
    • AppleScript -1743 (Automation of Messages not allowed) becomes not_permitted.
    • -1728 (no such chat) becomes invalid_chat.
    • No osascript becomes unsupported.
    • A send that runs past 2 minutes becomes timed_out.
    • Anything else becomes failed.
  • Stop condition and cleanup: the child is waited on, and on timeout it is killed and reaped. Nothing is left running.

Nothing leaves the Mac except the message Leo sends through his own Messages.app.

Tests

Two commits: the failing tests against stubs (5 of 5 red), then the implementation (5 of 5 green, the reader's 10 still green, clippy -D warnings clean on Linux CI). They use a fake runner, so no Messages.app or osascript is needed.

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 cmux_imessage::send, the sending half of the opt-in Messages mirror at the library level. Nothing calls it yet; the daemon op and composer follow in a later PR, behind the same off-by-default imessage.enabled setting, and every send needs a user gesture.

Security and validation

  • The chat guid and text reach a fixed AppleScript only as argv items, never spliced into its source, so a hostile message can't change what the script does.
  • Refuses empty text, text over 20,000 bytes, and NUL bytes; chat guids must match service;-;id or service;+;id with no control characters and no leading -.
  • AppleScript -1743 (Automation not allowed) maps to not_permitted, -1728 (no such chat) to invalid_chat, missing osascript to unsupported, a two-minute overrun to timed_out, and anything else to failed.

Tests

  • Tests use a fake runner, so no Messages.app or osascript is needed, and cover the hostile-string case, validation, one osascript call per send, and error-code mapping.

Written for commit fd985be. Summary will update on new commits.

View guided diff Turn on auto-fix

teamleaderleo and others added 2 commits November 2, 2026 19:16
Adds the send module's API with stub bodies and the tests it must pass:
the text reaches osascript only as argv (a hostile string stays data),
validation of empty, long and malformed chat ids, one osascript call per
send, and the Automation-denied / no-such-chat / missing-osascript /
timeout error codes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Codex <199175422+chatgpt-codex-connector[bot]@users.noreply.github.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-f62148d989879feda740
Runs osascript with a fixed script (`send messageText to chat id chatGuid`),
passing the chat guid and the text as argv only. Validates the request,
maps AppleScript -1743 to not_permitted (Automation not allowed) and -1728
to invalid_chat, and stops a send that runs past two minutes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Codex <199175422+chatgpt-codex-connector[bot]@users.noreply.github.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-f62148d989879feda740
@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 fd985be: 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=pr32919 -f ref=feat/imessage-mirror-send -f platform=macos -f backend_mode=local

red: cmux-next checks (god files, concurrency, crash safety, l10n); no finished base run on 1a31709 to compare; do not merge until green; see lane-rules

Shipped in:

@github-actions github-actions Bot added the risk:normal Risk tier (docs/ci/risk-tiers.md) label Nov 3, 2026
@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Review (codex, router-review): SHIP at fd985be

Reviewer: codex gpt-6-astra high, fast tier.

Follow-ups: 2. Each lands as an issue in this repo that links this receipt; the lane that opened the PR fixes it forward.

SHIP at fd985be
Visual verdict: no images; Leo tries the build

  1. [P2] [follow-up] send.rs:118: Drain stderr while the child runs. Currently, a child that fills the pipe blocks before exiting, while the parent waits for its exit before reading. This turns an ordinary command failure into a two-minute timeout and discards its diagnostic. Add a real subprocess test that exceeds pipe capacity.

  2. [P2] [follow-up] send.rs:180: Parse the terminal AppleScript error code instead of searching the entire diagnostic. A validly formatted but nonexistent GUID such as iMessage;-;(-1743) can appear in the quoted missing-chat diagnostic ending in (-1728), causing not_permitted instead of invalid_chat.

Tests could not run because Rust tooling is unavailable.

Follow-ups:

  • Drain stderr concurrently and test output exceeding pipe capacity.
  • Parse the terminal error code and test diagnostics containing misleading codes.

@teamleaderleo teamleaderleo added the ready-to-land Reviewed at this head; next-autoland merges it into feat-cmux-next when its only reds are base reds label Nov 3, 2026

@cmux-bot cmux-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cmux-bot approves fd985be: an independent review passed this exact head (router-review receipt by teamleaderleo). A push needs a new review; a later BLOCK at this head dismisses this approval.

@cmux-bot
cmux-bot Bot merged commit e55fbb6 into feat-cmux-next Nov 3, 2026
233 of 245 checks passed
@cmux-bot
cmux-bot Bot deleted the feat/imessage-mirror-send branch November 3, 2026 03:32

This branch was previously deployed

3 inactive deployments
ci-routing-agent — fd985be4 Deployed Nov 3, 2026 by github-actions[bot] via cmux-next macOS placement #64529
artifacts — fd985be4 Deployed Nov 3, 2026 by teamleaderleo via publish tree-addressed cmux-tui #103675
sentry-dsyms — fd985be4 Deployed Nov 3, 2026 by teamleaderleo via upload cmux-tui dSYMs to Sentry #103675
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