Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
88 commits
Select commit Hold shift + click to select a range
473afa7
island: add the island namespace + glasses.wifi facade (first host API)
aisraelov Jun 16, 2026
ff4f0fa
island: add bootstrap front door + glasses.display.mirror read facade
aisraelov Jun 16, 2026
17e9ed5
island: move the glasses device-state store into island (+ wifi statu…
aisraelov Jun 16, 2026
76dd70d
island: rename the public namespace island.* -> toolkit.*
aisraelov Jun 16, 2026
c6f85fa
island: move the display/mirror store into island (toolkit.display.mi…
aisraelov Jun 16, 2026
ca57985
island: move core/connection/gallerySync stores in + group hatches un…
aisraelov Jun 16, 2026
1cfc74d
island: add toolkit.glasses core facade + facade-buildout tracking spec
aisraelov Jun 16, 2026
5738c65
island: add toolkit.speech facade (STT/TTS model management)
aisraelov Jun 16, 2026
1394efd
Merge remote-tracking branch 'origin/dev' into aisraelov/island-names…
aisraelov Jun 16, 2026
e6d80d4
island: fix mobile-CI install (drop spurious cloud-client dep + non-f…
aisraelov Jun 16, 2026
e0dc26e
island: restore island tsconfig cloud-v2 paths + export store state t…
aisraelov Jun 16, 2026
f101cfb
island: install cloud-v2 deps in postinstall so the mobile typecheck …
aisraelov Jun 16, 2026
e4cdd56
bluetooth-sdk(ios): fix two pre-existing compile errors in setButtonP…
aisraelov Jun 16, 2026
41869b8
island: record logs-not-a-facade finding + host-coupled decision poin…
aisraelov Jun 16, 2026
e38c45e
docs(oem): add Runtime Toolkit reference for the shipped toolkit.* su…
aisraelov Jun 16, 2026
305b5ad
Merge remote-tracking branch 'origin/dev' into aisraelov/island-names…
aisraelov Jun 16, 2026
2332f2c
island(keystone #5, step 1): move cloud-client status store + secure …
aisraelov Jun 16, 2026
eb8e986
island(keystone #5, step 2): move the CloudClient singleton into isla…
aisraelov Jun 16, 2026
68b1fce
island(settings prep): move GlobalEventEmitter in + add loadSubKeys t…
aisraelov Jun 16, 2026
1076ab0
island(#6): move settings store + RestComms into island (the mutually…
aisraelov Jun 16, 2026
8921501
island: export SettingsState so toolkit.stores.settings emits declara…
aisraelov Jun 16, 2026
3ab1d2e
island: add toolkit.settings + toolkit.session.account + toolkit.dev …
aisraelov Jun 16, 2026
3fe955e
island: add toolkit.incidents facade + document settings/account/dev/…
aisraelov Jun 16, 2026
151aee7
island: address Cursor review-bot findings
aisraelov Jun 16, 2026
2837f6d
island: finish toolkit.display.mirror (setView/view) + add toolkit.mi…
aisraelov Jun 16, 2026
e07a98b
island: add toolkit.incidents.file() one-call submission
aisraelov Jun 16, 2026
7689299
island: fix 2 more review-bot findings
aisraelov Jun 16, 2026
2f397d8
ci(ios): self-heal corrupted CocoaPods prebuilt cache on pod install
aisraelov Jun 16, 2026
c63f668
island: add toolkit.glasses.settings + toolkit.pairing facades
aisraelov Jun 17, 2026
6f53c0e
island: glasses long-tail (connect/connectSimulated/setDefault + cont…
aisraelov Jun 17, 2026
c534a9c
island: add toolkit.permissions facade (lean, over react-native-permi…
aisraelov Jun 17, 2026
c1d2407
island: add toolkit.notifications (inbound alerts island->host) + wir…
aisraelov Jun 17, 2026
c6c2cf2
docs(oem): document permissions, phoneNotifications, notifications + …
aisraelov Jun 17, 2026
f86fce2
island: fix iOS background-location request + correct an init comment…
aisraelov Jun 17, 2026
106581b
docs(oem): fix Runtime Toolkit reference drift
aisraelov Jun 17, 2026
5142fc4
island: fix 2 review-bot findings (glasses.settings device sync, perm…
aisraelov Jun 17, 2026
73dfd0e
toolkit.glasses.settings: scope available() to real settings + doc ke…
aisraelov Jun 17, 2026
6cc5b88
island: phoneNotifications config sync to native is island-owned (rev…
aisraelov Jun 17, 2026
529e095
island: glasses.settings sync also pushes the FULL set on (re)connect…
aisraelov Jun 17, 2026
8b16fe2
island: remove MantleManager boot settings-push — island on-connect i…
aisraelov Jun 17, 2026
e1adbca
docs(oem): correct glasses.settings key table (recording time is minu…
aisraelov Jun 17, 2026
68793c8
mobile: route connection/pairing lifecycle calls through toolkit faca…
aisraelov Jun 17, 2026
45ec395
mobile: finish Tier 1 facade swaps + add toolkit.dev.getMemoryMB (Tie…
aisraelov Jun 17, 2026
9821a58
mobile: fold pre-connect settings seed into island + add Tier 2 facades
aisraelov Jun 17, 2026
bbaa50f
island: move device-status projection out of host MantleManager (Type…
aisraelov Jun 17, 2026
10731d5
island: move PhoneVideoCoordinator into island (Type-B coordinator #1)
aisraelov Jun 17, 2026
395f468
island: move PhonePhotoCoordinator into island (Type-B coordinator #2)
aisraelov Jun 17, 2026
2fb8c81
island: move PhoneStreamCoordinator into island (Type-B coordinator #3)
aisraelov Jun 17, 2026
5e672a2
island: move HeadingService into island (Type-B: heading domain)
aisraelov Jun 17, 2026
2693cc2
island: move NavigationService into island (Type-B: navigation domain)
aisraelov Jun 18, 2026
f96860c
island: OTA read/observe surface -> island OtaService + toolkit.ota (…
aisraelov Jun 18, 2026
c74be5c
island: toolkit.ota install/retry actions; route OTA install through …
aisraelov Jun 18, 2026
d130c96
island: move gallery sync into island + toolkit.gallery facade (Type-…
aisraelov Jun 18, 2026
87f19b9
island: guard gallery location-services check with a timeout (host pa…
aisraelov Jun 18, 2026
46d9494
island: dedupe toolkit.gallery.onStatus (match other read-model facades)
aisraelov Jun 18, 2026
38660fa
island: move mic_lc3 -> v2 cloud uplink into island (OEM audio/transc…
aisraelov Jun 18, 2026
eb53e1e
island: wire the two missing toolkit.notifications detectors
aisraelov Jun 18, 2026
67ff0b2
island: move cameraSettings + locationTier off host hooks into island
aisraelov Jun 18, 2026
b62489f
island: add toolkit.glasses.reconnect + isFirstPairing facade methods
aisraelov Jun 18, 2026
e523f95
Merge origin/dev into aisraelov/island-namespace-wifi
aisraelov Jun 18, 2026
ec03937
island: move display-output / mic-control / transcriber-restart off h…
aisraelov Jun 18, 2026
15ce86d
fix: dedupe MantleManager listeners + correct location-tier accuracy …
aisraelov Jun 18, 2026
1786dc4
island: DeviceEventRouter — own the inbound device-event plane (OEM d…
aisraelov Jun 18, 2026
f913e0f
island: read glasses status from the island store (drop glassesStatus…
aisraelov Jun 18, 2026
9abf905
Merge origin/dev into aisraelov/island-namespace-wifi
aisraelov Jun 18, 2026
86ab1f0
island: move AudioPlaybackService into island (drop the audioPlayback…
aisraelov Jun 18, 2026
5cd8a1f
Merge origin/dev into aisraelov/island-namespace-wifi
aisraelov Jun 18, 2026
a50049a
island: self-wire the settings hook + declare island's runtime deps (…
aisraelov Jun 18, 2026
613cbf0
island: own the MentraJS engine + start it in toolkit.start()
aisraelov Jun 18, 2026
ad5828c
island: declare react-native-nitro-modules dep + complete the island …
aisraelov Jun 18, 2026
9af45bc
Merge remote-tracking branch 'origin/dev' into aisraelov/island-names…
aisraelov Jun 19, 2026
5ecccaf
Merge remote-tracking branch 'origin/dev' into aisraelov/island-names…
aisraelov Jun 19, 2026
dfa88a8
island: address review-bot findings (detached incidents.file, await s…
aisraelov Jun 19, 2026
db4ad5d
island: arm gallery WiFi auto-retry on the user's choice, not optimis…
aisraelov Jun 19, 2026
bf7b1c4
island: route local_transcription to miniapps in DeviceEventRouter; d…
aisraelov Jun 19, 2026
5b6a213
Simplify deleting SocketCommsAdapter as we are dropping support for c…
Jun 20, 2026
b55671e
Collapse island runtime configure seams
Jun 20, 2026
2141ed9
Delete cloud v1 miniapp catalog
Jun 20, 2026
2d3285d
Merge branch 'dev' into aisraelov/island-namespace-wifi
PhilippeFerreiraDeSousa Jun 20, 2026
04bfca6
Restore home grid app launch feedback
Jun 20, 2026
3922567
Remove cloud v1 MiniApp Store from mobile
Jun 20, 2026
1fe3341
Remove stale MiniApp Store deeplinks
Jun 20, 2026
0997ca5
Seed Bluetooth settings before direct connect
Jun 20, 2026
f9b2bcf
Stop island runtime during logout
Jun 20, 2026
7e61237
Preserve partial Cloud V2 URL overrides
Jun 20, 2026
12b7220
Remove legacy cloud v1 audio path
Jun 20, 2026
17bc862
Remove legacy cloud v1 binary audio forwarding
Jun 20, 2026
1af6587
Remove legacy cloud applet routes
Jun 20, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion .github/workflows/mentra-app-ios-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,18 @@ jobs:

- name: Install CocoaPods dependencies
working-directory: ./mobile/ios
run: pod install
run: |
# Self-heal a corrupted prebuilt-framework cache: the cached Pods can be
# valid-by-lockfile-key yet missing the React-Core-prebuilt React.xcframework
# Info.plist (a known RN-0.83 prebuilt + CocoaPods cache flake on the
# self-hosted runners). On failure, clear the project Pods + the global pod
# cache and reinstall fresh. Happy path is unchanged.
pod install || {
echo "::warning::pod install failed (likely a stale/corrupt prebuilt cache) — clearing caches and retrying"
rm -rf Pods Podfile.lock
pod cache clean --all || true
pod install --repo-update
}

- name: List available simulators
run: xcrun simctl list devices available
Expand Down
106 changes: 106 additions & 0 deletions agents/island-facade-buildout.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
# Island facade buildout — tracking spec

Goal: build the OEM-facing `toolkit.*` typed facades by moving the backing logic
into `@mentra/island`, domain by domain, on branch `aisraelov/island-namespace-wifi`
(PR #3167). One branch, one commit per domain, green at every commit.

## Two move-patterns
1. **Self-contained logic** — move the file into island, fix relative imports
(btsdk types via `../../../bluetooth-sdk/build/_internal`), wrap in a facade.
Shim the old host path if the app still imports it. (Stores, speech, logs,
permissions, incidents.)
2. **Host-service-coupled** — move the logic in. Where it needs a host capability,
prefer **owning it in island** (the keystone moved storage + the status store +
the client itself in; only `auth` + endpoints come from the host, via the
permanent `configure()` front door, NOT a `configureRuntime` adapter). Per
OS-1622, every `configureRuntime` adapter is transitional scaffolding that
**deletes itself** as its domain lands — "zero permanent adapters remain." So a
`configureRuntime` bridge is a temporary means, not the destination; aim
adapter-free. The one permanent seam is `auth.getSubjectToken`.

Rule: stores are the Mentra-app escape hatch (`toolkit.stores.*`), NOT the OEM
contract. OEMs use the typed facade functions.

## cloud-v2 mobile-CI integration (was fully broken on dev)
The cloud-v2 merge left the mobile CI red on dev (install died on a 404, so the
typecheck never even ran). Three fixes, all on this branch (they un-red dev too):
1. **Spurious dep** — `mobile/modules/island/package.json` declared
`"@mentra/cloud-client": "*"`; cloud-client is resolved via metro+tsconfig path
aliases, not npm, so the `*` 404'd. Removed it.
2. **island standalone build** — `postinstall` builds island via `expo-module`
(`build:module`), whose isolated tsconfig lacks the cloud-v2 aliases → fails on
cloud-v2 imports. But island's `build/` is unused (metro + tsconfig resolve
`@mentra/island` → src). Made it non-fatal in `mobile/scripts/postinstall.mjs`.
3. **cloud-v2 deps** — the mobile typecheck follows the aliases into cloud-v2
SOURCE (`../cloud-v2/packages/*`), which import `zod`/`tweetnacl`; resolution is
file-relative so they must be in `cloud-v2/node_modules`, never installed (cloud-v2
is a separate bun workspace). Added a `bun install` in `../cloud-v2` to the mobile
postinstall.
Don't re-introduce island's `@mentra/cloud-client` package.json dep, and keep
`island/tsconfig.json`'s cloud-v2 `paths` (a local `build:module` regenerates and
strips them — don't commit that).

## Host-coupling reality (corrects the earlier "mechanical" optimism)
Only facades whose logic is ALREADY in island are quick wraps (done: glasses, wifi,
display.mirror, speech). The rest are HOST-SERVICE moves whose services are coupled
to host utils (i18n, theme, AlertUtils, storage, RestComms), so they need the
adapter-injection pattern (#2), not a trivial move:
- `permissions` — PermissionsUtils.tsx (1008 LOC, 24 consumers): imports i18n, theme,
AlertUtils, NotificationServiceUtils, storage. Adapter-coupled.
- `settings` — the keystone (RestComms + storage + react-native-localize + expo-device).
- `incidents`, `dev`, `gallery`, `phoneNotifications` — similar host coupling.
These are real per-domain efforts, each its own careful commit.

## Docs (keep current as we go)
Each shipped domain is documented in the OEM docs at `docs/glasses-oems/toolkit.mdx`
(Mintlify). When a facade lands, add its surface there in the same commit. The page is
written but **not yet nav-linked in `docs/docs.json`** — it's an unreleased Phase-1
API, so publishing to the live OEM site is gated until release (one-line nav add when
greenlit).

## Verification per commit
`npx tsc --noEmit -p .` (resolves `@mentra/island`→src, validates the real code) +
`bun run test`. The island standalone build can't run locally (cloud-v2 `zod` not
installed in this checkout) — CI confirms it; use the proven relative-`_internal`
pattern for btsdk types.

## Domains
| Domain | Backing logic lives | Pattern | Status |
|---|---|---|---|
| glasses.wifi | btsdk passthrough + glasses store | 1 | DONE (#3167) |
| display.mirror | island display store | 1 | DONE (#3167) |
| glasses (core) | glasses store + btsdk + ConnectionCoordinator | 1 | in progress |
| speech | STT/TTSModelManager (already island) | 1 | DONE (#3167) |
| ~~logs~~ | MentraJSLogPipeline (already island) | — | **NOT a facade** — island's pipeline is internal *miniapp*-log plumbing for MentraJSRouter; the app UI never reads it. The logging the UI uses (bug-report "send logs") is the HOST-side `logBuffer` (`mobile/src/utils/dev/logging.ts`) + `RestComms.uploadIncidentLogs` → belongs to the `incidents` domain, not a `logs` facade. Skip. |
| permissions | `utils/PermissionsUtils.tsx` (host) | 1 | todo |
| incidents | `services/bugReport/*` (host) | 1 | todo |
| dev | `utils/cloudClient/devHost.ts` + core store | 1 | todo |
| miniapps | apps store + LocalMiniappRuntime (island) + MiniappCatalog | 1/hard (WebView) | todo |
| pairing | pairing screens state machine (readiness primitive already island) | 1 (extract) | todo |
| **settings** | `stores/settings.ts` (964 LOC) + `RestComms` + `storage` | keystone | **DONE (#3167)** — settings store moved into island, `toolkit.stores.settings`. Moved **together with RestComms** (mutually coupled: settings→RestComms cloud-sync, RestComms→settings backend URL). Storage uses island's MMKV (ported `loadSubKeys`). Unblocks glasses.settings + phoneNotifications. The typed `toolkit.settings` keyed facade (get/set/onChanged) is still TODO on top of the moved store. |
| **RestComms** (v1 REST) | `services/RestComms.ts` (731 LOC) | move-with-settings | **DONE (#3167)** — moved into island with settings (the coupled pair). v1-transitional: deleted in place when v1 retires. Reads backend URL from the now-island settings store directly (no early-auth timing hack). Host `@/services/RestComms` is a shim. GlobalEventEmitter also moved in (one shared instance). |
| glasses.settings | settings store + btsdk | 2 (after settings) | blocked on settings |
| phoneNotifications | settings store + crust + permissions | 2 (after settings) | blocked on settings |
| gallery | `services/asg/gallerySyncService.ts` (~1000 LOC, hotspot) | hard | todo |
| notifications | scattered detectors → new event bus | hard (new) | todo |
| session | `cloud-client` (cloud-v2) | keystone | **DONE (#3167)** — `CloudClientService` owns the CloudClient in island (built from island UDP + MMKV secure store + `getAuth()` + endpoints via `getConfigValues()`); self-wires the `cloud`/`cloudConnection` runtime hooks; `toolkit.session` exposes status. Account ops (delete/export) deferred (still host RestComms). Host `@/services/cloudClient` is a thin wrapper keeping dev/settings endpoint resolution. |
| cloudClientStatus (store) | cloud-client types | — | **DONE (#3167)** — moved into island, `toolkit.stores.cloudClientStatus`. |
| cloud secure store (MMKV) | cloud-client KeyValueStore | — | **DONE (#3167)** — moved into island (react-native-mmkv already an island dep; adapter-free). |

## Sequence
**Cheap (logic already in island) — DONE this PR:** glasses-core, glasses.wifi,
speech, display.mirror + 5 device-store moves. `logs` was investigated and is NOT a
facade (see table). So the cheap tier is exhausted; everything below is a
host-service move needing the `configureRuntime` adapter seam.

**Decision point (host-coupled tier):** these move 1000+ LOC host services into
island behind adapters. The mobile engineer already pushed back on moving too much
in (routing/UI) — so align on the adapter contract BEFORE moving permissions/
settings/bugReport, rather than doing it blind. Recommended order once greenlit:
permissions → incidents → dev → **settings keystone** (own commit; unblocks
glasses.settings + phoneNotifications) → pairing → gallery → miniapps WebView →
notifications. Last: `git merge dev`, then session + cloudClientStatus.

This PR (#3167) is a clean, landable foundation at the cheap-tier boundary: the
core `toolkit.*` facade surface + store escape hatches, green. Land it, then
sequence the host-coupled tier deliberately.
Loading
Loading