nc://channel-imessage

v0.1.0Pinned
Backnodecode-ai
pomterrerooms: nodecode-channel-imessage, iMessage through a BlueBubbles server -- the operator, 2026-10-19: 'Let's also make an iMessage channel cell; make sure we are in parity functionally as Discord as the social platform allow'. iMessage has no bot API: the bot is an Apple ID in Messages on a Mac running BlueBubbles (github.com/BlueBubblesApp/bluebubbles-server, Apache-2.0, self-hosted; built in house over its REST API, not the rented Photon Spectrum the retired TS pack used). Package nci. events.lisp (pure): a message as the kit candidate (DM/group/thread from the chat guid and threadOriginatorGuid, handles normalized one way, a line in the bot's thread or quoting it addressed, HEIC/CAF served as JPEG/MP3, link previews dropped), tapbacks in every spelling (names, -names, 2000-2006/3000-3006, emoji) as the kit's reaction, mention_names as the group mention, the kit's controls flattened to numbered choices and a reply of the number or label picking one. rest.lisp: message/text (private-api inline reply in groups, apple-script otherwise, never retried), files and voice (ogg to mp3 via ffmpeg, isAudioMessage) as multipart before the words, tapbacks (eyes emphasize, tick like, cross dislike), typing; the card is never posted (Messages edits five times and marks Edited): a failed card says why in a message, an ended or retired card and every send stop the typing bubble; the password rides the query, added by the executor and redacted. adapter.lisp: platform (choices t, plan-reaction only with the Private API), poll lap by message ROWID kept at channels/imessage/<server>.cursor (first start skips the backlog), contact names asked once, press routing to said-line/control-pressed, door nci:request. probe.lisp: server, Private API, latest chats, people with contact names; channels.imessage section. Tests over a fake BlueBubbles server on 127.0.0.1: .github/test-cell.sh rooms/nodecode-channel-imessage gives 19 imessage tests, 0 failed. Not live-proved: no Mac with BlueBubbles reachable yet.e88dac1· 19 Oct1 commit
test5 filesadapter.lisp19.4 KBevents.lisp15.2 KBprobe.lisp11.4 KBrest.lisp20.0 KBtext.lisp4.4 KB

nodecode-channel-imessage

A Nodecode add-on that lets people talk to your Nodecode over iMessage. iMessage has no bot API, so the bot is an Apple ID of its own, signed into Messages on a Mac that runs the BlueBubbles server (Apache-2.0, self-hosted). Nodecode polls that server's REST API, so this machine needs no public address and the Mac needs no route back to it.

  • Direct messages: every message is an ask, answered in the chat.
  • Group chats: call the bot by one of its mention_names and it answers as an inline reply under your message. Inside that thread, keep talking without the name; each reply continues the same conversation.
  • Answers: plain text. Messages draws no Markdown, so headings, emphasis and links are spelled the way a person would type them.
  • While a turn runs: the typing bubble, and (with reactions) a ‼️ tapback on your message that turns 👍 when the turn is done, 👎 when it failed. A turn that fails says why in a message. There is no status line: Messages can edit a message five times and marks it Edited, so a card ticking in place is not something it can carry. Type /stop to stop a turn.
  • Choices: what Discord shows as buttons comes as numbered lines under the message; reply with the number (or the choice's words) to pick one. Commands work typed: /help, /models, /status, ...
  • Tapbacks: a tapback on one of the bot's messages reaches the conversation as a line of context, the way a reaction does on Discord.
  • Files: Nodecode reads photos (HEIC arrives as JPEG), voice notes (as MP3, transcribed), and files people send, and can send files and voice messages back (voice needs ffmpeg on this machine).
  • Restarts: the read position is kept, so a restart neither replays old messages nor answers what was said before the bot first started.

Private API

BlueBubbles sends in two ways. AppleScript works on any Mac: words, files and choices. Its Private API (a helper inside Messages; needs SIP partly disabled, see the BlueBubbles docs) adds inline replies, tapbacks, the typing bubble and unsend. The adapter asks the server which it has at start and serves accordingly: without the Private API, group answers go into the chat instead of inline, and there are no tapbacks or typing bubble.

Install

In Nodecode, run /setup → Choose and pick nodecode-channel-imessage. Or copy this folder into ~/.nodecode/addons/nodecode-channel-imessage/. Either way, the channel kit that ships with Nodecode comes with it.

Set up the Mac

  1. Make the bot an Apple ID of its own. Never use your own.
  2. On a Mac that stays on, sign that Apple ID into Messages.
  3. Install the BlueBubbles server from bluebubbles.app, grant it Full Disk Access and Accessibility, and set a server password. For inline replies, tapbacks and typing, turn on its Private API.
  4. Note the address this machine reaches it at: the Mac's LAN address and port (http://192.168.1.20:1234), its Tailscale address, or the server's own Cloudflare or ngrok tunnel.
  5. Keep the server password in a file (mode 600) or an environment variable, never in the config.

Configure

Add a channels.imessage section to ~/.nodecode/config.jsonc; config.example.jsonc has every key. The least that works:

"channels": {
  "imessage": {
    "url": "http://192.168.1.20:1234",
    "password_file": "~/.nodecode/secrets/bluebubbles-password",
    "allowed_users": ["+15551234567"],
    "owner": ["+15551234567"]
  }
}

People are their handles: a phone number with its country code (written any way, +1 (555) 123-4567 included) or an email address. Chats are their BlueBubbles guids: iMessage;-;+15551234567 for a direct message, iMessage;+;chat... for a group. Say "set up imessage" to Nodecode, or run (nck:probe "imessage"): the probe checks the server and names its chats and the people in them, so you can pick ids by name.

Talk to it from Nodecode

The model reaches the server as the bot through (nci:request METHOD PATH &key body), the password added for it, for anything the adapter does not do itself: read a chat's history, send to another chat, rename a group.

Tests

.github/test-cell.sh rooms/nodecode-channel-imessage runs the lane end to end against a fake BlueBubbles server on 127.0.0.1 (test/fake-bluebubbles.lisp).

Add nc://channel-imessage

  1. 1

    Install Nodecode

    Once per machine.

    $ curl -fsSL https://nodecode.ai/install.sh | sh
  2. 2

    Add the cell

    Pinned at e88dac1. It brings channel-kit, which ships with Nodecode.

    $ nodecode add nc://channel-imessage

    Or tell the agent add the channel imessage cell.