| name | bloom-navigate |
| description | Modify your generated project: swap the active AI provider, add notification channels, configure runtime permissions, or cleanly remove any built-in feature |
kmp-navigate
Use this skill when modifying or removing existing features in the Catylst project.
Swap the AI Provider
The AI layer uses a strategy pattern — swap providers by changing one line in AppModule.kt.
Open composeApp/src/commonMain/kotlin/io/jadu/catylst/di/AppModule.kt and change the binding:
single<AiProvider> { ClaudeProvider(get(), AppConfig.claudeApiKey) }
single<AiProvider> { GroqProvider(get(), AppConfig.groqApiKey) }
single<AiProvider> { GeminiProvider(get(), AppConfig.geminiApiKey) }
Only one line should be active at a time.
API Key Setup
cp local.properties.example local.properties
Edit local.properties:
claude.api.key=sk-ant-...
groq.api.key=gsk_...
gemini.api.key=AIza...
| Provider | Auth | Base URL |
|---|
| Claude | x-api-key + anthropic-version: 2023-06-01 | https://api.anthropic.com/v1/messages |
| Groq | Authorization: Bearer <key> | https://api.groq.com/openai/v1/chat/completions |
| Gemini | ?key=<key> query param | https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent |
Adding a Custom Provider
- Create
ai/providers/MyProvider.kt implementing AiProvider.
- Add key to
AppConfig.kt and inject in MainActivity.onCreate.
- Add
buildConfigField in androidApp/build.gradle.kts.
- Register:
single<AiProvider> { MyProvider(get(), AppConfig.myApiKey) }.
Configure Notifications
Architecture:
commonMain: NotificationScheduler.kt (expect), AppNotificationChannel.kt
androidMain: NotificationScheduler.android.kt, NotificationWorker.kt
iosMain: NotificationScheduler.ios.kt
desktopMain: NotificationScheduler.jvm.kt
Add a Channel
Open notifications/AppNotificationChannel.kt:
enum class AppNotificationChannel(val channelId: String, val channelName: String) {
REMINDERS("reminders", "Reminders"),
MY_CHANNEL("my_channel", "My Channel"),
}
Android creates it automatically. iOS maps channelId to categoryIdentifier.
Schedule / Cancel
val scheduler: NotificationScheduler = koinInject()
scheduler.schedule(
id = "notif-1",
title = "Hello",
body = "Body text",
delaySeconds = 60L,
channel = AppNotificationChannel.REMINDERS
)
scheduler.cancel(id = "notif-1")
Add a Runtime Permission
Architecture:
commonMain: Permission.kt (enum), PermissionState.kt, PermissionController.kt (expect)
androidMain: PermissionController.android.kt
iosMain: PermissionController.ios.kt
Step 1 — Add to Permission.kt enum:
MY_NEW_PERMISSION,
Step 2 — Map on Android in PermissionController.android.kt:
Permission.MY_NEW_PERMISSION -> android.Manifest.permission.MY_ANDROID_PERMISSION
Step 3 — Handle on iOS in PermissionController.ios.kt (checkPermission + requestPermission).
Step 4 — Declare in AndroidManifest.xml and Info.plist.
Use in a Composable
val controller = rememberPermissionController()
val state by controller.permissionState(Permission.MY_NEW_PERMISSION).collectAsState()
when (state) {
PermissionState.Granted -> { }
PermissionState.Denied -> Button(onClick = { controller.requestPermission(Permission.MY_NEW_PERMISSION) }) { Text("Grant") }
else -> { }
}
Remove a Feature
After any removal, run ./gradlew :androidApp:assembleDebug to confirm no errors.
Remove AI Services
- Delete
ai/ directory and config/AppConfig.kt.
- Delete
ui/screens/AiDemoScreen.kt and ui/viewmodel/AiViewModel.kt.
- In
AppModule.kt — remove AiProvider, AiRepository, AiViewModel bindings and imports.
- In
Screen.kt / AppNavigation.kt / HomeScreen.kt — remove Screen.AiDemo and its wiring.
- In
MainActivity.kt — remove AppConfig.*apiKey = BuildConfig.* lines.
- In
androidApp/build.gradle.kts — remove the three buildConfigField lines and buildConfig = true.
Remove Notifications
- Delete
notifications/ across all source sets.
- Delete
ui/screens/NotificationDemoScreen.kt.
- Remove
NotificationScheduler from all PlatformModule files.
- Remove
Screen.Notifications from Screen.kt, AppNavigation.kt, HomeScreen.kt.
- Remove
workmanager from composeApp/build.gradle.kts and libs.versions.toml.
- Remove
POST_NOTIFICATIONS / SCHEDULE_EXACT_ALARM from AndroidManifest.xml.
Remove Permissions
- Delete
permissions/ across all source sets.
- Delete
ui/screens/PermissionDemoScreen.kt.
- Remove
Screen.Permissions from Screen.kt, AppNavigation.kt, HomeScreen.kt.
- Remove permission
<uses-permission> entries from AndroidManifest.xml and Info.plist.
Remove Preferences
- Delete
data/preferences/AppPreferences.kt and ui/screens/PreferencesDemoScreen.kt.
- Remove
AppPreferences(get()) from AppModule.kt and ObservableSettings/Settings from PlatformModule.
- Remove
Screen.Preferences from navigation files.
- Remove
multiplatform-settings from build.gradle.kts and libs.versions.toml.
Remove Room Database
- Delete
data/local/ across all source sets.
- Remove
AppDatabase binding from AppModule.kt.
- Remove
room.runtime, sqlite.bundled, ksp, room plugin from build.gradle.kts and libs.versions.toml.
Remove Networking (Ktor)
- Delete
network/ directory.
- Remove
HttpClient and ApiService from AppModule.kt.
- Remove all
ktor.* entries from build.gradle.kts and libs.versions.toml.
General Debugging
After any change, find broken imports:
./gradlew :androidApp:assembleDebug 2>&1 | grep "error:"
Fix each reported import by removing the dead reference.