Skill: DI and Navigation 3 Architecture
SkillDev toolsLets your agent look up the Android app for controlling Meshtastic mesh radio devices.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the Skill: DI and Navigation 3 Architecture skill
About this capability
Android application for Meshtastic
What this skill tells your AI
The instructions your AI receives, as published by meshtastic/meshtastic-android in .skills/navigation-and-di/SKILL.md and read by ahel’s review.
Description
This skill covers dependency injection (Koin Annotations 4.2.x) and JetBrains Navigation 3 (1.1.x) architecture, constraints, and anti-patterns within the Meshtastic-Android KMP codebase.
Dependency Injection (Koin)
Guidelines
- Annotations First: Use
@Module,@ComponentScan, and@KoinViewModelannotations directly incommonMainshared modules to encapsulate dependency graphs per feature. - App Root Assembly: Don't assume feature/core
@Moduleclasses are active automatically. Ensure they are included by the app root module (@Module(includes = [...])) inandroidApp/src/main/kotlin/org/meshtastic/app/di/AppKoinModule.ktanddesktopApp/.../DesktopKoinModule.kt. - No Platform Bleed: Don't put Android framework dependencies (
Context,Activity,Application) into sharedcommonMainbusiness logic. Inject interfaces instead. - Resolution: Resolve app-layer wrappers via
koinViewModel()or injected bindings within Compose navigation graphs.
Anti-Patterns
- Compile Safety Outside An Entry Point: Do not enable
compileSafetyon a library module. Validation is whole-graph and runs at the@KoinApplicationentry point, so a library validates against a graph it cannot see and reportsKOIN-D003for definitions its consumers supply.KoinConventionPluginenables it only for the modules inKOIN_ENTRY_POINTS. - Default Parameters: Do not expect Koin to inject default parameters automatically. The K2 plugin's
skipDefaultValues = truebehavior skips parameters with default Kotlin values.
Koin Startup Pattern (K2 Compiler Plugin)
The project uses the K2 Compiler Plugin (koin-compiler-plugin, not KSP). The canonical startup uses the plugin's typed startKoin<T>() stub, which the plugin transforms at compile time via IR:
// Bootstrap class — separate from @Module, references the root module graph
@KoinApplication(modules = [AppKoinModule::class])
object AndroidKoinApp
// In Application.onCreate()
startKoin<AndroidKoinApp> {
androidContext(this@MeshUtilApplication)
workManagerFactory()
}
@KoinApplicationgoes on a dedicated bootstrap object, not on a@Moduleclass.startKoin<T>()(fromorg.koin.plugin.module.dsl) is a compiler plugin stub — if the plugin isn't applied, it throwsNotImplementedError.stopKoin()uses the standard runtime API (org.koin.core.context.stopKoin).compileSafetyis on at the entry points only (:androidApp,:desktopApp). Plugin 1.1.0 replaced per-module validation with whole-graph validation, so the flag is only meaningful where the graph is assembled. A new app target must be added toKOIN_ENTRY_POINTSor it is never validated.- A definition two
@Module(includes = ...)levels below the entry point is invisible to the index. The flavor modules carry@Configurationas well as theirincludesfor this reason; dropping theincludesremoves them from the runtime graph, whichKoinVerificationTestcatches. - Hand-written DSL
module { }definitions are not reachable by the assembled graph, which is why:desktopAppuses@Moduleclasses.
Navigation 3
Guidelines
- Types: Use Navigation 3 types consistently (
NavKey,NavBackStack,EntryProviderScope). - Typed Routes: Keep route definitions in
core:navigation/src/commonMain/.../Routes.ktas@Serializable sealed interfacehierarchies. Don't use ad-hoc strings. - Graph Assembly: Define feature navigation graphs as extension functions on
EntryProviderScope<NavKey>incommonMain(e.g.,fun EntryProviderScope<NavKey>.settingsGraph(backStack)). - Host Integration: Use
MeshtasticNavDisplay(fromcore:ui/commonMain) as the Navigation 3 host. Do not configure decorators manually inside feature modules. - Back Handlers: Use
NavigationBackHandlerfromandroidx.navigationevent:navigationevent-composefor back gestures in multiplatform code. Do not use Android'sBackHandler. - Deep Links: Use
DeepLinkRouter.route()incore:navigationto synthesize typed backstacks from RESTful paths.
Anti-Patterns
- Single Backstack for Multiple Tabs: Do not use a single
NavBackStacklist for multiple tabs. UseMultiBackstack(fromcore:navigation). - Decorator Reuse Across Tabs: Do not reuse the same
NavEntryDecoratorinstances across different backstacks. When rendering an active tab inMeshtasticNavDisplay, you must supply a fresh set of decorators (usingremember(backStack) { ... }) bound to the active backstack instance to prevent permanentViewModelStoredestruction. - Custom Backstack Mutation: Do not mutate back navigation with custom stacks disconnected from the app backstack. Mutate
NavBackStack<NavKey>directly withadd(...)andremoveLastOrNull().
Reference Anchors
- App Startup / Koin Bootstrap:
androidApp/src/main/kotlin/org/meshtastic/app/MeshUtilApplication.kt - DI Bootstrap Object:
androidApp/src/main/kotlin/org/meshtastic/app/di/AndroidKoinApp.kt - DI App Wiring:
androidApp/src/main/kotlin/org/meshtastic/app/di/AppKoinModule.kt - Shared Routes:
core/navigation/src/commonMain/kotlin/org/meshtastic/core/navigation/Routes.kt - Desktop Nav Shell:
desktopApp/src/main/kotlin/org/meshtastic/desktop/ui/DesktopMainScreen.kt
Signals
- GitHub stars
- 2k
- Forks
- 515
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
navigation-and-di- Source
- github.com/meshtastic/meshtastic-android