This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Beacon is an offline-first emergency response app that runs on-device AI (Gemma 4 via LiteRT) to provide survival guidance without network connectivity. It spans three codebases: a React+TypeScript frontend, a Dart backend for offline business logic, and native Android (Kotlin) / iOS (Swift/Obj-C++) shells connected through Capacitor.
npm install # install frontend dependencies
npm run dev # start Vite dev server
npm run build # typecheck + production build (output: dist/)
npm test # run frontend tests (Vitest)dart pub get # install Dart dependencies
dart test # run all Dart tests
dart test test/path_test.dart # run a single Dart test filenpm run mobile:build # build web → sync Capacitor → validate native projects
npm run mobile:android # build + open Android Studio
npm run mobile:ios # build + open Xcode
npm run mobile:android:release # full release APK + AAB
npm run mobile:android:release:github # lightweight ARM64-only APK (no bundled model)cd android && ./gradlew testDebugUnitTest assembleDebugGitHub Actions runs npm test, npm run build, dart pub get, and dart test on push to main and on PRs.
User input/photo → React UI → BeaconEngine (retrieval + prompt composition)
→ Capacitor bridge → Native plugin (Android/iOS) → LiteRT local inference
→ Response with evidence grounding → React UI
App.tsx— root component, manages chat state and model lifecyclesrc/lib/beaconEngine.ts— core engine: knowledge retrieval, evidence bundling, semantic query matching, prompt compositionsrc/lib/capacitorBridge.ts— Capacitor JSBridge abstraction for native communicationsrc/lib/session.ts— conversation session state and memory managementsrc/lib/knowledgeBase.ts— offline knowledge card indexing and searchsrc/lib/scenarioHints.ts— scenario categorization (20+ emergency patterns)src/lib/types.ts— shared TypeScript types (messages, model responses, configs)src/i18n/— 20-language support;messages.tsis the main catalog (~100K lines),languages.tsis the language registry
Contract-based architecture with dependency injection (no singletons):
lib/src/contracts/— interfaces:ModelRuntime,KnowledgeStore,MeshTransport,ModelDownloaderlib/src/services/—TriageService,ModelManagerService,PowerModeService,SosServicelib/src/rag/— offline retrieval pipeline for evidence groundinglib/src/models/— domain objects (emergency, evidence, knowledge, SOS)lib/src/mesh/— peer-to-peer SOS broadcast
BeaconNativePlugin.kt— Capacitor plugin exposing LiteRT inference to JSBeaconPromptComposer.kt— multilingual prompt generationBeaconSessionMemoryManager.kt— native-side context persistenceBeaconModelFiles.kt— model asset staging and validation
BeaconNativePlugin.m— Obj-C++ LiteRT bridgeBeaconLiteRtSafeBridge.mm— Metal GPU acceleration safety wrapper
- Offline-first: all core functionality must work without network. Never introduce cloud-only fallbacks for emergency guidance.
- No fake AI fallback: do not generate canned or fake model responses when the model is unavailable.
- Panic-proof UI: user-facing language must be simple, clear, and calming. High-contrast OLED-friendly palette (#000000 background).
- RTL support: Arabic locale requires right-to-left layout handling.
- Knowledge base changes: add new sources through
scripts/build_offline_knowledge.mjsand the manifest — never hand-editgeneratedKnowledge.ts. - Model artifacts: Android stages LiteRT model files (Gemma 4 E2B/E4B) via Gradle tasks; iOS uses a dynamic xcframework with optional Metal GPU.
- Concurrent inference:
runTriage,handleQuickAction, andhandleVisualAnalysisall guard against overlapping streaming sessions. Panic and camera buttons are disabled while streaming. - Model sync retry cap: the native model sync loop has a 20-retry (30s) ceiling to prevent infinite polling. After timeout the model manager opens with an explicit error.
- Accessibility: all interactive elements have
:focus-visibleoutlines,aria-labelattributes, andprefers-reduced-motionsupport. Chat input placeholder meets WCAG AA 4.5:1 contrast. - i18n quality: French and German translations must use proper diacritics (é, è, ê, ü, ö, ß). Add all new i18n keys to every language in
messages.ts.