Skip to content

feat(client): persist offline environment data and mobile preferences#3795

Merged
juliusmarminge merged 29 commits into
mainfrom
agent/offline-environment-cache
Jul 9, 2026
Merged

feat(client): persist offline environment data and mobile preferences#3795
juliusmarminge merged 29 commits into
mainfrom
agent/offline-environment-cache

Conversation

@juliusmarminge

@juliusmarminge juliusmarminge commented Jul 8, 2026

Copy link
Copy Markdown
Member

Summary

Adds durable offline environment data, centralized mobile preferences, and scoped client-cache management.

Offline environment data

  • Persists the last complete server configuration, including provider and model metadata, per environment.
  • Persists complete, unfiltered Git ref lists for offline branch selection.
  • Hydrates cached server configuration and refs while disconnected, then replaces them with live data after reconnecting.
  • Debounces server configuration writes and flushes pending data during teardown.
  • Uses live errors while connected instead of silently falling back to stale refs.
  • Uses IndexedDB version 4 stores on web and a schema-versioned Expo SQLite database on mobile.
  • Runs the mobile database through one scoped Effect layer with WAL enabled and a managed close finalizer.
  • Reclaims the obsolete mobile file-cache directories on the first SQLite migration.

Mobile preferences

  • Centralizes preference loading and updates behind an Effect service and keep-alive atoms.
  • Stores non-secret preferences in SQLite and migrates the legacy SecureStore preference blob on first read.
  • Keeps credentials, connection metadata, and device identity in SecureStore.
  • Migrates appearance preferences away from component-level hydration effects.
  • Preserves optimistic updates made before the initial preference read completes.
  • Persists collapsed home-screen project groups through the shared preference state so they survive restarts.

Client storage controls

  • Adds App → Client Storage settings with aggregate and per-environment cache inspection.
  • Supports clearing one environment cache or all client caches.
  • Cache clears intentionally preserve environment connections, credentials, account data, and app preferences.

Impact

Mobile users can configure pending tasks with their last-known model and branch while offline, inspect locally cached data, and reclaim it without disconnecting environments. Web clients share the durable environment-cache behavior. Mobile preferences now have one async state owner with predictable hydration and update semantics.

Validation

  • vp check
  • vp run typecheck
  • vp run lint:mobile
  • vp test apps/mobile/src (76 files, 427 tests)
  • React Doctor on the changed React surface (no diagnostics)
  • Expo public config evaluation

Note

Medium Risk
One-time SQLite and legacy file-cache migration on app start can leave partial data if migration fails; preference SQLite/SecureStore reconciliation affects appearance and Live Activity behavior across upgrades.

Overview
Mobile offline data moves from document-directory JSON files into Expo SQLite (expo-sqlite plugin, t3code-client.db) via a new MobileDatabase service and a dedicated EnvironmentCacheStore implementation for shell/thread snapshots, server config, and VCS refs. Legacy file caches are migrated on first DB upgrade; corrupt rows are dropped on read. The old inline cache logic is removed from connection/storage.ts; EnvironmentCacheStore is composed through persistence/layer and the app runtime.

Persistence refactor deletes lib/storage.ts in favor of MobileSecureStorage, MobileStorage, and MobilePreferencesStore (SQLite for preferences with SecureStore fallback/reconciliation). Connection catalog storage now yield*s secure storage instead of injected storage objects. persistence/imperative.ts keeps Promise APIs for legacy call sites on top of the shared managed runtime.

Preferences UX adds keep-alive atoms (mobilePreferencesAtom / updateMobilePreferencesAtom) with optimistic patches, wires appearance and settings to them, persists collapsed home project groups, and adds Settings → Client Storage to inspect and clear per-environment or all offline caches without touching connections/credentials.

Live Activities / cloud link uses linkEnvironmentToCloudWithPreference with explicit flags, updateAgentAwarenessRegistrationPreferences with in-flight preference overrides, and rolls back local and relay state when toggling fails.

Build/tooling: EAS profiles set NODE_OPTIONS=--max-old-space-size=4096; new dev:client:preview script. Effect service conventions doc gains dependency/runtime boundary guidance. Minor CursorAdapter test splits JSON log assertions.

Reviewed by Cursor Bugbot for commit 9dd6245. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Persist offline environment data and mobile user preferences in the mobile app

  • Introduces a SQLite-backed MobileDatabase service and a structured EnvironmentCacheStore to cache server configuration and VCS branch lists per environment, enabling cached data to be shown when offline and refreshed when connected.
  • Adds MobilePreferencesStore backed by MobileSecureStorage (expo-secure-store) with optimistic update support; preferences now survive app restarts and failed saves attempt rollback.
  • Replaces the deleted src/lib/storage.ts with a structured persistence layer under src/persistence/ comprising mobile-database.ts, mobile-preferences.ts, mobile-secure-storage.ts, mobile-storage.ts, and a unified layer.ts wired into the app runtime.
  • Persists home screen project group collapse state and appearance preferences via the new atom-based preferences state (mobilePreferencesAtom); Live Activity preference changes now propagate to all linked cloud environments and revert locally and remotely on failure.
  • Adds a "Client Storage" settings screen (SettingsClientStorageRouteScreen) showing per-environment SQLite cache usage with options to clear individual or all environment caches.
  • Extends the web EnvironmentCacheStore and client-runtime persistence contracts to include loadServerConfig/saveServerConfig and loadVcsRefs/saveVcsRefs methods.
  • Risk: IndexedDB schema version bumped from 2 to 4 on web; existing users will trigger a DB upgrade creating new server-config and vcs-refs object stores.

Macroscope summarized 9dd6245.

@coderabbitai

coderabbitai Bot commented Jul 8, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 4482278b-f0ec-4fe3-abf4-d60417ebb015

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch agent/offline-environment-cache

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:XL 500-999 changed lines (additions + deletions). labels Jul 8, 2026
@juliusmarminge
juliusmarminge marked this pull request as ready for review July 8, 2026 11:39
@macroscopeapp

macroscopeapp Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

Diff is too large for automated approval analysis. A human reviewer should evaluate this PR.

You can customize Macroscope's approvability policy. Learn more.

Comment thread packages/client-runtime/src/state/vcs.ts
Comment thread packages/client-runtime/src/state/vcs.ts
Comment thread apps/mobile/src/connection/storage.ts Outdated
Comment thread packages/client-runtime/src/state/vcs.ts Outdated
Comment thread packages/client-runtime/src/state/vcs.ts
Comment thread packages/client-runtime/src/state/vcs.ts Outdated
Comment thread packages/client-runtime/src/state/vcs.ts Outdated
Comment thread packages/client-runtime/src/state/vcs.ts
Comment thread packages/client-runtime/src/state/vcs.ts
Move home collapse persistence and shared mobile preference state onto the persistence-focused branch. Model preference storage as an Effect service and expose hydration through keep-alive atoms.

Co-authored-by: codex <codex@users.noreply.github.com>
@juliusmarminge juliusmarminge changed the title Persist offline environment metadata feat(client): persist offline environment data and mobile preferences Jul 9, 2026
juliusmarminge and others added 2 commits July 9, 2026 07:36
Use idiomatic Effect services and errors, make optimistic preference rollback concurrency-safe, avoid stale teardown writes, and self-heal bounded mobile cache files.

Co-authored-by: codex <codex@users.noreply.github.com>
Co-authored-by: codex <codex@users.noreply.github.com>
@juliusmarminge juliusmarminge added the 🚀 Mobile Continuous Deployment Trigger Expo preview build label Jul 9, 2026
Regenerate the workspace lockfile with both desktop packaging updates and Expo SQLite persistence.\n\nCo-authored-by: codex <codex@users.noreply.github.com>
Comment thread apps/mobile/src/lib/storage.ts Outdated
Comment thread packages/client-runtime/src/state/server.ts
Comment thread apps/mobile/src/persistence/mobile-database.ts Outdated
Comment thread apps/mobile/src/features/home/HomeScreen.tsx
Comment thread apps/mobile/src/state/preferences.ts
@github-actions github-actions Bot added size:XXL 1,000+ changed lines (additions + deletions). and removed size:XL 500-999 changed lines (additions + deletions). labels Jul 9, 2026
Co-authored-by: codex <codex@users.noreply.github.com>
Comment thread apps/mobile/src/lib/storage.ts Outdated
Co-authored-by: codex <codex@users.noreply.github.com>
Comment thread apps/mobile/src/lib/storage.ts Outdated
juliusmarminge and others added 3 commits July 9, 2026 09:21
Co-authored-by: codex <codex@users.noreply.github.com>
Co-authored-by: codex <codex@users.noreply.github.com>
Co-authored-by: codex <codex@users.noreply.github.com>
Comment thread apps/mobile/src/features/settings/SettingsRouteScreen.tsx
Co-authored-by: codex <codex@users.noreply.github.com>
Comment thread apps/mobile/src/features/settings/SettingsRouteScreen.tsx Outdated
Co-authored-by: codex <codex@users.noreply.github.com>
Comment thread apps/mobile/src/features/agent-awareness/liveActivityPreferences.ts
Co-authored-by: codex <codex@users.noreply.github.com>
Comment thread apps/mobile/src/features/agent-awareness/liveActivityPreferences.ts
Comment thread apps/mobile/src/features/agent-awareness/liveActivityPreferences.ts
Co-authored-by: codex <codex@users.noreply.github.com>
Comment thread apps/mobile/src/features/settings/SettingsRouteScreen.tsx

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix is ON, but a cloud agent failed to start.

Reviewed by Cursor Bugbot for commit 43884b5. Configure here.

Comment thread apps/mobile/src/features/settings/SettingsRouteScreen.tsx Outdated
Co-authored-by: codex <codex@users.noreply.github.com>
@juliusmarminge
juliusmarminge merged commit 2250e3e into main Jul 9, 2026
21 of 23 checks passed
@juliusmarminge
juliusmarminge deleted the agent/offline-environment-cache branch July 9, 2026 09:23
eyeveil added a commit to eyeveil/t3code that referenced this pull request Jul 9, 2026
… + desktop packaging)

Merge upstream/main into the fork. Notable upstream changes: Clerk stack
upgrade (pingdotgg#3821), mobile offline persistence + preferences refactor (pingdotgg#3795),
mobile PR number badges + a11y (pingdotgg#3827, pingdotgg#3828), font embedding (pingdotgg#3823),
worktree metadata preservation during branch sync (pingdotgg#3822), codex reasoning
labels (pingdotgg#3824), desktop native optional dependency packaging (pingdotgg#3816).

Preserved fork features across conflicts: iOS personal-team build support,
Material3 dynamic accent theming, verbose work-log, mobile visible queue,
MarkdownCodeBlock, native Android composer/header layout, and the fork's
asar:false + afterPack/afterSign node_modules copy hooks for desktop packaging.
Lockfile regenerated on pnpm 11 (upstream lock as base).
wizzoapp Bot added a commit to agriffiths-bots/t3code that referenced this pull request Jul 10, 2026
…-sync mocks

Upstream pingdotgg#3795 expanded the EnvironmentCacheStore interface with
loadServerConfig/saveServerConfig/loadVcsRefs/saveVcsRefs; add those
stubs to the fork-local shell-sync mock stores so typecheck passes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
wizzoapp Bot added a commit to agriffiths-bots/t3code that referenced this pull request Jul 10, 2026
… subscription

Upstream pingdotgg#3795's makeEnvironmentServerConfigState subscribed to
subscribeServerConfig with {} instead of the fork-local shared
SERVER_CONFIG_SUBSCRIPTION_INPUT ({ supportsHeartbeat: true }). That
opts the quiet offline-persistence subscription out of the server's
keepalive frames (and diverges from the shared subscription key), so
idle transports/proxies could drop it and leave provider/model metadata
stale. Hoist the const above makeEnvironmentServerConfigState and pass
it at the subscription site so every consumer shares the same input.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
adamfgr pushed a commit to agriffiths-bots/t3code that referenced this pull request Jul 10, 2026
* Fix desktop native optional dependency packaging (pingdotgg#3816)

* [codex] Upgrade Clerk stack (pingdotgg#3821)

Co-authored-by: codex <codex@users.noreply.github.com>

* [codex] Preserve worktree metadata during branch sync (pingdotgg#3822)

Co-authored-by: codex <codex@users.noreply.github.com>

* feat(client): persist offline environment data and mobile preferences (pingdotgg#3795)

Co-authored-by: Julius Marminge <julius@mac.lan>
Co-authored-by: codex <codex@users.noreply.github.com>

* [codex] Label max and ultra reasoning (pingdotgg#3824)

Co-authored-by: codex <codex@users.noreply.github.com>

* fix(mobile): embed fonts and render project favicons reliably (pingdotgg#3823)

Co-authored-by: codex <codex@users.noreply.github.com>

* Show compact PR number badges in mobile thread rows (pingdotgg#3827)

Co-authored-by: codex <codex@users.noreply.github.com>

* Expose mobile PR indicator labels to accessibility (pingdotgg#3828)

Co-authored-by: codex <codex@users.noreply.github.com>

* test(client-runtime): stub new EnvironmentCacheStore methods in shell-sync mocks

Upstream pingdotgg#3795 expanded the EnvironmentCacheStore interface with
loadServerConfig/saveServerConfig/loadVcsRefs/saveVcsRefs; add those
stubs to the fork-local shell-sync mock stores so typecheck passes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(client-runtime): pass heartbeat opt-in from offline server-config subscription

Upstream pingdotgg#3795's makeEnvironmentServerConfigState subscribed to
subscribeServerConfig with {} instead of the fork-local shared
SERVER_CONFIG_SUBSCRIPTION_INPUT ({ supportsHeartbeat: true }). That
opts the quiet offline-persistence subscription out of the server's
keepalive frames (and diverges from the shared subscription key), so
idle transports/proxies could drop it and leave provider/model metadata
stale. Hoist the const above makeEnvironmentServerConfigState and pass
it at the subscription site so every consumer shares the same input.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Patricio Gómez Meneses <107218376+Prgm-code@users.noreply.github.com>
Co-authored-by: Julius Marminge <julius0216@outlook.com>
Co-authored-by: codex <codex@users.noreply.github.com>
Co-authored-by: Julius Marminge <julius@mac.lan>
Co-authored-by: wizzoapp[bot] <254688279+wizzoapp[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
aaditagrawal pushed a commit to aaditagrawal/t3code that referenced this pull request Jul 10, 2026
…pingdotgg#3795)

Co-authored-by: Julius Marminge <julius@mac.lan>
Co-authored-by: codex <codex@users.noreply.github.com>
tarik02 added a commit to tarik02/t3code that referenced this pull request Jul 13, 2026
* Add middle-click close for right panel tabs (pingdotgg#3161)

Co-authored-by: Julius Marminge <jmarminge@gmail.com>

* fix: warm WSL before preflight in WSL-only backend mode (pingdotgg#3588)

* Add Claude Sonnet 5 as the default Claude model (pingdotgg#3620)

* Restore the ultrathink frame border effect (pingdotgg#3625)

* fix(dev): Fix electron dev launch and add test (pingdotgg#3662)

* Add adaptive split-view layout for iPad/mobile workspace (pingdotgg#3514)

Co-authored-by: codex <codex@users.noreply.github.com>
Co-authored-by: Julius Marminge <julius@mac.lan>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>

* fix(mobile): compile patched native pods from source on EAS (pingdotgg#3667)

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>

* Make the thread composer read as elevated liquid glass (pingdotgg#3668)

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>

* Upgrade Vite Plus and enable bundled dev opt-in (pingdotgg#3679)

* Surface pending tasks in mobile home and draft flow (pingdotgg#3670)

* fix(mobile): combined test branch — scroll, back-swipe, thread lists, computer switching (pingdotgg#3687)

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>

* Add repo-root favicon.svg so t3 code shows its own icon (pingdotgg#3683)

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>

* Load thread snapshots over HTTP before live sync (pingdotgg#3719)

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>

* Fix mobile legend anchor under automatic iOS insets (pingdotgg#3684)

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>

* Improve live activity routing and diagnostics (pingdotgg#3685)

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>

* Prevent Add Project sheet from collapsing on relayout (pingdotgg#3759)

* Use variant-specific splash icons in mobile app (pingdotgg#3762)

* Fix Expo widget asset wiring order (pingdotgg#3763)

* Extend Done display to 15 minutes and show up to 5 Live Activity banner rows (pingdotgg#3761)

* Clear VCS presentation state on finish (pingdotgg#3764)

* Lead with the outcome when no agents are active in the Live Activity (pingdotgg#3768)

* Add T3 Connect onboarding for mobile and web (pingdotgg#3765)

* Revert "Add T3 Connect onboarding for mobile and web" (pingdotgg#3776)

* Expose Clerk Google sign-in env vars to Expo (pingdotgg#3772)

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>

* Set up Cursor Cloud dev environment (web + Android toolchain) (pingdotgg#3755)

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Theo Browne <t3dotgg@users.noreply.github.com>

* Revert "Revert "Add T3 Connect onboarding for mobile and web"" (pingdotgg#3777)

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>

* Use rounded depth logo for production splash screen (pingdotgg#3780)

Co-authored-by: Cursor Agent <cursoragent@cursor.com>

* fix(release): stage pnpm 11 allowBuilds for desktop installs (pingdotgg#3781)

Co-authored-by: Cursor Agent <cursoragent@cursor.com>

* Upgrade Clerk toolchain to latest versions (pingdotgg#3785)

* fix(release): bump electron-builder so pnpm 11 deduped deps land in the asar (pingdotgg#3790)

* Fix desktop native optional dependency packaging (pingdotgg#3816)

* [codex] Upgrade Clerk stack (pingdotgg#3821)

Co-authored-by: codex <codex@users.noreply.github.com>

* [codex] Preserve worktree metadata during branch sync (pingdotgg#3822)

Co-authored-by: codex <codex@users.noreply.github.com>

* feat(client): persist offline environment data and mobile preferences (pingdotgg#3795)

Co-authored-by: Julius Marminge <julius@mac.lan>
Co-authored-by: codex <codex@users.noreply.github.com>

* [codex] Label max and ultra reasoning (pingdotgg#3824)

Co-authored-by: codex <codex@users.noreply.github.com>

* fix(mobile): embed fonts and render project favicons reliably (pingdotgg#3823)

Co-authored-by: codex <codex@users.noreply.github.com>

* Show compact PR number badges in mobile thread rows (pingdotgg#3827)

Co-authored-by: codex <codex@users.noreply.github.com>

* Expose mobile PR indicator labels to accessibility (pingdotgg#3828)

Co-authored-by: codex <codex@users.noreply.github.com>

* Fix truncated chat error alert layout (pingdotgg#3899)

* fix(marketing): show platform-appropriate commit shortcut on the website (pingdotgg#3644)

* [codex] Add Android mobile support (pingdotgg#3579)

Co-authored-by: Horus Lugo <horusgoul@gmail.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: maria-rcks <maria@kuuro.net>
Co-authored-by: Shivam Sharma <91240327+shivamhwp@users.noreply.github.com>
Co-authored-by: Ben Davis <45952064+bmdavis419@users.noreply.github.com>
Co-authored-by: Alex <me@pixp.cc>
Co-authored-by: codex <codex@users.noreply.github.com>
Co-authored-by: Julius Marminge <julius@mac.lan>

---------

Co-authored-by: Hugo Blom <6117705+huxcrux@users.noreply.github.com>
Co-authored-by: Julius Marminge <jmarminge@gmail.com>
Co-authored-by: Utkarsh Patil <73941998+UtkarshUsername@users.noreply.github.com>
Co-authored-by: Julius Marminge <julius0216@outlook.com>
Co-authored-by: Theo Browne <me@t3.gg>
Co-authored-by: codex <codex@users.noreply.github.com>
Co-authored-by: Julius Marminge <julius@mac.lan>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Theo Browne <t3dotgg@users.noreply.github.com>
Co-authored-by: Rowan <rowan@cardow.co>
Co-authored-by: Patricio Gómez Meneses <107218376+Prgm-code@users.noreply.github.com>
Co-authored-by: Jake Leventhal <jakeleventhal@me.com>
Co-authored-by: Vedank Purohit <VedankPurohit2@gmail.com>
Co-authored-by: Horus Lugo <horusgoul@gmail.com>
Co-authored-by: maria-rcks <maria@kuuro.net>
Co-authored-by: Shivam Sharma <91240327+shivamhwp@users.noreply.github.com>
Co-authored-by: Ben Davis <45952064+bmdavis419@users.noreply.github.com>
Co-authored-by: Alex <me@pixp.cc>
znoraka added a commit to znoraka/t3code that referenced this pull request Jul 13, 2026
Bring over upstream changes: Clerk stack upgrade + Google sign-in,
desktop release/packaging fixes (pnpm 11), mobile offline persistence
(pingdotgg#3795), font embedding (pingdotgg#3823), PR badge polish, T3 Connect onboarding,
and the rounded-depth production splash.

Conflict resolutions:
- apps/mobile/app.config.ts: kept fork's bundle-id/EAS/relying-party
  parametrization + OTA buildConfig; grafted in upstream font embedding
  and Clerk Google sign-in extras.
- connection/catalog-store.ts, storage.ts: took upstream's persistence
  rework (our fork's edits there were cosmetic on now-relocated code).
- splash-icon-prod.png: took upstream's newer rounded-depth logo (pingdotgg#3780).
- pnpm-lock.yaml: regenerated via pnpm 11.10.0 install.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🚀 Mobile Continuous Deployment Trigger Expo preview build size:XXL 1,000+ changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant