Skip to content

Push notifications for the bb mobile app, end to end - #1989

Draft
SawyerHood wants to merge 1 commit into
mainfrom
bb-mobile-4-push
Draft

Push notifications for the bb mobile app, end to end#1989
SawyerHood wants to merge 1 commit into
mainfrom
bb-mobile-4-push

Conversation

@SawyerHood

@SawyerHood SawyerHood commented Aug 20, 2026

Copy link
Copy Markdown
Collaborator

Stack layer 4 of 4 for the bb mobile app (stack #1990). Prerequisite: #1988 (the app). This layer holds most of the server changes so it can be reviewed and landed separately from the app.

What was wrong

bb has no way to notify a phone when a thread needs attention: there is no device-token storage, no sender, and no client registration. The web/PWA only has in-session signals (WebSocket changes, GET /system/attention).

What changed

Server owns the policy; no daemon change (HOST_DAEMON_PROTOCOL_VERSION untouched).

  • packages/db: push_subscriptions table (0104_push_subscriptions, Drizzle-generated migration + snapshot) and data helpers with in-memory tests.
  • packages/server-contract + packages/domain: GET/POST/DELETE /api/v1/notifications/push-subscriptions schemas (strict; POST upserts by Expo token), pushNotificationData {kind, projectId, threadId}.
  • apps/server: routes + services/notifications/push-sender.ts — sends through the Expo Push API (https://exp.host/--/api/v2/push/send, batched, DeviceNotRegistered cleanup) on three triggers: new pending interaction, turn finished (latestAttentionAt), thread error / provider failure; coalesced per thread (2 s, strongest kind wins); skipped when any client read the thread after the trigger, the interaction resolved, the thread became active again, or was archived/deleted. Title = thread title, body = short preview. Config BB_PUSH_NOTIFICATIONS (default on) and BB_EXPO_PUSH_URL (test override) in packages/config + docs/configuration.md.
  • packages/sdk: sdk.notifications.pushSubscriptions.{list,add,remove}; packages/bb-app public SDK gains the area; apps/cli: bb notifications push-subscriptions list|add|remove [--json]; guide template + bb-cli SKILL per docs/cli-guide-and-skill.md.
  • apps/mobile: push client (expo-notifications registration per server profile through the SDK area, re-register on token change, unregister on profile removal, per-profile toggle in Settings → Notifications, foreground toast with Open, tap routing to the thread, client-derived badge) and the restored integration points in _layout.tsx / SettingsScreen.tsx / e2e flow. Registration stays off with a clear message until the app is built with an EAS project id.

How you verified

  • Tests: packages/db 407, apps/server push-sender + public notifications tests (fake exp.host; triggers, coalescing, read-skip, DeviceNotRegistered cleanup) + all test/public (336), sdk 97, cli 458, config 109, domain 145, server-contract 57, templates 43, bb-app 64, mobile 822 — all pass; drizzle-kit generate reports no schema drift.
  • pnpm exec turbo run typecheck lint for mobile/server/db/sdk/cli/config/domain/server-contract/bb-app/templates/app/integration-tests — pass (except the pre-existing conversation-outline-parity.test.ts typecheck failure on main from Keep mid-turn user exchanges visible after a turn completes #1657).
  • On the simulator (harness backend + Metro): phase1-shell, phase4b-send, phase5-links (asserts the Settings push row) pass; xcrun simctl push exercised the foreground toast, background banner + badge, and tap routing with a temporary fake EAS project id.
  • Not verifiable yet: real delivery through exp.host needs an EAS project + APNs key + a signed build on a physical iPhone.

AGENT GENERATED: by Claude Opus 5

@SawyerHood
SawyerHood force-pushed the bb-mobile-4-push branch 2 times, most recently from a4aac2d to a006cd6 Compare August 20, 2026 02:47
@SawyerHood
SawyerHood force-pushed the bb-mobile-4-push branch 2 times, most recently from 3a1f4f1 to 706c87d Compare August 20, 2026 03:13
Base automatically changed from bb-mobile-3-app to main August 20, 2026 03:43
SawyerHood added a commit that referenced this pull request Aug 20, 2026
Stack layer 3 of 4 for the bb mobile app (stack #1990). Prerequisites:
#1986 (`@bb/client-core`) and #1987 (core prep). Next layer: #1989 (push
notifications).

## What was wrong

bb has no native phone client. The PWA works on a phone but is bounded
by mobile-web limits (keyboard/viewport hacks, no push, no background
reconnect, no secure credential storage, no camera/photo attachments,
WebKit style-recalc stalls). Plan, decisions, and research:
`plans/bb-mobile-expo.md`, `plans/bb-mobile-research/`; execution log
with per-phase verification: `plans/bb-mobile-progress.md`.

## What changed

New `apps/mobile` (`@bb/mobile`, Expo SDK 57 / React Native 0.86 / Expo
Router / NativeWind v5, iOS first; ~81k lines of app code, ~20k of unit
tests, 26 Maestro flows). Everything else in this PR is toolchain/docs;
no server or web behavior changes.

- Connectivity: server profiles in SecureStore; Direct mode (LAN /
Tailscale / simulator) and bb connect (machine enrollment by QR/code →
desktop-session cookie in the native jar, renewal, re-pair); per-profile
SDK + realtime manager (ping/pong, watermark reconnect, AppState
suspend/resume) + QueryClient with realtime invalidation; global
mutation error toasts.
- Screens: drawer sidebar + home thread list (organize/sort, pinned,
unread glyphs, long-press actions), search, archived, compose with
pickers (project, provider, model+reasoning, permission mode, service
tier, environment incl. reuse/worktree/branch/path, machine), new
project + project settings + machine setup, thread detail (FlashList
timeline with every row kind via a renderer registry, native markdown,
native diffs, ANSI, lightbox, unread divider, ToC, prompt-stack cards),
prompt area (composer with mentions/typeahead/attachments/voice/drafts,
send/queue/steer/stop, queued messages, pending-interaction banner incl.
approvals, questions, ask-user-question and secret-request forms,
context banner with git/PR/parent/children, message/thread/git action
sheets, fork/handoff), workspace panel (Info, Diff, Files + previews,
terminal = bundled xterm WebView with RN-owned socket + accessory bar,
synced thread tabs), settings (general, appearance palettes from
`theme.css`, experiments, providers, usage, machines list/detail/add,
updates, plugins management + marketplaces, skills library/registry,
haptics), deep links (`bb://`, universal link mapping, thread-open
signal), outbound share.
- Design system: generated native theme tokens
(`scripts/generate-native-theme.ts` from `theme.css`, drift-tested),
primitives (sheets, action sheets, toasts, etc.), Inter + Fira Code,
hugeicons.
- Toolchain: Metro resolves `@bb/*` from TS source (`source` condition
scoped to workspace packages), `pnpm patch` for
`expo-modules-jsi@57.0.4` on Xcode 26.2, scoped `lightningcss` override
for NativeWind v5, turbo/eslint/prettier wiring,
`.github/workflows/mobile-e2e.yml` (label `mobile-e2e` / nightly;
Release build + Maestro) and `mobile-runner-probe.yml`, `eas.json`
profiles, docs (`docs/platform-support.md`,
`docs/repository-overview.md`).
- Early access: the bb-side pairing surfaces (Settings → Remote access →
Add mobile device, `bb connect machine-code`) are behind the `mobileApp`
experiment from #1987; the app's own Settings → Experiments screen lists
that toggle too (it is shared server state).
- Not in this layer: push notifications (#1989). Not yet: Android,
plugin frontends (SPA-in-WebView planned), inbound share (needs a native
rebuild), TestFlight (needs an EAS account).

## How you verified

- `pnpm exec turbo run typecheck lint test --filter=@bb/mobile` — 794
tests / 117 files, 0 lint findings.
- Every phase was built by parallel agents and independently
re-verified; the full Maestro regression (26 flows) passed on the iPhone
17 Pro simulator (iOS 26.3) against the seeded harness backend
(`tests/integration/mobile-e2e/backend.ts`) and the connect stub gate;
results table and screenshots list in `plans/bb-mobile-progress.md`.
Connect enrollment was also exercised against the real `bee.getbb.app`.
- On this layer specifically (no push): `phase1-shell`, `phase4b-send`,
`phase5-links` flows re-run and pass.
- Known gap carried in the log: on bb connect profiles the left-edge
drawer swipe can also press the home row under the touch (Direct
profiles are fine).

> AGENT GENERATED: by Claude Opus 5

---------

Co-authored-by: Claude <noreply@anthropic.com>
Server: a `push_subscriptions` table (migration 0104) with `@bb/db` data
helpers, `@bb/domain` push types, `/api/v1/notifications/push-subscriptions`
(list / upsert-by-token / delete) in the server contract and routes, and a
push sender that listens to the notification hub and posts to the Expo Push
API when a thread gains a pending interaction, a root thread's turn finishes
and waits for input, or a run fails (2 s coalescing per thread, skipped when
the thread was read or the interaction answered, stale tokens pruned after a
failed delivery). `BB_PUSH_NOTIFICATIONS` / `BB_EXPO_PUSH_URL` server config
(startup-only, threaded through the bb-app launcher), the
`sdk.notifications.pushSubscriptions` area (plus the bb-app public SDK
façade), `bb notifications push-subscriptions list|add|remove`, guide /
skill / docs updates.

Mobile: the Expo push client — registration sync on connect / AppState /
token roll / toggle (pure policy in `src/data/notifications`, RN glue in
`src/notifications`), tap routing to the owning profile's thread, foreground
toast, app-icon badge, the one-time "Get notified" sheet, and the
Settings → Notifications per-server rows — wired into the root layout,
Settings screen, e2e reset, and the phase 5 links flow.

Co-Authored-By: Claude <noreply@anthropic.com>
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