Sovereign Memory Server for Your Pocket
An Android app that turns your phone into a personal knowledge server. Runs the Anchor Engine (a compiled ARM64 Node.js binary) as a background process, exposes it via HTTP on localhost:3160, and wraps it in a full-screen Flutter WebView. Accessible to AI coding tools over Tailscale.
🚧 v0.2.0 — Flutter + ARM64 binary runtime working; chmod +x fix in progress (PR #13)
┌──────────────────────────────────────────────┐
│ Android Phone │
│ ┌──────────────────────────────────────────┐ │
│ │ Flutter App (EngineBootstrap) │ │
│ │ ┌────────────────────────────────────┐ │ │
│ │ │ anchor-engine (ARM64 binary) │ │ │
│ │ │ - Compiled Node.js runtime │ │ │
│ │ │ - Anchor Engine JS bundle │ │ │
│ │ │ - Port: 3160 │ │ │
│ │ └────────────────────────────────────┘ │ │
│ │ ┌────────────────────────────────────┐ │ │
│ │ │ WebView (full-screen) │ │ │
│ │ │ http://localhost:3160 │ │ │
│ │ └────────────────────────────────────┘ │ │
│ └──────────────────────────────────────────┘ │
│ ┌──────────────────────────────────────────┐ │
│ │ Tailscale (Mesh VPN) │ │
│ │ - Encrypted tunnel │ │
│ │ - No open ports to internet │ │
│ └──────────────────────────────────────────┘ │
└──────────────────────────────────────────────-┘
▲ ▲
│ HTTP │ HTTP
│ (Tailscale) │ (Tailscale)
┌──────────┴──────────┐ ┌───┴──────────────────┐
│ Your Laptop │ │ AI Coding Tools │
│ (VS Code, etc.) │ │ (Qwen, Claude) │
│ in tailnet │ │ anywhere │
└──────────────────────┘ └──────────────────────┘
| Document | Description | Location |
|---|---|---|
| Technical Specification | Single source of truth for architecture | specs/spec.md |
| Task Tracking | Current sprint, backlog, and progress | specs/tasks.md |
| Changelog | Version history and releases | CHANGELOG.md |
| Quickstart | Get started in 5 minutes | docs/quickstart.md |
| Architecture | Detailed system design with diagrams | docs/architecture.md |
| Contributing | How to contribute | CONTRIBUTING.md |
- ✅ Flutter app with
EngineBootstrapboot sequence - ✅ ARM64 Node.js binary extracted from Flutter assets at runtime
- ✅ Health-poll loop — WebView loads only after engine is ready
- ✅ Verbose file-based logger (
anchor_engine_verbose.login Downloads) - ✅ Storage permission requests (MANAGE_EXTERNAL_STORAGE + WRITE_EXTERNAL_STORAGE)
- ✅ CI pipeline — builds APK from public
anchor-engine-noderepo automatically ⚠️ chmod +xfix in progress (PR #13)
- ⏳ GitHub repo sync UI (tarball ingestion, token entry)
- ⏳ Tailscale status display
- ⏳ Settings screen (GitHub token, sync interval, port)
- ⏳ Background sync worker
- ⏳ Native Android UI with Jetpack Compose
- Linux or WSL2 (ARM64 binary compilation requires Linux)
- Node.js ≥ 18 and pnpm (for engine build)
- Flutter SDK (stable channel)
- Android SDK (API 34)
-
Build the engine binary (must run on Linux/WSL2)
./sync_engine.sh # Output: flutter_app/assets/engine/anchor-engine (~50MB ARM64 binary) -
Build the Flutter APK
cd flutter_app flutter pub get flutter build apk --release # Output: build/app/outputs/flutter-apk/app-release.apk
-
Install on device/emulator
adb install build/app/outputs/flutter-apk/app-release.apk
The CI workflow (.github/workflows/build.yml) runs automatically on push:
- Clones
anchor-engine-nodefrom the public URL. - Runs
sync_engine.shto compile the ARM64 binary. - Builds the Flutter APK (
flutter build apk --release). - Uploads the APK as a build artifact.
No secrets are required — anchor-engine-node is a public repository.
App launch
└─ _requestStoragePermissions() ← MANAGE_EXTERNAL_STORAGE dialog
└─ _extractBinary() ← Copy asset to writable path + chmod +x
└─ _startEngine() ← Process.start(binary, PORT=3160, ...)
└─ _waitForReady() ← Poll localhost:3160/health (90s timeout)
└─ WebViewScreen ← Loads http://localhost:3160
All engine console.log, console.error, and console.warn calls are captured by
logger.js and appended to:
/storage/emulated/0/Download/anchor_engine_verbose.log
Format: [2026-03-05T00:07:01.581Z] [LOG] Anchor Engine starting on port 3160
Pull logs with ADB:
adb pull /storage/emulated/0/Download/anchor_engine_verbose.log ./engine.logOnce the engine is running on localhost:3160:
| Endpoint | Method | Description |
|---|---|---|
/health |
GET | Health check |
/stats |
GET | Database statistics |
/v1/memory/search |
POST | Search knowledge base |
/v1/chat/completions |
POST | Chat with RAG context |
/v1/system/paths |
GET/POST/DELETE | Manage watched paths |
The engine can automatically ingest GitHub repositories.
- User enters GitHub token in settings (coming in v0.3.0)
- App fetches tarball:
https://api.github.com/repos/{owner}/{repo}/tarball/{branch} - Unpacks to
engine_data/github/{owner}-{repo}-{sha}/ - Engine watchdog ingests files; tags extracted, molecules created
// Planned for v0.3.0
Future<void> syncRepo(String owner, String repo, String token) async {
final url = 'https://api.github.com/repos/$owner/$repo/tarball/main';
final response = await http.get(
Uri.parse(url),
headers: {'Authorization': 'token $token'},
);
final destDir = Directory('${appDir.path}/engine_data/github/$owner-$repo');
await unpackTarball(response.bodyBytes, destDir);
// Engine watchdog auto-ingests new files
}fun getTailscaleIP(): String? {
val networks = Collections.list(NetworkInterface.getNetworkInterfaces())
for (network in networks) {
if (network.name == "tailscale0") {
return network.inetAddresses.asSequence()
.firstOrNull { !it.isLoopbackAddress }?.hostAddress
}
}
return null
}Once Tailscale is running on the phone:
- Phone gets a Tailscale IP (e.g.,
100.x.y.z) - Engine is accessible at
http://100.x.y.z:3160 - Any device in the same tailnet can query it
-
Create Emulator
- Pixel 6 or similar, Android 14 (API 34), at least 4GB RAM
-
Install Tailscale on Emulator
- Download from Play Store; log in to your tailnet
-
Test Connectivity
curl http://100.x.y.z:3160/health
-
Check Engine Logs
adb pull /storage/emulated/0/Download/anchor_engine_verbose.log ./engine.log cat engine.log
| Metric | Idle | Under Load |
|---|---|---|
| RAM | ~150MB | ~300MB |
| Battery | ~1%/hour | ~3%/hour |
| Storage | ~50MB (APK) | +repo sizes |
| Network | 0 KB/s | ~100 KB/s (sync) |
- ✅ No open ports (Tailscale only)
- ✅ All traffic encrypted (WireGuard/Tailscale)
- ✅ GitHub token stored in Android Keystore (planned; settings UI pending)
- ✅ CI uses
permissions: contents: read(least privilege) - ✅ Engine data in app-private sandbox (
getApplicationSupportDirectory())
- Flutter + ARM64 binary architecture
- EngineBootstrap with health polling
- Verbose file-based logger
- Storage permissions
- CI pipeline (public engine repo, no secrets needed)
- chmod +x fix (PR #13, in progress)
- GitHub sync UI
- Tailscale status display
- Settings screen
- Background sync worker
- Native Android UI (Jetpack Compose)
- Direct query interface
- Sync scheduling
- Production stability
- F-Droid publication
- Multi-user support (shared tailnets)
- Check engine log:
adb pull /storage/emulated/0/Download/anchor_engine_verbose.log - Check adb logcat:
adb logcat | grep -E "(Engine|Flutter)" - Ensure storage permissions were granted (check for
[Permissions]lines in logcat) - Verify binary was bundled:
adb shell ls {data}/app_flutter/anchor-engine
- Check that the ARM64 binary was built for the correct architecture
- Try increasing
_waitForReadytimeout for slow devices - Check if another process is using port 3160
- Grant
MANAGE_EXTERNAL_STORAGEin Settings → Apps → Anchor → Permissions - On Android 11+, you may need to tap "Allow access to manage all files"
- Ensure Tailscale is running on the phone
- Verify both devices are in the same tailnet
- Check firewall / ACL rules
AGPL-3.0
See CONTRIBUTING.md for guidelines.
- PR #13: Review and merge the
chmod +xfix - GitHub Sync: Implement tarball fetch + unpack (v0.3.0)
- Tailscale SDK: Integrate official Tailscale Android library
- Tests: Write Flutter unit/integration tests for
EngineBootstrap
Part of Anchor OS — Sovereign Knowledge Engine
🚧 Prototype - Basic structure complete, Node.js integration pending
┌─────────────────────────────────────────┐
│ Your Android Phone │
│ ┌─────────────────────────────────────┐ │
│ │ EngineService (Foreground) │ │
│ │ ┌───────────────────────────────┐ │ │
│ │ │ Node.js Runtime │ │ │
│ │ │ (nodejs-mobile) │ │ │
│ │ │ - Anchor Engine │ │ │
│ │ │ - Port: 3160 │ │ │
│ │ └───────────────────────────────┘ │ │
│ └─────────────────────────────────────┘ │
│ ┌─────────────────────────────────────┐ │
│ │ Tailscale (Mesh VPN) │ │
│ │ - Encrypted tunnel │ │
│ │ - No open ports │ │
│ └─────────────────────────────────────┘ │
│ ┌─────────────────────────────────────┐ │
│ │ Storage │ │
│ │ - /mirrored_brain/ │ │
│ │ - /github/ │ │
│ └─────────────────────────────────────┘ │
└───────────────────────────────────────────┘
▲ ▲
│ HTTP │ HTTP
│ (Tailscale) │ (Tailscale)
┌──────────┴──────────┐ ┌───┴──────────────────┐
│ Your Laptop │ │ AI Coding Tools │
│ (VS Code, etc) │ │ (Qwen, Claude) │
│ in tailnet │ │ anywhere │
└──────────────────────┘ └──────────────────────┘
This project follows the Anchor OS Documentation Policy.
| Document | Description | Location |
|---|---|---|
| Technical Specification | Single source of truth for architecture | specs/spec.md |
| Task Tracking | Current sprint, backlog, and progress | specs/tasks.md |
| Changelog | Version history and releases | CHANGELOG.md |
| Quickstart | Get started in 5 minutes | docs/quickstart.md |
| Architecture | Detailed system design with diagrams | docs/architecture.md |
| Contributing | How to contribute to the project | CONTRIBUTING.md |
- API Reference - Engine endpoints and Kotlin APIs (coming soon)
- Integration Guide - Node.js + Tailscale setup (coming soon)
- Testing Guide - Emulator and device testing (coming soon)
- ✅ Basic Android app structure
- ✅ Foreground service for engine
- ✅ WebView UI wrapper
- ✅ Storage management
- ⏳ Node.js integration via nodejs-mobile
- ⏳ GitHub repo sync (tarball ingestion)
- ⏳ Tailscale auto-detection
- ⏳ Background sync service
- ⏳ Settings UI (GitHub token, sync interval)
- Android Studio (Arctic Fox or newer)
- Android SDK (API 34)
- Node.js (for bundling engine code)
-
Open in Android Studio
File → Open → Select anchor-android directory -
Sync Gradle
- Android Studio will automatically sync
- Wait for dependencies to download
-
Bundle Engine Code (Manual for now)
- Copy engine code to
app/src/main/assets/engine/ - Include:
engine/dist/,package.json,node_modules/
- Copy engine code to
-
Build APK
Build → Build Bundle(s) / APK(s) → Build APK(s) -
Install on Device/Emulator
Run → Run 'app' (Shift+F10)
The app uses nodejs-mobile to run the Anchor Engine.
-
Add dependency to
app/build.gradle.kts:implementation("com.nicollite:nodejs-mobile-android:0.1.0") -
Initialize in EngineService.kt:
import com.nicollite.nodejs.NodeJS private fun initializeEngine() { val nodeJS = NodeJS.getInstance(applicationContext) // Copy assets to app storage copyAssets("engine", filesDir.absolutePath) // Start engine nodeJS.start( script = "${filesDir.absolutePath}/engine/dist/index.js", args = arrayOf("--port", "3160") ) // Wait for engine to be ready waitForPort(3160) }
-
Bundle engine in assets:
- Create
app/src/main/assets/engine/ - Copy entire engine directory there
- Compress if needed to reduce APK size
- Create
The app can automatically sync GitHub repositories:
- User enters GitHub token in settings
- App fetches tarball:
https://api.github.com/repos/{owner}/{repo}/tarball/{branch} - Unpacks to
mirrored_brain/github/{owner}-{repo}-{sha}/ - Engine watchdog ingests files
- Tags extracted, molecules created
// In a background worker
suspend fun syncRepo(owner: String, repo: String, token: String) {
// Fetch tarball
val url = "https://api.github.com/repos/$owner/$repo/tarball/main"
val response = httpClient.get(url) {
header("Authorization", "token $token")
}
// Unpack
val tarball = response.bodyAsBytes()
val destDir = File(filesDir, "mirrored_brain/github/$owner-$repo")
unpackTarball(tarball, destDir)
// Engine watchdog will auto-ingest
}fun getTailscaleIP(): String? {
val networks = Collections.list(NetworkInterface.getNetworkInterfaces())
for (network in networks) {
if (network.name == "tailscale0") {
val addresses = Collections.list(network.inetAddresses)
for (address in addresses) {
if (!address.isLoopbackAddress) {
return address.hostAddress
}
}
}
}
return null
}Once Tailscale is running on the phone:
- Phone gets a Tailscale IP (e.g.,
100.x.y.z) - Engine is accessible at
http://100.x.y.z:3160 - Any device in the same tailnet can query it
Once running, the engine exposes:
| Endpoint | Method | Description |
|---|---|---|
/health |
GET | Health check |
/stats |
GET | Database statistics |
/v1/memory/search |
POST | Search knowledge base |
/v1/chat/completions |
POST | Chat with RAG context |
/v1/system/paths |
GET/POST/DELETE | Manage watched paths |
-
Create Emulator
- Pixel 6 or similar
- Android 14 (API 34)
- At least 4GB RAM
-
Install Tailscale on Emulator
- Download from Play Store
- Login with your tailnet
-
Test Connectivity
adb shell ping 100.x.y.z # From your laptop curl http://100.x.y.z:3160/health
| Metric | Idle | Under Load |
|---|---|---|
| RAM | ~150MB | ~300MB |
| Battery | ~1%/hour | ~3%/hour |
| Storage | ~50MB (app) | +repo sizes |
| Network | 0 KB/s | ~100 KB/s (sync) |
- ✅ No open ports (Tailscale only)
- ✅ All traffic encrypted
- ✅ GitHub token stored in Android Keystore
- ✅ Foreground service (can't be killed silently)
- Basic app structure
- Foreground service
- Node.js integration
- Basic WebView UI
- GitHub sync UI
- Tailscale status display
- Settings screen
- Background sync worker
- Native Android UI (Compose)
- Direct query interface
- Repo management
- Sync scheduling
- Check logcat:
adb logcat | grep EngineService - Ensure assets are copied correctly
- Verify Node.js runtime is bundled
- Ensure Tailscale is running on phone
- Check firewall settings
- Verify both devices are in same tailnet
- Engine should idle when not in use
- Check for runaway queries
- Consider adding sleep mode
AGPL-3.0
This is a prototype. Contributions welcome!
- Node.js Integration: Help bundle nodejs-mobile properly
- GitHub Sync: Implement robust tarball fetching/unpacking
- Tailscale SDK: Integrate official Tailscale Android library
- UI/UX: Design a native Android interface
Part of Anchor OS - Sovereign Knowledge Engine