Repository implementation guidelines for coding agents working with MentraOS.
MentraOS is an open source operating system, app store, and development framework for smart glasses.
- Architecture: Smart glasses connect to the user's phone via BLE; the Mentra App runs miniapps locally and connects to Cloud V2 services
- Mobile app:
mobile(React Native with native modules) - Android logic:
android_core - iOS native module:
mobile/ios - Backend & web portals:
cloud-v2(Core, Runtime, Cloud Client, CLI, admin, and portal) - Android-based smart glasses client:
asg_client(usesandroid_coreas a library) - Websites:
cloud-v2/websites/(admin portal, workspace portal, sign-in site). The Mentra Miniapp Store and Developer Console live in the separate Mentra Miniapp Store service.
- The Mentra App already supports screen-off and background operation using its
Bluetooth background mode infrastructure. See
UIBackgroundModesinmobile/app.config.ts. - Bulk gallery transfers over the glasses' SoftAP already work in the background
on iOS. Reuse the existing gallery and local network transport paths, including
mobile/modules/engine/src/services/asg/localNetworkTransport.ts. - Treat these as established product behavior when planning streaming features. Do not infer that iOS SoftAP or background operation is structurally impossible from generic platform restrictions or older spike notes. Investigate the new media pipeline and its routing requirements against the existing implementation.
This is a monorepo with module-specific guidance:
/mobile/AGENTS.md- React Native mobile app guidelines
Consult module-specific AGENTS.md when working within that module.
Core client app lives in mobile/ (Expo React Native). Backend services, the Cloud Client, protocol package, CLI, web portals, and cloud tests live in cloud-v2/. The local Mentra Miniapp SDK is mobile/modules/miniapp/; developer tooling is in sdk/. Platform SDKs are in mobile/modules/bluetooth-sdk/ and sdk_ios/; hardware tooling lives in mcu_client/. Public Mintlify docs live in mintlify-docs/; notes and plans live in agents/ and notes/ — see notes/README.md for the specs/plans convention.
First-party miniapps and their backends also live in miniapps/. All of those
miniapps are part of this repository's source scope, for example
com.mentra.captions in miniapps/captions/.
Package identifiers can be found in miniapps/**/miniapp.json; the surrounding
component directories contain backend and deployment files. A separate backend
hostname does not imply a separate repository or third-party ownership.
The external first-party miniapp repositories are listed under
"Related Miniapp Repositories" below; their source can be private.
- Start dev server:
npm startorbun start - Run on platforms:
npm run android,npm run iosorbun android,bun ios - Build Android:
npm run build-android,npm run build-android-release - Run tests:
npm test,npm test -- -t "test name"(single test) - Lint code:
npm run lintorbun lint - iOS setup:
cd ios && pod install && cd .. - Prebuild:
bun expo prebuild(syncs native projects - NEVER use --clean or --clear flags!)
- ASG client compile check:
./scripts/check-android-compile.sh asg - Bluetooth SDK Android compile check:
./scripts/check-android-compile.sh bluetooth-sdk - Both checks:
./scripts/check-android-compile.sh
The Bluetooth SDK Android sources under mobile/modules/bluetooth-sdk/android
are compiled through the generated Expo Android project at mobile/android,
matching CI. Do not rely on a system gradle install from the SDK source
directory; use the repo script so the Gradle wrapper and prebuild setup are
consistent. The Bluetooth SDK check runs with -PmentraPublicSdk=true so it
validates the public Maven artifact dependency shape.
- Install deps:
cd cloud-v2 && bun install - Setup environment:
bun run setup(orbun run setup:testfor tests) - Dev:
bun run dev - Type check:
bun run typecheck - Test:
bun run test - Web portals:
bun run dev:adminorbun run dev:portal
- macOS or Linux (recommended for mobile development) - Windows has known issues with this project
- Use nvm (Node Version Manager) to manage Node.js versions
- Node.js 20.x (recommended version)
- Node.js ^18.18.0 || >=20.0.0 (20.x recommended)
- nvm (Node Version Manager - highly recommended)
- npm/yarn/bun (bun preferred)
- Android Studio (for Android development)
- Xcode (for iOS development on macOS)
- Docker and Docker Compose (for cloud development)
- Java SDK 17 (for Android components)
- Java SDK 17 required
- Classes: PascalCase
- Methods: camelCase
- Constants: UPPER_SNAKE_CASE
- Member variables: mCamelCase (with m prefix)
- Javadoc for public methods and classes
- 2-space indentation
- EventBus for component communication
- Functional components with React hooks
- Imports: Group by external/internal, alphabetize within groups
- Formatting: Prettier with single quotes, no bracket spacing, trailing commas (2-space indent)
- Navigation: React Navigation with typed params (expo-router for mobile)
- Context API for app-wide state
- Feature-based organization under src/
- Use try/catch with meaningful error messages
- Strict typing with interfaces for message types
- PascalCase for components/classes/interfaces/types, camelCase for variables/functions/hooks
- UPPER_SNAKE_CASE for environment keys
- Use
swiftformatfor formatting
- Code follows language-specific conventions (Java, TypeScript, Swift)
miniappis always one word, lowercase, in running text.- Products take a capital
M: "Mentra Miniapp SDK", "Mentra Miniapp Store". When you write "miniapp SDK" capitalize it as "Miniapp SDK"; the full product name is "Mentra Miniapp SDK" (not "MentraOS miniapp SDK"). - The iOS/Android mobile app is the "Mentra App" (not "MentraOS app", not "Mentra app").
- Miniapps in general (apps that run on the Mentra platform) are "Mentra miniapp" / "Mentra miniapps" (not "MentraOS apps").
- The store is the "Mentra Miniapp Store".
- "MentraOS" stays as-is when it names the operating system / platform / repo (e.g. "MentraOS is the operating system for smart glasses"). Don't swap it for "Mentra" in those cases.
- The package identifier
@mentra/miniappis code; leave it in code formatting.
Cloud V2 services use Bun tests via cd cloud-v2 && bun run test; add suites in cloud-v2/tests/ or beside the relevant package code and mock external providers. Mobile UI logic uses Jest (bun test, bun test:watch) with files colocated in mobile/test/ and snapshots beside components. Device flows rely on Maestro (bun test:maestro), so update scripts whenever navigation or pairing shifts. Features touching pairing, BLE, or transcription need unit coverage plus an end-to-end path.
For a failing nightly device suite, use
fix-nightly-failures. Keep independent
members running, diagnose failures as they arrive, and choose targeted manual runs
or held authoring for verification after the suite finishes.
When adding or editing GitHub Actions workflows, use the
configure-workflow-runners skill.
Use Blacksmith for Linux jobs and the existing office Mac mini self-hosted runner
for macOS jobs. Do not add GitHub-hosted Linux runners unless the user explicitly
requests an exception. Apply this to reusable workflows and runner matrices too.
Write imperative, present-tense commit subjects (e.g., "Add BLE retry delay") and keep scope focused. Reference issue IDs or Slack threads in the body when applicable. Before opening a PR, run relevant bun run test suites and platform builds, attach log excerpts for hardware-dependent steps, and call out configuration updates. PR descriptions should outline scope, test evidence, and screenshots or screen recordings for UI-impacting changes.
When opening or updating a PR, use the
select-pr-routines skill to search
device-test coverage. Add relevant routine:<id> labels for existing coverage;
when the behavior needs changed or new coverage, submit the skill's authoring
brief with routine-work:edit or routine-work:create. Explain the coverage and
any missing prerequisite in the PR; a request is not a passing test result.
Do not add Co-Authored-By: trailers that name AI assistants (Claude, Codex, Copilot, etc.) to commit messages. Do not include "Generated with" or similar attribution lines (e.g., 🤖 Generated with [Claude Code]) in commit messages or PR descriptions. Commits and PRs should reflect the human author responsible for the change; the tools used to produce it are not part of the durable record.
When a feature or deployment needs a new or changed backend environment variable, use manage-cloud-env, including for first-party miniapps and their external repositories. Doppler is the source of truth. Put environment-independent settings in a shared inheritable config; keep environment-specific values in child configs. Check or establish the native Doppler-to-Porter connection before writing settings. Porter application overrides are a last resort, never the default workaround for a missing key or broken sync. Create a Doppler project and a shared parent when onboarding a deployment that has neither, even if it initially has only one deployment environment.
Cloud V2 services require local environment configuration; use cloud-v2/scripts/setup.ts and keep secrets out of the repository. Mobile secrets belong in mobile/app.config.ts or the secure config service—avoid committing device-specific tokens. Rebuild native projects after modifying BLE or camera modules to keep generated code in sync, and install Java 17, Android Studio, Xcode, Docker, and Bun/Node before the first build.
CRITICAL: When running MongoDB locally with Docker, always bind to localhost only:
ports:
- "127.0.0.1:27017:27017" # Correct - localhost only
# NOT "27017:27017" which exposes to all interfacesAutomated ransomware scanners actively target exposed MongoDB instances. Use MongoDB Atlas for production deployments.
- Mentra Notes Miniapp
- Mentra Call Miniapp
- Livestreamer Miniapp
- Mentra AI Miniapp
- Mentra Enterprise Miniapp
- Merge Miniapp (
com.mentra.merge)
If a MentraOS PR also requires changes to one of the external miniapps above, or you are otherwise asked to change one of those miniapps:
- Clone the external miniapp repository if needed, or pull the latest
mainbranch if it is already available locally. - Make the changes in the external miniapp repository, bump its version, and
push the changes directly to that repository's
mainbranch. - Package the updated miniapp as a ZIP archive.
- Add the new ZIP archive to
mobile/assets/miniapps/in the MentraOS monorepo so the external miniapp update is included in the MentraOS mobile PR.
Use the investigate-incident skill for report IDs and incident Slack links. Fetch reports and artifacts through the API script below, not admin-console browser or computer-use automation.
Bug reports and feedback filed from the Mentra App land in the Cloud V2 reports system. Report ids look like rep_01... and appear in the reports Slack notifications and in the admin console's Incident system page (admin.mentraglass.com).
- Get the report id (from Slack, the admin console, or the user)
- Fetch it:
./scripts/fetch-incident-logs.sh {reportId}— downloadsreport.jsonplus every artifact into./incident-logs/{reportId}/ - Requires
MENTRA_ADMIN_TOKENin your environment: an operator key with the incident read scope (mak_..., created in the admin portal under Operator keys). An older admin key (msk_...) whoseapi-key@<keyId>.localaddress is onCLOUD_CORE_ADMIN_EMAILSworks as an operator key too - Without an environment override, the script tries prod, dev, then staging and reports which backend succeeded. Use
--env prod|dev|stagingorMENTRA_CORE_URLto target one backend explicitly.
What you get:
report.json- Full report document:kind(bug/feedback/automatic),trigger,report(actual/expected behavior, severity, contact email),feedback,context(phone/glasses/app state snapshot), artifact metadata, and asset rowsNN-logs-{source}.json- Log bundles uploaded by the devices (e.g. phone, glasses), each{entries: [{timestamp, level, message, source?}]}NN-screenshot-phone-*.{png,jpg}- Screenshots attached by the user
Other modes: --json prints the raw report JSON to stdout (no downloads); --list [--kind ...] [--status ...] [--limit N] lists recent reports.
Example:
export MENTRA_ADMIN_TOKEN=mak_your-operator-key
./scripts/fetch-incident-logs.sh rep_01JZWY3V8N0F2E9GQ4T6KXH5RDGlasses MCU firmware lives in the sibling mentra-live-bes repo, not this monorepo. Follow that repo's AGENTS.md when changing it.
After every BES firmware source change, run the OTA sanity gates in that repo (./build_pz.sh OTA or python3 tools/verify_ota_build.py …). A successful compile is not enough: a raw best1502x_ibrt_bpone.bin >= 1,966,080 bytes will brick a device that receives it via OTA. Do not install or release if that gate fails.
- Mintlify docs:
/mintlify-docs/ - Architecture specs, design docs, and working notes:
/notes/(convention:notes/README.md) - Module-specific implementation details: See module-specific
AGENTS.mdfiles - Teams calling (ACS) native pipeline, end to end:
mobile/modules/acs-meeting/README.md, with the shared transport inmobile/modules/glasses-media/README.md