Guidance for coding agents working in reticulum_mobile_emergency_management.
- This repository is a mixed workspace:
apps/mobile: Vue 3 + Vite + Capacitor mobile/web clientpackages/node-client: TypeScript bridge used by the app to talk to the native plugin surfacecrates/reticulum_mobile: Rust runtime, UniFFI bridge, and LXMF/Reticulum integrationtools/codegen: UniFFI binding generation scriptse2e: Playwright end-to-end coverage
- Primary product focus is emergency coordination over Reticulum mesh networking, including peer discovery, action messages, event replication, and telemetry.
- Start from the repo root unless a package-specific command clearly belongs elsewhere.
- Check
git statusbefore editing. This repo often has generated Android/Rust artifacts in the worktree. - Do not hand-edit generated or build output unless the task is explicitly about generated artifacts or native packaging.
- Keep fixes scoped. A UI change should not casually rewrite transport or runtime behavior.
- Prefer updating the real source of truth rather than patching copied artifacts.
- Use the compiled
LXMF-rsimplementation through the existing Rust bridge and generated bindings. Do not recreate LXMF protocol functionality in TypeScript, Vue stores, or ad hoc Rust compatibility code when the compiled library already provides it.
apps/mobile/src/views: route-level screensapps/mobile/src/components: reusable UI piecesapps/mobile/src/stores: Pinia stores; most app behavior lives hereapps/mobile/src/utils: protocol helpers, peer parsing, replication helpers, mission sync helpersapps/mobile/src/services: platform-facing helpers such as sharing, notifications, telemetry helpersapps/mobile/src/types/domain.ts: shared app domain typespackages/node-client/src/index.ts: TS client boundary for the native bridgecrates/reticulum_mobile/src/runtime.rs: main Rust runtime behaviorcrates/reticulum_mobile/src/sdk_bridge.rs: SDK-facing LXMF bridge layercrates/reticulum_mobile/src/jni_bridge.rs: native boundary used by the mobile sidecrates/reticulum_mobile/src/reticulum_mobile.udl: UniFFI interface definitiondocs/architecture.md: transport and replication architecture notes
Treat these as generated or disposable unless the task explicitly targets them:
node_modules/target/playwright-report/test-results/tmp/apps/tmp-playwright-ui.errapps/mobile/tmp-playwright-ui.errapps/mobile/tmp-playwright-ui.outapps/mobile/android/app/build/apps/mobile/android/app/src/main/jniLibs/apps/mobile/android/uniffi/apps/mobile/ios/uniffi/
On Windows, broad recursive directory scans can fail inside Android build intermediates. Prefer scoped searches over targeted source directories instead of walking the entire repo.
- Vue code is written with Vue 3 Composition API and
<script setup lang="ts">. - TypeScript is
strictin both the app andpackages/node-client. - Pinia stores hold most stateful behavior. Keep business logic in stores and utilities, not inside view templates.
- Reuse existing domain types from
apps/mobile/src/types/domain.tsbefore inventing near-duplicates. - Keep wire/protocol helpers centralized in
apps/mobile/src/utilsand Rust runtime files rather than scattering message-shape logic across components. - App-wide button press feedback is defined on global
buttonrules inapps/mobile/src/styles.css; component buttons should set the existing CSS custom properties rather than adding one-off:activebehavior. - Maintain the existing style conventions in touched files:
- double quotes
- semicolons
- explicit typing when it improves clarity at boundaries
Apply these additional rules whenever a task touches Rust code, Cargo.toml, or the UniFFI/native bridge:
- Treat the installed Rust skills bundle as the default routing layer for Rust work:
- general Rust questions or ambiguous Rust tasks:
rust-router - ownership, borrowing, lifetimes, and move errors:
m01-ownership - smart pointers and resource ownership patterns:
m02-resource - error modeling and propagation:
m06-error-handling - async,
Send/Sync, threading, and channels:m07-concurrency unsafe, FFI, raw pointers, JNI, and bridge boundary reviews:unsafe-checker
- general Rust questions or ambiguous Rust tasks:
- For new Rust crates or new
Cargo.tomlpackage sections created in this repo, default to:edition = "2024"rust-version = "1.85"[lints.rust] unsafe_code = "warn"[lints.clippy] all = "warn"andpedantic = "warn"
- Prefer domain-correct design fixes over borrow-checker workarounds. Do not reach for cloning or ownership duplication until the ownership model is justified by the runtime and protocol design.
- Use
?and typed error propagation in library/runtime code instead ofunwrap()orexpect(), unless a crash is intentionally part of the boundary behavior. - Every
unsafeblock must carry a nearby// SAFETY:comment that states the invariant making the block sound. - Keep Rust changes aligned with the existing project architecture in this file, especially the rules about using the compiled
LXMF-rsimplementation through the current bridge instead of recreating protocol behavior in higher layers.
Use this map to decide where a change belongs:
- UI layout, forms, route behavior:
apps/mobile/src/viewsapps/mobile/src/components
- Persisted app state, peer lists, message/event/telemetry workflows:
apps/mobile/src/stores
- Wire format, mission sync, peer parsing, announce capability logic:
apps/mobile/src/utils
- Capacitor-facing TypeScript API surface:
packages/node-client/src/index.ts
- Native runtime behavior, packet/LXMF handling, delivery tracking:
crates/reticulum_mobile/src/runtime.rscrates/reticulum_mobile/src/sdk_bridge.rscrates/reticulum_mobile/src/jni_bridge.rs
- UniFFI interface or generated mobile bindings:
crates/reticulum_mobile/src/reticulum_mobile.udl- then run the appropriate
tools/codegenscript instead of editing copied bindings by hand
Run the narrowest command set that proves the change:
- Install JS dependencies:
npm install
- App development:
npm run web:devnpm run mobile:dev
- Builds:
npm run web:buildnpm run mobile:buildnpm run node-client:buildnpm --workspace packages/node-client run build
- Capacitor native workflow:
npm --workspace apps/mobile run syncnpm --workspace apps/mobile run androidnpm --workspace apps/mobile run ios- Current project release work does not target iOS compilation. For Android packaging, prefer
npx cap sync androidfromapps/mobileinstead of fullnpm --workspace apps/mobile run sync, because full sync also tries the iOS CocoaPods step.
- Type checking:
npm --workspace apps/mobile run typecheck
- E2E:
npx playwright install chromiumnpm run test:e2enpm run test:e2e:headednpm run test:e2e:debug
- Rust:
cargo test --manifest-path crates/reticulum_mobile/Cargo.toml
- UniFFI code generation:
- PowerShell:
./tools/codegen/generate-uniffi-bindings.ps1 -Language kotlin - PowerShell:
./tools/codegen/generate-uniffi-bindings.ps1 -Language swift - Shell:
./tools/codegen/generate-uniffi-bindings.sh kotlin - Shell:
./tools/codegen/generate-uniffi-bindings.sh swift - The PowerShell script falls back to the workspace
tools/uniffi-bindgencrate whenuniffi-bindgenis not onPATH. - The shell script does not have the same fallback: it skips Kotlin binding generation without
uniffi-bindgenonPATHand fails for Swift.
- PowerShell:
- Android release artifacts:
- From
apps/mobile/android:cmd /c gradlew.bat assembleRelease bundleRelease
- From
There is no dedicated root lint script at the moment. For most app changes, typecheck + the relevant build + the closest Playwright spec is the minimum useful validation.
- If you change a payload shape or delivery flow in TypeScript, verify whether the same change must be reflected in:
apps/mobile/src/utils/missionSync.tsapps/mobile/src/utils/replicationParser.tspackages/node-client/src/index.tscrates/reticulum_mobile/src/jni_bridge.rscrates/reticulum_mobile/src/runtime.rsdocs/architecture.md
- Preserve the current architecture where LXMF behavior comes from compiled
LXMF-rscode. Extend the bridge or SDK integration when needed, but do not duplicate encoding, delivery tracking, or protocol logic in higher layers just to bypass the compiled library. - If you change the UniFFI contract, regenerate bindings instead of editing generated outputs manually.
- If you change event or telemetry behavior, update or add the closest Playwright coverage in
e2e/. - If transport behavior changes, document the new flow in
docs/architecture.mdor the relevant README.
crates/reticulum_mobile/Cargo.tomlcurrently pointslxmfandlxmf-sdkto local path dependencies. Do not replace those paths casually; they reflect this workspace's current development setup.- Android signing uses local, ignored configuration under
apps/mobile/android/keystore.properties. - This project currently does not try to compile for iOS. Do not treat iOS build or CocoaPods failures as release blockers unless the user explicitly asks for iOS work.
- Root Playwright config starts the web app and exercises the app through the browser at
/dashboard.
Before finishing, make sure you can state:
- what changed
- which layer(s) were touched
- which verification commands were run
- whether any generated artifacts were intentionally updated
- whether docs or tests were updated to match behavior changes