From dc4028f7e7ec563a4ff85e339f47522aa787da0b Mon Sep 17 00:00:00 2001 From: Minkyu Cho Date: Wed, 28 Jan 2026 11:24:04 +0900 Subject: [PATCH 1/3] feat(ios): add NSE setup guide with SDK-aligned implementation - Update NotificationService.swift template to use ClixNotificationServiceExtension - Add CocoaPods and SPM dependency setup instructions for extension target - Add ENABLE_USER_SCRIPT_SANDBOXING build setting guidance for Xcode 15+ - Add NSE setup section to install skill for consistency - Regenerate embedded-skills.ts with updated local skills --- src/lib/embedded-skills.ts | 300 ++++++++++++++++++++++++++ src/lib/ios/agent-prompt-generator.ts | 61 +++--- src/lib/skills/install/SKILL.md | 26 +++ src/lib/skills/ios-setup/SKILL.md | 54 +++++ 4 files changed, 414 insertions(+), 27 deletions(-) diff --git a/src/lib/embedded-skills.ts b/src/lib/embedded-skills.ts index c76dbd3..ce3b179 100644 --- a/src/lib/embedded-skills.ts +++ b/src/lib/embedded-skills.ts @@ -160,6 +160,206 @@ variables exist — you still need a payload + console verification. - \`references/common-patterns.md\` - Copy/paste patterns for messages + URLs + guards - \`references/debugging.md\` - Troubleshooting missing variables and Message Logs +`, + 'auditing-deep-link-contracts': `--- +name: auditing-deep-link-contracts +display-name: Auditing Deep Link Contracts +short-description: Deep link contract audit +description: Audits deep link contracts and routing behavior. Use when validating + supported routes, required parameters, and cold or warm start handling. +user-invocable: true +--- + +# Auditing Deep Link Contracts + +Use this skill to define and audit deep link behavior so links open the correct +screen with correct parameters across cold and warm starts. + +## What this skill does + +- Defines a deep link contract for supported routes +- Checks required and optional parameters +- Generates cold and warm start test vectors +- Produces a concise audit report with fixes + +## Workflow + +\`\`\` +Deep link contract audit progress: + +- [ ] 1) Confirm minimum inputs (platforms, routes, entry points) +- [ ] 2) Draft a deep-link contract (JSON) +- [ ] 3) Validate the contract (script) +- [ ] 4) Generate test vectors (script) +- [ ] 5) Audit routing behavior (findings + fixes) +- [ ] 6) Verify fixes (cold and warm start) +\`\`\` + +## 1) Confirm the minimum inputs + +Ask only what is needed: + +- **Platforms**: iOS, Android, or both +- **Entry points**: push, email, web, in-app, marketing campaigns +- **Routes**: list of deep link routes that must be supported +- **Auth rules**: which routes require login +- **Fallbacks**: where to send users if data is missing + +## 2) Draft a deep-link contract + +Create \`deep-link-contract.json\` in \`.mobile/\` (recommended) or project root. + +Recommended location: \`.mobile/deep-link-contract.json\` + +Example: + +\`\`\`json +{ + "base": "myapp://", + "routes": [ + { + "name": "order_detail", + "path": "/orders/{order_id}", + "required_params": ["order_id"], + "optional_params": ["ref"], + "auth_required": true, + "supported_states": ["cold", "warm"] + } + ] +} +\`\`\` + +## 3) Validate the contract + +Run: + +\`\`\`bash +bash skills/auditing-deep-link-contracts/scripts/validate-deep-link-contract.sh \\ + .mobile/deep-link-contract.json +\`\`\` + +## 4) Generate test vectors + +Run: + +\`\`\`bash +bash skills/auditing-deep-link-contracts/scripts/generate-deep-link-test-vectors.sh \\ + .mobile/deep-link-contract.json \\ + .mobile/deep-link-test-vectors.json +\`\`\` + +## 5) Audit routing behavior + +For each test vector, confirm: + +- The app opens the expected screen +- Required parameters are present and parsed +- Missing parameters trigger the expected fallback +- Auth-required routes handle logged-out users +- Cold start and warm start behave consistently + +## 6) Verify fixes + +Re-run the test vectors after changes and confirm all expected behaviors. + +## Progressive Disclosure + +- **Level 1**: This \`SKILL.md\` +- **Level 2**: \`references/\` +- **Level 3**: \`examples/\` (optional) +- **Level 4**: \`scripts/\` (execute; do not load) + +## References + +- \`references/deep-link-contract.md\` +`, + 'auditing-permission-ux': `--- +name: auditing-permission-ux +display-name: Auditing Permission UX +short-description: Permission UX audit +description: Audits notification permission request flows. Use when reviewing or improving permission prompts, settings paths, or denial handling. +user-invocable: true +--- + +# Auditing Permission UX + +Use this skill to audit how a mobile app requests notification permission and guides +users to settings, then produce actionable improvements based on Apple and Android +best practices. + +## What this skill does + +- Reviews permission timing, context, and explanation quality +- Checks denial handling and settings recovery paths +- Flags platform-specific risks (iOS vs Android) +- Produces a structured audit report with fixes + +## Workflow + +\`\`\` +Permission UX audit progress: + +- [ ] 1) Confirm minimum inputs (platforms, flow, current UX) +- [ ] 2) Audit current flow (map prompts, copy, and settings paths) +- [ ] 3) Produce audit report (findings + fixes) +- [ ] 4) Verify improvements (ensure UX changes align with platform rules) +\`\`\` + +## 1) Confirm the minimum inputs + +Ask only what is needed: + +- **Platforms**: iOS, Android, or both +- **Entry points**: where the app asks for permission +- **Prompt timing**: first launch, after action, onboarding step, etc. +- **Primer**: is there an in-app explanation before the system prompt +- **Settings path**: how users enable later after denial +- **Denial handling**: how the app behaves if permission is denied + +## 2) Audit the current flow + +Document the current permission flow directly from the app: + +- Where the permission prompt appears and what precedes it +- What copy is shown to explain value +- How the app behaves after deny or dismiss +- How users can enable notifications later + +## 3) Produce the audit report + +Output a concise report in markdown with: + +- **Findings**: each gap mapped to best practice +- **Risk**: what the user impact is +- **Fix**: concrete UX change +- **Platform notes**: iOS-only or Android-only specifics + +Optional: generate a report template: + +\`\`\`bash +bash skills/auditing-permission-ux/scripts/generate-permission-ux-audit-report.sh .mobile/permission-ux-audit.md +\`\`\` + +## 4) Verify improvements + +Confirm: + +- Prompt timing is contextual (not forced on first launch) +- Primer explains value clearly and is dismissible +- Denied users can still use the app +- Settings path is discoverable and clear +- Android importance/channel strategy is not misleading + +## Progressive Disclosure + +- **Level 1**: This \`SKILL.md\` +- **Level 2**: \`references/\` +- **Level 3**: \`examples/\` (optional) +- **Level 4**: \`scripts/\` (execute; do not load) + +## References + +- \`references/permission-ux-best-practices.md\` `, integration: `--- name: clix-integration @@ -1246,6 +1446,32 @@ Only these require user action: For these, provide brief instructions but don't wait for confirmation. +### iOS Notification Service Extension (Recommended) + +For rich push notifications (images, buttons), create a Notification Service Extension: + +1. In Xcode: File > New > Target > Notification Service Extension +2. Add Clix SDK to the extension target: + - **CocoaPods**: Add \`target 'YourExtension' do pod 'Clix' end\` to Podfile, then \`pod install\` + - **SPM**: Add Clix package to extension target in Xcode (General > Frameworks) +3. Implement NotificationService.swift: + \`\`\`swift + import UserNotifications + import Clix + + class NotificationService: ClixNotificationServiceExtension { + override func didReceive(_ request: UNNotificationRequest, + withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) { + register(projectId: "YOUR_PROJECT_ID") + super.didReceive(request, withContentHandler: contentHandler) + } + } + \`\`\` +4. Add App Groups capability to both main app and extension (same group ID: \`group.clix.{BUNDLE_ID}\`) +5. For Xcode 15+: Set \`ENABLE_USER_SCRIPT_SANDBOXING\` to "No" in extension's Build Settings + +For detailed setup, run \`clix ios-setup\` or \`/ios-setup\` in interactive mode. + ## Output Format After completion, report: @@ -1486,6 +1712,60 @@ Create or modify entitlements files. Use Write/Edit tools for these operations. **Note:** Replace \`{BUNDLE_ID}\` with the actual bundle identifier (e.g., \`com.example.myapp\`). +### Phase 3.5: Notification Service Extension Setup + +Create a Notification Service Extension for rich push notifications (images, buttons, etc.). + +**Create Extension Target in Xcode:** +\`\`\`text +1. File > New > Target +2. Select "Notification Service Extension" +3. Name it "{AppName}NotificationServiceExtension" +4. Click "Finish" (Cancel the "Activate scheme" dialog) +\`\`\` + +**Implement NotificationService.swift:** + +\`\`\`swift +import UserNotifications +import Clix + +class NotificationService: ClixNotificationServiceExtension { + override func didReceive( + _ request: UNNotificationRequest, + withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void + ) { + register(projectId: "YOUR_PROJECT_ID") + super.didReceive(request, withContentHandler: contentHandler) + } +} +\`\`\` + +**Note:** Replace \`YOUR_PROJECT_ID\` with your actual Clix project ID from https://console.clix.so/ + +**Add Clix SDK to Extension Target:** + +For CocoaPods projects, add to Podfile: +\`\`\`ruby +target '{AppName}NotificationServiceExtension' do + pod 'Clix' +end +\`\`\` +Then run: \`cd ios && pod install\` + +For SPM projects in Xcode: +1. Select the extension target +2. Go to General > Frameworks, Libraries, and Embedded Content +3. Click + and add the Clix package + +**Configure Build Settings (Xcode 15+):** + +For the extension target: +- Set \`ENABLE_USER_SCRIPT_SANDBOXING\` to "No" in Build Settings + +For React Native projects with Firebase: +- In Build Phases, move "Embed Foundation Extensions" above "[RNFB] Core Configuration" + ### Phase 4: Apple Developer Portal Configuration Guide user through manual portal configuration. These steps CANNOT be automated. @@ -1688,6 +1968,26 @@ export const EMBEDDED_SKILL_METADATA: SkillMetadata[] = [ 'Helps developers author and debug Clix personalization templates (Liquid-style) for message content, deep links/URLs, and audience targeting. Use when the user mentions personalization variables, Liquid, templates, conditional logic, loops, filters, deep links, message logs, or when the user types `clix-personalization`.', userInvocable: true, }, + { + folder: 'auditing-deep-link-contracts', + name: 'auditing-deep-link-contracts', + commandName: 'auditing-deep-link-contracts', + displayName: 'Auditing Deep Link Contracts', + shortDescription: 'Deep link contract audit', + description: + 'Audits deep link contracts and routing behavior. Use when validating supported routes, required parameters, and cold or warm start handling.', + userInvocable: true, + }, + { + folder: 'auditing-permission-ux', + name: 'auditing-permission-ux', + commandName: 'auditing-permission-ux', + displayName: 'Auditing Permission UX', + shortDescription: 'Permission UX audit', + description: + 'Audits notification permission request flows. Use when reviewing or improving permission prompts, settings paths, or denial handling.', + userInvocable: true, + }, { folder: 'integration', name: 'clix-integration', diff --git a/src/lib/ios/agent-prompt-generator.ts b/src/lib/ios/agent-prompt-generator.ts index 198c6a5..793f8ac 100644 --- a/src/lib/ios/agent-prompt-generator.ts +++ b/src/lib/ios/agent-prompt-generator.ts @@ -53,40 +53,39 @@ Create the NotificationService.swift file with Clix SDK integration: \`\`\`swift import UserNotifications -import ClixSDK - -class NotificationService: UNNotificationServiceExtension { - var contentHandler: ((UNNotificationContent) -> Void)? - var bestAttemptContent: UNMutableNotificationContent? +import Clix +class NotificationService: ClixNotificationServiceExtension { override func didReceive( _ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void ) { - self.contentHandler = contentHandler - bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent) - - if let bestAttemptContent = bestAttemptContent { - // Let Clix SDK handle the notification - Clix.shared.handleNotificationServiceExtension( - request: request, - content: bestAttemptContent - ) { processedContent in - contentHandler(processedContent) - } - } - } - - override func serviceExtensionTimeWillExpire() { - if let contentHandler = contentHandler, - let bestAttemptContent = bestAttemptContent { - contentHandler(bestAttemptContent) - } + register(projectId: "YOUR_PROJECT_ID") + super.didReceive(request, withContentHandler: contentHandler) } } \`\`\` -#### 4. Create Extension Entitlements [Required] +**Note:** Replace \`YOUR_PROJECT_ID\` with your actual Clix project ID from https://console.clix.so/ + +#### 4. Add Clix SDK to Extension Target [Required] + +**For CocoaPods projects:** +Add to your Podfile: +\`\`\`ruby +target '${context.appName}NotificationServiceExtension' do + pod 'Clix' +end +\`\`\` +Then run: \`cd ios && pod install\` + +**For SPM projects:** +In Xcode: +1. Select the extension target +2. Go to General > Frameworks, Libraries, and Embedded Content +3. Click + and add the Clix package + +#### 5. Create Extension Entitlements [Required] Create entitlements file for the extension at \`${context.iosDir}/NotificationServiceExtension/NotificationServiceExtension.entitlements\`: \`\`\`xml @@ -102,7 +101,7 @@ Create entitlements file for the extension at \`${context.iosDir}/NotificationSe \`\`\` -#### 5. Update Extension Info.plist [Required] +#### 6. Update Extension Info.plist [Required] Ensure the extension's Info.plist has the correct NSExtension configuration: \`\`\`xml @@ -115,11 +114,19 @@ Ensure the extension's Info.plist has the correct NSExtension configuration: \`\`\` +#### 7. Configure Build Settings [Required - Xcode 15+] + +For the extension target in Xcode: +- Set \`ENABLE_USER_SCRIPT_SANDBOXING\` to "No" in Build Settings + +For React Native projects with Firebase: +- In Build Phases, move "Embed Foundation Extensions" above "[RNFB] Core Configuration" + ### Important Notes - The extension must share the same App Group as the main app - The extension's bundle ID must be a child of the main app's bundle ID -- Add the ClixSDK to the extension target's frameworks - Ensure the extension is added to the app's "Embed App Extensions" build phase +- Replace \`YOUR_PROJECT_ID\` with your actual Clix project ID Please complete these tasks by modifying the Xcode project files directly.`; } diff --git a/src/lib/skills/install/SKILL.md b/src/lib/skills/install/SKILL.md index 854c490..810806a 100644 --- a/src/lib/skills/install/SKILL.md +++ b/src/lib/skills/install/SKILL.md @@ -163,6 +163,32 @@ Only these require user action: For these, provide brief instructions but don't wait for confirmation. +### iOS Notification Service Extension (Recommended) + +For rich push notifications (images, buttons), create a Notification Service Extension: + +1. In Xcode: File > New > Target > Notification Service Extension +2. Add Clix SDK to the extension target: + - **CocoaPods**: Add `target 'YourExtension' do pod 'Clix' end` to Podfile, then `pod install` + - **SPM**: Add Clix package to extension target in Xcode (General > Frameworks) +3. Implement NotificationService.swift: + ```swift + import UserNotifications + import Clix + + class NotificationService: ClixNotificationServiceExtension { + override func didReceive(_ request: UNNotificationRequest, + withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) { + register(projectId: "YOUR_PROJECT_ID") + super.didReceive(request, withContentHandler: contentHandler) + } + } + ``` +4. Add App Groups capability to both main app and extension (same group ID: `group.clix.{BUNDLE_ID}`) +5. For Xcode 15+: Set `ENABLE_USER_SCRIPT_SANDBOXING` to "No" in extension's Build Settings + +For detailed setup, run `clix ios-setup` or `/ios-setup` in interactive mode. + ## Output Format After completion, report: diff --git a/src/lib/skills/ios-setup/SKILL.md b/src/lib/skills/ios-setup/SKILL.md index 82914e5..5808918 100644 --- a/src/lib/skills/ios-setup/SKILL.md +++ b/src/lib/skills/ios-setup/SKILL.md @@ -128,6 +128,60 @@ Create or modify entitlements files. Use Write/Edit tools for these operations. **Note:** Replace `{BUNDLE_ID}` with the actual bundle identifier (e.g., `com.example.myapp`). +### Phase 3.5: Notification Service Extension Setup + +Create a Notification Service Extension for rich push notifications (images, buttons, etc.). + +**Create Extension Target in Xcode:** +```text +1. File > New > Target +2. Select "Notification Service Extension" +3. Name it "{AppName}NotificationServiceExtension" +4. Click "Finish" (Cancel the "Activate scheme" dialog) +``` + +**Implement NotificationService.swift:** + +```swift +import UserNotifications +import Clix + +class NotificationService: ClixNotificationServiceExtension { + override func didReceive( + _ request: UNNotificationRequest, + withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void + ) { + register(projectId: "YOUR_PROJECT_ID") + super.didReceive(request, withContentHandler: contentHandler) + } +} +``` + +**Note:** Replace `YOUR_PROJECT_ID` with your actual Clix project ID from https://console.clix.so/ + +**Add Clix SDK to Extension Target:** + +For CocoaPods projects, add to Podfile: +```ruby +target '{AppName}NotificationServiceExtension' do + pod 'Clix' +end +``` +Then run: `cd ios && pod install` + +For SPM projects in Xcode: +1. Select the extension target +2. Go to General > Frameworks, Libraries, and Embedded Content +3. Click + and add the Clix package + +**Configure Build Settings (Xcode 15+):** + +For the extension target: +- Set `ENABLE_USER_SCRIPT_SANDBOXING` to "No" in Build Settings + +For React Native projects with Firebase: +- In Build Phases, move "Embed Foundation Extensions" above "[RNFB] Core Configuration" + ### Phase 4: Apple Developer Portal Configuration Guide user through manual portal configuration. These steps CANNOT be automated. From ac62e5fc4dd18cc405ed73a0fb37348d84794465 Mon Sep 17 00:00:00 2001 From: Minkyu Cho Date: Wed, 28 Jan 2026 11:43:47 +0900 Subject: [PATCH 2/3] fix(ios): use consistent NSE target name across all steps Remove alternative target name option to prevent mismatch between Podfile target, entitlements path, and actual extension target name. --- src/lib/embedded-skills.ts | 223 +------------------------- src/lib/ios/agent-prompt-generator.ts | 6 +- src/lib/skills/ios-setup/SKILL.md | 3 +- 3 files changed, 7 insertions(+), 225 deletions(-) diff --git a/src/lib/embedded-skills.ts b/src/lib/embedded-skills.ts index ce3b179..b7cf413 100644 --- a/src/lib/embedded-skills.ts +++ b/src/lib/embedded-skills.ts @@ -160,206 +160,6 @@ variables exist — you still need a payload + console verification. - \`references/common-patterns.md\` - Copy/paste patterns for messages + URLs + guards - \`references/debugging.md\` - Troubleshooting missing variables and Message Logs -`, - 'auditing-deep-link-contracts': `--- -name: auditing-deep-link-contracts -display-name: Auditing Deep Link Contracts -short-description: Deep link contract audit -description: Audits deep link contracts and routing behavior. Use when validating - supported routes, required parameters, and cold or warm start handling. -user-invocable: true ---- - -# Auditing Deep Link Contracts - -Use this skill to define and audit deep link behavior so links open the correct -screen with correct parameters across cold and warm starts. - -## What this skill does - -- Defines a deep link contract for supported routes -- Checks required and optional parameters -- Generates cold and warm start test vectors -- Produces a concise audit report with fixes - -## Workflow - -\`\`\` -Deep link contract audit progress: - -- [ ] 1) Confirm minimum inputs (platforms, routes, entry points) -- [ ] 2) Draft a deep-link contract (JSON) -- [ ] 3) Validate the contract (script) -- [ ] 4) Generate test vectors (script) -- [ ] 5) Audit routing behavior (findings + fixes) -- [ ] 6) Verify fixes (cold and warm start) -\`\`\` - -## 1) Confirm the minimum inputs - -Ask only what is needed: - -- **Platforms**: iOS, Android, or both -- **Entry points**: push, email, web, in-app, marketing campaigns -- **Routes**: list of deep link routes that must be supported -- **Auth rules**: which routes require login -- **Fallbacks**: where to send users if data is missing - -## 2) Draft a deep-link contract - -Create \`deep-link-contract.json\` in \`.mobile/\` (recommended) or project root. - -Recommended location: \`.mobile/deep-link-contract.json\` - -Example: - -\`\`\`json -{ - "base": "myapp://", - "routes": [ - { - "name": "order_detail", - "path": "/orders/{order_id}", - "required_params": ["order_id"], - "optional_params": ["ref"], - "auth_required": true, - "supported_states": ["cold", "warm"] - } - ] -} -\`\`\` - -## 3) Validate the contract - -Run: - -\`\`\`bash -bash skills/auditing-deep-link-contracts/scripts/validate-deep-link-contract.sh \\ - .mobile/deep-link-contract.json -\`\`\` - -## 4) Generate test vectors - -Run: - -\`\`\`bash -bash skills/auditing-deep-link-contracts/scripts/generate-deep-link-test-vectors.sh \\ - .mobile/deep-link-contract.json \\ - .mobile/deep-link-test-vectors.json -\`\`\` - -## 5) Audit routing behavior - -For each test vector, confirm: - -- The app opens the expected screen -- Required parameters are present and parsed -- Missing parameters trigger the expected fallback -- Auth-required routes handle logged-out users -- Cold start and warm start behave consistently - -## 6) Verify fixes - -Re-run the test vectors after changes and confirm all expected behaviors. - -## Progressive Disclosure - -- **Level 1**: This \`SKILL.md\` -- **Level 2**: \`references/\` -- **Level 3**: \`examples/\` (optional) -- **Level 4**: \`scripts/\` (execute; do not load) - -## References - -- \`references/deep-link-contract.md\` -`, - 'auditing-permission-ux': `--- -name: auditing-permission-ux -display-name: Auditing Permission UX -short-description: Permission UX audit -description: Audits notification permission request flows. Use when reviewing or improving permission prompts, settings paths, or denial handling. -user-invocable: true ---- - -# Auditing Permission UX - -Use this skill to audit how a mobile app requests notification permission and guides -users to settings, then produce actionable improvements based on Apple and Android -best practices. - -## What this skill does - -- Reviews permission timing, context, and explanation quality -- Checks denial handling and settings recovery paths -- Flags platform-specific risks (iOS vs Android) -- Produces a structured audit report with fixes - -## Workflow - -\`\`\` -Permission UX audit progress: - -- [ ] 1) Confirm minimum inputs (platforms, flow, current UX) -- [ ] 2) Audit current flow (map prompts, copy, and settings paths) -- [ ] 3) Produce audit report (findings + fixes) -- [ ] 4) Verify improvements (ensure UX changes align with platform rules) -\`\`\` - -## 1) Confirm the minimum inputs - -Ask only what is needed: - -- **Platforms**: iOS, Android, or both -- **Entry points**: where the app asks for permission -- **Prompt timing**: first launch, after action, onboarding step, etc. -- **Primer**: is there an in-app explanation before the system prompt -- **Settings path**: how users enable later after denial -- **Denial handling**: how the app behaves if permission is denied - -## 2) Audit the current flow - -Document the current permission flow directly from the app: - -- Where the permission prompt appears and what precedes it -- What copy is shown to explain value -- How the app behaves after deny or dismiss -- How users can enable notifications later - -## 3) Produce the audit report - -Output a concise report in markdown with: - -- **Findings**: each gap mapped to best practice -- **Risk**: what the user impact is -- **Fix**: concrete UX change -- **Platform notes**: iOS-only or Android-only specifics - -Optional: generate a report template: - -\`\`\`bash -bash skills/auditing-permission-ux/scripts/generate-permission-ux-audit-report.sh .mobile/permission-ux-audit.md -\`\`\` - -## 4) Verify improvements - -Confirm: - -- Prompt timing is contextual (not forced on first launch) -- Primer explains value clearly and is dismissible -- Denied users can still use the app -- Settings path is discoverable and clear -- Android importance/channel strategy is not misleading - -## Progressive Disclosure - -- **Level 1**: This \`SKILL.md\` -- **Level 2**: \`references/\` -- **Level 3**: \`examples/\` (optional) -- **Level 4**: \`scripts/\` (execute; do not load) - -## References - -- \`references/permission-ux-best-practices.md\` `, integration: `--- name: clix-integration @@ -1720,8 +1520,9 @@ Create a Notification Service Extension for rich push notifications (images, but \`\`\`text 1. File > New > Target 2. Select "Notification Service Extension" -3. Name it "{AppName}NotificationServiceExtension" +3. Name it "{AppName}NotificationServiceExtension" (e.g., "MyAppNotificationServiceExtension") 4. Click "Finish" (Cancel the "Activate scheme" dialog) +5. Note: Use this exact name consistently in Podfile, entitlements path, and SPM setup \`\`\` **Implement NotificationService.swift:** @@ -1968,26 +1769,6 @@ export const EMBEDDED_SKILL_METADATA: SkillMetadata[] = [ 'Helps developers author and debug Clix personalization templates (Liquid-style) for message content, deep links/URLs, and audience targeting. Use when the user mentions personalization variables, Liquid, templates, conditional logic, loops, filters, deep links, message logs, or when the user types `clix-personalization`.', userInvocable: true, }, - { - folder: 'auditing-deep-link-contracts', - name: 'auditing-deep-link-contracts', - commandName: 'auditing-deep-link-contracts', - displayName: 'Auditing Deep Link Contracts', - shortDescription: 'Deep link contract audit', - description: - 'Audits deep link contracts and routing behavior. Use when validating supported routes, required parameters, and cold or warm start handling.', - userInvocable: true, - }, - { - folder: 'auditing-permission-ux', - name: 'auditing-permission-ux', - commandName: 'auditing-permission-ux', - displayName: 'Auditing Permission UX', - shortDescription: 'Permission UX audit', - description: - 'Audits notification permission request flows. Use when reviewing or improving permission prompts, settings paths, or denial handling.', - userInvocable: true, - }, { folder: 'integration', name: 'clix-integration', diff --git a/src/lib/ios/agent-prompt-generator.ts b/src/lib/ios/agent-prompt-generator.ts index 793f8ac..32f2f16 100644 --- a/src/lib/ios/agent-prompt-generator.ts +++ b/src/lib/ios/agent-prompt-generator.ts @@ -43,8 +43,8 @@ Modify the Xcode project file (.pbxproj) to link the entitlements file: #### 2. Create Notification Service Extension [Required] Create a new Notification Service Extension target for rich push notifications: -- Target name: \`${context.appName}NotificationServiceExtension\` or \`NotificationServiceExtension\` -- Bundle ID: \`${context.bundleId}.NotificationServiceExtension\` +- Target name: \`${context.appName}NotificationServiceExtension\` +- Bundle ID: \`${context.bundleId}.${context.appName}NotificationServiceExtension\` - Deployment target: Same as main app or iOS 14.0+ - Create necessary files in the extension directory @@ -86,7 +86,7 @@ In Xcode: 3. Click + and add the Clix package #### 5. Create Extension Entitlements [Required] -Create entitlements file for the extension at \`${context.iosDir}/NotificationServiceExtension/NotificationServiceExtension.entitlements\`: +Create entitlements file for the extension at \`${context.iosDir}/${context.appName}NotificationServiceExtension/${context.appName}NotificationServiceExtension.entitlements\`: \`\`\`xml diff --git a/src/lib/skills/ios-setup/SKILL.md b/src/lib/skills/ios-setup/SKILL.md index 5808918..be6334a 100644 --- a/src/lib/skills/ios-setup/SKILL.md +++ b/src/lib/skills/ios-setup/SKILL.md @@ -136,8 +136,9 @@ Create a Notification Service Extension for rich push notifications (images, but ```text 1. File > New > Target 2. Select "Notification Service Extension" -3. Name it "{AppName}NotificationServiceExtension" +3. Name it "{AppName}NotificationServiceExtension" (e.g., "MyAppNotificationServiceExtension") 4. Click "Finish" (Cancel the "Activate scheme" dialog) +5. Note: Use this exact name consistently in Podfile, entitlements path, and SPM setup ``` **Implement NotificationService.swift:** From b4ad68b54addae7d6380365c32ca69591908a3e8 Mon Sep 17 00:00:00 2001 From: Minkyu Cho Date: Wed, 28 Jan 2026 12:54:40 +0900 Subject: [PATCH 3/3] docs(ios): add NSE setup documentation to README and llms.txt - Update README.md ios-setup section with NSE setup details - Update llms.txt with comprehensive NSE configuration guide - Fix bare URL markdown lint issue in SKILL.md --- README.md | 13 ++++++---- llms.txt | 40 +++++++++++++++++++++---------- src/lib/embedded-skills.ts | 2 +- src/lib/skills/ios-setup/SKILL.md | 2 +- 4 files changed, 38 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index d415c42..d7737f8 100644 --- a/README.md +++ b/README.md @@ -162,7 +162,7 @@ clix doctor ### `clix ios-setup` -Configure iOS capabilities required for the Clix SDK (Push Notifications and App Groups). +Configure iOS capabilities and Notification Service Extension (NSE) for the Clix SDK. ```bash clix ios-setup @@ -170,9 +170,14 @@ clix ios-setup **What it does:** 1. Analyzes your iOS project structure -2. Checks current capabilities status +2. Checks current capabilities status (Push Notifications, App Groups) 3. Creates/modifies entitlements files -4. Guides you through Xcode and Apple Developer Portal configuration +4. Guides NSE setup for rich push notifications: + - Creates `{AppName}NotificationServiceExtension` target + - Implements `NotificationService.swift` with `ClixNotificationServiceExtension` + - Configures CocoaPods/SPM dependencies for extension target + - Sets build settings (`ENABLE_USER_SCRIPT_SANDBOXING` for Xcode 15+) +5. Guides you through Xcode and Apple Developer Portal configuration **Note:** Some steps require manual action in Xcode and Apple Developer Portal. @@ -277,7 +282,7 @@ Use these commands within the interactive chat (`clix`): | `/install` | | Autonomous SDK installation | | `/doctor` | | Check SDK integration status | | `/debug` | | Interactive debugging assistant | -| `/ios-setup` | `/capabilities`, `/ios-capabilities` | Configure iOS capabilities | +| `/ios-setup` | `/capabilities`, `/ios-capabilities` | Configure iOS capabilities and NSE | ### Interactive Skills diff --git a/llms.txt b/llms.txt index 0bcc9d3..0516d81 100644 --- a/llms.txt +++ b/llms.txt @@ -241,7 +241,7 @@ These can be run from command-line (`clix `) or chat mode: - `/install` - Autonomous SDK installation with automatic file modifications - `/doctor` - Analyze SDK integration status (automatic scan, JSON output) - `/debug` - Interactive debugging assistant (asks for problem description) -- `/ios-setup` (aliases: `/capabilities`, `/ios-capabilities`) - Configure iOS capabilities for push notifications and app groups +- `/ios-setup` (aliases: `/capabilities`, `/ios-capabilities`) - Configure iOS capabilities and Notification Service Extension (NSE) #### Interactive Skills (5 commands) @@ -380,32 +380,44 @@ Describe the problem: Events not appearing in Clix dashboard [Provides fix with exact file location] ``` -#### `/ios-setup` - iOS Setup & Capabilities Configuration +#### `/ios-setup` - iOS Setup, Capabilities & NSE Configuration **Category:** Autonomous Command **Aliases:** `/capabilities`, `/ios-capabilities` -**What it does:** Configures iOS capabilities required for the Clix SDK, specifically Push Notifications and App Groups. +**What it does:** Configures iOS capabilities and Notification Service Extension (NSE) required for the Clix SDK. **Capabilities configured:** - **Push Notifications** - Enables APNs communication (entitlement: `aps-environment`) -- **App Groups** - Enables data sharing between app and Notification Service Extension (entitlement: `com.apple.security.application-groups`, format: `group.clix.{BUNDLE_ID}`) +- **App Groups** - Enables data sharing between app and NSE (entitlement: `com.apple.security.application-groups`, format: `group.clix.{BUNDLE_ID}`) + +**Notification Service Extension (NSE) setup:** +- **Target name:** `{AppName}NotificationServiceExtension` (consistent across all steps) +- **NotificationService.swift:** Uses `ClixNotificationServiceExtension` base class with `register(projectId:)` call +- **Dependency setup:** CocoaPods (`pod 'Clix'` in extension target) or SPM (add Clix package to extension) +- **Build settings:** `ENABLE_USER_SCRIPT_SANDBOXING = No` for Xcode 15+ +- **React Native + Firebase:** Move "Embed Foundation Extensions" above "[RNFB] Core Configuration" **Workflow:** 1. Analyzes iOS project structure (finds .xcodeproj/.xcworkspace) 2. Detects Bundle ID and checks current capabilities status 3. Creates/modifies entitlements files for main app and extension -4. Provides step-by-step instructions for Xcode configuration -5. Guides through Apple Developer Portal setup -6. Outputs verification report +4. Guides NSE target creation and NotificationService.swift implementation +5. Provides CocoaPods/SPM setup instructions for extension target +6. Provides step-by-step instructions for Xcode configuration +7. Guides through Apple Developer Portal setup +8. Outputs verification report **What can be automated:** - Creating/modifying entitlements files - Reading project configuration **What requires manual action:** +- Creating NSE target in Xcode (File > New > Target > Notification Service Extension) - Adding capabilities in Xcode UI (Signing & Capabilities) +- Adding Clix SDK to extension target (Podfile or SPM) +- Configuring build settings for Xcode 15+ - Enabling capabilities in Apple Developer Portal - Registering App Group IDs - Regenerating provisioning profiles @@ -420,12 +432,14 @@ App Groups: not configured Creating entitlements files... ✓ Created MyApp.entitlements -✓ Created NotificationServiceExtension.entitlements +✓ Created MyAppNotificationServiceExtension.entitlements -Manual steps required in Xcode: -1. Add Push Notifications capability to main target -2. Add App Groups capability with ID: group.clix.com.example.myapp -3. Add same App Group to extension target +Manual steps required: +1. Create NSE target: MyAppNotificationServiceExtension +2. Implement NotificationService.swift with ClixNotificationServiceExtension +3. Add Clix SDK to extension (Podfile or SPM) +4. Add Push Notifications and App Groups capabilities +5. Set ENABLE_USER_SCRIPT_SANDBOXING to No (Xcode 15+) {verification report JSON} ``` @@ -1254,7 +1268,7 @@ When helping users with Clix CLI, keep these points in mind: - "SDK integration" → Use `/install` for autonomous installation or `/integration` skill for guided steps - "iOS installation" → Detect: Package.swift (SPM, preferred), Podfile (CocoaPods), or suggest SPM for bare Xcode projects. SPM is the modern, recommended approach. - "SPM/Swift Package Manager" → Guide through Package.swift modification or Xcode UI (File > Add Package Dependencies) for adding packages -- "iOS capabilities" → Use `/ios-setup` to configure Push Notifications and App Groups +- "iOS capabilities" → Use `/ios-setup` to configure Push Notifications, App Groups, and Notification Service Extension (NSE) - "Event tracking" → Use `/event-tracking` skill (interactive, creates event plans) - "User management" → Use `/user-management` skill (setUserId, properties, logout handling) - "Personalization" → Use `/personalization` skill (Liquid templates for messages) diff --git a/src/lib/embedded-skills.ts b/src/lib/embedded-skills.ts index b7cf413..4aa57c5 100644 --- a/src/lib/embedded-skills.ts +++ b/src/lib/embedded-skills.ts @@ -1542,7 +1542,7 @@ class NotificationService: ClixNotificationServiceExtension { } \`\`\` -**Note:** Replace \`YOUR_PROJECT_ID\` with your actual Clix project ID from https://console.clix.so/ +**Note:** Replace \`YOUR_PROJECT_ID\` with your actual Clix project ID from **Add Clix SDK to Extension Target:** diff --git a/src/lib/skills/ios-setup/SKILL.md b/src/lib/skills/ios-setup/SKILL.md index be6334a..f42786f 100644 --- a/src/lib/skills/ios-setup/SKILL.md +++ b/src/lib/skills/ios-setup/SKILL.md @@ -158,7 +158,7 @@ class NotificationService: ClixNotificationServiceExtension { } ``` -**Note:** Replace `YOUR_PROJECT_ID` with your actual Clix project ID from https://console.clix.so/ +**Note:** Replace `YOUR_PROJECT_ID` with your actual Clix project ID from **Add Clix SDK to Extension Target:**