imsg/docs/advanced-imcore.md
Peter Steinberger bbd6b93a1e
Some checks failed
CI / build (push) Has been cancelled
pages / Deploy docs (push) Has been cancelled
docs: add per-feature docs site and deploy to imsg.sh
Per-feature pages (install, quickstart, permissions, chats, history,
watch, send, groups, attachments, json, rpc, completions, advanced-imcore,
troubleshooting) plus an Apple-styled static-site builder rendering them
to dist/docs-site. GitHub Pages workflow deploys on every docs/ change to
imsg.sh.
2026-05-05 19:09:09 +01:00

4.8 KiB

title description
Advanced IMCore features Read receipts, typing indicators, IMCore status, and Messages launch control — opt-in, SIP-disabled, and increasingly limited on macOS 26.

Most imsg workflows — chats, history, watch, send, react — are explicitly designed to not require any private framework or process injection. They go through Messages.app's published surfaces (SQLite, AppleScript, file events) and need only the documented permissions covered in Permissions.

The features documented here are the exception. They drive Messages.app from the inside via a helper dylib injected into the Messages process, and they trigger several macOS protections you have to disable to use them.

You almost certainly do not need any of this for normal use.

What's in scope

  • imsg read --to <handle> [--chat-id <id>] — mark a chat as read.
  • imsg typing --to <handle> [--duration 5s] [--stop true] — show or stop the typing indicator.
  • imsg launch [--dylib <path>] [--kill-only] — launch Messages.app with the helper dylib injected.
  • imsg status — read-only IMCore bridge status.

Why they're separate

These features depend on private IMCore APIs that aren't reachable from outside the Messages process. To touch them, imsg injects a small helper dylib into Messages.app via DYLD_INSERT_LIBRARIES (built by make build-dylib).

That injection requires three things to be true on the target machine:

  1. SIP disabled. System Integrity Protection blocks DYLD_INSERT_LIBRARIES into protected system apps. Without disabling SIP, the launch step refuses to proceed.
  2. Library validation off. macOS 26 (Tahoe) tightened library validation; even with SIP off, a dylib that isn't signed against Messages' team identifier can be rejected.
  3. No private-entitlement gate. macOS 26 also added imagent entitlement checks that can refuse direct IMCore clients regardless of injection success.

You should expect at least one of these gates to be active on a current macOS install. The features are documented because they remain useful for research, testing, and CI — not because they're stable user-facing functionality.

Building and launching

make build-dylib   # produces .build/release/imsg-bridge-helper.dylib (arm64e)
imsg launch        # launches Messages.app with the dylib injected
imsg status        # confirms the bridge is up

imsg launch refuses to inject when SIP is enabled. There's no override.

imsg status is read-only. It does not auto-launch or auto-inject. Run imsg launch first.

To revert: re-enable SIP from Recovery mode (csrutil enable), then reboot.

Read receipts

imsg read --to "+14155551212"
imsg read --to "+14155551212" --chat-id 42
imsg read --to "+14155551212" --chat-identifier "iMessage;+;chat..."
imsg read --to "+14155551212" --chat-guid "iMessage;+;chat..."

Marks the chat for that handle as read. Useful when you want a programmatic agent to clear the unread counter in Messages without spawning a UI action.

Typing indicators

imsg typing --to "+14155551212" --duration 5s
imsg typing --to "+14155551212" --duration 30s --service imessage
imsg typing --to "+14155551212" --stop true

Displays or hides the "typing" bubble on the recipient's device.

--service accepts imessage, sms, or auto. The IMCore typing chat lookup normalizes across iMessage, SMS, and any prefixes so the same handle works on either service.

On macOS 26, typing indicators frequently fail with an entitlement error. imsg reports this as an advanced-feature setup error rather than a misleading "chat not found" — see CHANGELOG.md 0.6.0 for the issue history.

Status

imsg status
imsg status --json

Reports whether Messages is running, whether the helper dylib is loaded, and whether the IMCore bridge is responding. Read-only; safe to run on any machine.

When the bridge isn't loaded, status prints the reason rather than attempting to fix it. Use imsg launch if you want to bring it up.

Launching Messages with a custom dylib

imsg launch --dylib /path/to/custom.dylib
imsg launch --kill-only           # quit Messages without launching
imsg launch --json                # machine-readable launch result

--kill-only is the inverse: it tears Messages down (to drop a stale injection) without relaunching.

When to use any of this

The honest answer for most readers: don't. The macOS 26 limits make these features unstable in production. They're useful when:

  • You're doing macOS / Messages.app research.
  • You're running CI inside a controlled VM with SIP disabled by configuration.
  • You need a typing-indicator demo on a single hand-tuned machine.

For agent integrations, prefer the standard CLI surfaces (send, react, watch). They cover the realistic interaction surface without touching SIP.