← all posts

10 june 2026

Today was mostly about turning my “mobile companion” into something that works standalone: offline-first, on-device search, and a clearer unpaired UX. I also invested in tooling (Claude Code + Android toolchain) and hit a few real-world “native mobile is different” issues that were good forcing functions.

What I learned

  • Sandboxed environments can break Git in surprising ways. A persistent .git/index.lock (and filesystem mount behavior) blocked commits; the practical fix was to clean lock files and do write operations in a real local shell.
  • Expo prebuild can clobber tracked TypeScript config. Running prebuild/Android builds deleted expo-env.d.ts and altered tsconfig.json, causing typecheck failures until I restored the committed versions.
  • Android build hygiene matters. I ran into a Gradle/JDK mismatch (JDK 21 vs required JDK 17) and fixed it by explicitly pointing JAVA_HOME at a JDK 17 install.
  • Emulator ≠ real device for on-device ML. OCR inference triggered a native crash (SIGILL) in the emulator even after model download/caching. The takeaway: some ExecuTorch inference paths aren’t reliable on my Apple Silicon emulator; hardware verification is required.
  • On-device “Q&A” doesn’t always require a big model. Splitting retrieval (local DB/vector search) from generation (LLM wording) makes offline mode feasible: many queries can be answered with local lookups/snippets.

What I built

  • Set up Claude Code CLI (install + OAuth) and used it to inspect repos, run status checks, and coordinate doc/code changes.
  • Android dev environment: installed/configured Android Studio, SDKs, created an emulator, booted it, and successfully built/installed the app via the Expo/Gradle pipeline.
  • Project doc sync across desktop + mobile repos: updated README/ROADMAP/HANDOFF/IMPROVEMENTS to match actual repo state and clarified workflow rules where they were contradictory.
  • Mobile Phase 0 shipped (offline-first core):
  • Added SQLite-backed local store (expo-sqlite) with a dev self-test run at app launch.
  • Integrated on-device embeddings using react-native-executorch and validated via logcat self-tests.
  • Implemented offline semantic search (ranking + UI) and added a dedicated Memories screen reachable even when unpaired.
  • Phase 1 capture work started:
  • Wired an image-pick / OCR plumbing path (plus test-safe module structure to avoid native imports in Jest).
  • Prototyped voice capture pipeline using Expo audio streaming, with waveform helpers and a Record/Stop flow (including a silence guard for emulator quirks).
  • UX/routing improvements: changed routing so unpaired users land in an on-device-first experience instead of hitting a pairing wall; validated Connect/Skip round-trips in the emulator.
  • Icon/branding cleanup:
  • Generated and verified updated Android launcher/adaptive icons, fixed an APK signature mismatch by uninstalling/reinstalling.
  • Began aligning desktop icon/favicons so required assets are actually tracked (fixing .gitignore issues that would break fresh builds).

Experimenting with

  • Feature parity planning for desktop vs mobile: produced and iterated on parity docs and a phased roadmap, then revised it toward a more realistic “on-device core + optional desktop sync” model.
  • On-device OCR / STT / LLM feasibility with ExecuTorch hooks and model/download behavior, including the practical limits of emulator-based validation.