OpenClix Init
Purpose
This skill adds OpenClix functionality by copying client code into the user project, not by installing an SDK package.
Use a local-source integration model (shadcn-style): copy, adapt, wire, verify.
Core Rules
- Detect the real platform first using project files.
- Prioritize minimal edits to existing user code.
- Keep all OpenClix files in a dedicated namespace/directory.
- When creating local planning/report artifacts under
.openclix/**, ensure.openclix/is listed in.gitignore(add it if missing). - Reuse existing dependencies whenever possible.
- Do not add or update dependencies without explicit user approval.
- Run a build after integration and fix only integration-caused issues.
- Do not use in-memory fallback in production integration paths.
- For bundled JSON config delivery, keep runtime loader path and copied file path identical (same directory + same case-sensitive filename).
- Use
openclix-config.jsonas the default filename; do not invent case variants such asOpenClix-config.json.
Platform Detection
Use file evidence in this order:
| Priority | Platform | Required Evidence |
|---|---|---|
| 1 | Expo | app.json or app.config.* with expo |
| 2 | React Native | package.json with react-native and typical ios/ + android/ structure |
| 3 | Flutter | pubspec.yaml with Flutter SDK |
| 4 | iOS native | *.xcodeproj or *.xcworkspace or Package.swift |
| 5 | Android native | build.gradle or build.gradle.kts |
If signals conflict, trust concrete file evidence and report the mismatch.
Template Selection
- Expo / React Native:
templates/react-native/ - Flutter:
templates/flutter/ - iOS:
templates/ios/ - Android:
templates/android/(package namespaceai.openclix.*)
templates/react-native/ is the canonical reference when platform ports need alignment.
Existing Local Notification Detection
Before copying templates or wiring OpenClix touchpoints, inspect the host app for pre-existing local notification code outside the OpenClix namespace.
Detection must cover these paths when they exist:
- notification scheduling
- notification permission request/status
- foreground display handling
- notification tap/open handling
For each detected path, classify it as either:
migration-capable: can be redirected into OpenClix with localized edits, no new dependencies, and no broad refactorkeep-as-is: should remain untouched during OpenClix integration
If no existing local notification code is found, continue with the normal integration flow.
If existing local notification code is found, report:
- the files or entry points detected
- whether each path is
migration-capableorkeep-as-is - why any path is not migration-capable
Migration Capability Rules
Use these rules conservatively:
- React Native / Expo:
migration-capableonly when the app already uses@notifee/react-nativeorexpo-notifications- detect and classify existing scheduler, permission, foreground, and open-handling code against those libraries
- other notification stacks remain
keep-as-is
- Flutter:
migration-capableonly when the existing plugin can provide the current OpenClix callback contract forschedule,cancel,listPending, permission request/status, and optional foreground setup- if the plugin cannot satisfy that contract without adding dependencies or broad rewrites, mark it
keep-as-is
- iOS native:
migration-capablewhen the app already usesUNUserNotificationCenterlocal notifications and the existing permission/delegate path can be reused with localized edits- preserve any unsupported notification behavior outside the OpenClix content model
- Android native:
migration-capablewhen the current local notification flow is platform-local scheduling/display that can be redirected into the OpenClix scheduler path without adding dependencies or broad refactors- vendor-owned or heavily customized flows remain
keep-as-is
Always mark these scenarios as keep-as-is unless the user asks for a separate redesign:
- remote push delivery infrastructure
- vendor-specific notification products outside current OpenClix adapters
- rich actions or advanced features not represented by the current OpenClix content model
- notification flows tightly coupled to unrelated business logic
Migration Decision
If one or more detected paths are migration-capable, ask the user before rewriting existing notification behavior.
Use this decision wording:
I found existing local notifications outside OpenClix. Some paths are migration-capable. Do you want me to migrate the supported local-notification flows into OpenClix, or keep the existing implementation unchanged? If you do not choose, I will keep the existing implementation.
Decision rules:
- default migration-capable paths to
keep-as-isif the user does not explicitly choose - if the user chooses
keep, treat migration-capable paths askeep-as-is, integrate OpenClix alongside the current notification system, and do not rewrite existing notification flows - if the user chooses
migrate, migrate only supported engagement-style local notification flows that fit the current OpenClix model - leave unsupported or unrelated notification flows untouched even when the user chooses
migrate - if no detected path is migration-capable, explain that and proceed with coexistence only
- never silently replace an existing notification implementation
- include the final user choice in the integration handoff/report
Integration Workflow
- Identify platform and current startup/event/lifecycle entry points.
- Detect pre-existing local notification paths and classify them as
migration-capableorkeep-as-is. - If migration-capable paths exist, ask whether to migrate supported flows or keep the existing implementation unchanged. Default to keeping the existing implementation.
- Copy the selected template into a dedicated OpenClix area in the user project.
- Wire only required touchpoints:
- initialization at app startup
- event tracking call path
- foreground/app lifecycle trigger
- Keep existing architecture and code style intact; avoid broad refactors.
- Validate against
references/openclix.schema.jsonwhen config/schema changes are involved.
Adapter Selection Rules
Select adapters using existing dependencies only:
- Choose concrete adapters at integration time; avoid runtime dependency auto-detection.
- If the project already has a supported persistent storage dependency, wire that implementation.
- If notification libraries already exist, wire the matching scheduler adapter.
- If no compatible dependency exists, fail fast with a clear integration error.
- Keep degraded in-memory paths out of production template defaults.
React Native / Expo storage selection:
- AsyncStorage project: use
AsyncStorageCampaignStateRepository. - MMKV project: use
MmkvCampaignStateRepository. - If both exist, prefer the project standard and copy only one storage adapter into the app.
- Inject
campaignStateRepositoryexplicitly when callingOpenClix.initialize(...).
React Native / Expo scheduler selection:
- Notifee project: create
new NotifeeScheduler(notifee). - Expo notifications project: create
new ExpoNotificationScheduler(ExpoNotifications). - Inject
messageSchedulerexplicitly when callingOpenClix.initialize(...).
Platform expectations:
- React Native / Expo:
- Do not use runtime adapter auto-detection in
OpenClixcore for storage and scheduler adapters; select these at integration time. - Select storage/scheduler implementations during integration and inject their dependencies explicitly; lifecycle helpers (e.g.,
lifecycleStateReader) may be chosen by the template core based on the runtime environment when no project-specific implementation is required. - If compatible implementations are unavailable, initialization must fail with clear instructions.
- Do not use runtime adapter auto-detection in
- Flutter:
- Use callback-based scheduler adapter for existing notification plugin
- Require an explicit scheduler and state repository dependency at initialization
- iOS / Android native:
- Use platform-native implementations by default
- Do not introduce in-memory/no-op fallback as the default runtime behavior
Notification Permission and Foreground Setup
Notification permission must be requested before campaign triggers fire. Each platform template includes a permission utility; the integration agent must wire it at the appropriate location in the host app.
React Native / Expo — Permission
- Notifee projects: Import
requestNotifeePermissionfrominfrastructure/NotifeeNotificationSetup. Call it at app startup (e.g. inApp.tsxor a startup hook) passing the Notifee adapter. No foreground handler is needed — Notifee handles foreground display natively viapresentationOptions. - Expo projects: Import
requestExpoPermissionandsetupExpoForegroundHandlerfrominfrastructure/ExpoNotificationSetup. CallsetupExpoForegroundHandleronce during initialization, then callrequestExpoPermissionat app startup.
iOS — Permission and Foreground Display
- Permission: Call
await NotificationPermission.request()at app startup (e.g. inapplication(_:didFinishLaunchingWithOptions:)or a SwiftUI.taskmodifier). This callsUNUserNotificationCenter.requestAuthorization. - Foreground display: iOS suppresses notification banners when the app is active. The template provides
ForegroundNotificationHandler.handleWillPresent(notification:completionHandler:)as a static method.- Critical: iOS allows only ONE
UNUserNotificationCenterDelegateper app. Do NOT assignForegroundNotificationHandleras the delegate. Instead, set the app's existing delegate (usuallyAppDelegate) asUNUserNotificationCenter.current().delegate = self, and call the static method from the delegate'swillPresentimplementation.
- Critical: iOS allows only ONE
Android — Permission
- Manifest: Add
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />toAndroidManifest.xml. - Runtime request: On API 33+ (Android 13), call
NotificationPermission.shouldRequestPermission(context)at startup. If it returnstrue, use the Activity'srequestPermissions()orActivityResultLauncherto requestNotificationPermission.getPermissionString(). - Android does NOT need foreground display setup —
NotificationManager.notify()always displays regardless of app state.
Flutter — Permission and Foreground Display
The NotificationPermission class in notification/notification_permission.dart accepts callbacks. Wire the host app's notification plugin:
- Provide a
requestPermissioncallback that calls the plugin's permission request API. - Provide a
checkPermissionStatuscallback that checks current status. - Optionally provide a
setupForegroundHandlercallback to configure foreground display (required for iOS, not needed for Android). - Call
permission.request()at app startup before campaign triggers fire. - Call
permission.setupForeground()during initialization if the handler is provided.
Directory and Namespace Policy
OpenClix files must stay grouped in a dedicated location:
- React Native / Expo:
src/openclix/ - Flutter:
lib/openclix/ - iOS:
OpenClix/orSources/OpenClix/ - Android:
app/src/main/kotlin/ai/openclix/withai.openclix.*packages
Bundled Config Path Contract
When integration includes bundled config delivery (non-HTTP endpoint), enforce this contract:
- Detect the exact runtime load path from current startup code first.
- Copy
openclix-config.jsonto that exact path. - If no runtime load path exists yet, use these defaults:
- React Native / Expo:
assets/openclix/openclix-config.json - Flutter:
assets/openclix/openclix-config.jsonand add it topubspec.yaml - iOS:
<app-target>/OpenClix/openclix-config.jsonand include in "Copy Bundle Resources" - Android:
app/src/main/assets/openclix/openclix-config.json
- React Native / Expo:
- Ensure any bundled-path identifier (
OpenClixConfig.endpoint, asset key, bundle filename) matches the copied file path exactly. - Run a final path parity check before handoff and report:
- source config file path
- bundled runtime file path
- runtime loader reference location(s)
Dependency Policy
Before changing dependencies:
- Check what the selected template expects.
- Check what the user project already has.
- Prefer existing project libraries or platform APIs.
- If replacement is possible, adapt template code instead of adding dependencies.
- If no safe replacement exists, ask for approval before any dependency add/update.
Never run package-manager install/update commands without approval.
Build Verification
After wiring, run platform-appropriate build/analysis commands based on detected project structure. Prefer project-native commands first (existing scripts, Gradle tasks, Xcode scheme, Flutter workflow).
If unclear, use common fallback commands:
- React Native / Expo:
npx tsc --noEmit - Android:
./gradlew assembleDebug - iOS:
xcodebuild -scheme <scheme> buildorswift build - Flutter:
flutter analyze
If build fails, apply minimal targeted fixes and retry. Stop only on hard blockers.
Completion Checklist
- OpenClix code added under dedicated namespace/directory.
- Existing app code changes are minimal and localized.
- Existing local notification paths detected and classified before integration.
- Migration decision recorded when supported paths were found; defaulted to preserving existing behavior when the user did not opt in.
- Handoff/report states what was detected, what was migration-capable, what stayed untouched, and what was changed.
- No unapproved dependency additions or upgrades.
- Adapter wiring prefers existing dependencies and fails fast when unavailable.
- Bundled config path/filename parity verified when using local resource delivery.
- Build verification executed.
- Any remaining blockers clearly reported.