iMessage-first bridge for Codex via Sendblue.
Quick preview (tap/click to open full video):
Full demo video: https://youtube.com/shorts/Pp9IAUcCs3s
- Polls Sendblue for inbound iMessages from one trusted number.
- Routes user text to Codex app-server (
turn/start/turn/steer). - Forwards inbound media as attachment URLs into Codex context.
- Sends typing indicators and best-effort read receipts through Sendblue (configurable).
- Applies optional outbound Markdown-to-Unicode styling for iMessage readability.
- Accepts authenticated webhook notifications and routes them through Codex notification turns.
- Supports interrupt/reset/debug/control commands.
- Keeps structured local audit logs in SQLite.
- iMessage-native control surface for Codex without changing your daily messaging workflow.
- Local-first runtime (Mac terminal process + local Codex app-server).
- Auditable message/notification history with explicit operational controls.
- Runtime: local Mac terminal process
- Codex execution: bridge starts and manages a local Codex app-server process.
- Transport to Codex: local stdio JSON-RPC to app-server (
codex app-server --listen stdio://) - Transport to iMessage: Sendblue API polling + send message API
- Safety mode default: danger-full-access. Use with caution.
/help/status/stop/reset/debug/thread/thread new/compact/model <id>/effort [level]/spark/pause(kill switch)/resume/notifications [count] [source]/restart <codex|bridge|both>
- Install prerequisites:
- Node.js
>=24 - Sendblue account with one sending number and one trusted inbound number
- Codex CLI
>=0.101.0
- Verify Codex CLI:
codex --versionExpected: 0.101.0 or newer.
- Install bridge dependencies:
npm install- Create
.envfrom.env.exampleand fill values.
Recommended Codex settings:
CODEX_BIN=codex
CODEX_CWD=/absolute/path/to/your/workspace
CODEX_MODEL=gpt-5.3-codexBacklog behavior (recommended default):
DISCARD_BACKLOG_ON_START=1When enabled, each startup marks currently visible inbound history as seen so only messages that arrive after startup are processed.
Optional: Notification webhook setup (for webhook-driven notifications):
ENABLE_NOTIFICATION_WEBHOOK=1
NOTIFICATION_WEBHOOK_SECRET=<long-random-secret>
NOTIFICATION_WEBHOOK_PORT=8787
NOTIFICATION_WEBHOOK_PATH=/eventsSend webhook requests to:
POST http://<bridge-host>:8787/events
Authorization: Bearer <NOTIFICATION_WEBHOOK_SECRET>
Content-Type: application/jsonAuth behavior:
Authorization: Bearer <NOTIFICATION_WEBHOOK_SECRET>orX-Bridge-Secret.
If you do not need webhook ingress, set:
ENABLE_NOTIFICATION_WEBHOOK=0- Start the bridge:
./scripts/run.sh- Keep it running in a terminal:
./scripts/run.sh supervises intentional restarts:
- if bridge exits with code
42(from/restart bridgeor/restart both), it relaunches automatically. - for other non-zero exits, it stops so crash loops remain visible.
- it enforces a single-instance lock (
.bridge-run.lock) to prevent duplicate bridge processes.
- Optional detached mode via tmux:
tmux new -s imessage-bridge 'cd /absolute/path/to/imessage-codex-bridge && ./scripts/run.sh'- In iMessage, text from trusted number to the Sendblue number.
- Run exactly one bridge process at a time.
- If the script reports a stale lock after an unclean exit, delete
.bridge-run.lockand start again. - If you run it in tmux:
tmux attach -t imessage-bridge- Stop tmux-run bridge:
tmux kill-session -t imessage-bridgenpm run lint
npm test
npm run build- v1 is text outbound; inbound media is forwarded to Codex as URL context.
- v1 is single-trusted-user only.
- Supported Codex models include
gpt-5.3-codexandgpt-5.3-codex-spark. - Reasoning effort is model-specific and persisted per model (
none|minimal|low|medium|high|xhigh). - Default reasoning effort is
mediumfor non-spark models andxhighfor spark models. /effortshows/sets effort for the current model./modelcan optionally set effort inline (for example/model gpt-5.3-codex-spark-lowor/model gpt-5.3-codex-spark low)./sparktoggles between the current model and spark, preserving the prior model+effort pair.- If
gpt-5.3-codex-sparkis selected but unavailable for the current account, the bridge automatically falls back togpt-5.3-codexand sends a user-visible notice. - Notification decisions use per-turn
outputSchema(sendvssuppress) and are audited in SQLite. - Restart controls:
/restart codexsends an immediate "restarting" ack, restarts only the Codex app-server child, then sends a "back online" confirmation./restart bridgesends an immediate "restarting" ack, triggers a full bridge restart, then sends a "back online" confirmation after process relaunch./restart bothdoes the same as bridge restart and confirms both are back online after relaunch.
- Assistant/tool internals are not pushed by default; use
/debugfor timeline. - Requires Codex CLI
>=0.101.0. - Read receipts are best-effort: the Sendblue
mark-readcall can return success while iMessage UI still showsDelivered. - Outbound formatting defaults to
ENABLE_OUTBOUND_UNICODE_FORMATTING=1and converts markdown markers like**bold**,*italic*, and`code`. - Startup safety defaults to
DISCARD_BACKLOG_ON_START=1so inbound messages that predate startup are not replayed into Codex. - Notification retention defaults: 90 days plus 25,000-row cap.
- Add
/healthor/diagcommand with runtime diagnostics (thread, active turn, model, feature flags, recent inbound/outbound timestamps).
