The project's README from github.com/nixfred/blip. As one markdown file: README.md.
iMessage. On Linux. For real.
Read, send, group chats, blue dots, desktop toasts — from an Omarchy bar widget.
Your Mac does the talking. Your Linux box does the living.
⚠️ You need a Mac. That is the whole trick.
Blip does not reimplement iMessage. Apple's protocol only runs on Apple hardware, so Blip uses a Mac you already own — any Mac signed into your Apple ID, awake and reachable over SSH — as the gateway. The Linux side is a thin client. No Mac, no Blip. When the Mac sleeps, Blip dims and waits.
Every screenshot is the real client rendered against invented people —
scripts/demo/blip-shots points the shipping code at a fake bridge, so
nothing here is anyone's conversation. Numbers are in the 555-0100 range
reserved for fiction. The link card is a real fetch of a real public page.
Blip went public on 2026-08-31 and has moved fast since, much of it from people who showed up with pull requests. What is in it now:
SUPER+M, the ⇱ button in
the panel header, double-click the bar icon, or qs ipc … app. Remembers
size and whether it was open across shell restarts.pacman -S inter-font), then your theme font — so
nothing changes for anyone who has installed neither. blip-setup offers to
install Inter; ui_font=theme in bridge.conf opts out. ui_font_size=14
(9–24) is bubble text in pixels so Blip can be larger than the rest of the
shell.
Blip ships no fonts. SF Pro is Apple's and its licence forbids
redistribution, so it is never carried in this repo — if you want the exact
Messages face, get it from Apple.
See Fonts./attach, with captions.blip-setup installs
everything including a dedicated ssh key the Mac confines to the five
bridge tools.Full history: CHANGELOG.md.
iMessage is macOS-only. Everyone who lives on Linux and owns an iPhone knows the dance: pick up the phone, unlock it, type on glass, put it down, lose the thread. BlueBubbles wants SIP off. AirMessage wants a server and a prayer.
Blip does something simpler. The Mac you already own is the gateway. It
holds chat.db and it can drive Messages.app with AppleScript. Everything else
is one multiplexed SSH socket and a bar widget that looks like it belongs.
No SIP disabled. No daemon on the Mac. No private API. No message cache on the Linux side. If the Mac is asleep, the widget dims and says so.
|
In the bar
Thread list
|
Conversation
Toasts
Toast actions
Hotkey for the panel
The app
Real-time
|
Right-click any link — or just send or receive one — and the share sheet comes up on it.
No server, no telemetry, no accounts. Everything between the two machines travels inside ssh — message text, attachment bytes, the push ping — on a dedicated key the Mac confines to Blip's bridge tools — and, over Tailscale, to this machine's address; nothing is ever sent in the clear. The full inventory of what touches disk on both machines is in docs/PRIVACY.md — short version: message text never lands on disk; only attachments in conversations you open are cached (inline images ≤ 5 MB and link previews fetch when the thread does). The threat model and the findings of the 2026-08-31 security audit are in docs/SECURITY.md.
Linux Mac
───── ───
BarWidget.qml ── push/poll ──▶ collector.ts ──▶ ssh ──▶ imsg --json recent 150+
(sqlite, read-only)
BlipView.qml ── open thread ─▶ thread.ts ──▶ ssh ──▶ imsg --json thread <id> 80
BlipView.qml ── Enter ─────(body on stdin)──▶ ssh ──▶ imsg-send --to <id> --yes --text-stdin
imsg-send --chat-id "any;+;<guid>" …
(AppleScript → Messages.app)
The trick that makes it possible: sshd on macOS inherits both Full Disk
Access and Automation consent. cron gets neither. So a plain SSH session can
read chat.db and tell Messages.app to send, where every scheduled approach
dies at a TCC prompt nobody is there to click.
With ControlMaster in ~/.ssh/config, a round trip is ~47 ms warm. Fast
enough to poll, fast enough that the panel feels local.
Blip is one source: the Mac-side tools ride along in bridge/mac/
(vendored from claude-on-mac,
pinned in bridge/BRIDGE-VERSION), and blip-setup wires everything.
Blip renders in the first of these it finds, so it is optional either way:
| SF Pro | what Messages itself uses | developer.apple.com/fonts · Arch: otf-san-francisco (AUR, downloads it from Apple) |
| Inter | open licence, drawn for interfaces, very close | rsms/inter · Arch: inter-font — sudo pacman -S inter-font |
| your theme font | whatever Omarchy is set to | nothing to install |
blip-setup offers to install Inter if you have neither. ui_font=theme in
bridge.conf always uses the Omarchy family. ui_font_size=14 (9–24) sets
bubble text in pixels so Blip can be larger than the rest of the shell;
unset, it follows Omarchy's type size.
Blip ships no fonts. SF Pro is Apple's and its licence forbids redistribution, so it is not carried in this repo — note that even the AUR package fetches it from Apple rather than mirroring it.
Requirements
chat.db
mirrors your phone. Xcode Command Line Tools installed (xcode-select --install) — python3 on a fresh Mac is a stub until then.chat.db but cannot send.bun, jq, openssh, libnotify, wl-clipboard, xdg-utils.
blip-setup checks for each and prints the pacman line for what's missing.Honest note on dependencies. Blip is not a drop-in marketplace plugin the way a clock widget is: it needs
bunon the Linux side, a Mac you own with two manual permission grants, and an ssh key between them. The plugin files install like any other; the bridge is whatblip-setupexists for. Budget ten minutes and a trip to the Mac's System Settings.
If you are a human: budget ten minutes, keep the Mac's screen reachable for two permission prompts, and use your own number for the first test message. Nothing below sends anything until you press Enter in a conversation.
If you are an AI agent installing this for someone: run exactly the commands below, in order, and stop at step 3 until the human confirms the two grants on the Mac. Never send a test message to anyone but the user's own number. Do not edit
~/.ssh/configbeyond whatblip-setupwrites. Verify withblip-check, not by readingchat.dbyourself. Before changing code, readAGENTS.mdandCLAUDE.md.
1. Install the plugin (Omarchy's plugin manager clones it into
~/.config/omarchy/plugins/nixfred.blip and adds the bar widget)
omarchy plugin add https://github.com/nixfred/blip.git --enable
(Manual alternative: git clone https://github.com/nixfred/blip ~/.config/omarchy/plugins/nixfred.blip, then step 4.)
2. Run the wizard (idempotent — re-run any time; it prints the
pacman line for any missing Linux dependency and stops)
~/.config/omarchy/plugins/nixfred.blip/scripts/blip-setup you@your-mac
It writes ~/.config/blip/bridge.conf, adds an ssh ControlMaster block
(polling costs 50 ms instead of a handshake), installs the bridge shim as
`/bin/imsg, /bin/imsg-send/bin/contacts, , copies the Mac tools to /.blip/bin/.ssh/blip_ed25519on the Mac and runsinstall.sh there, generates a **dedicated ssh key** () that the Mac confines to the bridge tools and nothing else, then smoke-tests the bridge without printing any message content. Over Tailscale the key is also pinned to this machine's addresses (from=), so a copy of the key file is useless from anywhere else; over a LAN, where an address can change, it is not pinned — [docs/SECURITY.md](docs/SECURITY.md) shows the one-line manual pin. Re-run blip-setup` if the machine's Tailscale address ever changes.
3. Two grants on the Mac (macOS won't let a script do these — the wizard pauses here and re-checks when you press Enter)
/usr/libexec/sshd-keygen-wrapper (⌘⇧G in the file picker).
That is what lets an ssh session read chat.db.auth_reason 9,
"Prompt Timeout"), and on macOS 26 the switch under System Settings →
Privacy & Security → Automation → sshd-keygen-wrapper → Messages may then
refuse to turn on: you enter the password and it drops back off (#36).
Recovery, SIP intact, no database edits: on the Mac run
tccutil reset AppleEvents — Apple's own tool; it clears every app's
Automation grants (each simply asks again next time), because a
path-identified client like sshd-keygen-wrapper cannot be reset on its own —
then re-run blip-setup and sit at the Mac's screen for the prompt.ssh your-mac 'python3 "$HOME/.blip/bin/blip-check"' shows ✅/❌ per grant at any
time, with the fix for each ❌. It does not test the optional read-push grant
unless you add --markread, because that probe pops an Automation prompt of its
own and you should only be asked for a permission you actually want.
4. Bar widget. omarchy plugin add --enable already placed it. If you
cloned by hand: omarchy plugin enable nixfred.blip --section right, or add
{ "id": "nixfred.blip" } to bar.layout.right in
~/.config/omarchy/shell.json. Then omarchy-restart-shell — the speech
bubble is in your bar.
Clock and dates. Out of the box the time follows your locale — 9:08 PM
or 21:08 — and dates read the way Messages writes them: Aug 28, or
Aug 28, 2025 for another year. To change either, put Qt format strings on
the same entry, exactl