---
title: When a text leaves your inbox
---
# When a text leaves your inbox

## What it is

A new text does two things at once: it puts that conversation in your **Inbox**, and it
gives it an **unread dot** in the SMS list. Opening the conversation now clears both — the
thread leaves the Inbox and the dot goes away, in the same moment you open it.

Put simply: **reading a text is dealing with it.** You no longer have to open a thread and
then separately dismiss it to get it out of the Inbox.

## Where to find it

Nowhere to switch on — this is simply what opening an SMS conversation does. It applies
everywhere you can open one: the SMS panel, the Inbox, a notification or search result, the
phone/web view, and the CLI's `/sms/.../read` route.

## How it behaves

### What removes a thread from the Inbox

- **Opening it** — in the SMS panel, from the Inbox, from a notification, or from search.
- **Replying to it** inside Omniscio (unchanged).
- **Archiving it** (unchanged).
- **Replying from your phone** — picked up on the next sync (unchanged).
- **"Mark as read"** — from the Inbox row's menu, the batch Mark-as-read, or the button in a
  conversation (unchanged).

### What does NOT remove a thread

The app moves the cursor on its own, and none of those moves clear anything — otherwise a
text you never looked at could quietly vanish from your Inbox:

- the **cursor moving to the next row** after you dismiss, archive or snooze something, and
  after a bulk version of the same;
- the **automatic eject** — when a session changes status in the background and the app
  moves you off its row onto the next one;
- the **idle auto-select** that opens the first Inbox row when you're sitting on an empty pane;
- a **brand-new text auto-opening** into an empty Inbox;
- the **background refresh** when your phone syncs.

The line the app draws is **who moved**: your own click, key, swipe or notification tap
opens a thread and clears it; anything the app did by itself leaves it alone. That
distinction is checked by a test that scans every place the app can move the Inbox cursor,
so a new one can't quietly start clearing things.

### A text that arrives while you have the conversation open

It still lands in the Inbox and still counts as unread-worthy. Opening the conversation again
(or Mark-as-read) clears it. Omniscio deliberately does not treat "a thread happens to be
open" as "you read this" — the conversation stays selected while you're off in another
project, so trusting that would swallow a text you never saw.

### The trade, stated plainly

A text you read but never replied to leaves your Inbox — and it also leaves the **daily
digest**, which keys on the same "needs your attention" flag. Nothing is lost: the whole
conversation is always in the SMS list, and the next text from that number puts it straight
back in the Inbox.

## For agents

### Where it lives in code

- [src/main/db/queries-sms/conversations.ts](../../src/main/db/queries-sms/conversations.ts)
  — `markConversationHandled(...)`, the ONE "dispose from the inbox" write (clears
  `needs_attention` and `unread_count` together).
- [src/main/ipc/sms-handlers.ts](../../src/main/ipc/sms-handlers.ts) — the `sms:mark-read`
  handler (fired when a thread is opened) and its `sms:conversation-updated` push.
- [src/main/services/cli/cli-server-sms-routes.ts](../../src/main/services/cli/cli-server-sms-routes.ts)
  — `POST /sms/conversations/:phoneNumber/read`, the CLI twin.
- [src/renderer/src/stores/sms-store.ts](../../src/renderer/src/stores/sms-store.ts)
  — `selectConversation(phone, { markHandled })` (default `true` = a user open = dispose),
  the idempotent `markAsRead`, and the three app-driven call sites that pass `markHandled: false`.
- [src/renderer/src/lib/inbox-open-source.ts](../../src/renderer/src/lib/inbox-open-source.ts)
  — `isUserInboxOpen(source)`: the ONE classification of "a person opened this row" vs "the
  app moved the cursor onto it", with a scan test over every `activateUnifiedItem` call site.
- [src/renderer/src/stores/inbox-source-behaviors.ts](../../src/renderer/src/stores/inbox-source-behaviors.ts)
  · [src/renderer/src/stores/inbox-advance-side-effects.ts](../../src/renderer/src/stores/inbox-advance-side-effects.ts)
  — the SMS behavior's `openDetail` (which consults that classifier) and the idle
  auto-select / post-dismiss advance loaders.

The full engineering contract (the invariant, every writer of the flag, and the safe-change
checklist) is
[.claude/memory/contracts/sms-inbox-attention-contract.md](../../.claude/memory/contracts/sms-inbox-attention-contract.md).

## Related

- [inbox-overview.md](inbox-overview.md) — the unified triage view these rows appear in.
- [set-up-sms-integration.md](set-up-sms-integration.md) — how the SMS integration works.
- [sms-inbox-preload.md](sms-inbox-preload.md) — why the tap on a phone is instant.
- [cli-sms.md](cli-sms.md) — the same behaviour from an agent.
