feat(mobile): ship iOS, Android, and Bots companion apps - #41
Conversation
|
Final validation is green on commit
|
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes
Reviewed feature/mobile-apps-bots-pr at 78a43dd end-to-end: the raw diff TOC plus working-tree reads of the remote boundary, plus five focused reviewfrog specialists on the remaining orthogonal security surfaces. The substantive changes:
- Aiden Remote HTTP surface — a single router (
main/services/aiden-remote-router.ts) with per-route device grants,idempotency-key/if-matchconcurrency, origin rejection, and body/URL/JSON limits. - Pairing & credential lifecycle — QR + manual Crockford codes sealed into one consumed secret (HKDF/AES-256-GCM), scrypt credential digests, and a revocation fence that drains per-device authorizations.
- Opaque file/browser handles — hashed device/root/policy/snapshot-bound handles with
realpath+ device/inode re-resolution and single-use selection consume. - Bot authority — Full/Custom policy resolution that fails closed on missing/corrupt/future-version policy, per-bot managed homes with incarnation identity, and authoritative prompt rules appended after editable persona.
- Bot generation —
llm-client.tsadmits/revalidates the Bot authority around the provider call and allowlists tools per capability. - iOS / Android companion apps — native SwiftUI and Jetpack Compose trees with Keychain/EncryptedSharedPreferences credential storage, backup exclusion, and bounded ID-only Live Activity / App Intent surfaces.
- Desktop-side refactors — chat/workspace/schedule/provider IPC handlers moved behind application services; onboarding, provider thinking/visibility, and remote-access settings wiring.
The implementation is unusually consistent with its own docs/security/aiden-remote-threat-model.md, and the negative-path tests (bot-policy fail-closed, avatar decode, speech PCM bounds, idempotency replay, mobile credential leakage) are substantial and load-bearing rather than theatrical.
Two defense-in-depth observations below, neither actionable in this PR.
ℹ️ Legacy Bot migration relies on the seal file surviving alongside the policy store
For a pre-policy Bot, Full Access is minted during migrateLegacyBotsToFull. A missing/corrupt policy record with the migration seal intact fails closed (bot-application-service.ts throws when externallySealed && audit.missingBotIds.length > 0), and the checkpoint anchor adds a second guard. The only scenario where full is re-inferred from persisted-state absence is when an attacker with local filesystem write access deletes both bot-capabilities.json and the seal file together, making the app look like a first run. That is a filesystem-integrity loss beyond the stated "missing/corrupt/future-version record" threat, and the seal + checkpoint are the designed anchors — flagged for awareness, not as a fix request.
ℹ️ Android installation metadata asymmetry vs iOS
Android persists endpoint, serverSpkiSha256, deviceId, instanceId, and the pairing CA certificate in a plaintext app-private installations.json (excluded from cloud backup and device-to-device transfer via data_extraction_rules.xml). None of these are a credential or pairing secret, and the actual credential lives only in EncryptedSharedPreferences under a Keystore-bound MasterKey. iOS stores the equivalent metadata in the Keychain instead. Within the stated threat model on both platforms — noted only for cross-platform parity.
DeepSeek Pro | 𝕏
There was a problem hiding this comment.
ℹ️ No critical issues — one minor suggestion inline.
Reviewed changes
Reviewed the delta since the prior review at 78a43dd — a single Merge main into mobile companion apps commit (4476dbf) that folds main's display-image and speech work into the companion branch.
- Added fail-closed display-image recovery gates — chat reads now return
imageArtifactRecoveryPending/imageArtifactRecoveryUnavailable, and the remote HTTP layer maps both to a 409operation_in_progressso paired devices fail closed while a staged image response awaits recovery or storage repair. - Hardened chat deletion ordering — staged image artifacts are deleted after the durable subagent tombstone but before Pi effects, compaction, and the chat, with a source-reading test pinning the sequence.
- Moved PCM16 decode off the main process —
validateAidenRemotePcm16Base64bounds the wire payload without allocating a decode buffer; a versionedencodingdiscriminator shifts PCM16→float32 conversion into the utility process. - Wired
display_imageinto generation — artifacts are staged before announcement,displayedImagesis tracked separately fromsharedImages, and committed artifacts are cleared after persistence. - Extracted the message image gallery into a shared
message-attachments.tsxcomponent. - Bumped the release to
0.31.0and refreshed onboarding bento copy.
DeepSeek Pro | 𝕏
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes
Reviewed the delta since the prior pullfrog review (4476dbf) — a single fix(remote): avoid IPv4 listener collisions commit (16b0221) touching aiden-remote-service.ts and its test suite.
- Added an IPv4-loopback availability probe to LAN port selection — before committing a candidate,
AidenRemoteServicenow checks that127.0.0.1can bind the port. On macOS an IPv4-only loopback listener can coexist with the dual-stack::wildcard bind, which previously let Aiden report its HTTPS listener as ready while the IPv4 loopback still reached an unrelated plaintext service; fresh profiles now skip such a port, and committed profiles fail closed withAidenRemotePortInUseError. - Added a load-bearing regression test —
a fresh profile skips a LAN candidate occupied only on IPv4 loopbackreserves127.0.0.1on the preferred port and asserts the service commits the next complete pair, backed by a newipv4LoopbackPortIsAvailablehelper that mirrors the existingisAddressInUse/listen/closeServerseam.
The probe is additive and safe: it only rejects a port that is genuinely occupied on the IPv4 loopback (the exact unsafe condition), never forces a false skip of a usable port, and leaves the Tailscale loopback half to the existing listen-error handling. The suite passes 35/35 locally.
DeepSeek Pro | 𝕏

Summary
Ships the unified Aiden companion experience across iOS, Android, and Bots while preserving the existing Mac-hosted security boundary.
aiden-on-the-go-debug-apkIntentionally separate
Verification
npm test— passednpm run type-check,npm run lint,npm run build— passedDevice review notes
Portrait captures cover the Android Bots view, text-only app switcher, Workspaces landing view, populated Usage dashboard, elevated chat composer, keyboard placement, attachment chooser, native photo picker, and the iOS compact scroll-to-latest glass control.
Review focus