Skip to content

Mobile: Inbox on the phone, served by the desktop - #1287

Draft
Kaloyanes wants to merge 14 commits into
hardbeat920:mainfrom
Kaloyanes:pr/phone-inbox
Draft

Kaloyanes wants to merge 14 commits into
hardbeat920:mainfrom
Kaloyanes:pr/phone-inbox

Conversation

@Kaloyanes

@Kaloyanes Kaloyanes commented Nov 1, 2026 •

Copy link
Copy Markdown
Contributor

What changed

The phone gets an Inbox: a third page on each project, next to New session and Sessions. It lists the same GitHub, Linear, Jira, GitLab and Azure DevOps items as the desktop Inbox. The desktop serves it through the pairing link, so the phone never holds provider credentials.

Phone

  • List: All / Needs me / Done segments, source and project chips, search, and grouping (a SwiftUI picker on iOS, ChoiceMenu on Android). Swipe a row to mark it done, snooze it, or mark it read or unread, with an Undo toast. There are also offline and error banners, a loading skeleton, and pull to refresh.
  • Item sheet: the body, diff and checks of an item, plus "Start an agent", which opens a session on the desktop seeded with the item.
  • Store: a polling store with a local cache and optimistic marks, rolled back if the desktop refuses.
  • Push: a new inbox notification category. Tapping one opens the item.
  • Shared UI: the toast and swipe buttons move to ui/ (UndoToast, SwipeAction, useToast). New GlassSegments and GlassMenuButton. LiquidView gains interactive, so native glass reacts to touch without an onPress. useKeepsSwipe keeps a sideways-scrolling chip row from turning the page.
  • Older desktops: the phone only shows the Inbox when the catalog says inbox: true, so an older desktop app leaves it out.

Desktop host

  • Methods: inbox.list, inbox.item, inbox.diff, inbox.checks, inbox.mark, inbox.start and inbox.media, in shell/mobile_host/inbox.rs. The wire types and triage state live in monocode-core (mobile/inbox.rs, inbox/patch.rs), and the protocol is written up in docs/native/mobile-inbox-protocol.md.
  • List answers: the list comes from the cached snapshot right away and never waits on a provider. A stale snapshot starts a background refresh. refresh: true (pull to refresh) waits for a fresh fetch, 20 s at most.
  • Its own fetch: if the desktop Inbox's filters (assigned to me, one author, open only, hidden teams) or its project list would hide rows, the host keeps a second snapshot for the phone. That snapshot is fetched with default filters over the desktop's projects and the Monos' projects. Otherwise the desktop's snapshot is reused and nothing extra runs.
  • Triage: done, snooze and read state set on the phone are saved with the desktop's own read state, so both show the same thing.
  • Attention: GitHub items that ask the viewer for a review, mention them or assign them are marked. New items like that, or failed pipelines, are pushed to phones unless the desktop Inbox is on screen.
  • Images: images and avatars go through the existing allowlisted media fetcher, from an opaque key. They're downscaled for the phone, and SVG is refused.

Depends on #1225

The phone rows show each item's author, and the host reads the viewer login per provider. Both (Item.author, Snapshot.viewers) come from #1225 (Inbox author filter). This branch merges #1225's head, so the diff here includes it until #1225 lands. Review the commits after "Merge #1225 …".

Stacked on top of this: #1288 (Monos in sessions, archive with Undo).

How it was tested

  • cargo clippy -p monocode-core -p monocode-gpui --all-targets --profile native-dev -- -D warnings: clean.
  • cargo test -p monocode-core: 689 passed. Native inbox tests: 14 passed, including the phone triage and separate-fetch tests.
  • cargo fmt --check: clean for the touched files. main.rs and tests/review_wheel_tmp.rs are already unformatted on main and left alone.
  • mobile: tsc --noEmit clean, npm run lint 0 errors (2 existing warnings in dictation.ts), and vitest 32 files / 224 tests passed.
  • Not run: the full cargo test for monocode-gpui (disk space on the build machine) and an on-device run of this exact branch.

Kaloyanes and others added 14 commits October 29, 2026 21:01
…nflict-pr-head

# Conflicts:
#	crates/monocode-gpui/src/inbox.rs
…tic marks, fixtures

Phone side of the shared inbox contract: protocol types and request
helpers, scope/group/mark/undo/stale logic, a store with persisted last
page, offline handling and polling at the catalog's cadence, a provider,
and a fixture client behind EXPO_PUBLIC_INBOX_FIXTURES.

Co-Authored-By: Claude <noreply@anthropic.com>
Persist per-item done and snooze state next to Seen, add the slim
camelCase response types and pure list/page/slim/diff functions for the
phone Inbox, share the provider patch parser, and document the protocol.
… them

The list only knew items by repository, so the Inbox had no reason to show
for GitHub. Add best-effort review-requested and mentions searches per
repository and set attention_reason on the matching rows.
Add the inbox.list/item/diff/checks/mark/start/media handlers in
mobile_host/inbox.rs. A list is the cached snapshot, answered at once, with a
background refresh through the desktop Inbox; provider reads run off the UI
thread; triage is saved with the desktop's read state; inbox.start reuses the
session.start path and its command-id dedupe; images and avatars resolve
through the allowlisted media adapters from an opaque key or index.
… the catalog

Items the NotificationTracker reports as newly appeared and that carry a
review request, mention, assignment or failed pipeline go out as category
`inbox` with data {kind, key}, unless the desktop Inbox is on screen. The
workspace catalog gains `inbox: true`.
The undo toast, its timer and the swipe-action buttons move to ui/ so the
Sessions list can use the same ones. Adds an archive icon.
…ld hide rows, pull to refresh, grouping menu and glass segments

The host serves the phone from the desktop Inbox's snapshot only while the
desktop's filters and projects would not narrow it; otherwise it keeps a
second snapshot fetched with default filters over the desktop's and the
Monos' projects. A watching phone refreshes it after 30 s. `inbox.list`
takes `refresh: true` for pull to refresh and answers when that fetch ends
(20 s at most). On the phone the scope switch becomes GlassSegments, the
grouping menu moves to GroupMenu (SwiftUI picker on iOS, ChoiceMenu on
Android) behind a shared GlassMenuButton, chip rows keep the page swipe out
of their drag (useKeepsSwipe), and LiquidView gains `interactive` for native
glass without an onPress. Also runs cargo fmt over the Inbox files.
@coderabbitai

coderabbitai Bot commented Nov 1, 2026

Copy link
Copy Markdown
Contributor

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant