Guidance for Coding Agents (Claude Code or Codex, etc.) collaborating in this monorepo.
Read this file first, then load only the skills relevant to your current task — you do not need to read all files upfront. cross-platform-awareness.md and engineering-principles.md apply to every task; the rest are load-on-demand.
- Project Overview — Repo layout, ownership boundaries, and shared concepts
- Cross-Platform Awareness — Rules for changes that can affect both apps
- Development Commands — Root build, generate, localization, and platform entrypoint commands
- Architecture — High-level iOS, Android, and shared-layer architecture
- Engineering Principles — Clean-code rules shared across the repo
- Code Review — Review checklist for correctness, conventions, parity, and adversarial security hardening
- Security — Wallet-critical security rules for key material, signing, auth, and transaction handling
- Quality Checks — Lint, format, and static-analysis commands for each platform
- Maestro UI Testing — When to use Maestro flows vs unit or native UI tests, and cross-platform authoring rules
- Release Process — Branching, versioning, and commit expectations
- Localization — Shared localization flow and generated output locations
- New Feature Workflow — End-to-end sequence for cross-stack features (Core → bindings → iOS/Android)
- Decision Records — Non-obvious architectural choices and their rationale
Read the relevant platform guide(s) before editing code in that area:
- iOS — SwiftUI, MVVM, SPM modules, testing conventions
- Android — Kotlin, Compose, Hilt, Gradle workflow
- Core — Rust crates, UniFFI/TypeShare, clippy, defensive programming
If a task spans multiple platforms, read every affected guide. Do not treat every core/ edit as a cross-platform build change. Regenerate and verify the apps only when Core changes UniFFI/TypeShare interfaces, generated models, platform build inputs, or app-side integration. For internal Core implementation changes that preserve those contracts, run the relevant Core verification without building iOS or Android.
Cross-platform subsystem references live in docs/. Read the relevant one before changing that area:
- Deep links — deep link URL contract, support-chat links, and the web association requirements
- Device and subscriptions — device registration, subscription sync, and the iOS/Android contract
- Payments — payment decoding flow, implementation map, and QR test cases
- Swapper — quote flow, route preloading, and the shared route cache
Core-owned subsystems (keystore, device and wallet authentication, WebSockets, provider coverage) are documented in docs/; the architecture reference every new feature follows is docs/ARCHITECTURE.md, and the remaining migration work is docs/SERVICES.md.
This is a crypto wallet. Treat security-sensitive changes as high risk by default.
- Read skills/security.md before changing key management, wallet import/export, seed phrases, signing, transaction construction, auth, secure storage, or cryptographic flows
- Never log, print, persist, snapshot, or expose secret material unless the feature explicitly requires secure handling and existing patterns already support it
- Preserve transaction integrity: amounts, addresses, chain IDs, signatures, simulation data, and confirmation flows must stay explicit and verifiable
- Prefer existing secure-storage and auth layers over inventing new persistence or authentication paths
- If a
core/cryptography or signing change also affects mobile interfaces, generated outputs, platform build inputs, or app-side integration, regenerate and verify the affected apps
- Tests must verify intent, not just behavior. If the same test still passes after the business rule flips, it is a tautology — fix the assertion or the function under test
- When fixing a high-impact bug, add or update the smallest meaningful test only if it materially reduces regression risk; keep it compact, avoid trivial/framework/formatting-only coverage, and skip purely visual UI polish unless coverage is explicitly requested or already cheap to extend
- "Tests pass" is not a green light if any were skipped, marked
xfail, or guarded behind feature flags you did not run — report what you actually executed
- Use single-word names for Core settings keys;
_is reserved for separating the settings hierarchy in environment variables. - When two patterns contradict (iOS vs. Android handling of a shared flow, two error-mapping styles in
core/, parallel provider implementations), do not blend them. Pick the more recent or more tested one, state why, and flag the other for follow-up - Never wrap an immutable request client in a shared
Mutexor hold that client lock across network or database I/O. Use mutexes only for narrowly scoped mutable coordination - Prefer immutable bindings and transformations. Use
mutonly when ownership requires mutation, and keep its scope narrow - Use full domain terms in code names: write
transaction, nottx, except when preserving external protocol field names, database columns, or URLs verbatim - For multi-step work that crosses Core → bindings → iOS/Android, checkpoint after each step: state what changed, what was verified, what is left. Do not continue from a state you cannot describe back
- If a regeneration's effect on either app is unclear, stop and restate before adding more changes
- Mobile app localization source of truth lives in
localization/app/*.ftl, using Fluent message IDs with underscores, for examplecommon_cancel - Fluent comments are supported in source files (
#,##,###) and ignored by generation; use English comments inen.ftlfor section or string context - Add new keys in the right section by prefix (
common_*under# Common,wallet_*under# Wallet, etc.) - Add every new app key to every language file, translated for the context where the string is used; do not leave missing keys for generation to hide
- iOS InfoPlist localization source lives in
localization/InfoPlist/*.ftl - iOS widget localization source lives in
localization/widget/*.ftl - Run
just localizeafter editing localization source files - Generated outputs live under
ios/Packages/Localization/andandroid/ui/src/main/res/ - Do not edit generated iOS
.strings, generated SwiftGen files, or Androidstrings.xmlfiles by hand - Backend/core localization is separate; see core/CLAUDE.md before changing
core/crates/localizer/i18n
For documentation-only changes, do not run mobile/core build and test suites unless the docs change also modifies executable scripts, generated inputs, localization inputs, CI configuration, build configuration, or release/security procedures. Verify docs-only changes with lightweight checks such as git diff --check, link/path inspection, and a quick read-through of the edited files.
During active implementation, rebase conflict resolution, or compile-fix loops, prefer targeted build/test commands and defer broad verification until the change is ready to commit. Do not run full platform builds, full test suites, broad lint, or format after every small edit unless the risk of the change requires it.
Run final verification as a batch after you believe no more code edits are needed. If formatting, localization, generation, or a compile fix changes source after that batch starts, rerun the affected targeted checks before handoff.
Before finishing a task:
- Build the affected platform(s)
- Run the relevant test suites
- Review security impact for changes affecting secrets, signing, auth, transactions, or wallet recovery
- If
core/changed mobile interfaces, generated models, platform build inputs, or app-side integration, regenerate and verify the affected app(s); otherwise keep verification scoped to Core - Remove dead code, keep imports clean, and follow platform patterns
Do not close a task based only on reasoning, git diff, or file inspection. Run real verification commands for the changed area. If verification is blocked by unrelated repo state, report the exact command you ran and the blocking failure explicitly.
For wallet-critical flows (signing, secure storage, migrations, key import/export, transaction construction), "completed" is wrong if anything was skipped silently. Surface skipped records, swallowed errors, or untested branches explicitly — a silent success on these paths is the most expensive failure mode in this repo.