Off Grid v0.0.97
What's Changed in v0.0.97
Features
- feat(chat): collapsible list of tools sent to the model (29344bb)
- feat(mcp): max out context window when MCP tools are enabled (7e9d7d2)
- feat(tools): route MCP tools via on-device embedding model (ea127b1)
- feat: Pro Tools page + chat quick-settings Pro Tools entry (7658d6b)
- feat(pro): explain monthly cancellation via email, drop unused portal URL (1b49b07)
- feat(models): keep STT/TTS co-resident, evict only as a last resort (78145bf)
- feat(pro): ambient framing, July-flip pricing, management card, settings (404fbff)
- feat(pro): reactive activation, DEV pro toggle, app-root wiring (81090bb)
- feat(pro): Keygen license-key activation with a hard device cap (d6421e5)
- feat(models): show Pro upsell in Home voice sheet for free builds (e52e839)
- feat(components): add centered alert dialog (3b13dd4)
- feat(mcp): wire MCP SDK OAuth — URL polyfill, deps, submodule bump (af5e596)
- feat(audio): bump pro to audio-mode progress captions (60d0303)
- feat(tools): two-pass tool routing for on-device models (iOS llama + LiteRT) (319c348)
- feat(litert): direct audio input for LiteRT models on Android (22e486b)
- feat(litert): surface curated LiteRT models in onboarding (d460cd1)
- feat(pro): Get Pro opens web pay page directly; modal is verify-only (db231bf)
- feat(audio): larger voice mic + taller chat input (ab319e3)
- feat(chat-input): header Chat/Voice toggle, drop thinking bar icon, pass onSend to audio (39e2ddb)
- feat(audio): render the voice empty-state hero slot (aa0b31c)
- feat(litert): two-pass tool selection for large tool sets (7d917e4)
- feat(pro): reframe unlock copy around 'membership' / Get Pro (3e83836)
- feat(home): animated load progress + rotating tips on the loading overlay (1db5d14)
- feat(settings): release-visible Debug Logs button + MCP OAuth browser log (34bec91)
- feat(mcp): native OAuth adapters, boot wiring, and redirect scheme (dab716b)
- feat(transcription): multi-model — select/download/delete per model (514202a)
- feat(settings): remove Voice Transcription + Text to Speech settings screens (b4ab879)
- feat(chat): Models selector in chat header → shared manager sheet (2cd681e)
- feat(home): collapsed Models control + per-type pickers; bump pro (66842eb)
- feat(audio): wire streaming TTS + chat-mode select-text; bump pro (ae5eeb9)
- feat(routing): warm selected models at boot (text -> image -> TTS -> STT) (cf1605b)
- feat(routing): auto-provision the default SmolLM2 classifier (a328699)
- feat(routing): use the SMOL LLM classifier for image-only routing (19130b4)
- feat(routing): differentiate text vs image + load text model on demand (7ce42ae)
- feat(routing): remember last text model + preload it on chat open (2159ba3)
- feat(routing): make residency manager authoritative for model memory (0bde2b9)
- feat(image): disable prompt enhancement when no text model is available (46b384c)
- feat(routing): add model residency manager (memory budget + eviction) (ccd6bbe)
- feat(downloads): show voice + transcription models in Download Manager (e1e2f98)
- feat(models): add Transcription Models (speech-to-text) tab (e9cdb00)
- feat(models): add Voice Models tab with pro panel + non-pro upsell (4c3cc32)
- feat(chat-input): inline Chat/Audio toggle slot + fix clipped pill icons (1d16749)
- feat: pro unlock modal polish (dismiss, border, input-gated CTA) (48bfd36)
- feat: add RevenueCat config key placeholders (66ff0c4)
- feat: pro-gated email/calendar tools via ToolExtension (fcbc9c9)
- feat: in-app debug log viewer (99718d6)
- feat: RevenueCat pro license service + unlock modal (3d5613b)
- feat: tool extension seam + MCP wiring into the generation loop (26db7c0)
- feat: pro feature registry, license seam, and submodule (d300dbb)
- feat: pluggable TTS engine interface with Kokoro + OuteTTS adapters (609ddd5)
- feat: seekbar overlaid on waveform, visible on both user and AI bubbles (c26d7cc)
- feat: WhatsApp-style waveform progress + increase voice change cooldown (a2b41ea)
- feat: word highlighting in transcript, stop TTS on record, fix multi-click play (097286e)
- feat: draggable seekbar — tap or drag to seek (a3c5891)
- feat: seekable progress bar — tap to jump to position in audio (d8c9e00)
- feat: rename voices to mood personas with pre-configured speeds (996b986)
- feat: audio mode system prompt for conversational voice responses (ac6de63)
- feat: ChatMessage speak action, test fixes, and TTS plan update (11f099b)
- feat: TTS store, service, TTSButton, KokoroTTSManager, and App wiring (908af16)
- feat: multimodal audio input — pass WAV directly to audio-capable models (ff834e1)
- feat: VoiceSettingsScreen — HuggingFace model search (c072873)
- feat: expand Whisper model catalogue and add downloadFromUrl (9f5ad0d)
- feat: add TTS accordion to GenerationSettingsModal (6b337f3)
- feat: VoiceRecordButton — inline download prompt instead of navigation (3d1eb33)
- feat: Audio Mode full voice conversation — user audio bubbles + auto-send (bb4ff1f)
- feat: audio attachment type — duration, format, and recorder service (ef9b973)
- feat: replace sliders with NumericStepper in all settings screens (ce920a4)
- feat: add NumericStepper component (8ab6a50)
- feat: add Voice mode toggle to quick settings popover (78e40d5)
- feat: trigger TTS generation automatically after streaming in Audio Mode (6d269de)
- feat: add TTS with Audio Mode and Chat Mode (767e0b9)
Bug Fixes
- fix(ci): exclude pro-importing MCP test suites from open-core CI (38d4133)
- fix(models): stop Whisper STT models showing under Text models (b23dafe)
- fix(downloads): tag Whisper downloads as STT so they file under Voice (73eea0d)
- fix(voice): Kokoro iOS playback + recognize installed Whisper models at boot (1923a53)
- fix(whisper): seed totalBytes so transcription download shows progress (b0fea62)
- fix(pro): keep license-key activation reachable above the keyboard (b2e59e2)
- fix(share): one-tap X compose via x.com/intent/post, ambient copy, org links (2890daf)
- fix(ci): exclude KokoroTTSBridge test from tsc (imports the pro submodule) (07c357f)
- fix(deps): resolve react-dom override conflict so npm ci accepts the lock (2ec61dc)
- fix(deps): pin react/react-dom to 19.2.0 so npm ci stays in sync (9303dfa)
- fix(voice): keep the voice note on the user message in image mode (62e75d6)
- fix(voice): speak only the answer aloud, not the thinking process (e6953fe)
- fix(pro): reflect Pro activation in the Voice tab/sheet without a restart (31bc750)
- fix(voice): show a spinner while the STT model downloads + carry progress to Models (0229cde)
- fix(voice): recommend Whisper Base (142MB) instead of Small (466MB) (f98cda6)
- fix(chat): anchor quick-settings popover correctly after keyboard dismiss (e0973ec)
- fix(android): status bar icons follow the app theme via SystemBars (7d1599e)
- fix(chat): image-mode gate accepts a downloaded model (cbb2170)
- fix(models): Home selection marks active, loads lazily on send (f2fbc37)
- fix(android): edge-to-edge status bar follows the app theme (510a0c8)
- fix(chat): keep Qwen3 reasoning block on completion (386ef3d)
- fix(chat): remove keyboard whitespace under edge-to-edge (3aa9468)
- fix: point Wednesday links to wednesday.is (51b8519)
- fix(share): open X via deep link with web fallback (989dbdf)
- fix(stt): remove HuggingFace Whisper search, keep the built-in catalogue (13ddf6d)
- fix(downloads): keep Whisper download state in sync across surfaces (8602aac)
- fix(lint): baseline NotificationPermission (unused audio-api playback notification) (9b280c9)
- fix(deps): remove unused react-native-background-downloader (c9cfdc9)
- fix(lint): use template literal in audioRecorderService (prefer-template) (aa13b25)
- fix(ios): activate the AVAudioSession before recording (cd7b947)
- fix(deps): pin react-native-zip-archive to 7.1.0 so patch-package applies (a83e465)
- fix(deps): pin react-native-zip-archive to 7.1.0 so patch-package applies (b54aa1b)
- fix(lint): drop unused loop var left by the log strip (1acba96)
- fix(navigation): dedupe screen registration by name (47dd59c)
- fix(audio): wire MCP sheet into the audio-mode quick settings (94dc271)
- fix(lint): resolve pre-existing inline-style and complexity errors (013ac5e)
- fix(chat): honour the Tools 'N/A' gate during generation (3b08ce2)
- fix(whisper): keep transcription model list in sync with disk (1fc39bf)
- fix(chat): update OpenCL warning message for clarity on GPU support options (96ad679)
- fix(audio): clear attachments after a keyboard send in audio mode (380d20b)
- fix(litert): send image and audio together in one turn (094dfef)
- fix(ui): open the next sheet only after the Models manager fully closes (2431011)
- fix(audio): bump pro for TTS low-RAM + react-native-fs shim (a890f7e)
- fix(ios): consolidate react-native-fs onto the @dr.pogodin fork (3780e72)
- fix(models): engine-aware loaded check so LiteRT models don't reload (7c97849)
- fix(chat): restore KeyboardAvoidingView keyboard avoidance (6d00bf2)
- fix(litert): recover from native tool-call parse failures instead of crashing (9e20444)
- fix(logging): re-wire in-app debug viewer dev-only after taking main's logger (0a4aca2)
- fix(pro): open unlock modal in verify mode from "Already paid?" (3d036cb)
- fix(android-test): relax bytecode verification for unit tests (Amazon IAP VerifyError) (57d5caf)
- fix(settings): keep Debug Logs dev-only; bump pro pointer (7b43df5)
- fix(ci): move pro-source tests into the pro submodule (35f00e6)
- fix(tools): inject MCP hint once, and only when no native tool calling (c48f671)
- fix(audio): bump pro — cumulative seekbar position across streamed sentences (3047ba2)
- fix: detect Ollama vision capability from capabilities array (cd729ce)
- fix: disable persistent file logging to stop UI stalls/ANRs (f8c5719)
- fix(routing): don't lose the message when the model selector opens (ed6b3a6)
- fix(chat): load models inline, no full-screen takeover (a0de93d)
- fix(models): reuse shared search styling in Transcription tab (39ef4a0)
- fix(downloads): collapse TTS/STT chips into one Voice Models filter (e944b68)
- fix(chat): stop stacking bottom safe-area below the chat input (feeae0f)
- fix(boot): isolate RevenueCat init so Pro features load when billing is unavailable (42bd91f)
- fix: make CI green without the private pro submodule (f2ca569)
- fix: map @offgrid/core/* in tsconfig so tsc resolves the pro extension (18ee7f1)
- fix: drop streaming TTS chain, speak full response after streaming ends (6861c30)
- fix: stop TTS on retry/resend to prevent orphaned audio playback (4cf1a10)
- fix: tool-call audio rendering, transcript scroll, action menu, conditional Kokoro (a49e4a0)
- fix: audio playback state races, voice switch crash, chat scroll & UI (54f7a54)
- fix: remove negative right margin — waveform stays within bubble (42e606c)
- fix: bars flex to fill full waveform width — no right gap (ff738a0)
- fix: waveform extends to bubble right edge, spacing from play button (64c6a2a)
- fix: increase waveform left margin to SPACING.sm (e958dd4)
- fix: add left margin to waveform for spacing from play button (33dd403)
- fix: revert — play button back on left, reduce gap for wider waveform (e8bce31)
- fix: waveform full bubble width, play button moved to meta row (5d99192)
- fix: tighter bars, bigger speed chip, 2s voice cooldown from stream end (d14dd2a)
- fix: waveform bars span full width using space-between (e5b4816)
- fix: WhatsApp-style layout — waveform full width, meta row below (7410fe4)
- fix: seekbar thumb always visible, fix bar/thumb alignment (43d972b)
- fix: hide seekbar thumb when not playing — no stray dot at position 0 (b3d7077)
- fix: consistent bubble widths, fixed-width audio bubble (00075da)
- fix: remove inaccurate word highlighting, add playing state visual (372d40a)
- fix: voice change crash cooldown, single-word highlight with auto-scroll (47d44de)
- fix: all tests passing — mock executorch, update test assertions (094aea0)
- fix: remaining lint errors — unused var and param count (922594a)
- fix: center seekbar thumb dot vertically on track (8c3202e)
- fix: seekbar always visible on AI audio bubbles, not just during playback (298fcee)
- fix: center seekbar dot, stop TTS on back navigation (ea2222e)
- fix: defer voice config change until Kokoro is idle — prevents native crash (e60d245)
- fix: no flicker on seek, progress bar above show transcript (078e99b)
- fix: seekbar position preserved across stop/speak cycle (b9bd6c7)
- fix: always wait 300ms after kokoroRef.stop() before new speak() (410d828)
- fix: move seekbar below show transcript toggle (6d529ce)
- fix: full-width seekbar with debug logs, separate from waveform (6b7acf5)
- fix: seekbar now uses onLayout width instead of measure() (2542d56)
- fix: restore show transcript toggle on all audio bubbles (090bc80)
- fix: seekbar now integrated into waveform area — tap waveform to seek (6883ded)
- fix: remove bottom hitSlop from play/speed buttons so seekbar receives taps (dd97b03)
- fix: voice change crash, paused waveform, seekbar UX (29ebf34)
- fix: speed chip syncs with persona default speed from store (a472a28)
- fix: smooth progress bar, pause/resume on app switch, targeted store selectors (662f210)
- fix: waveform animation, voice picker popover, thinking block, playback timer (51bc18e)
- fix: thinking block blank bubble in audio mode (0870fed)
- fix: remove Transcribing text from audio mode mic button (dcd5102)
- fix: tap-to-toggle recording in audio mode (f856e8d)
- fix: move voice selector from audio bubbles to bottom bar (6cec1ab)
- fix: stop TTS on app background and screen lock (c49f6ea)
- fix: waveform animation, voice change crash, playback progress (73aad91)
- fix: thinking block width constraint + download manager UI updates (f47bb3c)
- fix: streaming TTS, parallel transcription, popover positioning (df030c8)
- fix: strip think tags, XML tool calls, and markdown from TTS speech (c310876)
- fix: Kokoro pause/resume, keepAlive, amplitude RMS + audio bubble UX (d86d857)
- fix: thinking block rendering in audio mode messages (0014dd1)
- fix: remove TTS chunking, add pause/resume and amplitude state (78cc400)
- fix: flatten audio mode bar, dismiss popover on mode switch (c56ce85)
- fix: live speed control, AI duration estimate, audio input layout (63db18a)
- fix: render all AI messages as audio bubbles in audio mode + voice label (e4cc785)
- fix: audio mode bubbles, waveform, chat-mode voice playback, input UI (a4a00c1)
- fix: audio mode messages now render as audio bubbles + streaming TTS (339839c)
- fix: audio bubble play, layout, voice cycling (3e54248)
- fix: smart audio mode flag — isAudioModeMessage persists per-message (63aefb9)
- fix: audio attachments render as compact badge in Chat Mode (becde09)
- fix: audio bubble playback and positioning (8bd96b3)
- fix: audio recording at 16 kHz and strip audio from non-audio LLM messages (b060674)
- fix: stale closure bug — Audio Mode TTS trigger reads fresh store state (51a2ba4)
- fix: pre-testing bug sweep — 4 real issues (e480690)
- fix: wire Audio Mode end-to-end — message audio fields, spinner logic, TTSButton placement (567b9ee)
- fix: move TTS rendering to MessageRenderer, fix global audio-api mock (1f9698c)
Refactors
- refactor(settings): extract shared SliderSetting component (d7e2f9f)
- refactor(models): move shared model sheets to components + shadow the home Models card (a5916b1)
- refactor(models): remove the modelLoadingStrategy (fast/optimised) setting (8f9e643)
- refactor: move audio/TTS mode into the pro submodule behind a slot/hook seam (0e12a06)
- refactor: static waveform bars — remove all animation/amplitude tracking (fbd7366)
- refactor: replace custom PanResponder seekbar with native Slider (aa71157)
- refactor: fix all lint errors — extract components, reduce complexity (52422d6)
Chores
- chore: bump version to 0.0.97 [skip ci] (5ec6eb1)
- chore: sync pro submodule to merged main (60d4497)
- chore(ios): lock MMKV + react-native-background-downloader pods (002401c)
- chore(ios): add npm run ios:device for manual-signing device builds (61c6808)
- chore(pro): point submodule at pro main (Kokoro delete/memory fix merged) (abb8978)
- chore(android): refresh lint baseline for background-downloader notification (d480b91)
- chore(pro): bump submodule for Kokoro delete + memory fixes (eb90a59)
- chore(ios): patch fmt for the Xcode 26 build (15d7f48)
- chore(pro): remove temporary 'Reset Pro identity' testing button (4a6ae56)
- chore(mcp): bump pro submodule — auth dropdown selected-state + form polish (8fdd8c8)
- chore: bump pro submodule (Kokoro voice-switch fixes + audio cleanup) (ee96d76)
- chore(logs): strip verbose debug logging from services and LiteRT (d6ea2a1)
- chore(android): strip RevenueCat-injected Play Billing permission (2030484)
- chore: bump pro submodule (audio + mcp UI fixes) (edd5dda)
- chore: remove temporary audio/sheet debug logging (c764027)
- chore: bump pro submodule to include 'drop MCP Servers settings entry' (6128f70)
- chore: bump pro submodule to drop MCP Servers settings entry (f9cceeb)
- chore: bump pro submodule — Gemini review fixes (7a8c1f6)
- chore: bump pro submodule to audio-mode UI work (4c606f2)
- chore(deps): add react-compiler-runtime (61b435e)
- chore: remove orphaned website revenuecat-link test (e1b9e57)
- chore(mcp): add native deps for OAuth sign-in (f0cba52)
- chore(pro): bump submodule to merged audio-mode tip (c00afad8) (6142e42)
- chore(knip): add tuned config and remove dead code it surfaced (52eeaa8)
- chore(home): delete dead ActiveModelsSection; drop audioSummaryLabel hook; bump pro (6dd4383)
- chore: remove website/, now in its own repo (#407) (23ee0e9)
- chore: bump pro submodule for MCP screen fixes (d17f218)
- chore: keep website out of Sonar scope; rename revenuecat link id (8609719)
- chore: interim (ea27099)
Tests
- test(chat): assert model load is deferred to send, not chat open (4a71b05)
- test: align tests with recent fixes (whisper base, popover settle delay) (5974924)
- test(audio): cover Kokoro delete + bridge teardown (c292ac4)
- test: ignore pro submodule suite locally, mock keyboard-controller (0a565b1)
- test: raise Jest branch coverage to 82.69% to pass CI gate (8ccb40d)
- test(ci): exclude pro-submodule suites from the public repo's CI (40d9092)
- test(audio): update ChatInputModeToggle for alert-based no-model flow (84db5bf)
- test(home): drive deferred manager-sheet flow; match LoadingOverlay (3c14a66)
- test(audio): cover voice panel disk-sync on focus (51b02f3)
- test(chat): cover the Tools N/A generation gate (846b4b0)
- test(settings): cover SliderSetting and its adopters (b61bdc9)
- test(whisper): cover per-model spinner and disk reconciliation (da75d34)
- test: update ChatInputModeToggle test to the dropdown UX + bump pro submodule (ae6f8b6)
- test(chat-input): give useAppStore mock a getState for supportsAudioInput (5c06870)
- test: restore branch coverage above 80% after merging main (89cc17c)
- test: fix tool-loop mock + cover tool-call parsing and native OAuth adapters (9ddf89f)
- test(mcp): cover schema trimming (pass-through, budget, required preserved) (c927452)
- test(mcp): unit tests for OAuth pkce, metadata, tokens, and client retry (b9b2981)
- test: update screen tests for the model-selector + voice redesign (27b0d21)
- test(audio): cover streaming TTS, multi-model transcription, voice routing (02765fd)
- test(routing): type preloader test mocks with rest params for tsc (ca37086)
- test(pro): fix pro-boot entitlement gating tests under DEV (16b0445)
- test(audio): cover GGUF download reroute + partial-file fix (697e7a3)
- test(models): fix mock typing in TranscriptionModelsTab test (8e09586)
- test(tts): cover Kokoro on-disk install-status detection (bce7187)
- test: update getAudioCacheSizeMB test for readDir-based implementation (c602566)
- test: add useTTSStore mock to ChatInput test suite (ee07ec2)
Documentation
- docs: point all Slack invite links to the current invite (5a0c9b0)
- docs(routing): pin classifier choice + gate routing on multiple models (157900d)
- docs: add reuse-before-building rule + model routing plan (238d406)
- docs: drop 'Larger models' bullet from README Pro section (#403) (fbd22c7)
- docs: drop redundant 'built by Wednesday Solutions' line (#398) (b94a57c)
- docs: dark-mode Wednesday logo, bump size (#397) (13c0883)
- docs: fix broken Wednesday logo src in README (#396) (a9bdce0)
- docs: surface Pro CTA in README, drop squad pitch (26c49be)
- docs: add cross-conversation RAG to personas plan (ed5a0c4)
Other
- perf(models): defer model loading until first send (d1d59f2)
- Update Slack community link in README (26e62f1)
- gate debug logs and reset pro button on release builds (501c6f3)
- fix supportemail type change from support@offgridmobile.co to support@offgridmobileai.co (beabd32)
- Hide pro banner once pro is registered (8053039)
- make litert model card ui similar to other cards (ab7b705)
- website: remove /early-access page (#402) (bb2d15e)
- website: drop alpha/round framing from home Pro section (#401) (d7e7f1c)
- website: point home Pro CTA at /pay (#400) (da5402b)
- website: swap Early Access for Get Pro in the sidebar (#399) (ae0feaf)
- Apply suggestions from code review (b0e4e7f)
- website: address second Gemini pass on the pay page (9393b2f)
- website: address Gemini review on the pay page (d19a2f4)
- website: make email regex linear-time to fix Sonar ReDoS hotspot (cc06a61)
- website: add Pro payments page with RevenueCat checkout (031fac8)
- website: add direct #pro-waitlist Slack CTAs on home + early-access (#393) (ca72b66)
- website(early-access): fix Slack channel link to #pro-waitlist (#392) (e9eccf7)
- website(early-access): route signups to Slack alpha-access channel (#391) (fe99fe7)
- website: rewrite homepage in brand voice, deploy at offgridmobileai.co apex (#390) (f4e8fd7)
- revert: keep KokoroTTSManager always mounted (51c33c0)
- debug: add logs to handlePlayPause to trace wrong transcript issue (483d232)
- debug: add logs to blur/stop handlers for TTS navigation debugging (19de292)
Full Changelog: v0.0.96...v0.0.97