The Problem

Mobile users who need AI‑driven chat, image creation, vision, or transcription must trust cloud services that ship data off‑device. For privacy‑sensitive or bandwidth‑constrained scenarios this is unacceptable, yet building a fully offline stack on Android/iOS is non‑trivial.

What This Does

off-grid-mobile bundles on‑device LLMs, Stable Diffusion, Whisper, and a small vision stack into a single React‑Native app. The core entry point is App.tsx, which bootstraps the UI and calls initializeApp (also in App.tsx). Model binaries live under android/app/src/main/assets/ (e.g., ggml-hexagon/*.so, qnnlibs/*.so) and are managed by src/services/modelManager.ts. UI screens such as src/screens/ChatScreen.tsx and src/screens/ModelsScreen.tsx render the chat UI and model download UI respectively. Shared constants, theme definitions, and TypeScript types reside in hub modules src/constants/index.ts, src/theme/index.ts, and src/types/index.ts.

How It Is Wired

Execution starts at App.tsxinitializeApp (line 57). initializeApp creates the app‑wide stores, then calls initialize in src/services/modelManager.ts, which ensures a model‑cache directory via RNFS.mkdir and triggers any pending downloads.

Key call‑graph hotspots:

FunctionCallersReach
showAlert55 places (e.g., CustomAlert.tsx)UI‑wide notification
getState39 places (e.g., ChatScreen.tsx, ModelCard.tsx)Central store access
useTheme / useThemedStyles39 / 31 placesTheme propagation
isModelLoaded21 places (model selector, generation flow)Guard before inference
generateImage10+ places (image‑gen UI) → updateState, isCurrentlyGeneratingImage pipeline

File‑level responsibilities (largest blast radius first):

  • src/theme/index.ts – defines getTheme, useTheme; imported by 35 modules (hub).
  • src/constants/index.ts – 36 dependents; holds static config used throughout.
  • src/types/index.ts – type definitions consumed by 35 modules.
  • src/services/modelManager.ts – 39 functions, handles filesystem I/O for model download/unpack.
  • src/services/llm.ts – 33 functions, prepares LLM session directories and computes optimal thread/batch sizes.

Import cycles exist among src/theme/index.ts, src/stores/index.ts, and src/services/index.ts (11 modules in total). This means a change in any of these files can trigger recompilation of the entire dependency graph and risks runtime circular‑reference errors.

Deep nesting (max depth 9) appears in src/services/activeModelService.ts, src/screens/HomeScreen.tsx, and the native Kotlin download manager, making the control flow hard to follow.

Oversized files (src/services/llm.ts, src/services/modelManager.ts, src/screens/ChatScreen.tsx) exceed 700 lines, concentrating many responsibilities and increasing change impact.

Duplicated 6‑line test blocks are scattered across contract and unit tests, indicating DRY violations.

How To Use It

# Clone the exact repo
git clone https://github.com/moses-y/off-grid-mobile
cd off-grid-mobile

# Install JS dependencies
npm install

# Android build
cd android && ./gradlew clean && cd ..
npm run android   # launches Metro and builds the APK

# iOS build (macOS only)
cd ios && pod install && cd ..
npm run ios       # launches Metro and builds the app via Xcode

The README’s “Install” section confirms these commands. No additional environment variables are required; model files are downloaded at runtime by modelManager.ts.

Real‑World Use

A field‑worker installs the APK on a rugged Android phone, opens the app, and selects a GGUF model in Models → Download. The UI calls downloadModelmodelManager.ts → native DownloadManagerModule.kt, which writes to the app’s private storage. Once complete, the worker launches Chat, speaks a query, and useWhisperTranscription (via whisper native module) returns text without any network traffic. The same flow can be switched to image generation, invoking imageGenerator.ts → native StableDiffusion libs.

Code Health & Issues

  • Critical – Private key committed (android/app/debug.keystore).
  • High – GitHub Actions not pinned to commit SHAs (.github/workflows/*).
  • High – CI pushes directly to default branch (release-ios.yml).
  • Medium – No least‑privilege GITHUB_TOKEN permissions (ci.yml).
  • Medium – No Dependabot/Renovate configured.
  • Medium – No dependency‑vulnerability scan in CI.
  • Medium – No pre‑commit secret‑leak gate.
  • Medium – Checkout step keeps token (persist-credentials missing).
  • Low – No job timeout limits in CI workflows.
  • High – Import cycles among theme, stores, and services.
  • High – Hub modules (constants, theme, types) have very high fan‑in.
  • High – Deep nesting (max depth 9) in key service files.
  • High – Oversized service and screen files (> 700 LOC).
  • High – Repeated test code blocks across contracts and unit tests.

The Bottom Line

off-grid-mobile delivers a functional, fully offline AI suite for mobile, with a solid React‑Native foundation and native model integration. The codebase works but suffers from architectural smells—import cycles, large hub modules, deep nesting, and oversized files—that will increase maintenance cost. Security hygiene needs immediate attention (private key, CI permissions). It is suitable for teams ready to invest in refactoring and hardening before production deployment.