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.
Agent Instruction File Update
After integration, append an OpenClix section to the project's agent instruction file so future sessions have context.
Detect which file to update:
- If
CLAUDE.mdexists: updateCLAUDE.md(Claude Code) - If
AGENTS.mdexists: updateAGENTS.md(Codex or other agents) - If both exist: update the one matching the current agent
- If neither exists: create the file matching the current agent convention
Append this section (do not overwrite existing content):
## OpenClix
OpenClix is integrated in this project. It provides local-first, config-driven mobile engagement logic.
Available skills:
- `openclix-design-campaigns`: Create and iterate campaign configurations from product goals.
- `openclix-analytics`: Wire events to a PA provider and produce retention impact reports.
- `openclix-update-campaigns`: Propose campaign operations from measured analytics performance.
- `openclix-update`: Sync integration source code with the latest template baseline.
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.