An offline, on-device "second brain" AI agent for Android. No Termux, no external Ollama server — the app embeds llama.cpp natively via Dart FFI and serves itself over a local HTTP API.
- Chat — talk to a locally-loaded
.ggufmodel. Every turn is grounded with a lightweight TF-IDF retrieval pass over your own stored notes (lib/memory_agent.dart) before it reaches the model. - Memory DB — browse, inspect, and delete anything the app has remembered (SQLite, on-device only).
- Server Config — pick a
.gguffile from local storage and start a local API server (http://127.0.0.1:<port>/api/generate) that any other app or script on the device can call.
| Layer | Tech |
|---|---|
| UI | Flutter (Material 3) |
| Inference | llama_cpp_dart, off the UI thread via LlamaParent/LlamaScope |
| Local server | shelf + shelf_router |
| Memory / RAG | sqflite + a pure-Dart TF-IDF keyword ranker |
| Native actions | a MethodChannel the model can trigger via <ACTION: X> tags |
CI (.github/workflows/build-apk.yml) does everything needed for a
sideloadable release APK — no production keystore required:
- Compiles
libllama.so(+ itslibggml*.sodependencies) from thellama.cppsource via the Android NDK, sincellama_cpp_dart0.2.x is a pure FFI binding and ships no prebuilt binary itself. The result lands inandroid/app/src/main/jniLibs/arm64-v8a/. - Runs
flutter build apk --release --target-platform android-arm64with R8/ProGuard shrinking and native debug-symbol stripping enabled (android/app/build.gradle). - Signs the release build with the standard Android debug keystore, cached across runs so every build shares the same signing key — that's what lets you install an updated APK over a previous one without uninstalling first. (This is fine for sideloading; it is not a Play Store–ready signature.)
- Uploads the finished APK as a workflow artifact.
To build locally instead, you'll need the Android NDK on your PATH and a
compiled libllama.so for your target ABI in
android/app/src/main/jniLibs/<abi>/ before running flutter build apk.
Early scaffold — chat, memory, and server-management UI are wired up;
model loading and generation go through the real llama_cpp_dart API
(LlamaParent + LlamaScope), but this hasn't yet been run against a real
device/model. Treat native-library and API surface details as "verify
against whatever llama_cpp_dart version is pinned in pubspec.yaml" —
that package's public API has changed release to release.