agentleFS
garfiecgarfiec/Librechat-Mobile/app/CLAUDE.md

Librechat-Mobile / app

CLAUDE.md149 starsChanged 7 days agoApache-2.0View on GitHub

Single Activity; MainActivity is the sole entry point. Depends on :shared, all :core:* and :feature:*.

The file

Files
CLAUDE.md

App Module

Single Activity; MainActivity is the sole entry point. Depends on :shared, all :core:* and :feature:*.

Navigation

LibreChatNavHost.kt (this module) wraps the shared LibreChatNavHost via a content lambda, adding deep links, share-intent routing and phone/tablet branching. The shared module owns the rest (Navigator, NavHostViewModel, MainNavDisplay, PhoneLayout, TabletLayout, drawer, all entry providers): see shared/CLAUDE.md. Feature modules get onNavigate/onBack lambdas, never NavBackStack.

Layout modes

  • Tablet layout at 680dp+ wide and 480dp+ tall (320dp sidebar + 360dp pane), else the phone drawer. Android picks here, iOS in the shared host, both via usesSidebarLayout (TabletLayout.kt): change the breakpoint there, not at a call site.
  • iOS switches layouts in place, so both layouts must place the one rememberMovableNavDisplay instance (a MainNavDisplay leaving composition clears every entry's ViewModels). Keep the layout choice in the host's own composition, not a subcomposition like BoxWithConstraints — only that case is covered (MovableNavDisplayTest).

Deep links

  • Scheme librechat://; hosts conversation/{id}, artifact/{uuid}, oauth.
  • Single source of truth: DeepLinks.resolve() (:shared/commonMain) → DeepLinkResolution (Route(target, requiresAuth) / Consumed / None). Add a link as one branch there; do NOT reintroduce a per-host allowlist here.
  • MainActivity.handleDeepLink() (and onNewIntent) resolves to accept/drop (DeepLinkUriAdapter.kt), then LibreChatNavHost resolves again to place the target. requiresAuth links go to login when signed out; artifact links open signed out. oauth is Consumed (sign-in is in-app WebView); keep the mapping so links from older builds still bring the app forward.

Share intents

  • MainActivity.handleShareIntent() only stages on ShareIntentConsumer. LibreChatNavHost reads navigator.currentRoute and calls dispatchTo(conversationId) (null = NewChat landing), navigating to a chat first if none is on screen.
  • A share must be addressed, never broadcast: several ChatViewModels are alive (the landing sits beneath an open Chat), and an unaddressed share goes to whichever collects first. Each screen uses sharesFor(conversationId); addressing lives in the nav host.
  • Drive delivery off ShareIntentConsumer.undelivered, not an activity counter: the launch intent is processed only on a fresh start, so a recreation during the theme/locale warm-up would strand the share.

Server banners

  • GET /api/banner returns one object or a 200 with empty body and no Content-Type, never an array. BannerApi reads the raw body; anything else still throws, so a proxy answer can't read as "no banner".
  • NavHostViewModel fetches via BannerRepository on init, account switch and auth-complete; no timer.
  • The server applies displayFrom/displayTo and type: 'banner'; don't re-check client-side (clock skew).
  • Dismissal lives in BannerStateHolder: in-memory (serverId, bannerId) key. Both halves are needed: by banner alone, a bannerId shared across servers arrives pre-dismissed; cleared on switch, A's banner returns. clearForAccountChange() drops the banner but must not touch dismissals.
  • BannerDisplay takes a nullable banner and decides visibility itself; don't hoist the null check (kills the enter/exit animation).
  • One treatment, secondaryContainer/onSecondaryContainer. Don't re-introduce a type-keyed palette or hardcoded hex (server only sends type: "banner"; fixed colours ignore the accent seed and dark mode).
  • persistable hides dismiss; a banner with no bannerId is not rendered.

Other

  • Session (shared NavHostViewModel): start at NewChat if signed in, else ServerUrl; sessionExpired clears the whole back stack into auth; drawer gestures are off during auth.
  • Top-level routes: NewChat, Conversations (drawer body), AgentMarketplace, Files, SettingsTabbed (drawer footer), all registered in shared MainNavDisplay.
  • ConnectivityObserver (injected into MainActivity) drives the offline banner.
  • PresetManager route is registered in SettingsNavigation.kt (Settings → Chat).

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.