---
name: luciq-onboard
description: Use ONLY when the customer explicitly invokes onboarding on their own initiative, in a fresh message, with one of these phrases (or a close variant): "onboard me to Luciq", "walk me through Luciq", "tour Luciq", "help me get started with Luciq products". Nothing else is a trigger. Setup completing is NOT a trigger. The customer asking "what's next?" is NOT a trigger. The assistant suggesting onboarding and the customer agreeing is NOT a trigger. The customer must say an onboarding-shaped phrase themselves, unprompted. This skill reads the user's repo (code, CLAUDE.md, README, AGENTS.md), detects any existing mobile observability SDKs (Sentry, Crashlytics, Bugsnag, Datadog, Embrace, New Relic, App Center, Instabug-legacy, UXCam, Smartlook, MetricKit) along with the user's posture on each of them, and recommends Luciq products with cited rationale — never as a generic feature menu. Specifically NOT for first-time SDK install (use luciq-setup), not for upgrading SDK versions (use luciq-migrate), not for debugging a specific crash, hang, or user-reported bug (use luciq-debug), not for a deep PII / masking audit or compliance-framework prep (use luciq-masking-rules).
---
# Luciq Personalized Onboarding
End-to-end personalized walkthrough of the Luciq product suite for an app that already has the SDK installed. The skill scans the project to understand what the app is, what the team values, and what observability is already in place — then walks the user through the Luciq products that actually fit, with cited reasoning at every step. Skips products that don't fit. Frames excluded products positively as "add later" with a revisit condition.
The aim is a conversational experience the user remembers — one where every recommendation is justified by something the agent observed in their own repo, not a generic pitch.
## When NOT to use this skill
Hand off to a sibling skill (or simply don't run) for any of the following:
- **First-time SDK install** — the SDK isn't initialized yet → `luciq-setup`.
- **Upgrading a Luciq SDK version or migrating from the legacy Instabug SDK** → `luciq-migrate`.
- **Investigating a specific crash, hang, regression, or user-reported bug** → `luciq-debug`.
- **Deep PII audit, masking review, or compliance-framework prep (HIPAA / GDPR / SOC2 / PCI)** → `luciq-masking-rules`. Onboard does shallow per-view masking inline; the deep audit (auto-mask types, network mask key list, behavior matrix, consent gating, grayscale, FLAG_SECURE, SSUI `isPrivate`, compliance presets, pre-prod checklist) belongs in `luciq-masking-rules`.
- **API signature lookups** — point the user at https://docs.luciq.ai.
- **After `luciq-setup` completes.** Setup does not invite onboarding. Wait for the customer to invoke this skill on their own, in a fresh ask.
If the user's ask matches any of the above, STOP and route them. Running `luciq-onboard` on an uninstrumented project produces incorrect recommendations because every analysis step assumes the SDK init is already present.
## Canonical sources of truth
Verify product names, dashboard URLs, and config keys against the live docs before quoting them in the conversation. Hardcoded values in this skill are illustrative.
| Concern | Source |
| --- | --- |
| Product setup details (per platform) | https://docs.luciq.ai |
| iOS product setup | https://docs.luciq.ai/ios/setup-luciq-for-ios |
| Android product setup | https://docs.luciq.ai/android |
| React Native product setup | https://docs.luciq.ai/react-native |
| Flutter product setup | https://docs.luciq.ai/flutter |
| KMP product setup | https://docs.luciq.ai/kmp |
| User's apps and workspace | Luciq MCP `list_applications` (if authenticated) |
| User's prior crashes / patterns | Luciq MCP `crash_patterns`, `list_crashes`, `list_bugs` |
| The user's repo | local file system — read directly |
## Operating principles
These shape every conversational turn the skill produces. Internalize them; they're the difference between onboarding that feels like a wizard and onboarding that feels like a thoughtful peer.
1. **Cite every recommendation.** Never say "I recommend X" without naming the source: a CLAUDE.md line quoted verbatim, a file:line in the user's code, a precedent from their other Luciq apps, or a specific archetype rationale.
2. **Show your work before asking.** If a question can be answered by reading the repo, answer it — don't ask. Only ask the user things only the user knows.
3. **One conversational beat at a time.** Never present a wizard form. Present one product, one decision, one ask.
4. **Default to recommending, fall back to asking.** Every question is a tax on the user; reserve it for genuinely undecidable cases.
5. **Skip and defer are first-class.** A user who says "not now" hasn't failed — they've made a choice. Capture it with a reason and a revisit condition, then move on.
6. **Honest about competitors, never disparaging — and competitor presence is context, not a downgrade.** Position Luciq's strengths alongside what the user already has. Never criticize a competitor's product. **Never move a Luciq product out of "Recommended now" just because a competitor SDK covers similar ground.** If the Luciq product fits the customer's app on its own merits, recommend it on its own merits. Name the competitor honestly in the Ask so the customer can decide whether to adopt alongside, evaluate as a swap, or stay on what they have. The choice is theirs; the skill does not pre-decide deferral for them.
7. **Activation > configuration.** A configured product the user hasn't seen working is a half-delivery. End the walk with a single concrete verification step that produces real data on the user's dashboard.
## Workflow checklist
Track every phase. STOP on any phase that can't complete with confidence — never fake progress.
```
Onboarding Progress:
- [ ] 0. Detect mode (FAST / AUDIT / GUIDED)
- [ ] 1. Analyze the project (silent, parallel)
- [ ] 2. Recap — conflicts first, then app understanding
- [ ] 3. Present the plan (three positive buckets)
- [ ] 4. Product walk (Ask → Apply → Summarize per product)
- [ ] 5. End-of-walk activation (one consolidated Aha)
- [ ] 6. Handoff — write LUCIQ_ONBOARDING.md
```
## 0. Detect mode
Read the user's trigger phrasing and pick a mode. Different modes produce different conversation lengths.
| Trigger phrasing | Mode | Behavior |
| --- | --- | --- |
| "must-haves", "fast", "quick", "just the basics" | **FAST** | Apply the top 3 "Recommended now" products with one-line confirms each. No end-of-walk activation. ~2 minutes. |
| "what am I missing", "audit", "what should I set up" | **AUDIT** | Report-only. Print the analysis, present the plan in three buckets, write the handoff doc. Apply nothing without explicit per-product confirmation in a follow-up. |
| anything else, including "onboard me", "walk me through", "tour" | **GUIDED** | Full arc with conflict recap, per-product walk, and end-of-walk activation. ~10 minutes. This is the default. |
If unclear, default to GUIDED. Confirm the chosen mode in one line at the start so the user knows what they're about to spend time on.
## 1. Analyze the project (silent, parallel)
This phase runs without conversation. The output is a single structured **project profile** the rest of the workflow reads from. Do all four analysis tracks in parallel — they're independent and deterministic.
### Track A — Context docs
Read in priority order. Stop at the first source rich enough to anchor the recap. Augment with later sources if shallow.
1. `CLAUDE.md` (repo root + any nested)
2. `AGENTS.md`, `.cursorrules`, `.windsurfrules`
3. `README.md`, `ARCHITECTURE.md`, `docs/*.md`
Extract: app purpose (one sentence), team's stated priorities, PII / privacy posture, mention of compliance frameworks (GDPR, HIPAA, SOC2, PCI), and any quotable line (with line number) the recap can cite verbatim. The cited quote is what makes the recap feel uncanny — find at least one if context exists.
### Track B — Archetype + money path + auth + sensitive view enumeration
From the existing `luciq-setup` profile (or a fresh scan), infer:
- **Archetype**: e-commerce / fintech / social / media / productivity / gaming / B2B-tool / internal — based on deps (`Stripe`, `RevenueCat`, `Firebase Auth`, `Auth0`) and screen names (`CheckoutView`, `FeedView`, `DashboardView`).
- **Money path**: the file:line of the screen where revenue is captured (checkout, paywall, subscription). E-commerce without an identified money path means the archetype guess is shaky — ask once.
- **Auth flow**: login and logout file:line. Needed for product recommendations that depend on `identifyUser`.
- **Sensitive view enumeration**: for each sensitive screen (money path, auth, settings/profile, anywhere PII surfaces), enumerate the *individual views* that bind to PII-flavored properties. This is the difference between *"mask the checkout screen"* and *"mark these 4 specific TextFields as `luciq_privateView`."* Downstream products (Bug Reporting, Session Replay) consume this list to propose per-view privacy markers — not just screen-level masking.
#### What counts as a "sensitive view"
A view is sensitive when **two signals agree**:
1. **The view type can render or capture text/images.** SwiftUI: `TextField`, `SecureField`, `Text`, `TextEditor`, `Image`, `AsyncImage`. UIKit: `UITextField`, `UITextView`, `UILabel`, `UIImageView`. Compose: `TextField`, `OutlinedTextField`, `Text`, `Image`, `AsyncImage`. Android Views: `EditText`, `TextView`, `ImageView`. React Native: `TextInput`, `Text`, `Image`. Flutter: `TextField`, `Text`, `Image`.
2. **The bound property or surrounding identifier matches a PII pattern.** Identifier-shaped strings: `password`, `email`, `cardNumber`, `card_number`, `cvv`, `ssn`, `pin`, `iban`, `dob`, `birthDate`, `phone`, `phoneNumber`, `address`, `firstName`, `lastName`, `fullName`, `accountNumber`, `routingNumber`, `taxId`, `passport`, `driverLicense`.
Filter out matches in test/spec/mock paths, validator/regex utilities, and anything under `node_modules`, `Pods/`, `build/`. False positives are common — never apply markers in bulk.
#### Suggested marker per platform (verify against the live setup docs)
| Platform | View type | Suggested marker |
|---|---|---|
| iOS SwiftUI | `TextField`, `SecureField`, `Text`, `Image`, `TextEditor` | `.luciq_privateView()` modifier, or wrap in `LuciqPrivateView { ... }` |
| iOS UIKit | `UITextField`, `UILabel`, `UITextView`, `UIImageView` | `view.luciq_privateView = true` (UIView category property) |
| Android Compose | `TextField`, `Text`, `Image` | `Modifier.luciqPrivate()` |
| Android Views | `EditText`, `TextView`, `ImageView` | `Luciq.addPrivateViews(view)` or `LuciqPrivateView.setPrivateView(view, true)` |
| React Native | `TextInput`, `Text`, `Image` | wrap in `<LuciqPrivateView>...</LuciqPrivateView>` |
| Flutter | `TextField`, `Text`, `Image` | wrap in `LuciqPrivateView(child: ...)` |
Verify the exact import path, method signature, and any version gating against the live setup docs for the user's platform before quoting them in a diff. The markers above evolved through the Instabug → Luciq rebrand and may differ across SDK versions.
The structured output is `sensitive_views: [{screen, file, line, view_type, binding, suggested_marker}]` on the profile.
**Confirmation policy in Phase 4 Apply.** Confirm the **first 3–5 views individually** so the user sees the pattern, the platform marker syntax, and the kinds of false positives the detector can produce. After that threshold, switch to **batch confirm**: list the remaining views in one block (`file:line — view_type — binding`) and ask a single question — *"apply markers to the remaining N views? [yes / no / show details for any specific one]."* If the user picks a row to inspect, fall back to per-match confirmation for that row only.
Never bulk-apply silently — but never burn 15 conversational turns on a single screen either. The point of per-match confirmation is to catch false positives, not to ritualize every view.
If a competitor SDK in Track C has equivalent view-level masking (e.g., Sentry replay `mask` tag, UXCam's view-tagging, Smartlook's blacklisted views), translate the **same view set** to Luciq's marker — that's the privacy-posture style-match at the view level, mirroring what the user's team already considers sensitive.
#### Accessibility posture (lightweight, same pass)
In the same sweep that enumerates sensitive views, count how often the platform-appropriate accessibility identifier API appears on **interactive** views (buttons, text fields, tappable images). The identifiers themselves do no technical work for Luciq — they're a *posture signal* that lets Phase 4 pick more accessible defaults.
| Platform | Identifier APIs to grep |
|---|---|
| iOS SwiftUI / UIKit | `.accessibilityIdentifier(`, `accessibilityIdentifier =`, `accessibilityLabel =` |
| Android Views | `contentDescription`, `setContentDescription(` |
| Android Compose | `Modifier.semantics`, `Modifier.testTag(`, `contentDescription =` |
| React Native | `testID=`, `accessibilityLabel=` |
| Flutter | `Semantics(identifier:`, `Semantics(label:` |
Filter out matches in tests, mocks, generated code, and `node_modules` / `Pods/` / `build/` — same exclusions as sensitive-view enumeration.
Compute coverage as `(interactive views with any identifier) / (total interactive views)` and pair with explicit CLAUDE.md / README mentions of WCAG, VPAT, VoiceOver, TalkBack, screen reader, a11y audit.
The structured output is one field on the profile:
```
accessibility_posture: "strong" | coverage > 60% OR doc mention present
| "partial" | 10% ≤ coverage ≤ 60%
| "absent" | coverage < 10% AND no doc mention
```
Also stash one cited example (`file:line` of a representative identifier site) so Phase 2's recap can quote it verbatim — same evidence-citing pattern the rest of the skill uses.
### Track C — Mobile observability SDK scan + deep config read
Detect every active mobile observability SDK on the project, then for each one read its init site and extract what's on, what's off, and what's tuned. See `references/observability-sdks.md` for the v1 detection patterns, config keys per SDK, and the coverage matrix.
Three signals per SDK:
1. **Manifest match** — package declared in Podfile / Package.swift / build.gradle(.kts) / package.json / pubspec.yaml.
2. **Init call match** — the start/configure call is present in source.
3. **Config artifact match** — config files like `GoogleService-Info.plist`, `sentry.properties`.
A package without an init call is **shelf-ware** — flag it (offer cleanup later), don't treat it as active. All three signals together = confirmed active.
For each confirmed-active SDK, extract:
- **What's on** (enabled features)
- **What's off** (explicitly disabled features — this is the most valuable column, signals team intent)
- **What's tuned** (non-default sample rates, thresholds, redaction lists, env gating)
From the extracted config, infer a **style** (one line): "privacy-conservative, low sample, strict env gating" / "permissive, full PII capture, debug+release". Luciq's defaults in Phase 4 should match this style.
### Track D — Workspace precedent (MCP)
If the Luciq MCP is authenticated, call `list_applications` to enumerate the user's other Luciq apps. For each, optionally call `apm_list_groups` and read masking/replay config patterns to infer the team's "house style" across apps. A precedent quote like *"your other 3 apps run replay at 5%"* is one of the strongest trust-building moves available.
If MCP is not authenticated, skip silently — do not nag the user to authenticate. Precedent is a nice-to-have, not a requirement.
### Track E — Infrastructure, distribution & integration sites
Five small enumerations that turn vague handoff pointers ("set up dSYM upload in CI", "register push token") into real Phase-4 Apply diffs. Each unblocks one or more product cards.
**Lazy execution.** Track C runs first in the parallel sweep (cheap manifest scan + init detection only). Once Track C identifies which Luciq products will plausibly land in *Recommended now* vs *covered by competitor*, gate the Track E sub-tracks:
| Sub-track | Run when | Skip when |
|---|---|---|
| **E1 — CI / build system** | No active competitor crash reporter; OR competitor present but flagged as a vendor-swap candidate by the user | Crashlytics / Sentry / Bugsnag / Embrace is active with confirmed symbol upload in their existing CI step (Crash Reporting will land in "covered by another SDK") |
| **E2 — Push token site** | `auth_flow` was detected in Track B, OR push SDK is in the manifest | No auth flow and no push SDK in manifest (In-App Replies is going to "Can be added later" with revisit-when-identifyUser-wired anyway) |
| **E3 — Network client + base URLs** | No active competitor APM with network tracking | Datadog RUM / New Relic Mobile / Sentry perf / Firebase Performance is active with network capture on (APM will land in "covered by another SDK") |
| **E4 — Distribution model** | Always | — |
| **E5 — Locales** | Always | — |
When a gate causes a skip, the consumer card falls back to its doc-pointer behavior (handoff "What's left for you" line instead of a Phase-4 diff). Re-running the skill after the user resolves the competing SDK will pick up the skipped detection on the next pass.
#### E1 — CI / build system
Detect the CI system in use. Determines whether symbol upload (dSYM, ProGuard / R8 mapping, native debug symbols) and env-gated SDK init can be proposed as concrete diffs to existing workflows rather than left-for-you doc pointers.
| Signal | Locations to grep |
|---|---|
| GitHub Actions | `.github/workflows/*.yml`, `*.yaml` |
| Fastlane | `Fastfile`, `fastlane/` |
| Bitrise | `bitrise.yml` |
| CircleCI | `.circleci/config.yml` |
| GitLab CI | `.gitlab-ci.yml` |
| Xcode Cloud | `ci_scripts/`, `.xcode-cloud/` |
| App Center | `appcenter-*.yml` |
Output: `ci_system: { kind, primary_workflow_file, release_lane_or_job, env_matrix }` or `none`. Consumed by **Crash Reporting** (dSYM / mapping upload step), **SDK init** (env-gated tokens when `env_matrix` has multiple build configs).
#### E2 — Push notification registration site
Detect where the app obtains its push token. Makes In-App Replies' delivery path (and Surveys' push delivery, when used) a real diff at a known file:line rather than a doc pointer.
| Platform | Grep patterns |
|---|---|
| iOS | `didRegisterForRemoteNotificationsWithDeviceToken`, `UNUserNotificationCenter`, `registerForRemoteNotifications` |
| Android | `FirebaseMessaging.getInstance()`, `onNewToken`, classes extending `FirebaseMessagingService` |
| React Native | `messaging().getToken()`, `@react-native-firebase/messaging`, `expo-notifications` `getDevicePushTokenAsync` |
| Flutter | `FirebaseMessaging.instance.getToken()`, `flutter_local_notifications` |
Output: `push_token_site: { file, line, library }` or `null`. Consumed by **In-App Replies** Apply step (`Luciq.setPushNotificationToken(token)` immediately after token acquisition).
#### E3 — Network client + base URLs
Detect the network client and the host strings it talks to. Lets **APM** propose specific tracked-hosts and per-header masking diffs at the client init site, instead of generic suggestions.
| Platform | Grep patterns |
|---|---|
| iOS | `Alamofire.AF`, `Session(`, `URLSession`, base-URL constants in `Configuration.swift` / `APIConstants.swift` |
| Android | `OkHttpClient.Builder()`, `Retrofit.Builder().baseUrl(` |
| React Native | `axios.create({ baseURL:` |
| Flutter | `Dio()`, `BaseOptions(baseUrl:` |
Output: `network_client: { type, init_file_line, base_urls: [...] }`. Consumed by **APM** (concrete `setNetworkHosts([...])` call, masking proposed at the interceptor / adapter site rather than generically).
#### E4 — Distribution model
Detect how the app reaches users. Explicit signal — current archetype + store-presence inference is too indirect for honest handling of App Ratings and Rollout Management.
| Channel | Signals |
|---|---|
| App Store | `pilot`, App Store Connect API key, `upload_to_app_store` lane, `.itmsp` in CI |
| Play Store | `upload_to_play_store`, Google Play API key, `bundle release` task |
| TestFlight only | `pilot` lane without `deliver` / `upload_to_app_store` |
| Firebase App Distribution | `firebase appdistribution:distributors`, `appDistribution` Gradle task |
| Enterprise | Distribution provisioning profile with enterprise team ID |
| Internal / MDM | Intune / JAMF / AirWatch config artifacts |
Output: `distribution_model: { primary: "appstore" | "playstore" | "testflight-only" | "firebase-appdist" | "enterprise" | "internal" | "unknown", channels: { ... booleans ... } }`. Consumed by **App Ratings** (real anti-signal when not store-bound), **Rollout Management** (unlock condition), **Surveys** (pre-launch anti-signal).
#### E5 — Locales
Count the locales the app ships. Multi-locale apps need locale-aware survey copy, App Ratings dashboards split per locale, and Bug Reporting prompt translations — and the skill should surface that as a "What's left for you" item, not silently default to English.
| Platform | Signals |
|---|---|
| iOS | `*.lproj` directories, `Localizable.strings`, `String(localized:)` |
| Android | `res/values-*/strings.xml` |
| React Native | `i18next`, `react-i18next`, `expo-localization`, `react-native-localize` |
| Flutter | `flutter_localizations`, `intl`, generated `S.of(context)` |
Output: `locales: { codes: [...], count: N }`. Consumed by **Surveys** + **App Ratings** + **Bug Reporting** ("What's left for you" notes about locale-aware copy on the dashboard when `count > 1`).
### Conflict detection (in the same pass)
Conflicts are deterministic logic over what the analysis already found — compute them in the same parallel sweep. See `references/observability-sdks.md` for the per-SDK conflict rules. Severity:
- **High** — dual crash handlers, racing ANR detectors, multiple session-replay capturers. Today's capture is non-deterministic. State this honestly.
- **Medium** — multiple network interceptors, overlapping method swizzling on lifecycle methods.
- **Low** — shelf-ware packages, deprecated SDKs still in the manifest.
Conflicts get **surfaced** in Phase 2's recap, never as a separate phase. Capture all of them in the handoff doc whether or not the user addresses them.
## 2. Recap — conflicts first, then app understanding
Open with conflicts if any exist. State them plainly, separate from any Luciq recommendation. This is the trust moment — surfacing problems the user has *independent* of whether they adopt Luciq is what earns credibility for everything that follows.
Example opener for a project with detected conflicts:
> Heads-up before we start: Sentry (AppDelegate.swift:23) and Firebase Crashlytics (AppDelegate.swift:18) both install crash signal handlers. Only one captures any given crash today — your crash capture is non-deterministic. Worth fixing regardless of what we do next.
Then the cited app understanding. Every line is sourced — a CLAUDE.md quote with line number, a file:line for the money path, an inferred style from a competitor's config:
> Quick read on your app:
> - iOS SwiftUI e-commerce app. Money path on `CheckoutView.swift:42`.
> - Your CLAUDE.md line 12 says *"never log financial data"* — I'll default masking aggressive on checkout.
> - Sentry is configured conservatively (replay at 5%, `attachScreenshot: false`, `sendDefaultPii: false`) — Luciq's defaults below will match that posture.
> - Your other 2 apps in this workspace both use Bug Reporting with shake invocation.
If no conflicts and no rich context exist, the recap is two lines instead of six — don't pad. Quality of evidence over quantity of lines.
**Cap the recap at 6 cited lines.** The recap's job is to land the *"how did you know that"* moment in a single readable block — not to inventory every signal Phase 1 collected. Across all detection tracks (A, B, C, D, E + a11y posture + sensitive views) the profile may carry 10+ citable findings; the recap picks the strongest 4–6 and saves the rest for the per-product Asks in Phase 4, where each citation fires next to the product it actually justifies.
Pick recap citations by this priority:
1. A verbatim CLAUDE.md / AGENTS.md / README line with line number (highest — these are the user's own words).
2. The money path file:line (anchors the archetype claim).
3. A competitor SDK's specific posture quote (e.g. `tracesSampleRate: 0.1` from Sentry config) — proves the skill read their actual config, not just the package list.
4. A workspace-precedent quote from MCP (*"your other 3 apps run replay at 5%"*).
5. The strongest one a11y / infrastructure citation if the team's posture is clearly differentiated (e.g. *"every TextField on CheckoutView labels accessibilityIdentifier"*).
Citations that don't make the recap cut — push token site, network base URLs, CI workflow path, locale count, individual sensitive-view enumerations — land in the corresponding Phase 4 Ask where they justify a *specific* recommendation. That's where they have the most force anyway.
## 3. Present the plan — three positive buckets
Score each Luciq product against the profile (see `references/product-cards.md` for per-product fit signals and anti-signals). Group into three buckets. **Never use negative labels like "not a fit" or "skip" in user-facing copy** — always frame as timing.
Only products with an SDK-side diff to confirm are eligible for the buckets. Capabilities that auto-derive from configured products, live only on the dashboard, or need Luciq support / admin enablement (FFS, App Health, Issues List, Business Impact, Alerts & Rules, Rollout Management, Team Ownership, One Code Apps, Detect / Resolve / Release Agents) are handled in Phase 6 via `references/post-onboarding-capabilities.md` — never bucketed here.
- **Recommended now** — strong fit, applying this session.
- **Optional — add if you'd like** — reasonable fit; user's call this session or later.
- **Can be added later** — better timed for the future, with a specific revisit condition stated.
Every item in "Can be added later" must name *when* it makes sense:
> Can be added later:
> – **App Ratings** — best once you're live on the App Store. I'll wire it then.
> – **In-App Replies** — depends on `identifyUser`. When you wire your auth flow, add this.
> – **Feature Requests** — fits better once you have an active user base submitting feedback.
Only put a product in "Can be added later" for a *timing* reason — pre-launch, missing prerequisite, awaiting a real-world event. **Never put a product in "Can be added later" just because a competitor covers similar ground.** That's the customer's call, not the skill's. See Operating Principle 6.
Close the plan presentation with one question: *"Want to adjust any bucket before I start?"* If the user moves something between buckets, accept it and proceed.
In AUDIT mode, stop here — write the handoff doc (Phase 6) and exit. Don't apply anything.
## 4. Product walk — per-product micro-flow
For each product in "Recommended now" (and any "Optional" the user picked up), run the three-step micro-flow. Per-product copy and apply targets live in `references/product-cards.md`. Read that file before starting the walk.
### A. Ask
One line: name the product, give one-line value, give the user's *specific* reason for fit (cited).
> **Bug Reporting** — your users shake the phone or screenshot to send a report with logs, network, repro steps. Strong fit for you because no competitor on your stack handles user-initiated reports, and your CLAUDE.md mentions support load. Include it?
Three responses available: **Yes / No / Tell me more**. "Tell me more" expands the why; "No" goes to defer (record the reason).
### B. Apply
Derive the *exact* changes from the profile, not from defaults. Show a diff before applying. Confirm.
- Use the **money path** to scope APM and Session Replay aggressiveness.
- Use the **competitor's style** to set sample rates, screenshot capture, env gating.
- Use the **CLAUDE.md privacy line** to set masking aggressiveness.
- Use the **auth flow file:line** for `identifyUser` injection sites.
If a required file edit conflicts with uncommitted user changes, STOP and surface — don't overwrite work.
Delegate the actual API calls to the patterns in `luciq-setup` when they exist (don't reinvent installation primitives).
### C. Summarize
After applying, three short blocks:
> Done. Here's what I did:
> - Enabled Bug Reporting in `NotDemoAppApp.swift:14`
> - Set invocation to shake (matched your Sentry's conservative posture)
> - Masked text inputs on `CheckoutView.swift:42` per your CLAUDE.md line 12
>
> What's left for you (no code needed):
> - Nothing required — reports start arriving on next launch.
>
> Moving to the next product: **Session Replay**.
The "What's left for you" block lives in `references/product-cards.md` per product. Only list items the user genuinely needs to do — dashboard config, optional symbol upload setup. Never list third-party tool integrations by name. If nothing is left for the user, say so plainly.
## 5. End-of-walk activation
After all selected products are configured, run **one consolidated activation moment** — not one per product. The aim is a single concrete round-trip that proves Luciq is working end-to-end.
Use the **primary product** as the activation vehicle (Bug Reporting if included, otherwise the highest-ranked recommended product). The verification has three concrete steps and one waiting moment:
> All set. To see Luciq working end-to-end:
> 1. Build and launch the app.
> 2. Shake the simulator (Ctrl+Cmd+Z) — or use your chosen invocation event.
> 3. Type "test from onboarding" and submit.
> 4. Open your dashboard: `<dashboard URL for this app>`
>
> Tell me when you see the report — or just come back later.
Wait for confirmation. If the user reports they don't see it after 60 seconds, diagnose (build still running? wrong app token? simulator not invoking?) — never claim success without confirmation. If the user says "later," accept and move on — record in the handoff that activation was not verified.
In FAST mode, skip this phase. The handoff doc still includes the verification steps so the user can do it themselves.
## 6. Handoff — write LUCIQ_ONBOARDING.md
Write `LUCIQ_ONBOARDING.md` at the repo root using the template in `references/handoff-template.md`. The doc is the durable artifact of the session — re-readable next week, hand-off-able to a teammate, queryable by `luciq-debug` later.
The doc is structured as **two halves separated by a hard `---` divider**. Don't merge them, don't reorder, don't add a third section. The split is what makes the doc usable by both a PM/exec skim and an engineer audit.
**🎉 Top half — the celebration.** Plain English only. Anyone — engineer, PM, exec — should grasp what shipped in under a minute. No API names, no file:line citations, no SDK jargon. Contains:
- A stat strip on one line: conflicts count, *All PII masked*, any other earned win this session genuinely delivered.
- One short paragraph (2–3 sentences) of what the app can do now that it couldn't yesterday — lead with the team's benefit.
- **Enabled now** — a two-column table per active product: emoji + name, and a one-sentence user-facing value (what the team/user gets, never what the API does).
- **Ready when you are** — a two-column table per deferred product: emoji + name, and a plain-English "turn on when…" trigger.
- **Do this next** — three concrete steps + the three primary dashboard URLs. This is the verification round-trip from Phase 5, restated for the durable doc.
**🔧 Bottom half — the audit trail.** Cite-heavy, complete, organized for engineers. Opens with an explicit *"skip if you just wanted the wins above"* italic line. Covers:
- **What was wired (and where)** — table per product: code change with file:line, key decision with citation. Mark *⚠️ Not verified yet* until the user confirms first data; replace with *✅ Verified <timestamp>* once activation lands.
- **What's left for you (no code needed)** — doc-pointer items from each active product, deduplicated.
- **"Ready when you are" — implementation notes** — per-product pointer for when the trigger fires.
- **Dashboard capabilities** — split into *Live now* (auto-derived from this session's products) and *Unlock later* (with revisit condition stated verbatim), both sourced from `references/post-onboarding-capabilities.md`.
- **Conflicts detected (independent of Luciq)** — every conflict from Phase 2, even if the user didn't address it this session. Accountability survives.
- **Competitor coverage** — products the customer chose to stay on a competitor for, with their reason verbatim if given.
- **How the agent figured this out** — context docs cited, money path, auth flow, sensitive views, accessibility posture, detected SDK style, workspace precedent.
- **When to reach for sibling skills** — `luciq-debug`, `luciq-migrate`, `luciq-verify`, `luciq-masking-rules`. Always include `luciq-masking-rules` when Bug Reporting, Session Replay, or APM were configured — per-view markers applied this session are layer 1 of 3, and the user should know how to revisit the full posture later.
**Footer.** Session metadata (mode, operator, SDK name + version, package manager, product name, import) lives in an italic one-liner at the very bottom — present for the audit trail, absent from the celebration.
**Dashboard URL sourcing.** Derive URLs from MCP `list_applications` or the live Luciq dashboard. Never construct paths by stitching slug + capability name — surface shapes change between versions and constructed URLs become broken links.
If `LUCIQ_ONBOARDING.md` already exists, *append* a new dated session block — don't overwrite. The file accumulates the team's Luciq journey across sessions and contributors.
## Style
- ALWAYS show diffs before applying any code edit. Confirm.
- Cite every recommendation with a source — CLAUDE.md line, file:line, precedent quote, or named archetype rationale.
- One conversational beat at a time. No wizard forms.
- Skip and defer are first-class. Capture reasons and revisit conditions.
- Never criticize a competitor. Position Luciq alongside what's there.
- Verify product names and dashboard surfaces against the live docs before quoting them.
- Match the team's observed style — if their Sentry is privacy-conservative, Luciq's defaults should be too.
## Red flags — STOP and surface to the user
If you catch yourself thinking any of these, you're about to ship a bad onboarding. Stop, surface, do not proceed:
- *"I'll recommend this even though there's no signal for it — it's a good Luciq feature."* Recommendation without citation breaks the trust the whole skill rests on. If you can't cite, don't recommend.
- *"I'll skip the conflict — it's not Luciq's problem."* Surfacing conflicts is the trust-building move. Skip it and the rest of the conversation feels like sales.
- *"Their CLAUDE.md says one thing but I'll override it because Luciq's default is better."* The user's stated intent wins. If you disagree, ask, don't override.
- *"I'll claim activation succeeded — the build is probably fine."* Activation needs explicit user confirmation that data is visible on the dashboard. Otherwise it's a half-delivery.
- *"I'll keep going even though MCP failed."* MCP failures are fine to skip silently in Phase 1 (precedent is optional). But if MCP fails *during apply* — e.g., looking up an app token — surface and stop. Don't fabricate a token or guess.
- *"They said 'not now' but I'll keep pitching it."* Defer means defer. Capture the reason, move on, leave it in the handoff doc with a revisit condition.
- *"I'll flag App Ratings as 'not a fit' since this is B2B."* Don't say "not a fit." Say "better added when you launch on the App Store" — same honesty, no sting.
- *"Sentry covers crashes; I'll park Luciq Crash in 'add later.'"* Don't pre-defer a Luciq product because a competitor covers similar ground. Recommend it on its own merits, name the competitor in the Ask, and let the customer choose to add alongside, swap, or stay on what they have. Pre-deferring takes the choice away from them and reads as a sales-shy posture, not honesty.
- *"Sentry covers crashes; I'll oversell Luciq Crash and pressure them to switch."* The opposite failure. Name the competitor honestly, state Luciq's specific differentiators, and let the customer decide. No pressure language, no FUD about the competitor.
Every shortcut here trades "looks done" for "actually helpful." The skill's job is to make the user *feel understood* and leave them with working Luciq products they trust — not to maximize feature adoption in one session.