State Architecture
Off Grid uses Zustand for state management with AsyncStorage persistence. State is split across five stores, each with a single responsibility.Store Overview
appStore
Path: src/stores/appStore.ts:122 Responsibilities:- Downloaded models (text, image, Whisper)
- Active model IDs
- Settings (temperature, context length, GPU config, image gen params)
- Device hardware info (RAM, CPU)
- Gallery (generated images metadata)
- Background generation state (progress, status, preview path)
Schema
Key Actions
Model Management:Persistence Strategy
downloadProgress(ephemeral download state)deviceInfo(recalculated on app start)isGeneratingImage,imageGenerationProgress,imageGenerationStatus(runtime state)
chatStore
Path: src/stores/chatStore.ts:48 Responsibilities:- Conversations (title, messages, metadata)
- Streaming state (current streaming message, thinking indicator)
- Message operations (add, update, delete)
Schema
Key Actions
Conversation Management:Persistence Strategy
projectStore
Path: src/stores/projectStore.ts Responsibilities:- Custom system prompts (called “projects”)
- Active project selection
Schema
Key Actions
authStore
Path: src/stores/authStore.ts Responsibilities:- Passphrase lock state
- Authentication status
Schema
whisperStore
Path: src/stores/whisperStore.ts Responsibilities:- Whisper model selection (Tiny, Base, Small)
- Transcription configuration
Schema
Service-Store Synchronization
Services update stores to maintain UI reactivity. The pattern is unidirectional: services write to stores, UI components read from stores.Pattern: Service Updates Store
Why Both Service State AND Store State?
Service state:- Maintains generation across component unmounts
- Holds complex objects not suitable for AsyncStorage persistence
- Allows services to communicate with each other
- Triggers React re-renders via Zustand subscriptions
- Persists critical fields to AsyncStorage
- Provides global access to UI components
Data Flow Diagram
Persistence Implementation
AsyncStorage Adapter
Zustand’spersist middleware uses createJSONStorage(() => AsyncStorage) to automatically save/restore state.
Migration Example
When adding new fields or changing defaults, use themerge option: