Set up SMS integration
Omniscio can send and receive text messages using your own Android phone — no Twilio and no separate SMS number. Once connected, Omniscio notifies you by SMS when a session needs your attention, and anything you reply from your phone appears inside the app. Two ways to connect: Pushbullet, which mirrors texts through its cloud and handles pictures; or Native, which goes straight over your own carrier.
What it is
Omniscio can send and receive text messages using your own Android phone — no Twilio, no separate SMS number. Once connected, Omniscio notifies you by SMS when a session needs your attention, and any reply you send from your phone shows up inside the app.
There are two ways to connect, chosen under Settings → SMS → "SMS provider":
- Pushbullet (default) — the easiest path. Texts are mirrored through the Pushbullet cloud using the Pushbullet Android app. Supports pictures (MMS) and GIFs. Free Pushbullet accounts cap SMS at 100/month.
- Native (my phone) — texts go straight over your phone's real SIM via a free, open-source Android app (capcom6 "SMS Gateway for Android") that runs a tiny server on your home network, with no third-party cloud in the path and no monthly cap. It is text-only for now — pictures, MMS, and GIFs aren't sent or received under Native yet, so use Pushbullet if you need those.
You can switch providers anytime; conversations and history are shared, so nothing is lost.
Where to find it
SMS lives on its own page inside Settings — open Settings and choose SMS (settings search reaches it too). At the top you pick how your texts travel: Pushbullet, which mirrors them through the Pushbullet cloud, or Native, which sends straight over your own phone's SIM through a small server running on the phone. Choosing a provider reveals a short setup wizard underneath, and you can switch between them at any time without losing your conversations.
Once connected, your text threads appear in Omniscio's Inbox and you can reply from inside the app. When SMS is switched on but stops working, a single alert appears in your Inbox along with one desktop notification, and the switch that controls that alert sits on the same SMS page.
How it behaves
Set up Pushbullet (the default)
- Open Settings → SMS, leave the provider on Pushbullet. You'll see a three-step wizard: Token → Device → Connect.
- Get a Pushbullet API token. Install Pushbullet on your Android phone and sign in. Then visit
pushbullet.com/accounton desktop, scroll to "Access Tokens", and click "Create Access Token". You'll get a string that starts witho.— copy it. - Paste the token into Settings. Click "Save & Verify". Omniscio confirms the token, encrypts it, and stores it on disk. Then it lists your Pushbullet devices — pick the Android phone marked "SMS capable".
- Wait for "Connected". Omniscio opens a WebSocket to Pushbullet and the status dot turns green. Send yourself a test SMS from another number — it should appear in Omniscio's Inbox within a few seconds.
Re-entering your token or re-picking your device automatically refreshes the connection, and a socket that sticks mid-handshake recovers on its own within ~15 seconds — so you rarely need to click Retry if you hit "Taking longer than expected" at Step 3. If the token is rejected, double-check you copied the whole string including the o. prefix.
Set up Native (your own phone, self-hosted)
Native runs a tiny web server on your phone that texts flow through — nothing touches anyone else's cloud.
- Install the app. On your Android phone, install the free SMS Gateway for Android app (from F-Droid or the project's GitHub release — it isn't on the Play Store because Google restricts SMS-forwarding apps). On Android 15+, open the app's App info → ⋮ → "Allow restricted settings" once so it can run its local server in the background.
- Run it in Local Server mode. The app shows a local address like
http://192.168.1.5:8080plus a username and password — that's your phone's own SMS API on your Wi-Fi. - In Omniscio, Settings → SMS, switch SMS provider to Native (my phone). Fill in the phone address, username, and password from the app, and set a webhook secret (any strong phrase — you'll paste the same one into the phone app).
- Point the phone app's webhook at Omniscio. Omniscio shows an Inbound webhook URL to copy into the app's webhook settings, and to sign each request with that shared secret. This requires Mobile Access (Settings → Remote Access) to be on so your phone can reach Omniscio.
- Test it. Text yourself from another number — it should land in Omniscio's Inbox. Send a reply from Omniscio — your phone sends it over your SIM.
Off Wi-Fi: the local address only works while your phone and PC share a network. To send/receive when you're away, put both on a private tunnel like Tailscale (free) and use the tunnel address, or use the phone app's own cloud relay — see the app's docs.
If SMS goes offline
If SMS is turned on but stops working, Omniscio raises a single "SMS is offline" alert in your Inbox plus one desktop notification, rather than failing silently — for Pushbullet, that's a saved token that can no longer be read (for example after a hardware or Windows change that resets saved keys) or a connection that drops for a sustained stretch; for Native, it's missing connection settings. A missing/unreadable credential alerts right away (it won't fix itself); a dropped Pushbullet connection waits out a short grace window first, so a brief blip or a laptop sleep doesn't nag you. The alert clears itself automatically once SMS reconnects. Turn it off under Settings → SMS → "Alert me when SMS goes offline" (on by default). The watchdog (/src/main/services/sms/sms-health-monitor.ts) ticks once a minute; its behaviour is locked by sms-channel-health-contract.md.
Keyboard support
SMS and Telegram triage in Omniscio is deliberately mouse-first — every action in the messaging panes (archive, snooze, mark-as-read, mark-as-spam, reply) is a visible button, and none of them is keyboard-only. That's a declared decision, not an omission, for two reasons:
- You're usually on your phone. The whole point of SMS/Telegram integration is replying from your phone; the in-app panes are a convenience, not the primary workspace.
- The app-wide shortcut set stays clean. Omniscio's global session shortcuts (J/K to move between sessions, R to reply in the focused session, E to archive, H to snooze) are built around the Claude session list and composer. Messaging threads deliberately don't mirror that layout, so wiring a second, conflicting shortcut set onto them would fight the app-wide keys.
Recorded as a declared keyboard-light exemption to the "never ship shortcut-less by omission" rule (audit universal-feature-compliance finding F011, 2026-08-10).
For agents
How it works
A small provider seam (/src/main/services/sms/sms-provider.ts) reads your smsProvider setting and routes every send / status / connect call to the live backend, so the rest of Omniscio doesn't care which provider is active. Both providers feed the same incoming pipeline — dedup, spam filter, notifications, automations — so your Inbox, threads, and history behave identically either way.
- Pushbullet (/src/main/services/sms/pushbullet-service.ts) — outbound calls Pushbullet's
POST /texts(your phone sends over your carrier, so texts count against your phone plan, not Pushbullet's); inbound is a WebSocket towss://stream.pushbullet.com(three event types:sms_changedpushes,ticklefetch signals, mirrored notifications), plus a 30-second background sync that catches anything the socket missed — and when that sync sees the newest message in a thread is one you sent, it clears the thread's inbox attention (locked by sms-inbox-attention-contract.md). Credentials (pushbulletApiToken,pushbulletDeviceIden) are encrypted with ElectronsafeStorage. - Native (/src/main/services/sms/native-sms-service.ts) — outbound POSTs to the phone app's local
/messageAPI; inbound is an HMAC-signed webhook (POST /sms/native/inboundon Omniscio's web-access server) that Omniscio verifies before accepting a text. There's no socket to keep open (the phone pushes to Omniscio), so "connected" just means "configured", and there's no device list or monthly quota. The phone password + webhook secret are encrypted at rest and never leave the main process. Behaviour is locked by native-sms-contract.md.
Phone-number storage is canonical (E.164). Every write to sms_conversations or sms_messages routes the phone string through canonicalizePhoneNumber() (backed by libphonenumber-js) before the row lands in SQLite — for BOTH providers. That way a raw 10-digit number typed in the compose dialog (5551234567) and the canonical form a sync/webhook returns (+15551234567) end up under the same phone_number primary key — one thread per person, matching what your phone's Messages app already does. Short carrier codes (3–6 digits with no leading +, like 22395) stay raw so libphonenumber doesn't mangle them. A lint test tests/unit/lint/sms-canonical-phone-key-coverage.test.ts enforces that every SMS-write caller imports the helper, and migration v247 backfills any legacy non-canonical rows on startup.
Related
- snooze-a-session.md — temporarily hide sessions from the inbox
- configure-notifications.md — route session alerts to SMS, desktop, or email (stub)
- set-up-pushbullet-account.md — Pushbullet account + device prerequisites (stub)
Last verified 2026-09-28