diff --git a/src/lib/embedded-skills.ts b/src/lib/embedded-skills.ts
index f7c8328..c61b87e 100644
--- a/src/lib/embedded-skills.ts
+++ b/src/lib/embedded-skills.ts
@@ -458,30 +458,175 @@ Create or update documentation:
### iOS (Swift)
-**Initialization Pattern:**
+**SwiftUI App Pattern (simple initialization):**
\`\`\`swift
+import SwiftUI
import Clix
@main
struct MyApp: App {
init() {
// Load credentials from your app configuration (do NOT hardcode).
- // Example: store values in Info.plist keys.
let projectId = Bundle.main.object(forInfoDictionaryKey: "CLIX_PROJECT_ID") as? String ?? ""
let apiKey = Bundle.main.object(forInfoDictionaryKey: "CLIX_PUBLIC_API_KEY") as? String
let config = ClixConfig(projectId: projectId, apiKey: apiKey)
Clix.initialize(config: config)
}
+
+ var body: some Scene {
+ WindowGroup {
+ ContentView()
+ }
+ }
+}
+\`\`\`
+
+**AppDelegate Pattern (RECOMMENDED for push notifications):**
+
+For apps that need push notifications, use the AppDelegate pattern with full delegate methods:
+
+\`\`\`swift
+import UIKit
+import UserNotifications
+import Clix
+
+@main
+class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {
+
+ func application(_ application: UIApplication,
+ didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
+ // Initialize Clix SDK
+ let projectId = Bundle.main.object(forInfoDictionaryKey: "CLIX_PROJECT_ID") as? String ?? ""
+ let apiKey = Bundle.main.object(forInfoDictionaryKey: "CLIX_PUBLIC_API_KEY") as? String
+ let config = ClixConfig(projectId: projectId, apiKey: apiKey)
+ Clix.initialize(config: config)
+
+ // Set notification delegate
+ UNUserNotificationCenter.current().delegate = self
+
+ // Request push notification permission
+ UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { granted, error in
+ if granted {
+ DispatchQueue.main.async {
+ application.registerForRemoteNotifications()
+ }
+ }
+ }
+
+ return true
+ }
+
+ // MARK: - Push Token Registration
+
+ func application(_ application: UIApplication,
+ didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
+ // Pass the device token to Clix for push notification delivery
+ Clix.setPushToken(deviceToken)
+ }
+
+ func application(_ application: UIApplication,
+ didFailToRegisterForRemoteNotificationsWithError error: Error) {
+ print("Failed to register for push notifications: \\(error)")
+ }
+
+ // MARK: - UNUserNotificationCenterDelegate
+
+ // Handle foreground notifications - show banner even when app is active
+ func userNotificationCenter(_ center: UNUserNotificationCenter,
+ willPresent notification: UNNotification,
+ withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
+ completionHandler([.banner, .sound, .badge])
+ }
+
+ // Handle notification tap - track engagement and process deep links
+ func userNotificationCenter(_ center: UNUserNotificationCenter,
+ didReceive response: UNNotificationResponse,
+ withCompletionHandler completionHandler: @escaping () -> Void) {
+ Clix.handleNotificationResponse(response)
+ completionHandler()
+ }
+}
+\`\`\`
+
+**SwiftUI App with AppDelegate (hybrid pattern):**
+
+For SwiftUI apps that need push notification handling:
+
+\`\`\`swift
+import SwiftUI
+import UserNotifications
+import Clix
+
+class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDelegate {
+ func application(_ application: UIApplication,
+ didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
+ // Initialize Clix SDK
+ let projectId = Bundle.main.object(forInfoDictionaryKey: "CLIX_PROJECT_ID") as? String ?? ""
+ let apiKey = Bundle.main.object(forInfoDictionaryKey: "CLIX_PUBLIC_API_KEY") as? String
+ let config = ClixConfig(projectId: projectId, apiKey: apiKey)
+ Clix.initialize(config: config)
+
+ // Set notification delegate
+ UNUserNotificationCenter.current().delegate = self
+
+ // Request push notification permission
+ UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { granted, error in
+ if granted {
+ DispatchQueue.main.async {
+ application.registerForRemoteNotifications()
+ }
+ }
+ }
+
+ return true
+ }
+
+ func application(_ application: UIApplication,
+ didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
+ Clix.setPushToken(deviceToken)
+ }
+
+ func application(_ application: UIApplication,
+ didFailToRegisterForRemoteNotificationsWithError error: Error) {
+ print("Failed to register for push notifications: \\(error)")
+ }
+
+ func userNotificationCenter(_ center: UNUserNotificationCenter,
+ willPresent notification: UNNotification,
+ withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
+ completionHandler([.banner, .sound, .badge])
+ }
+
+ func userNotificationCenter(_ center: UNUserNotificationCenter,
+ didReceive response: UNNotificationResponse,
+ withCompletionHandler completionHandler: @escaping () -> Void) {
+ Clix.handleNotificationResponse(response)
+ completionHandler()
+ }
+}
+
+@main
+struct MyApp: App {
+ @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
+
+ var body: some Scene {
+ WindowGroup {
+ ContentView()
+ }
+ }
}
\`\`\`
**Key Points:**
-- Initialize in \`@main\` app struct or \`AppDelegate\`
-- Use environment variables, never hardcode
-- Handle optional API key for analytics-only mode
+- For push notifications, use the AppDelegate pattern (not just SwiftUI \`init\`)
+- Set \`UNUserNotificationCenter.current().delegate = self\` before registering
+- Implement all delegate methods: \`didRegisterForRemoteNotificationsWithDeviceToken\`, \`willPresent\`, \`didReceive\`
+- Call \`Clix.setPushToken(deviceToken)\` in the token registration callback
+- Call \`Clix.handleNotificationResponse(response)\` when notification is tapped
+- Use environment variables (Info.plist), never hardcode credentials
### Android (Kotlin)
diff --git a/src/lib/skills.ts b/src/lib/skills.ts
index d6a6c25..269e1ca 100644
--- a/src/lib/skills.ts
+++ b/src/lib/skills.ts
@@ -185,24 +185,43 @@ COMPLETION CRITERIA:
/**
* Interactive mode instruction for Guided Interactive Workflow.
- * Instructs the agent to follow the Confirm → Propose → Validate → Implement → Verify pattern.
+ * Instructs the agent to be proactive about automatable tasks while asking for confirmation when needed.
*/
const INTERACTIVE_MODE_INSTRUCTION = `
-IMPORTANT: This is an interactive conversation session. Follow the Guided Interactive Workflow.
-
-EXECUTION GUIDELINES:
-- ALWAYS follow the workflow steps in order: Confirm → Propose → Validate → Implement → Verify
-- DO NOT skip to implementation without completing earlier steps
-- ASK for required inputs before proceeding (platform, goals, preferences)
-- PROPOSE your plan and wait for user approval before making changes
-- NEVER modify files without explicit user confirmation
-- If information is missing, ASK the user rather than assuming
-
-WORKFLOW ENFORCEMENT:
-- Start by confirming the minimum required inputs from the user
-- Present your proposed plan for review
-- Only proceed to implementation after the user approves the plan
-- Validate before implementing, verify after implementing
+IMPORTANT: This is an interactive conversation session.
+
+AUTOMATION GUIDELINES:
+Distinguish between what CAN and CANNOT be automated:
+
+**CAN AUTOMATE (use Write/Edit tools immediately without asking):**
+- Creating new files (configuration files, source code, entitlements)
+- Modifying existing source code (adding initialization code, imports, delegate methods)
+- Updating config files (Podfile, package.json, build.gradle, pubspec.yaml)
+- Creating extension files (NotificationService.swift, Info.plist, entitlements)
+- Running installation commands (pod install, npm install, flutter pub get)
+
+**CANNOT AUTOMATE (provide clear instructions):**
+- Xcode UI actions (File > New > Target, Signing & Capabilities)
+- Apple Developer Portal configuration (App IDs, certificates, provisioning profiles)
+- IDE-specific settings (Build Settings, linking entitlements)
+- Android Studio capability configuration
+
+EXECUTION WORKFLOW:
+1. Analyze the project and detect platform/configuration
+2. For automatable tasks: DO THEM DIRECTLY using Write/Edit/Bash tools
+3. For non-automatable tasks: Provide clear step-by-step instructions
+4. Verify the integration and report what was done
+
+ASK FOR CONFIRMATION ONLY WHEN:
+- Multiple valid implementation approaches exist (user preference matters)
+- Destructive changes are needed (deleting files, overwriting significant code)
+- Critical decisions require user input (which package manager to use)
+
+DO NOT ASK FOR CONFIRMATION FOR:
+- Standard file creation/modification (always proceed)
+- Adding initialization code to entry points
+- Creating configuration files
+- Running standard installation commands
`;
/**
diff --git a/src/lib/skills/install/SKILL.md b/src/lib/skills/install/SKILL.md
index 810806a..6e611a2 100644
--- a/src/lib/skills/install/SKILL.md
+++ b/src/lib/skills/install/SKILL.md
@@ -154,41 +154,149 @@ Use `/firebase` command in interactive mode to check and configure Firebase cred
- Provide manual steps for code changes - make the changes
- Wait for user input (except for IDE-only tasks)
+## iOS Notification Service Extension (Recommended)
+
+For rich push notifications (images, buttons), the Notification Service Extension (NSE) is required.
+
+### What CAN Be Automated (use Write/Edit tools immediately)
+
+Create these files AUTOMATICALLY without asking for permission:
+
+**1. Create NotificationService.swift**
+
+Create file at `ios/{AppName}NotificationServiceExtension/NotificationService.swift`:
+
+```swift
+import UserNotifications
+import Clix
+
+class NotificationService: ClixNotificationServiceExtension {
+ override func didReceive(
+ _ request: UNNotificationRequest,
+ withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void
+ ) {
+ register(projectId: "YOUR_CLIX_PROJECT_ID")
+ super.didReceive(request, withContentHandler: contentHandler)
+ }
+}
+```
+
+**2. Create Extension Info.plist**
+
+Create file at `ios/{AppName}NotificationServiceExtension/Info.plist`:
+
+```xml
+
+
+
+
+ CFBundleDisplayName
+ {AppName}NotificationServiceExtension
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIdentifier
+ $(PRODUCT_BUNDLE_IDENTIFIER)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ $(PRODUCT_NAME)
+ CFBundlePackageType
+ $(PRODUCT_BUNDLE_PACKAGE_TYPE)
+ CFBundleShortVersionString
+ $(MARKETING_VERSION)
+ CFBundleVersion
+ $(CURRENT_PROJECT_VERSION)
+ NSExtension
+
+ NSExtensionPointIdentifier
+ com.apple.usernotifications.service
+ NSExtensionPrincipalClass
+ $(PRODUCT_MODULE_NAME).NotificationService
+
+
+
+```
+
+**3. Create Extension Entitlements**
+
+Create file at `ios/{AppName}NotificationServiceExtension/{AppName}NotificationServiceExtension.entitlements`:
+
+```xml
+
+
+
+
+ com.apple.security.application-groups
+
+ group.clix.{BUNDLE_ID}
+
+
+
+```
+
+**4. Create/Update Main App Entitlements**
+
+Create or update file at `ios/{AppName}/{AppName}.entitlements`:
+
+```xml
+
+
+
+
+ aps-environment
+ development
+ com.apple.security.application-groups
+
+ group.clix.{BUNDLE_ID}
+
+
+
+```
+
+**5. Update Podfile (CocoaPods projects only)**
+
+Add extension target to Podfile:
+
+```ruby
+target '{AppName}NotificationServiceExtension' do
+ pod 'Clix', :git => 'https://github.com/clix-so/clix-ios-sdk.git'
+end
+```
+
+Then run: `cd ios && pod install`
+
+### What CANNOT Be Automated (provide instructions only)
+
+Only these steps require manual Xcode UI interaction:
+
+1. **Create Xcode target**: File > New > Target > Notification Service Extension
+ - Name it `{AppName}NotificationServiceExtension`
+ - After creating, Xcode will generate a default `NotificationService.swift` - replace it with our version
+
+2. **Link entitlements in Build Settings**:
+ - Select extension target > Build Settings
+ - Search for "Code Signing Entitlements"
+ - Set path to `{AppName}NotificationServiceExtension/{AppName}NotificationServiceExtension.entitlements`
+
+3. **Add App Groups capability in Xcode**:
+ - Main app target > Signing & Capabilities > + Capability > App Groups
+ - Extension target > Signing & Capabilities > + Capability > App Groups
+ - Select the same group ID: `group.clix.{BUNDLE_ID}`
+
+4. **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.
+
## IDE-Only Manual Steps
Only these require user action:
-- Xcode: Adding capabilities, configuring entitlements
-- Android Studio: Firebase setup UI, capability configuration
+- Xcode: Adding capabilities in Signing & Capabilities tab, creating extension target
+- Apple Developer Portal: Registering App Group ID, enabling Push Notifications on App ID
+- Android Studio: Firebase setup UI
- Building and running the project
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 f42786f..9f49b46 100644
--- a/src/lib/skills/ios-setup/SKILL.md
+++ b/src/lib/skills/ios-setup/SKILL.md
@@ -132,16 +132,13 @@ Create or modify entitlements files. Use Write/Edit tools for these operations.
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" (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
-```
+#### What CAN Be Automated (use Write/Edit tools immediately)
+
+**IMPORTANT:** Create these files AUTOMATICALLY without asking for permission.
-**Implement NotificationService.swift:**
+**1. Create NotificationService.swift**
+
+Use Write tool to create `ios/{AppName}NotificationServiceExtension/NotificationService.swift`:
```swift
import UserNotifications
@@ -152,28 +149,106 @@ class NotificationService: ClixNotificationServiceExtension {
_ request: UNNotificationRequest,
withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void
) {
- register(projectId: "YOUR_PROJECT_ID")
+ register(projectId: "YOUR_CLIX_PROJECT_ID")
super.didReceive(request, withContentHandler: contentHandler)
}
}
```
-**Note:** Replace `YOUR_PROJECT_ID` with your actual Clix project ID from
+**2. Create Extension Info.plist**
+
+Use Write tool to create `ios/{AppName}NotificationServiceExtension/Info.plist`:
+
+```xml
+
+
+
+
+ CFBundleDisplayName
+ {AppName}NotificationServiceExtension
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIdentifier
+ $(PRODUCT_BUNDLE_IDENTIFIER)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ $(PRODUCT_NAME)
+ CFBundlePackageType
+ $(PRODUCT_BUNDLE_PACKAGE_TYPE)
+ CFBundleShortVersionString
+ $(MARKETING_VERSION)
+ CFBundleVersion
+ $(CURRENT_PROJECT_VERSION)
+ NSExtension
+
+ NSExtensionPointIdentifier
+ com.apple.usernotifications.service
+ NSExtensionPrincipalClass
+ $(PRODUCT_MODULE_NAME).NotificationService
+
+
+
+```
+
+**3. Create Extension Entitlements**
+
+Use Write tool to create `ios/{AppName}NotificationServiceExtension/{AppName}NotificationServiceExtension.entitlements`:
+
+```xml
+
+
+
+
+ com.apple.security.application-groups
+
+ group.clix.{BUNDLE_ID}
+
+
+
+```
+
+**4. Update Podfile (CocoaPods projects)**
-**Add Clix SDK to Extension Target:**
+Use Edit tool to add extension target to Podfile:
-For CocoaPods projects, add to Podfile:
```ruby
target '{AppName}NotificationServiceExtension' do
- pod 'Clix'
+ pod 'Clix', :git => 'https://github.com/clix-so/clix-ios-sdk.git'
end
```
+
Then run: `cd ios && pod install`
-For SPM projects in Xcode:
+**Note:** Replace `{AppName}` with the actual app name and `{BUNDLE_ID}` with the actual bundle identifier (e.g., `com.example.myapp`).
+
+#### What CANNOT Be Automated (provide instructions only)
+
+These steps require manual Xcode UI interaction:
+
+**Create Extension Target in Xcode:**
+```text
+1. File > New > Target
+2. Select "Notification Service Extension"
+3. Name it "{AppName}NotificationServiceExtension" (e.g., "MyAppNotificationServiceExtension")
+4. Click "Finish" (Cancel the "Activate scheme" dialog)
+5. Xcode will create a default NotificationService.swift - the automated version above will replace it
+```
+
+**Link Entitlements in Build Settings:**
+```text
1. Select the extension target
-2. Go to General > Frameworks, Libraries, and Embedded Content
-3. Click + and add the Clix package
+2. Go to Build Settings
+3. Search for "Code Signing Entitlements"
+4. Set the path to: {AppName}NotificationServiceExtension/{AppName}NotificationServiceExtension.entitlements
+```
+
+**Add App Groups Capability:**
+```text
+1. Select extension target > Signing & Capabilities
+2. Click "+ Capability" > "App Groups"
+3. Select the same group ID used in main app: group.clix.{BUNDLE_ID}
+```
**Configure Build Settings (Xcode 15+):**
@@ -183,6 +258,13 @@ For the extension target:
For React Native projects with Firebase:
- In Build Phases, move "Embed Foundation Extensions" above "[RNFB] Core Configuration"
+**For SPM projects in Xcode:**
+```text
+1. Select the extension target
+2. Go to General > Frameworks, Libraries, and Embedded Content
+3. Click + and add the Clix package
+```
+
### Phase 4: Apple Developer Portal Configuration
Guide user through manual portal configuration. These steps CANNOT be automated.