[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill-launchdarkly-launchdarkly-flag-qualitative-feedback-setup":3,"mdc-ttx4dm-key":40,"related-repo-launchdarkly-launchdarkly-flag-qualitative-feedback-setup":3474,"related-org-launchdarkly-launchdarkly-flag-qualitative-feedback-setup":3562},{"slug":4,"name":4,"fn":5,"description":6,"org":7,"tags":11,"stars":26,"repoUrl":27,"updatedAt":28,"license":29,"forks":30,"topics":31,"repo":35,"sourceUrl":38,"mdContent":39},"launchdarkly-flag-qualitative-feedback-setup","integrate LaunchDarkly qualitative user feedback","Integrate LaunchDarkly qualitative user feedback into a JavaScript\u002FTypeScript codebase. Guides framework and design system detection, builds the sendFeedback utility and feedback widget matching existing project patterns. Use when the user wants to add a Give Feedback widget, collect user sentiment tied to feature flags, set up feedback collection, or wire up the $ld:feedback tracking event.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},"launchdarkly","LaunchDarkly","https:\u002F\u002Fpexgzepcugksgbtrxkhf.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Forg-logos\u002Flaunchdarkly.png",[12,16,19,22,23],{"name":13,"slug":14,"type":15},"Integrations","integrations","tag",{"name":17,"slug":18,"type":15},"TypeScript","typescript",{"name":20,"slug":21,"type":15},"JavaScript","javascript",{"name":9,"slug":8,"type":15},{"name":24,"slug":25,"type":15},"Frontend","frontend",20,"https:\u002F\u002Fgithub.com\u002Flaunchdarkly\u002Fai-tooling","2026-08-06T06:09:15.745229","Apache-2.0",6,[32,33,34],"agent-skills","launchdarkly-ai","managed-by-terraform",{"repoUrl":27,"stars":26,"forks":30,"topics":36,"description":37},[32,33,34],"LaunchDarkly's official AI tooling","https:\u002F\u002Fgithub.com\u002Flaunchdarkly\u002Fai-tooling\u002Ftree\u002FHEAD\u002Fskills\u002Ffeature-flags\u002Flaunchdarkly-flag-qualitative-feedback-setup","---\nname: launchdarkly-flag-qualitative-feedback-setup\ndescription: \"Integrate LaunchDarkly qualitative user feedback into a JavaScript\u002FTypeScript codebase. Guides framework and design system detection, builds the sendFeedback utility and feedback widget matching existing project patterns. Use when the user wants to add a Give Feedback widget, collect user sentiment tied to feature flags, set up feedback collection, or wire up the $ld:feedback tracking event.\"\nlicense: Apache-2.0\ncompatibility: Requires the remotely hosted LaunchDarkly MCP server\nmetadata:\n  author: launchdarkly\n  version: \"1.0.0-experimental\"\n---\n\n# LaunchDarkly Qualitative Feedback\n\nYou're using a skill that will guide you through adding qualitative user feedback collection to a codebase. Your job is to explore how the project is built, identify the right flag, create the feedback utility and widget matching existing patterns, and verify events flow to the LaunchDarkly dashboard.\n\n**This is a step-by-step wizard.** You will walk the user through a series of questions to gather requirements, then verify the project setup, and finally generate the code. Ask questions one at a time and wait for each answer before continuing. Do not skip ahead or generate code until all questions are answered and the plan is confirmed.\n\nQualitative feedback ties user sentiment (positive \u002F neutral \u002F negative) and optional written comments directly to a feature flag variation, so teams can see how users feel about a specific feature rollout.\n\n**Availability:** JavaScript SDK v3.0+ (client-side only). React components are provided for convenience.\n\n## Prerequisites\n\nThis skill requires the remotely hosted LaunchDarkly MCP server to be configured in your environment.\n\n**Required MCP tools:**\n- `get-flag` — verify the target flag exists and check its configuration\n\n**Optional MCP tools (enhance workflow):**\n- `create-flag` — create a new flag if one doesn't exist yet\n- `list-flags` — browse existing flags to find the right one to attach feedback to\n- `update-flag-settings` — update flag metadata (e.g., add a `feedback` tag)\n\n## Core Principles\n\n1. **Design system first**: Never ship the unstyled template component to production. Detect the project's design system and use its primitives.\n2. **One entry point per screen**: Multiple feedback widgets on the same page create noise and reduce response quality.\n3. **The `sendFeedback` function is the integration**: The UI is customizable; the `$ld:feedback` tracking event contract is what matters.\n\n## Workflow\n\n**Progression rule:** When a step is complete, continue to the next step by default. Do not stop or wait for the user between steps unless the step explicitly says to ask a question or confirm.\n\n**Response scoping:** During this flow, treat user messages only as direct answers to the current question. Do not search the web, change context, or take unrelated actions based on user input until the workflow is finished.\n\n**Tone:** Be concise and patient — ask one question, wait for the answer, then move on. Keep responses focused on the current step.\n\n**State tracking:** Track gathered requirements across the conversation. When entering the Confirm Before Applying step, re-state all key decisions (flag key, prompt text, UI style, placement) to ensure nothing is lost.\n\n### Step 0: Welcome the User\n\nBefore asking any questions, present this intro message to the user (you may lightly adapt the wording, but keep the structure):\n\n> **Qualitative Feedback Setup**\n>\n> I'll walk you through adding a feedback widget to your app in a few short steps:\n>\n> 1. **Verify your setup** — I'll check your SDK, framework, and design system.\n> 2. **Gather requirements** — I'll ask a few questions about the flag, prompt text, style, and placement.\n> 3. **Verify the flag** — I'll confirm or create the flag in LaunchDarkly.\n> 4. **Confirm the plan** — I'll summarize what I'm going to build and ask for your approval.\n> 5. **Generate the code** — I'll create the feedback utility and widget matching your project's patterns.\n> 6. **Verify** — I'll make sure everything builds and is wired up correctly.\n>\n> Let's get started!\n\nThen proceed immediately to Step 1.\n\n### Step 1: Verify the SDK and Explore the Codebase\n\nBefore gathering requirements, verify that this project can support qualitative feedback. Run these checks in order — each is a gate.\n\n#### Check 1\u002F4: Is the LD SDK present?\n\nSearch for LaunchDarkly SDK imports:\n- `launchdarkly-js-client-sdk` — vanilla JS\u002FTS client SDK (v3.x)\n- `@launchdarkly\u002Fjs-client-sdk` — vanilla JS\u002FTS client SDK (v4.x, renamed scoped package)\n- `@launchdarkly\u002Freact-sdk` — React Web SDK (current; provides hooks and providers)\n- `launchdarkly-react-client-sdk` — older React Web SDK package name (renamed to `@launchdarkly\u002Freact-sdk`)\n\nAlso search for SDK initialization (`initialize(` for v3.x, or `createClient(`\u002F`start(` for v4.x, plus React provider signals `\u003CLDProvider`, `asyncWithLDProvider`, or `createLDReactProvider`). If not found, ask the user where LDClient is initialized or accessible.\n\n- If **no LD SDK is found at all** → inform the user that qualitative feedback requires a LaunchDarkly client-side SDK to be installed and initialized → **STOP. Do not proceed.**\n- If found → continue to Check 2.\n\n#### Check 2\u002F4: Is it a client-side SDK?\n\nQualitative feedback is a **client-side only** feature. Verify the SDK found in Check 1 is a client-side SDK. Refer to [references\u002Fclient-side-sdk-list.md](references\u002Fclient-side-sdk-list.md) and [references\u002Fserver-side-sdk-list.md](references\u002Fserver-side-sdk-list.md) for the complete lists.\n\nIf the SDK is **server-side only** with no client SDK present → explain that qualitative feedback requires a client-side SDK and cannot be sent from server code → **STOP. Do not proceed.**\n\nIf unclear, ask the user whether their SDK is client-side or server-side before continuing.\n\n#### Check 3\u002F4: Is the SDK version compatible?\n\nCheck `package.json` for the exact version. The `$ld:feedback` event requires **v3.0+** of the JavaScript\u002FReact SDK.\n\n- If version **\u003C 3.0** → inform the user they need to upgrade before feedback can be added → **STOP. Do not proceed.**\n- If version **>= 3.0** → continue to Check 4.\n\n#### Check 4\u002F4: Is feedback already configured?\n\nSearch for `$ld:feedback`, `sendFeedback`, `FeedbackPopover`, or `Give feedback` to check for existing feedback integration.\n\n- If a **`sendFeedback` function exists** that calls `client.track('$ld:feedback', ...)` → **reuse it**. Record its import path — Step 5 will be skipped. Continue to Step 2.\n- If a **feedback widget exists** but not the `sendFeedback` utility → note the widget pattern for consistency.\n- If **nothing found** → continue normally.\n\n#### Remaining exploration\n\nAfter the checks above pass, gather the remaining context:\n\n1. **Find the SDK initialization.** Search for:\n   - `initialize(` from `launchdarkly-js-client-sdk` (v3.x)\n   - `createClient(` \u002F `start(` from `@launchdarkly\u002Fjs-client-sdk` (v4.x)\n   - `\u003CLDProvider`, `asyncWithLDProvider`, or `createLDReactProvider` from the React SDK\n   - How the `LDClient` instance is accessed (direct reference, React context, custom hook, etc.)\n\n2. **Check for observability.** Search for `@launchdarkly\u002Fobservability` and `@launchdarkly\u002Fsession-replay`. If present, feedback can be linked to session replays.\n\n3. **Detect the UI framework and design system.**\n\n   | Signal | Framework |\n   |--------|-----------|\n   | `react`, `react-dom` in deps | React |\n   | `vue` in deps | Vue (adapt vanilla JS pattern to Vue component) |\n   | `@angular\u002Fcore` in deps | Angular (adapt vanilla JS pattern to Angular component) |\n   | `svelte` in deps | Svelte (adapt vanilla JS pattern to Svelte component) |\n   | None of the above | Vanilla JS\u002FTS |\n\n   Then check for a **design system or component library**:\n   - `@mui\u002Fmaterial`, `@emotion\u002Freact` → MUI\n   - `@chakra-ui\u002Freact` → Chakra UI\n   - `antd` → Ant Design\n   - `@radix-ui\u002F*` or `@shadcn\u002F*` → Radix\u002Fshadcn\n   - `tailwindcss` in deps or `tailwind.config.*` → Tailwind CSS\n   - `bootstrap` or `react-bootstrap` → Bootstrap\n   - Custom design system → look for a `components\u002F` directory with shared primitives (Button, Modal, Popover, etc.)\n\n   **If a design system is detected, use its primitives** (Button, Popover, TextArea, IconButton) instead of the inline-styled template component. The template components in [references\u002F](references\u002F) are a **starting point** — always adapt them to match the project's existing patterns.\n\n### Step 2: Understand the Goal\n\n**STOP. Do not proceed to Step 3 until you have answers to ALL of the following.** Check the user's request — if it already answers a question, you don't need to re-ask it. For anything not covered, ask the user and wait for their response before continuing.\n\n**Ask only one question at a time.** Wait for the user's answer before asking the next. Do not list multiple questions in one message. **When presenting options, use `AskUserQuestion`** to render interactive selectors in the agent console. For free-text questions (like prompt text), ask as a normal text message.\n\n1. **Which feature\u002Fflag?** Feedback is always tied to a flag key. Search the codebase for existing flag keys, then use `AskUserQuestion` with the discovered flags as options (plus a \"Create a new flag\" option). If no flags are found, ask as a text question.\n2. **What question do you want to ask the user?** This becomes the prompt text shown in the feedback widget (e.g., \"How do you feel about this view?\" or \"Did this work as expected?\"). Ask this as a normal text message since it requires free-text input.\n3. **What type of feedback?** Use `AskUserQuestion` with header \"Type\" and these options:\n   - label: \"Sentiment + text (Recommended)\", description: \"Sentiment buttons with a text area for comments, in a popover\"\n   - label: \"Sentiment only\", description: \"One-click sentiment buttons inline — no popover, no text input\"\n   - label: \"Text only\", description: \"Just a text area for written feedback in a popover, no sentiment buttons\"\n   If the user selects \"Sentiment + text\" or \"Sentiment only\", follow up with `AskUserQuestion` header \"Icons\" and these options:\n   - label: \"Thumbs up \u002F down\", description: \"Two buttons: positive \u002F negative\"\n   - label: \"Smiley faces\", description: \"Three buttons: positive \u002F neutral \u002F negative\"\n4. **Where should the feedback widget go?** Before asking, search the codebase for pages, routes, or main components. Then use `AskUserQuestion` with header \"Placement\" and 2–4 concrete placement options that make sense for this repo (e.g., \"Next to the results heading on the Simulator page\", \"In the page header\", \"Below the main content area\"). Prefer page-level placement — don't bury feedback in small sub-components unless it's workflow-specific confirmation.\n\n### Step 3: Verify the Flag in LaunchDarkly\n\nUse `get-flag` to confirm the target flag exists and is configured for client-side use.\n\n- If the flag **doesn't exist**, use `create-flag` (or direct the user to the [flag create skill](..\u002Flaunchdarkly-flag-create\u002FSKILL.md)).\n- If the flag **exists but doesn't have client-side SDK availability enabled**, inform the user they need to enable it in the flag's Advanced Controls section.\n- If the flag was created or verified, **provide the user with a direct link** to the flag in the LaunchDarkly dashboard.\n- Optionally use `update-flag-settings` to add a `feedback` tag.\n\n### Step 4: Confirm Before Applying\n\n**STOP. Do not write any code until the user explicitly confirms the plan.** This applies every time — including when the user provides all details upfront, when re-running for a second flag in the same conversation, or when reusing existing utilities. A detailed user request is not implicit approval.\n\nSummarize the planned changes using **future tense** (e.g., \"Files to create\", \"Files to modify\") — no code has been written yet:\n- Flag key and whether it exists or needs creation\n- The `sendFeedback` utility: where it will live, whether it will be reused from a prior step, and whether it includes session replay\n- The feedback widget: component name, UI style, placement location\n- Which files will be created or modified\n\nThen use `AskUserQuestion` with header \"Confirm\" and these options:\n- label: \"Looks good\", description: \"Proceed with the plan as described\"\n- label: \"Change something\", description: \"I want to adjust part of the plan before you start\"\n\nIf the user selects \"Change something\" (or provides custom input), address their feedback and re-present the updated plan with the same confirmation prompt. Do not proceed to Step 5 until the user selects \"Looks good\".\n\n### Step 5: Add the sendFeedback Function\n\n**If Check 4 found an existing `sendFeedback` function, skip this step entirely.** Use the recorded import path from that check and proceed directly to Step 6.\n\nThis is the core integration. Create a utility function that sends the `$ld:feedback` tracking event.\n\nStart from the template in [references\u002FsendFeedback.ts](references\u002FsendFeedback.ts). For JavaScript projects, adapt by removing type annotations.\n\nThe essential contract:\n\n```typescript\nclient.track('$ld:feedback', {\n    feedback_answer: string,  \u002F\u002F required — the user's written feedback\n    flag_key: string,         \u002F\u002F required — the flag this feedback is about\n    sentiment: \"positive\" | \"neutral\" | \"negative\",  \u002F\u002F defaults to \"neutral\"\n    feedback_prompt: string,  \u002F\u002F optional — the question shown to the user\n    o11y_session_id: string,  \u002F\u002F optional — links to session replay\n    custom_properties: Record\u003Cstring, any>,  \u002F\u002F optional — extra metadata to attach to the feedback event\n});\nclient.flush();\n```\n\n**Key decisions:**\n- Match the `LDClient` type import to the project's SDK version: `launchdarkly-js-client-sdk` for v3.x, `@launchdarkly\u002Fjs-client-sdk` for v4.x. The templates import from `launchdarkly-js-client-sdk` — update it if the project is on v4. (The `client.track` \u002F `client.flush` calls are the same across both.)\n- If `@launchdarkly\u002Fsession-replay` is in the project, include the session ID via `LDRecord.getSession()?.sessionSecureID`. If not, remove the session replay import and `o11y_session_id` logic from the template.\n- Place the utility where the project keeps its LD-related code (alongside existing flag helpers, in a `lib\u002F` or `utils\u002F` directory, etc.)\n- Export the `LDFeedbackSentiment` type if using TypeScript\n\n**Verification:** After creating the file, search the codebase to confirm it exists and contains the expected content — a `sendFeedback` export that calls `client.track('$ld:feedback', ...)` followed by `client.flush()`. If not found, fix before proceeding.\n\n### Step 6: Build the Feedback Widget\n\nBuild the UI using the project's existing design system and component patterns.\n\nStart from the appropriate template in [references\u002F](references\u002F). For JavaScript projects, adapt by removing type annotations.\n- **Sentiment + text** → [PopoverFeedback.tsx](references\u002FPopoverFeedback.tsx) with `icons=\"thumbs\"` or `icons=\"smileys\"`\n- **Text only** → [PopoverFeedback.tsx](references\u002FPopoverFeedback.tsx) with `icons=\"none\"`\n- **Sentiment only** → [InlineFeedback.tsx](references\u002FInlineFeedback.tsx) with `icons=\"thumbs\"` or `icons=\"smileys\"`\n\nThese templates use inline styles and SVG icons so they work without any CSS framework or icon library. When the project has a design system, replace template elements with its primitives:\n\n| Template element | Replace with |\n|------------------|-------------|\n| Inline `style={{...}}` | Project's CSS approach (Tailwind classes, CSS modules, styled-components, etc.) |\n| `\u003Cbutton>` | Design system's `\u003CButton>` component |\n| Positioned `\u003Cdiv>` popover | Design system's `\u003CPopover>` or `\u003CDropdown>` component |\n| `\u003Ctextarea>` | Design system's `\u003CTextArea>` or `\u003CInput>` component |\n| Inline SVG icons | Project's icon library (Lucide, Heroicons, MUI icons, etc.) |\n\nAlways use `fill=\"currentColor\"` (not hardcoded hex colors) in SVG icons so they inherit the parent's text color.\n\n**Do NOT use find-and-replace for `PROMPT_TO_REPLACE`.** Instead, make `prompt` a string prop on the component. This makes the widget reusable across flags without code duplication. Pass the user's prompt text from Step 2 as a prop when rendering.\n\n**Standard UX pattern** (follow this regardless of design system):\n- A **trigger button** with a speech-bubble icon and \"Give feedback\" label (for popover styles)\n- A **popover** that opens on click, containing:\n  - A text area with the prompt text as its placeholder\n  - Sentiment controls matching the style chosen in Step 2:\n    - **Thumbs up \u002F thumbs down** — two icon buttons toggling positive\u002Fnegative\n    - **Smiley-face scale** — three icon buttons for positive (smile), neutral (meh), negative (frown)\n    - **Text-only** — no sentiment buttons; omit the `sentiment` field from `sendFeedback`\n  - A submit button\n- **After submission:** Track a `submitted` state. Replace the widget with a \"Thanks for your feedback!\" confirmation message. Do not just close the popover silently — the user needs to know their feedback was received.\n- **Quick thumbs \u002F inline smileys** (no popover): inline prompt text with sentiment buttons; sends feedback immediately on click with no text input. After click, replace with a thank-you message.\n\n**Placement:** Use the location chosen in Step 2. Do not add multiple feedback entry points on the same screen.\n\n#### Wire the component into the target\n\nAfter building the widget, add it to the target location from Step 2:\n\n1. **Find the target file.** Search the codebase for the page or component matching the placement chosen in Step 2. State the file path you found and ask the user to confirm it's correct before modifying it. If they say no, ask for clarification and try again.\n2. **Import and render.** Import the feedback component into the confirmed target file. Render it and pass the required props: `flagKey` string and `prompt` string. For React SDK projects, the component should use the `useLDClient()` hook internally rather than accepting `ldClient` as a prop.\n3. **Verification:** Search the target component to confirm it imports and renders the feedback component with the required props (`flagKey`, `prompt`). If the import or render is missing, fix before proceeding.\n\n#### Framework-specific approach\n\n**React** — Start from the template, then adapt to the project's design system using the table above.\n\n**Vanilla JS\u002FTS** — Wire up DOM elements to the `sendFeedback` function:\n```typescript\nsubmitButton.addEventListener('click', () => {\n    sendFeedback(client, flagKey, feedbackInput.value, selectedSentiment, promptText);\n});\n```\n\n**Vue \u002F Angular \u002F Svelte** — Translate the React component pattern into the framework's idiom. The `sendFeedback` function is framework-agnostic; only the UI wrapper changes.\n\n### Step 7: Verify\n\n**Pre-condition check:** Before verifying, confirm that all prior steps produced their expected outputs:\n- (a) The `sendFeedback` utility file exists (or an existing one was reused from Check 4).\n- (b) The feedback widget component file exists.\n- (c) The widget is imported and rendered in the target location with the required props.\n\nIf any are missing, go back and complete the relevant step before proceeding.\n\nWalk the user through validation step by step:\n\n1. **Run the build.** Execute the project's build or lint command. If it fails, fix the errors before continuing.\n2. **Start the app locally.** Ask the user to run their dev server (or run it yourself if you can). Confirm it starts without errors.\n3. **Navigate to the feedback location.** Tell the user to open the page where the widget was placed. Ask them to confirm the \"Give feedback\" button (or inline thumbs) is visible and styled correctly.\n4. **Submit test feedback.** Walk the user through: click the trigger → enter test text → select a sentiment → click Send. Ask them to open the browser's Network tab and confirm a POST to the LaunchDarkly events endpoint fired containing `$ld:feedback`.\n5. **Check the dashboard.** Provide a direct link to the flag's **Feedback** tab in the LaunchDarkly dashboard. Tell the user to wait ~1 minute and then refresh — their test feedback should appear.\n6. **Session replay (if applicable).** If `@launchdarkly\u002Fsession-replay` is configured, ask the user to check for a **Replay** button next to the feedback entry in the dashboard.\n\nAfter the user confirms everything works, mention:\n- They can subscribe Slack channels to receive feedback notifications: go to the flag's **Feedback** tab → **Subscribe** → select Slack channels (requires the LaunchDarkly Slack app).\n- Provide the direct link to the flag's Feedback tab so they can bookmark it for monitoring.\n\n## Edge Cases\n\n| Situation | Action |\n|-----------|--------|\n| No LD SDK found | **STOP** — handled by Check 1 |\n| Server-side SDK only, no client SDK | **STOP** — handled by Check 2 |\n| SDK version \u003C 3.0 | **STOP** — handled by Check 3 |\n| Existing `sendFeedback` function found | Reuse it, skip Step 5 — handled by Check 4 |\n| React SDK (`@launchdarkly\u002Freact-sdk` \u002F `launchdarkly-react-client-sdk`) | Access client via `useLDClient()` hook instead of a direct reference |\n| Flag doesn't have client-side availability | User must enable it in the flag's Advanced Controls |\n| Observability not installed | Skip the `o11y_session_id` field; session replay won't be available |\n| No design system detected | Use the template component with minimal inline styles as a starting point |\n| Multiple flags need feedback | Create separate `sendFeedback` calls per flag; each widget targets one flag key |\n\n## What NOT to Do\n\n- Don't ship the unstyled template component to production — always adapt to the project's design system.\n- Don't add multiple feedback widgets on the same screen.\n- Don't forget to call `client.flush()` after `client.track()`.\n- Don't hardcode flag keys — use the project's existing constant\u002Fconfig pattern for flag keys.\n- Don't send feedback from server-side code — this is a client-side feature only.\n\n## Templates\n\nCode templates live in [references\u002F](references\u002F) alongside the SDK lists:\n\n| File | Description |\n|------|-------------|\n| [sendFeedback.ts](references\u002FsendFeedback.ts) | Utility that sends the `$ld:feedback` tracking event, with session replay support |\n| [PopoverFeedback.tsx](references\u002FPopoverFeedback.tsx) | Popover with text area + configurable sentiment icons (`icons=\"thumbs\"` \u002F `\"smileys\"` \u002F `\"none\"`) |\n| [InlineFeedback.tsx](references\u002FInlineFeedback.tsx) | Inline one-click sentiment buttons (`icons=\"thumbs\"` \u002F `\"smileys\"`) |\n\nAll templates are TypeScript — for JavaScript projects, adapt by removing type annotations. Templates include inline SVG icons and work without external icon libraries. Adapt them to the project's design system and pass the user's prompt text as a prop.\n\n## References\n\n- [Official Docs: User feedback SDK](https:\u002F\u002Flaunchdarkly.com\u002Fdocs\u002Fsdk\u002Ffeatures\u002Fuser-feedback)\n- [Official Docs: Viewing feedback](https:\u002F\u002Flaunchdarkly.com\u002Fdocs\u002Fhome\u002Freleases\u002Fuser-feedback)\n- [Tutorial: Collecting user feedback](https:\u002F\u002Flaunchdarkly.com\u002Fdocs\u002Ftutorials\u002Fcollect-qualitative-user-feedback-homepage)\n\n## Example Flows\n\nThese show how the decision tree plays out for common scenarios.\n\n**Happy path — React + TypeScript, new flag, thumbs popover:**\nStep 0 → welcome. Step 1 → finds `@launchdarkly\u002Freact-sdk`, React + Tailwind, no existing feedback. Step 2 → user picks a new flag `checkout-redesign`, prompt \"How do you feel about the new checkout?\", thumbs style, placed below the order summary. Step 3 → creates flag via `create-flag`. Step 4 → user approves. Step 5 → creates `sendFeedback.ts` in `lib\u002Fld\u002F`. Step 6 → creates `FeedbackPopover.tsx` adapted to Tailwind, wires it into `CheckoutPage.tsx` with `useLDClient()`. Step 7 → build passes, event fires.\n\n**Existing sendFeedback — reuse and skip:**\nStep 1 → Check 4 finds `src\u002Futils\u002FsendFeedback.ts` already calling `client.track('$ld:feedback', ...)`. Records the import path. Step 2 → gathers requirements normally. Steps 3–4 → as usual. Step 5 → **skipped** (reuses existing function). Step 6 → builds widget, imports `sendFeedback` from the existing path. Step 7 → build passes, event fires.\n\n**Server-side SDK — early STOP:**\nStep 1 → Check 1 finds `@launchdarkly\u002Fnode-server-sdk`. Check 2 → it's in `server-side-sdk-list.md`, no client SDK present. → Informs user that qualitative feedback requires a client-side SDK. **STOP.**\n\n**No design system — minimal styles:**\nStep 1 → finds `launchdarkly-js-client-sdk` v3.2, no React, no Tailwind, no component library. Step 6 → uses the template with inline styles as the baseline, adapts to the project's vanilla JS patterns and existing CSS conventions.\n",{"data":41,"body":45},{"name":4,"description":6,"license":29,"compatibility":42,"metadata":43},"Requires the remotely hosted LaunchDarkly MCP server",{"author":8,"version":44},"1.0.0-experimental",{"type":46,"children":47},"root",[48,57,63,74,79,89,96,101,109,126,134,178,184,234,240,250,260,270,280,287,292,377,382,388,393,400,405,459,512,537,543,570,586,591,597,624,654,660,692,756,762,767,1161,1167,1177,1200,1299,1305,1317,1389,1395,1405,1417,1446,1458,1471,1476,1482,1499,1511,1523,1528,1859,1867,1978,2010,2016,2021,2031,2111,2116,2259,2272,2297,2307,2425,2435,2441,2446,2522,2528,2537,2553,2697,2714,2720,2730,2755,2760,2765,2855,2860,2886,2892,3084,3090,3132,3138,3149,3256,3261,3267,3301,3307,3312,3381,3420,3451,3468],{"type":49,"tag":50,"props":51,"children":53},"element","h1",{"id":52},"launchdarkly-qualitative-feedback",[54],{"type":55,"value":56},"text","LaunchDarkly Qualitative Feedback",{"type":49,"tag":58,"props":59,"children":60},"p",{},[61],{"type":55,"value":62},"You're using a skill that will guide you through adding qualitative user feedback collection to a codebase. Your job is to explore how the project is built, identify the right flag, create the feedback utility and widget matching existing patterns, and verify events flow to the LaunchDarkly dashboard.",{"type":49,"tag":58,"props":64,"children":65},{},[66,72],{"type":49,"tag":67,"props":68,"children":69},"strong",{},[70],{"type":55,"value":71},"This is a step-by-step wizard.",{"type":55,"value":73}," You will walk the user through a series of questions to gather requirements, then verify the project setup, and finally generate the code. Ask questions one at a time and wait for each answer before continuing. Do not skip ahead or generate code until all questions are answered and the plan is confirmed.",{"type":49,"tag":58,"props":75,"children":76},{},[77],{"type":55,"value":78},"Qualitative feedback ties user sentiment (positive \u002F neutral \u002F negative) and optional written comments directly to a feature flag variation, so teams can see how users feel about a specific feature rollout.",{"type":49,"tag":58,"props":80,"children":81},{},[82,87],{"type":49,"tag":67,"props":83,"children":84},{},[85],{"type":55,"value":86},"Availability:",{"type":55,"value":88}," JavaScript SDK v3.0+ (client-side only). React components are provided for convenience.",{"type":49,"tag":90,"props":91,"children":93},"h2",{"id":92},"prerequisites",[94],{"type":55,"value":95},"Prerequisites",{"type":49,"tag":58,"props":97,"children":98},{},[99],{"type":55,"value":100},"This skill requires the remotely hosted LaunchDarkly MCP server to be configured in your environment.",{"type":49,"tag":58,"props":102,"children":103},{},[104],{"type":49,"tag":67,"props":105,"children":106},{},[107],{"type":55,"value":108},"Required MCP tools:",{"type":49,"tag":110,"props":111,"children":112},"ul",{},[113],{"type":49,"tag":114,"props":115,"children":116},"li",{},[117,124],{"type":49,"tag":118,"props":119,"children":121},"code",{"className":120},[],[122],{"type":55,"value":123},"get-flag",{"type":55,"value":125}," — verify the target flag exists and check its configuration",{"type":49,"tag":58,"props":127,"children":128},{},[129],{"type":49,"tag":67,"props":130,"children":131},{},[132],{"type":55,"value":133},"Optional MCP tools (enhance workflow):",{"type":49,"tag":110,"props":135,"children":136},{},[137,148,159],{"type":49,"tag":114,"props":138,"children":139},{},[140,146],{"type":49,"tag":118,"props":141,"children":143},{"className":142},[],[144],{"type":55,"value":145},"create-flag",{"type":55,"value":147}," — create a new flag if one doesn't exist yet",{"type":49,"tag":114,"props":149,"children":150},{},[151,157],{"type":49,"tag":118,"props":152,"children":154},{"className":153},[],[155],{"type":55,"value":156},"list-flags",{"type":55,"value":158}," — browse existing flags to find the right one to attach feedback to",{"type":49,"tag":114,"props":160,"children":161},{},[162,168,170,176],{"type":49,"tag":118,"props":163,"children":165},{"className":164},[],[166],{"type":55,"value":167},"update-flag-settings",{"type":55,"value":169}," — update flag metadata (e.g., add a ",{"type":49,"tag":118,"props":171,"children":173},{"className":172},[],[174],{"type":55,"value":175},"feedback",{"type":55,"value":177}," tag)",{"type":49,"tag":90,"props":179,"children":181},{"id":180},"core-principles",[182],{"type":55,"value":183},"Core Principles",{"type":49,"tag":185,"props":186,"children":187},"ol",{},[188,198,208],{"type":49,"tag":114,"props":189,"children":190},{},[191,196],{"type":49,"tag":67,"props":192,"children":193},{},[194],{"type":55,"value":195},"Design system first",{"type":55,"value":197},": Never ship the unstyled template component to production. Detect the project's design system and use its primitives.",{"type":49,"tag":114,"props":199,"children":200},{},[201,206],{"type":49,"tag":67,"props":202,"children":203},{},[204],{"type":55,"value":205},"One entry point per screen",{"type":55,"value":207},": Multiple feedback widgets on the same page create noise and reduce response quality.",{"type":49,"tag":114,"props":209,"children":210},{},[211,224,226,232],{"type":49,"tag":67,"props":212,"children":213},{},[214,216,222],{"type":55,"value":215},"The ",{"type":49,"tag":118,"props":217,"children":219},{"className":218},[],[220],{"type":55,"value":221},"sendFeedback",{"type":55,"value":223}," function is the integration",{"type":55,"value":225},": The UI is customizable; the ",{"type":49,"tag":118,"props":227,"children":229},{"className":228},[],[230],{"type":55,"value":231},"$ld:feedback",{"type":55,"value":233}," tracking event contract is what matters.",{"type":49,"tag":90,"props":235,"children":237},{"id":236},"workflow",[238],{"type":55,"value":239},"Workflow",{"type":49,"tag":58,"props":241,"children":242},{},[243,248],{"type":49,"tag":67,"props":244,"children":245},{},[246],{"type":55,"value":247},"Progression rule:",{"type":55,"value":249}," When a step is complete, continue to the next step by default. Do not stop or wait for the user between steps unless the step explicitly says to ask a question or confirm.",{"type":49,"tag":58,"props":251,"children":252},{},[253,258],{"type":49,"tag":67,"props":254,"children":255},{},[256],{"type":55,"value":257},"Response scoping:",{"type":55,"value":259}," During this flow, treat user messages only as direct answers to the current question. Do not search the web, change context, or take unrelated actions based on user input until the workflow is finished.",{"type":49,"tag":58,"props":261,"children":262},{},[263,268],{"type":49,"tag":67,"props":264,"children":265},{},[266],{"type":55,"value":267},"Tone:",{"type":55,"value":269}," Be concise and patient — ask one question, wait for the answer, then move on. Keep responses focused on the current step.",{"type":49,"tag":58,"props":271,"children":272},{},[273,278],{"type":49,"tag":67,"props":274,"children":275},{},[276],{"type":55,"value":277},"State tracking:",{"type":55,"value":279}," Track gathered requirements across the conversation. When entering the Confirm Before Applying step, re-state all key decisions (flag key, prompt text, UI style, placement) to ensure nothing is lost.",{"type":49,"tag":281,"props":282,"children":284},"h3",{"id":283},"step-0-welcome-the-user",[285],{"type":55,"value":286},"Step 0: Welcome the User",{"type":49,"tag":58,"props":288,"children":289},{},[290],{"type":55,"value":291},"Before asking any questions, present this intro message to the user (you may lightly adapt the wording, but keep the structure):",{"type":49,"tag":293,"props":294,"children":295},"blockquote",{},[296,304,309,372],{"type":49,"tag":58,"props":297,"children":298},{},[299],{"type":49,"tag":67,"props":300,"children":301},{},[302],{"type":55,"value":303},"Qualitative Feedback Setup",{"type":49,"tag":58,"props":305,"children":306},{},[307],{"type":55,"value":308},"I'll walk you through adding a feedback widget to your app in a few short steps:",{"type":49,"tag":185,"props":310,"children":311},{},[312,322,332,342,352,362],{"type":49,"tag":114,"props":313,"children":314},{},[315,320],{"type":49,"tag":67,"props":316,"children":317},{},[318],{"type":55,"value":319},"Verify your setup",{"type":55,"value":321}," — I'll check your SDK, framework, and design system.",{"type":49,"tag":114,"props":323,"children":324},{},[325,330],{"type":49,"tag":67,"props":326,"children":327},{},[328],{"type":55,"value":329},"Gather requirements",{"type":55,"value":331}," — I'll ask a few questions about the flag, prompt text, style, and placement.",{"type":49,"tag":114,"props":333,"children":334},{},[335,340],{"type":49,"tag":67,"props":336,"children":337},{},[338],{"type":55,"value":339},"Verify the flag",{"type":55,"value":341}," — I'll confirm or create the flag in LaunchDarkly.",{"type":49,"tag":114,"props":343,"children":344},{},[345,350],{"type":49,"tag":67,"props":346,"children":347},{},[348],{"type":55,"value":349},"Confirm the plan",{"type":55,"value":351}," — I'll summarize what I'm going to build and ask for your approval.",{"type":49,"tag":114,"props":353,"children":354},{},[355,360],{"type":49,"tag":67,"props":356,"children":357},{},[358],{"type":55,"value":359},"Generate the code",{"type":55,"value":361}," — I'll create the feedback utility and widget matching your project's patterns.",{"type":49,"tag":114,"props":363,"children":364},{},[365,370],{"type":49,"tag":67,"props":366,"children":367},{},[368],{"type":55,"value":369},"Verify",{"type":55,"value":371}," — I'll make sure everything builds and is wired up correctly.",{"type":49,"tag":58,"props":373,"children":374},{},[375],{"type":55,"value":376},"Let's get started!",{"type":49,"tag":58,"props":378,"children":379},{},[380],{"type":55,"value":381},"Then proceed immediately to Step 1.",{"type":49,"tag":281,"props":383,"children":385},{"id":384},"step-1-verify-the-sdk-and-explore-the-codebase",[386],{"type":55,"value":387},"Step 1: Verify the SDK and Explore the Codebase",{"type":49,"tag":58,"props":389,"children":390},{},[391],{"type":55,"value":392},"Before gathering requirements, verify that this project can support qualitative feedback. Run these checks in order — each is a gate.",{"type":49,"tag":394,"props":395,"children":397},"h4",{"id":396},"check-14-is-the-ld-sdk-present",[398],{"type":55,"value":399},"Check 1\u002F4: Is the LD SDK present?",{"type":49,"tag":58,"props":401,"children":402},{},[403],{"type":55,"value":404},"Search for LaunchDarkly SDK imports:",{"type":49,"tag":110,"props":406,"children":407},{},[408,419,430,441],{"type":49,"tag":114,"props":409,"children":410},{},[411,417],{"type":49,"tag":118,"props":412,"children":414},{"className":413},[],[415],{"type":55,"value":416},"launchdarkly-js-client-sdk",{"type":55,"value":418}," — vanilla JS\u002FTS client SDK (v3.x)",{"type":49,"tag":114,"props":420,"children":421},{},[422,428],{"type":49,"tag":118,"props":423,"children":425},{"className":424},[],[426],{"type":55,"value":427},"@launchdarkly\u002Fjs-client-sdk",{"type":55,"value":429}," — vanilla JS\u002FTS client SDK (v4.x, renamed scoped package)",{"type":49,"tag":114,"props":431,"children":432},{},[433,439],{"type":49,"tag":118,"props":434,"children":436},{"className":435},[],[437],{"type":55,"value":438},"@launchdarkly\u002Freact-sdk",{"type":55,"value":440}," — React Web SDK (current; provides hooks and providers)",{"type":49,"tag":114,"props":442,"children":443},{},[444,450,452,457],{"type":49,"tag":118,"props":445,"children":447},{"className":446},[],[448],{"type":55,"value":449},"launchdarkly-react-client-sdk",{"type":55,"value":451}," — older React Web SDK package name (renamed to ",{"type":49,"tag":118,"props":453,"children":455},{"className":454},[],[456],{"type":55,"value":438},{"type":55,"value":458},")",{"type":49,"tag":58,"props":460,"children":461},{},[462,464,470,472,478,480,486,488,494,496,502,504,510],{"type":55,"value":463},"Also search for SDK initialization (",{"type":49,"tag":118,"props":465,"children":467},{"className":466},[],[468],{"type":55,"value":469},"initialize(",{"type":55,"value":471}," for v3.x, or ",{"type":49,"tag":118,"props":473,"children":475},{"className":474},[],[476],{"type":55,"value":477},"createClient(",{"type":55,"value":479},"\u002F",{"type":49,"tag":118,"props":481,"children":483},{"className":482},[],[484],{"type":55,"value":485},"start(",{"type":55,"value":487}," for v4.x, plus React provider signals ",{"type":49,"tag":118,"props":489,"children":491},{"className":490},[],[492],{"type":55,"value":493},"\u003CLDProvider",{"type":55,"value":495},", ",{"type":49,"tag":118,"props":497,"children":499},{"className":498},[],[500],{"type":55,"value":501},"asyncWithLDProvider",{"type":55,"value":503},", or ",{"type":49,"tag":118,"props":505,"children":507},{"className":506},[],[508],{"type":55,"value":509},"createLDReactProvider",{"type":55,"value":511},"). If not found, ask the user where LDClient is initialized or accessible.",{"type":49,"tag":110,"props":513,"children":514},{},[515,532],{"type":49,"tag":114,"props":516,"children":517},{},[518,520,525,527],{"type":55,"value":519},"If ",{"type":49,"tag":67,"props":521,"children":522},{},[523],{"type":55,"value":524},"no LD SDK is found at all",{"type":55,"value":526}," → inform the user that qualitative feedback requires a LaunchDarkly client-side SDK to be installed and initialized → ",{"type":49,"tag":67,"props":528,"children":529},{},[530],{"type":55,"value":531},"STOP. Do not proceed.",{"type":49,"tag":114,"props":533,"children":534},{},[535],{"type":55,"value":536},"If found → continue to Check 2.",{"type":49,"tag":394,"props":538,"children":540},{"id":539},"check-24-is-it-a-client-side-sdk",[541],{"type":55,"value":542},"Check 2\u002F4: Is it a client-side SDK?",{"type":49,"tag":58,"props":544,"children":545},{},[546,548,553,555,561,563,568],{"type":55,"value":547},"Qualitative feedback is a ",{"type":49,"tag":67,"props":549,"children":550},{},[551],{"type":55,"value":552},"client-side only",{"type":55,"value":554}," feature. Verify the SDK found in Check 1 is a client-side SDK. Refer to ",{"type":49,"tag":556,"props":557,"children":559},"a",{"href":558},"references\u002Fclient-side-sdk-list.md",[560],{"type":55,"value":558},{"type":55,"value":562}," and ",{"type":49,"tag":556,"props":564,"children":566},{"href":565},"references\u002Fserver-side-sdk-list.md",[567],{"type":55,"value":565},{"type":55,"value":569}," for the complete lists.",{"type":49,"tag":58,"props":571,"children":572},{},[573,575,580,582],{"type":55,"value":574},"If the SDK is ",{"type":49,"tag":67,"props":576,"children":577},{},[578],{"type":55,"value":579},"server-side only",{"type":55,"value":581}," with no client SDK present → explain that qualitative feedback requires a client-side SDK and cannot be sent from server code → ",{"type":49,"tag":67,"props":583,"children":584},{},[585],{"type":55,"value":531},{"type":49,"tag":58,"props":587,"children":588},{},[589],{"type":55,"value":590},"If unclear, ask the user whether their SDK is client-side or server-side before continuing.",{"type":49,"tag":394,"props":592,"children":594},{"id":593},"check-34-is-the-sdk-version-compatible",[595],{"type":55,"value":596},"Check 3\u002F4: Is the SDK version compatible?",{"type":49,"tag":58,"props":598,"children":599},{},[600,602,608,610,615,617,622],{"type":55,"value":601},"Check ",{"type":49,"tag":118,"props":603,"children":605},{"className":604},[],[606],{"type":55,"value":607},"package.json",{"type":55,"value":609}," for the exact version. The ",{"type":49,"tag":118,"props":611,"children":613},{"className":612},[],[614],{"type":55,"value":231},{"type":55,"value":616}," event requires ",{"type":49,"tag":67,"props":618,"children":619},{},[620],{"type":55,"value":621},"v3.0+",{"type":55,"value":623}," of the JavaScript\u002FReact SDK.",{"type":49,"tag":110,"props":625,"children":626},{},[627,643],{"type":49,"tag":114,"props":628,"children":629},{},[630,632,637,639],{"type":55,"value":631},"If version ",{"type":49,"tag":67,"props":633,"children":634},{},[635],{"type":55,"value":636},"\u003C 3.0",{"type":55,"value":638}," → inform the user they need to upgrade before feedback can be added → ",{"type":49,"tag":67,"props":640,"children":641},{},[642],{"type":55,"value":531},{"type":49,"tag":114,"props":644,"children":645},{},[646,647,652],{"type":55,"value":631},{"type":49,"tag":67,"props":648,"children":649},{},[650],{"type":55,"value":651},">= 3.0",{"type":55,"value":653}," → continue to Check 4.",{"type":49,"tag":394,"props":655,"children":657},{"id":656},"check-44-is-feedback-already-configured",[658],{"type":55,"value":659},"Check 4\u002F4: Is feedback already configured?",{"type":49,"tag":58,"props":661,"children":662},{},[663,665,670,671,676,677,683,684,690],{"type":55,"value":664},"Search for ",{"type":49,"tag":118,"props":666,"children":668},{"className":667},[],[669],{"type":55,"value":231},{"type":55,"value":495},{"type":49,"tag":118,"props":672,"children":674},{"className":673},[],[675],{"type":55,"value":221},{"type":55,"value":495},{"type":49,"tag":118,"props":678,"children":680},{"className":679},[],[681],{"type":55,"value":682},"FeedbackPopover",{"type":55,"value":503},{"type":49,"tag":118,"props":685,"children":687},{"className":686},[],[688],{"type":55,"value":689},"Give feedback",{"type":55,"value":691}," to check for existing feedback integration.",{"type":49,"tag":110,"props":693,"children":694},{},[695,727,745],{"type":49,"tag":114,"props":696,"children":697},{},[698,700,710,712,718,720,725],{"type":55,"value":699},"If a ",{"type":49,"tag":67,"props":701,"children":702},{},[703,708],{"type":49,"tag":118,"props":704,"children":706},{"className":705},[],[707],{"type":55,"value":221},{"type":55,"value":709}," function exists",{"type":55,"value":711}," that calls ",{"type":49,"tag":118,"props":713,"children":715},{"className":714},[],[716],{"type":55,"value":717},"client.track('$ld:feedback', ...)",{"type":55,"value":719}," → ",{"type":49,"tag":67,"props":721,"children":722},{},[723],{"type":55,"value":724},"reuse it",{"type":55,"value":726},". Record its import path — Step 5 will be skipped. Continue to Step 2.",{"type":49,"tag":114,"props":728,"children":729},{},[730,731,736,738,743],{"type":55,"value":699},{"type":49,"tag":67,"props":732,"children":733},{},[734],{"type":55,"value":735},"feedback widget exists",{"type":55,"value":737}," but not the ",{"type":49,"tag":118,"props":739,"children":741},{"className":740},[],[742],{"type":55,"value":221},{"type":55,"value":744}," utility → note the widget pattern for consistency.",{"type":49,"tag":114,"props":746,"children":747},{},[748,749,754],{"type":55,"value":519},{"type":49,"tag":67,"props":750,"children":751},{},[752],{"type":55,"value":753},"nothing found",{"type":55,"value":755}," → continue normally.",{"type":49,"tag":394,"props":757,"children":759},{"id":758},"remaining-exploration",[760],{"type":55,"value":761},"Remaining exploration",{"type":49,"tag":58,"props":763,"children":764},{},[765],{"type":55,"value":766},"After the checks above pass, gather the remaining context:",{"type":49,"tag":185,"props":768,"children":769},{},[770,858,883],{"type":49,"tag":114,"props":771,"children":772},{},[773,778,780],{"type":49,"tag":67,"props":774,"children":775},{},[776],{"type":55,"value":777},"Find the SDK initialization.",{"type":55,"value":779}," Search for:",{"type":49,"tag":110,"props":781,"children":782},{},[783,800,823,845],{"type":49,"tag":114,"props":784,"children":785},{},[786,791,793,798],{"type":49,"tag":118,"props":787,"children":789},{"className":788},[],[790],{"type":55,"value":469},{"type":55,"value":792}," from ",{"type":49,"tag":118,"props":794,"children":796},{"className":795},[],[797],{"type":55,"value":416},{"type":55,"value":799}," (v3.x)",{"type":49,"tag":114,"props":801,"children":802},{},[803,808,810,815,816,821],{"type":49,"tag":118,"props":804,"children":806},{"className":805},[],[807],{"type":55,"value":477},{"type":55,"value":809}," \u002F ",{"type":49,"tag":118,"props":811,"children":813},{"className":812},[],[814],{"type":55,"value":485},{"type":55,"value":792},{"type":49,"tag":118,"props":817,"children":819},{"className":818},[],[820],{"type":55,"value":427},{"type":55,"value":822}," (v4.x)",{"type":49,"tag":114,"props":824,"children":825},{},[826,831,832,837,838,843],{"type":49,"tag":118,"props":827,"children":829},{"className":828},[],[830],{"type":55,"value":493},{"type":55,"value":495},{"type":49,"tag":118,"props":833,"children":835},{"className":834},[],[836],{"type":55,"value":501},{"type":55,"value":503},{"type":49,"tag":118,"props":839,"children":841},{"className":840},[],[842],{"type":55,"value":509},{"type":55,"value":844}," from the React SDK",{"type":49,"tag":114,"props":846,"children":847},{},[848,850,856],{"type":55,"value":849},"How the ",{"type":49,"tag":118,"props":851,"children":853},{"className":852},[],[854],{"type":55,"value":855},"LDClient",{"type":55,"value":857}," instance is accessed (direct reference, React context, custom hook, etc.)",{"type":49,"tag":114,"props":859,"children":860},{},[861,866,868,874,875,881],{"type":49,"tag":67,"props":862,"children":863},{},[864],{"type":55,"value":865},"Check for observability.",{"type":55,"value":867}," Search for ",{"type":49,"tag":118,"props":869,"children":871},{"className":870},[],[872],{"type":55,"value":873},"@launchdarkly\u002Fobservability",{"type":55,"value":562},{"type":49,"tag":118,"props":876,"children":878},{"className":877},[],[879],{"type":55,"value":880},"@launchdarkly\u002Fsession-replay",{"type":55,"value":882},". If present, feedback can be linked to session replays.",{"type":49,"tag":114,"props":884,"children":885},{},[886,891,1012,1016,1018,1023,1025,1137,1140,1145,1147,1152,1154,1159],{"type":49,"tag":67,"props":887,"children":888},{},[889],{"type":55,"value":890},"Detect the UI framework and design system.",{"type":49,"tag":892,"props":893,"children":894},"table",{},[895,914],{"type":49,"tag":896,"props":897,"children":898},"thead",{},[899],{"type":49,"tag":900,"props":901,"children":902},"tr",{},[903,909],{"type":49,"tag":904,"props":905,"children":906},"th",{},[907],{"type":55,"value":908},"Signal",{"type":49,"tag":904,"props":910,"children":911},{},[912],{"type":55,"value":913},"Framework",{"type":49,"tag":915,"props":916,"children":917},"tbody",{},[918,945,963,981,999],{"type":49,"tag":900,"props":919,"children":920},{},[921,940],{"type":49,"tag":922,"props":923,"children":924},"td",{},[925,931,932,938],{"type":49,"tag":118,"props":926,"children":928},{"className":927},[],[929],{"type":55,"value":930},"react",{"type":55,"value":495},{"type":49,"tag":118,"props":933,"children":935},{"className":934},[],[936],{"type":55,"value":937},"react-dom",{"type":55,"value":939}," in deps",{"type":49,"tag":922,"props":941,"children":942},{},[943],{"type":55,"value":944},"React",{"type":49,"tag":900,"props":946,"children":947},{},[948,958],{"type":49,"tag":922,"props":949,"children":950},{},[951,957],{"type":49,"tag":118,"props":952,"children":954},{"className":953},[],[955],{"type":55,"value":956},"vue",{"type":55,"value":939},{"type":49,"tag":922,"props":959,"children":960},{},[961],{"type":55,"value":962},"Vue (adapt vanilla JS pattern to Vue component)",{"type":49,"tag":900,"props":964,"children":965},{},[966,976],{"type":49,"tag":922,"props":967,"children":968},{},[969,975],{"type":49,"tag":118,"props":970,"children":972},{"className":971},[],[973],{"type":55,"value":974},"@angular\u002Fcore",{"type":55,"value":939},{"type":49,"tag":922,"props":977,"children":978},{},[979],{"type":55,"value":980},"Angular (adapt vanilla JS pattern to Angular component)",{"type":49,"tag":900,"props":982,"children":983},{},[984,994],{"type":49,"tag":922,"props":985,"children":986},{},[987,993],{"type":49,"tag":118,"props":988,"children":990},{"className":989},[],[991],{"type":55,"value":992},"svelte",{"type":55,"value":939},{"type":49,"tag":922,"props":995,"children":996},{},[997],{"type":55,"value":998},"Svelte (adapt vanilla JS pattern to Svelte component)",{"type":49,"tag":900,"props":1000,"children":1001},{},[1002,1007],{"type":49,"tag":922,"props":1003,"children":1004},{},[1005],{"type":55,"value":1006},"None of the above",{"type":49,"tag":922,"props":1008,"children":1009},{},[1010],{"type":55,"value":1011},"Vanilla JS\u002FTS",{"type":49,"tag":1013,"props":1014,"children":1015},"br",{},[],{"type":55,"value":1017},"Then check for a ",{"type":49,"tag":67,"props":1019,"children":1020},{},[1021],{"type":55,"value":1022},"design system or component library",{"type":55,"value":1024},":",{"type":49,"tag":110,"props":1026,"children":1027},{},[1028,1046,1057,1068,1087,1106,1124],{"type":49,"tag":114,"props":1029,"children":1030},{},[1031,1037,1038,1044],{"type":49,"tag":118,"props":1032,"children":1034},{"className":1033},[],[1035],{"type":55,"value":1036},"@mui\u002Fmaterial",{"type":55,"value":495},{"type":49,"tag":118,"props":1039,"children":1041},{"className":1040},[],[1042],{"type":55,"value":1043},"@emotion\u002Freact",{"type":55,"value":1045}," → MUI",{"type":49,"tag":114,"props":1047,"children":1048},{},[1049,1055],{"type":49,"tag":118,"props":1050,"children":1052},{"className":1051},[],[1053],{"type":55,"value":1054},"@chakra-ui\u002Freact",{"type":55,"value":1056}," → Chakra UI",{"type":49,"tag":114,"props":1058,"children":1059},{},[1060,1066],{"type":49,"tag":118,"props":1061,"children":1063},{"className":1062},[],[1064],{"type":55,"value":1065},"antd",{"type":55,"value":1067}," → Ant Design",{"type":49,"tag":114,"props":1069,"children":1070},{},[1071,1077,1079,1085],{"type":49,"tag":118,"props":1072,"children":1074},{"className":1073},[],[1075],{"type":55,"value":1076},"@radix-ui\u002F*",{"type":55,"value":1078}," or ",{"type":49,"tag":118,"props":1080,"children":1082},{"className":1081},[],[1083],{"type":55,"value":1084},"@shadcn\u002F*",{"type":55,"value":1086}," → Radix\u002Fshadcn",{"type":49,"tag":114,"props":1088,"children":1089},{},[1090,1096,1098,1104],{"type":49,"tag":118,"props":1091,"children":1093},{"className":1092},[],[1094],{"type":55,"value":1095},"tailwindcss",{"type":55,"value":1097}," in deps or ",{"type":49,"tag":118,"props":1099,"children":1101},{"className":1100},[],[1102],{"type":55,"value":1103},"tailwind.config.*",{"type":55,"value":1105}," → Tailwind CSS",{"type":49,"tag":114,"props":1107,"children":1108},{},[1109,1115,1116,1122],{"type":49,"tag":118,"props":1110,"children":1112},{"className":1111},[],[1113],{"type":55,"value":1114},"bootstrap",{"type":55,"value":1078},{"type":49,"tag":118,"props":1117,"children":1119},{"className":1118},[],[1120],{"type":55,"value":1121},"react-bootstrap",{"type":55,"value":1123}," → Bootstrap",{"type":49,"tag":114,"props":1125,"children":1126},{},[1127,1129,1135],{"type":55,"value":1128},"Custom design system → look for a ",{"type":49,"tag":118,"props":1130,"children":1132},{"className":1131},[],[1133],{"type":55,"value":1134},"components\u002F",{"type":55,"value":1136}," directory with shared primitives (Button, Modal, Popover, etc.)",{"type":49,"tag":1013,"props":1138,"children":1139},{},[],{"type":49,"tag":67,"props":1141,"children":1142},{},[1143],{"type":55,"value":1144},"If a design system is detected, use its primitives",{"type":55,"value":1146}," (Button, Popover, TextArea, IconButton) instead of the inline-styled template component. The template components in ",{"type":49,"tag":556,"props":1148,"children":1150},{"href":1149},"references\u002F",[1151],{"type":55,"value":1149},{"type":55,"value":1153}," are a ",{"type":49,"tag":67,"props":1155,"children":1156},{},[1157],{"type":55,"value":1158},"starting point",{"type":55,"value":1160}," — always adapt them to match the project's existing patterns.",{"type":49,"tag":281,"props":1162,"children":1164},{"id":1163},"step-2-understand-the-goal",[1165],{"type":55,"value":1166},"Step 2: Understand the Goal",{"type":49,"tag":58,"props":1168,"children":1169},{},[1170,1175],{"type":49,"tag":67,"props":1171,"children":1172},{},[1173],{"type":55,"value":1174},"STOP. Do not proceed to Step 3 until you have answers to ALL of the following.",{"type":55,"value":1176}," Check the user's request — if it already answers a question, you don't need to re-ask it. For anything not covered, ask the user and wait for their response before continuing.",{"type":49,"tag":58,"props":1178,"children":1179},{},[1180,1185,1187,1198],{"type":49,"tag":67,"props":1181,"children":1182},{},[1183],{"type":55,"value":1184},"Ask only one question at a time.",{"type":55,"value":1186}," Wait for the user's answer before asking the next. Do not list multiple questions in one message. ",{"type":49,"tag":67,"props":1188,"children":1189},{},[1190,1192],{"type":55,"value":1191},"When presenting options, use ",{"type":49,"tag":118,"props":1193,"children":1195},{"className":1194},[],[1196],{"type":55,"value":1197},"AskUserQuestion",{"type":55,"value":1199}," to render interactive selectors in the agent console. For free-text questions (like prompt text), ask as a normal text message.",{"type":49,"tag":185,"props":1201,"children":1202},{},[1203,1220,1230,1282],{"type":49,"tag":114,"props":1204,"children":1205},{},[1206,1211,1213,1218],{"type":49,"tag":67,"props":1207,"children":1208},{},[1209],{"type":55,"value":1210},"Which feature\u002Fflag?",{"type":55,"value":1212}," Feedback is always tied to a flag key. Search the codebase for existing flag keys, then use ",{"type":49,"tag":118,"props":1214,"children":1216},{"className":1215},[],[1217],{"type":55,"value":1197},{"type":55,"value":1219}," with the discovered flags as options (plus a \"Create a new flag\" option). If no flags are found, ask as a text question.",{"type":49,"tag":114,"props":1221,"children":1222},{},[1223,1228],{"type":49,"tag":67,"props":1224,"children":1225},{},[1226],{"type":55,"value":1227},"What question do you want to ask the user?",{"type":55,"value":1229}," This becomes the prompt text shown in the feedback widget (e.g., \"How do you feel about this view?\" or \"Did this work as expected?\"). Ask this as a normal text message since it requires free-text input.",{"type":49,"tag":114,"props":1231,"children":1232},{},[1233,1238,1240,1245,1247],{"type":49,"tag":67,"props":1234,"children":1235},{},[1236],{"type":55,"value":1237},"What type of feedback?",{"type":55,"value":1239}," Use ",{"type":49,"tag":118,"props":1241,"children":1243},{"className":1242},[],[1244],{"type":55,"value":1197},{"type":55,"value":1246}," with header \"Type\" and these options:\n",{"type":49,"tag":110,"props":1248,"children":1249},{},[1250,1255,1260,1272,1277],{"type":49,"tag":114,"props":1251,"children":1252},{},[1253],{"type":55,"value":1254},"label: \"Sentiment + text (Recommended)\", description: \"Sentiment buttons with a text area for comments, in a popover\"",{"type":49,"tag":114,"props":1256,"children":1257},{},[1258],{"type":55,"value":1259},"label: \"Sentiment only\", description: \"One-click sentiment buttons inline — no popover, no text input\"",{"type":49,"tag":114,"props":1261,"children":1262},{},[1263,1265,1270],{"type":55,"value":1264},"label: \"Text only\", description: \"Just a text area for written feedback in a popover, no sentiment buttons\"\nIf the user selects \"Sentiment + text\" or \"Sentiment only\", follow up with ",{"type":49,"tag":118,"props":1266,"children":1268},{"className":1267},[],[1269],{"type":55,"value":1197},{"type":55,"value":1271}," header \"Icons\" and these options:",{"type":49,"tag":114,"props":1273,"children":1274},{},[1275],{"type":55,"value":1276},"label: \"Thumbs up \u002F down\", description: \"Two buttons: positive \u002F negative\"",{"type":49,"tag":114,"props":1278,"children":1279},{},[1280],{"type":55,"value":1281},"label: \"Smiley faces\", description: \"Three buttons: positive \u002F neutral \u002F negative\"",{"type":49,"tag":114,"props":1283,"children":1284},{},[1285,1290,1292,1297],{"type":49,"tag":67,"props":1286,"children":1287},{},[1288],{"type":55,"value":1289},"Where should the feedback widget go?",{"type":55,"value":1291}," Before asking, search the codebase for pages, routes, or main components. Then use ",{"type":49,"tag":118,"props":1293,"children":1295},{"className":1294},[],[1296],{"type":55,"value":1197},{"type":55,"value":1298}," with header \"Placement\" and 2–4 concrete placement options that make sense for this repo (e.g., \"Next to the results heading on the Simulator page\", \"In the page header\", \"Below the main content area\"). Prefer page-level placement — don't bury feedback in small sub-components unless it's workflow-specific confirmation.",{"type":49,"tag":281,"props":1300,"children":1302},{"id":1301},"step-3-verify-the-flag-in-launchdarkly",[1303],{"type":55,"value":1304},"Step 3: Verify the Flag in LaunchDarkly",{"type":49,"tag":58,"props":1306,"children":1307},{},[1308,1310,1315],{"type":55,"value":1309},"Use ",{"type":49,"tag":118,"props":1311,"children":1313},{"className":1312},[],[1314],{"type":55,"value":123},{"type":55,"value":1316}," to confirm the target flag exists and is configured for client-side use.",{"type":49,"tag":110,"props":1318,"children":1319},{},[1320,1347,1358,1370],{"type":49,"tag":114,"props":1321,"children":1322},{},[1323,1325,1330,1332,1337,1339,1345],{"type":55,"value":1324},"If the flag ",{"type":49,"tag":67,"props":1326,"children":1327},{},[1328],{"type":55,"value":1329},"doesn't exist",{"type":55,"value":1331},", use ",{"type":49,"tag":118,"props":1333,"children":1335},{"className":1334},[],[1336],{"type":55,"value":145},{"type":55,"value":1338}," (or direct the user to the ",{"type":49,"tag":556,"props":1340,"children":1342},{"href":1341},"..\u002Flaunchdarkly-flag-create\u002FSKILL.md",[1343],{"type":55,"value":1344},"flag create skill",{"type":55,"value":1346},").",{"type":49,"tag":114,"props":1348,"children":1349},{},[1350,1351,1356],{"type":55,"value":1324},{"type":49,"tag":67,"props":1352,"children":1353},{},[1354],{"type":55,"value":1355},"exists but doesn't have client-side SDK availability enabled",{"type":55,"value":1357},", inform the user they need to enable it in the flag's Advanced Controls section.",{"type":49,"tag":114,"props":1359,"children":1360},{},[1361,1363,1368],{"type":55,"value":1362},"If the flag was created or verified, ",{"type":49,"tag":67,"props":1364,"children":1365},{},[1366],{"type":55,"value":1367},"provide the user with a direct link",{"type":55,"value":1369}," to the flag in the LaunchDarkly dashboard.",{"type":49,"tag":114,"props":1371,"children":1372},{},[1373,1375,1380,1382,1387],{"type":55,"value":1374},"Optionally use ",{"type":49,"tag":118,"props":1376,"children":1378},{"className":1377},[],[1379],{"type":55,"value":167},{"type":55,"value":1381}," to add a ",{"type":49,"tag":118,"props":1383,"children":1385},{"className":1384},[],[1386],{"type":55,"value":175},{"type":55,"value":1388}," tag.",{"type":49,"tag":281,"props":1390,"children":1392},{"id":1391},"step-4-confirm-before-applying",[1393],{"type":55,"value":1394},"Step 4: Confirm Before Applying",{"type":49,"tag":58,"props":1396,"children":1397},{},[1398,1403],{"type":49,"tag":67,"props":1399,"children":1400},{},[1401],{"type":55,"value":1402},"STOP. Do not write any code until the user explicitly confirms the plan.",{"type":55,"value":1404}," This applies every time — including when the user provides all details upfront, when re-running for a second flag in the same conversation, or when reusing existing utilities. A detailed user request is not implicit approval.",{"type":49,"tag":58,"props":1406,"children":1407},{},[1408,1410,1415],{"type":55,"value":1409},"Summarize the planned changes using ",{"type":49,"tag":67,"props":1411,"children":1412},{},[1413],{"type":55,"value":1414},"future tense",{"type":55,"value":1416}," (e.g., \"Files to create\", \"Files to modify\") — no code has been written yet:",{"type":49,"tag":110,"props":1418,"children":1419},{},[1420,1425,1436,1441],{"type":49,"tag":114,"props":1421,"children":1422},{},[1423],{"type":55,"value":1424},"Flag key and whether it exists or needs creation",{"type":49,"tag":114,"props":1426,"children":1427},{},[1428,1429,1434],{"type":55,"value":215},{"type":49,"tag":118,"props":1430,"children":1432},{"className":1431},[],[1433],{"type":55,"value":221},{"type":55,"value":1435}," utility: where it will live, whether it will be reused from a prior step, and whether it includes session replay",{"type":49,"tag":114,"props":1437,"children":1438},{},[1439],{"type":55,"value":1440},"The feedback widget: component name, UI style, placement location",{"type":49,"tag":114,"props":1442,"children":1443},{},[1444],{"type":55,"value":1445},"Which files will be created or modified",{"type":49,"tag":58,"props":1447,"children":1448},{},[1449,1451,1456],{"type":55,"value":1450},"Then use ",{"type":49,"tag":118,"props":1452,"children":1454},{"className":1453},[],[1455],{"type":55,"value":1197},{"type":55,"value":1457}," with header \"Confirm\" and these options:",{"type":49,"tag":110,"props":1459,"children":1460},{},[1461,1466],{"type":49,"tag":114,"props":1462,"children":1463},{},[1464],{"type":55,"value":1465},"label: \"Looks good\", description: \"Proceed with the plan as described\"",{"type":49,"tag":114,"props":1467,"children":1468},{},[1469],{"type":55,"value":1470},"label: \"Change something\", description: \"I want to adjust part of the plan before you start\"",{"type":49,"tag":58,"props":1472,"children":1473},{},[1474],{"type":55,"value":1475},"If the user selects \"Change something\" (or provides custom input), address their feedback and re-present the updated plan with the same confirmation prompt. Do not proceed to Step 5 until the user selects \"Looks good\".",{"type":49,"tag":281,"props":1477,"children":1479},{"id":1478},"step-5-add-the-sendfeedback-function",[1480],{"type":55,"value":1481},"Step 5: Add the sendFeedback Function",{"type":49,"tag":58,"props":1483,"children":1484},{},[1485,1497],{"type":49,"tag":67,"props":1486,"children":1487},{},[1488,1490,1495],{"type":55,"value":1489},"If Check 4 found an existing ",{"type":49,"tag":118,"props":1491,"children":1493},{"className":1492},[],[1494],{"type":55,"value":221},{"type":55,"value":1496}," function, skip this step entirely.",{"type":55,"value":1498}," Use the recorded import path from that check and proceed directly to Step 6.",{"type":49,"tag":58,"props":1500,"children":1501},{},[1502,1504,1509],{"type":55,"value":1503},"This is the core integration. Create a utility function that sends the ",{"type":49,"tag":118,"props":1505,"children":1507},{"className":1506},[],[1508],{"type":55,"value":231},{"type":55,"value":1510}," tracking event.",{"type":49,"tag":58,"props":1512,"children":1513},{},[1514,1516,1521],{"type":55,"value":1515},"Start from the template in ",{"type":49,"tag":556,"props":1517,"children":1519},{"href":1518},"references\u002FsendFeedback.ts",[1520],{"type":55,"value":1518},{"type":55,"value":1522},". For JavaScript projects, adapt by removing type annotations.",{"type":49,"tag":58,"props":1524,"children":1525},{},[1526],{"type":55,"value":1527},"The essential contract:",{"type":49,"tag":1529,"props":1530,"children":1534},"pre",{"className":1531,"code":1532,"language":18,"meta":1533,"style":1533},"language-typescript shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","client.track('$ld:feedback', {\n    feedback_answer: string,  \u002F\u002F required — the user's written feedback\n    flag_key: string,         \u002F\u002F required — the flag this feedback is about\n    sentiment: \"positive\" | \"neutral\" | \"negative\",  \u002F\u002F defaults to \"neutral\"\n    feedback_prompt: string,  \u002F\u002F optional — the question shown to the user\n    o11y_session_id: string,  \u002F\u002F optional — links to session replay\n    custom_properties: Record\u003Cstring, any>,  \u002F\u002F optional — extra metadata to attach to the feedback event\n});\nclient.flush();\n","",[1535],{"type":49,"tag":118,"props":1536,"children":1537},{"__ignoreMap":1533},[1538,1591,1620,1646,1718,1744,1769,1815,1833],{"type":49,"tag":1539,"props":1540,"children":1543},"span",{"class":1541,"line":1542},"line",1,[1544,1550,1556,1562,1567,1572,1577,1581,1586],{"type":49,"tag":1539,"props":1545,"children":1547},{"style":1546},"--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8",[1548],{"type":55,"value":1549},"client",{"type":49,"tag":1539,"props":1551,"children":1553},{"style":1552},"--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF",[1554],{"type":55,"value":1555},".",{"type":49,"tag":1539,"props":1557,"children":1559},{"style":1558},"--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF",[1560],{"type":55,"value":1561},"track",{"type":49,"tag":1539,"props":1563,"children":1564},{"style":1546},[1565],{"type":55,"value":1566},"(",{"type":49,"tag":1539,"props":1568,"children":1569},{"style":1552},[1570],{"type":55,"value":1571},"'",{"type":49,"tag":1539,"props":1573,"children":1575},{"style":1574},"--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D",[1576],{"type":55,"value":231},{"type":49,"tag":1539,"props":1578,"children":1579},{"style":1552},[1580],{"type":55,"value":1571},{"type":49,"tag":1539,"props":1582,"children":1583},{"style":1552},[1584],{"type":55,"value":1585},",",{"type":49,"tag":1539,"props":1587,"children":1588},{"style":1552},[1589],{"type":55,"value":1590}," {\n",{"type":49,"tag":1539,"props":1592,"children":1594},{"class":1541,"line":1593},2,[1595,1601,1605,1610,1614],{"type":49,"tag":1539,"props":1596,"children":1598},{"style":1597},"--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178",[1599],{"type":55,"value":1600},"    feedback_answer",{"type":49,"tag":1539,"props":1602,"children":1603},{"style":1552},[1604],{"type":55,"value":1024},{"type":49,"tag":1539,"props":1606,"children":1607},{"style":1546},[1608],{"type":55,"value":1609}," string",{"type":49,"tag":1539,"props":1611,"children":1612},{"style":1552},[1613],{"type":55,"value":1585},{"type":49,"tag":1539,"props":1615,"children":1617},{"style":1616},"--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic",[1618],{"type":55,"value":1619},"  \u002F\u002F required — the user's written feedback\n",{"type":49,"tag":1539,"props":1621,"children":1623},{"class":1541,"line":1622},3,[1624,1629,1633,1637,1641],{"type":49,"tag":1539,"props":1625,"children":1626},{"style":1597},[1627],{"type":55,"value":1628},"    flag_key",{"type":49,"tag":1539,"props":1630,"children":1631},{"style":1552},[1632],{"type":55,"value":1024},{"type":49,"tag":1539,"props":1634,"children":1635},{"style":1546},[1636],{"type":55,"value":1609},{"type":49,"tag":1539,"props":1638,"children":1639},{"style":1552},[1640],{"type":55,"value":1585},{"type":49,"tag":1539,"props":1642,"children":1643},{"style":1616},[1644],{"type":55,"value":1645},"         \u002F\u002F required — the flag this feedback is about\n",{"type":49,"tag":1539,"props":1647,"children":1649},{"class":1541,"line":1648},4,[1650,1655,1659,1664,1669,1674,1679,1683,1688,1692,1696,1700,1705,1709,1713],{"type":49,"tag":1539,"props":1651,"children":1652},{"style":1597},[1653],{"type":55,"value":1654},"    sentiment",{"type":49,"tag":1539,"props":1656,"children":1657},{"style":1552},[1658],{"type":55,"value":1024},{"type":49,"tag":1539,"props":1660,"children":1661},{"style":1552},[1662],{"type":55,"value":1663}," \"",{"type":49,"tag":1539,"props":1665,"children":1666},{"style":1574},[1667],{"type":55,"value":1668},"positive",{"type":49,"tag":1539,"props":1670,"children":1671},{"style":1552},[1672],{"type":55,"value":1673},"\"",{"type":49,"tag":1539,"props":1675,"children":1676},{"style":1552},[1677],{"type":55,"value":1678}," |",{"type":49,"tag":1539,"props":1680,"children":1681},{"style":1552},[1682],{"type":55,"value":1663},{"type":49,"tag":1539,"props":1684,"children":1685},{"style":1574},[1686],{"type":55,"value":1687},"neutral",{"type":49,"tag":1539,"props":1689,"children":1690},{"style":1552},[1691],{"type":55,"value":1673},{"type":49,"tag":1539,"props":1693,"children":1694},{"style":1552},[1695],{"type":55,"value":1678},{"type":49,"tag":1539,"props":1697,"children":1698},{"style":1552},[1699],{"type":55,"value":1663},{"type":49,"tag":1539,"props":1701,"children":1702},{"style":1574},[1703],{"type":55,"value":1704},"negative",{"type":49,"tag":1539,"props":1706,"children":1707},{"style":1552},[1708],{"type":55,"value":1673},{"type":49,"tag":1539,"props":1710,"children":1711},{"style":1552},[1712],{"type":55,"value":1585},{"type":49,"tag":1539,"props":1714,"children":1715},{"style":1616},[1716],{"type":55,"value":1717},"  \u002F\u002F defaults to \"neutral\"\n",{"type":49,"tag":1539,"props":1719,"children":1721},{"class":1541,"line":1720},5,[1722,1727,1731,1735,1739],{"type":49,"tag":1539,"props":1723,"children":1724},{"style":1597},[1725],{"type":55,"value":1726},"    feedback_prompt",{"type":49,"tag":1539,"props":1728,"children":1729},{"style":1552},[1730],{"type":55,"value":1024},{"type":49,"tag":1539,"props":1732,"children":1733},{"style":1546},[1734],{"type":55,"value":1609},{"type":49,"tag":1539,"props":1736,"children":1737},{"style":1552},[1738],{"type":55,"value":1585},{"type":49,"tag":1539,"props":1740,"children":1741},{"style":1616},[1742],{"type":55,"value":1743},"  \u002F\u002F optional — the question shown to the user\n",{"type":49,"tag":1539,"props":1745,"children":1746},{"class":1541,"line":30},[1747,1752,1756,1760,1764],{"type":49,"tag":1539,"props":1748,"children":1749},{"style":1597},[1750],{"type":55,"value":1751},"    o11y_session_id",{"type":49,"tag":1539,"props":1753,"children":1754},{"style":1552},[1755],{"type":55,"value":1024},{"type":49,"tag":1539,"props":1757,"children":1758},{"style":1546},[1759],{"type":55,"value":1609},{"type":49,"tag":1539,"props":1761,"children":1762},{"style":1552},[1763],{"type":55,"value":1585},{"type":49,"tag":1539,"props":1765,"children":1766},{"style":1616},[1767],{"type":55,"value":1768},"  \u002F\u002F optional — links to session replay\n",{"type":49,"tag":1539,"props":1770,"children":1772},{"class":1541,"line":1771},7,[1773,1778,1782,1787,1792,1797,1801,1806,1810],{"type":49,"tag":1539,"props":1774,"children":1775},{"style":1597},[1776],{"type":55,"value":1777},"    custom_properties",{"type":49,"tag":1539,"props":1779,"children":1780},{"style":1552},[1781],{"type":55,"value":1024},{"type":49,"tag":1539,"props":1783,"children":1784},{"style":1546},[1785],{"type":55,"value":1786}," Record",{"type":49,"tag":1539,"props":1788,"children":1789},{"style":1552},[1790],{"type":55,"value":1791},"\u003C",{"type":49,"tag":1539,"props":1793,"children":1794},{"style":1546},[1795],{"type":55,"value":1796},"string",{"type":49,"tag":1539,"props":1798,"children":1799},{"style":1552},[1800],{"type":55,"value":1585},{"type":49,"tag":1539,"props":1802,"children":1803},{"style":1546},[1804],{"type":55,"value":1805}," any>",{"type":49,"tag":1539,"props":1807,"children":1808},{"style":1552},[1809],{"type":55,"value":1585},{"type":49,"tag":1539,"props":1811,"children":1812},{"style":1616},[1813],{"type":55,"value":1814},"  \u002F\u002F optional — extra metadata to attach to the feedback event\n",{"type":49,"tag":1539,"props":1816,"children":1818},{"class":1541,"line":1817},8,[1819,1824,1828],{"type":49,"tag":1539,"props":1820,"children":1821},{"style":1552},[1822],{"type":55,"value":1823},"}",{"type":49,"tag":1539,"props":1825,"children":1826},{"style":1546},[1827],{"type":55,"value":458},{"type":49,"tag":1539,"props":1829,"children":1830},{"style":1552},[1831],{"type":55,"value":1832},";\n",{"type":49,"tag":1539,"props":1834,"children":1836},{"class":1541,"line":1835},9,[1837,1841,1845,1850,1855],{"type":49,"tag":1539,"props":1838,"children":1839},{"style":1546},[1840],{"type":55,"value":1549},{"type":49,"tag":1539,"props":1842,"children":1843},{"style":1552},[1844],{"type":55,"value":1555},{"type":49,"tag":1539,"props":1846,"children":1847},{"style":1558},[1848],{"type":55,"value":1849},"flush",{"type":49,"tag":1539,"props":1851,"children":1852},{"style":1546},[1853],{"type":55,"value":1854},"()",{"type":49,"tag":1539,"props":1856,"children":1857},{"style":1552},[1858],{"type":55,"value":1832},{"type":49,"tag":58,"props":1860,"children":1861},{},[1862],{"type":49,"tag":67,"props":1863,"children":1864},{},[1865],{"type":55,"value":1866},"Key decisions:",{"type":49,"tag":110,"props":1868,"children":1869},{},[1870,1918,1945,1965],{"type":49,"tag":114,"props":1871,"children":1872},{},[1873,1875,1880,1882,1887,1889,1894,1896,1901,1903,1909,1910,1916],{"type":55,"value":1874},"Match the ",{"type":49,"tag":118,"props":1876,"children":1878},{"className":1877},[],[1879],{"type":55,"value":855},{"type":55,"value":1881}," type import to the project's SDK version: ",{"type":49,"tag":118,"props":1883,"children":1885},{"className":1884},[],[1886],{"type":55,"value":416},{"type":55,"value":1888}," for v3.x, ",{"type":49,"tag":118,"props":1890,"children":1892},{"className":1891},[],[1893],{"type":55,"value":427},{"type":55,"value":1895}," for v4.x. The templates import from ",{"type":49,"tag":118,"props":1897,"children":1899},{"className":1898},[],[1900],{"type":55,"value":416},{"type":55,"value":1902}," — update it if the project is on v4. (The ",{"type":49,"tag":118,"props":1904,"children":1906},{"className":1905},[],[1907],{"type":55,"value":1908},"client.track",{"type":55,"value":809},{"type":49,"tag":118,"props":1911,"children":1913},{"className":1912},[],[1914],{"type":55,"value":1915},"client.flush",{"type":55,"value":1917}," calls are the same across both.)",{"type":49,"tag":114,"props":1919,"children":1920},{},[1921,1922,1927,1929,1935,1937,1943],{"type":55,"value":519},{"type":49,"tag":118,"props":1923,"children":1925},{"className":1924},[],[1926],{"type":55,"value":880},{"type":55,"value":1928}," is in the project, include the session ID via ",{"type":49,"tag":118,"props":1930,"children":1932},{"className":1931},[],[1933],{"type":55,"value":1934},"LDRecord.getSession()?.sessionSecureID",{"type":55,"value":1936},". If not, remove the session replay import and ",{"type":49,"tag":118,"props":1938,"children":1940},{"className":1939},[],[1941],{"type":55,"value":1942},"o11y_session_id",{"type":55,"value":1944}," logic from the template.",{"type":49,"tag":114,"props":1946,"children":1947},{},[1948,1950,1956,1957,1963],{"type":55,"value":1949},"Place the utility where the project keeps its LD-related code (alongside existing flag helpers, in a ",{"type":49,"tag":118,"props":1951,"children":1953},{"className":1952},[],[1954],{"type":55,"value":1955},"lib\u002F",{"type":55,"value":1078},{"type":49,"tag":118,"props":1958,"children":1960},{"className":1959},[],[1961],{"type":55,"value":1962},"utils\u002F",{"type":55,"value":1964}," directory, etc.)",{"type":49,"tag":114,"props":1966,"children":1967},{},[1968,1970,1976],{"type":55,"value":1969},"Export the ",{"type":49,"tag":118,"props":1971,"children":1973},{"className":1972},[],[1974],{"type":55,"value":1975},"LDFeedbackSentiment",{"type":55,"value":1977}," type if using TypeScript",{"type":49,"tag":58,"props":1979,"children":1980},{},[1981,1986,1988,1993,1995,2000,2002,2008],{"type":49,"tag":67,"props":1982,"children":1983},{},[1984],{"type":55,"value":1985},"Verification:",{"type":55,"value":1987}," After creating the file, search the codebase to confirm it exists and contains the expected content — a ",{"type":49,"tag":118,"props":1989,"children":1991},{"className":1990},[],[1992],{"type":55,"value":221},{"type":55,"value":1994}," export that calls ",{"type":49,"tag":118,"props":1996,"children":1998},{"className":1997},[],[1999],{"type":55,"value":717},{"type":55,"value":2001}," followed by ",{"type":49,"tag":118,"props":2003,"children":2005},{"className":2004},[],[2006],{"type":55,"value":2007},"client.flush()",{"type":55,"value":2009},". If not found, fix before proceeding.",{"type":49,"tag":281,"props":2011,"children":2013},{"id":2012},"step-6-build-the-feedback-widget",[2014],{"type":55,"value":2015},"Step 6: Build the Feedback Widget",{"type":49,"tag":58,"props":2017,"children":2018},{},[2019],{"type":55,"value":2020},"Build the UI using the project's existing design system and component patterns.",{"type":49,"tag":58,"props":2022,"children":2023},{},[2024,2026,2030],{"type":55,"value":2025},"Start from the appropriate template in ",{"type":49,"tag":556,"props":2027,"children":2028},{"href":1149},[2029],{"type":55,"value":1149},{"type":55,"value":1522},{"type":49,"tag":110,"props":2032,"children":2033},{},[2034,2064,2084],{"type":49,"tag":114,"props":2035,"children":2036},{},[2037,2042,2043,2049,2051,2057,2058],{"type":49,"tag":67,"props":2038,"children":2039},{},[2040],{"type":55,"value":2041},"Sentiment + text",{"type":55,"value":719},{"type":49,"tag":556,"props":2044,"children":2046},{"href":2045},"references\u002FPopoverFeedback.tsx",[2047],{"type":55,"value":2048},"PopoverFeedback.tsx",{"type":55,"value":2050}," with ",{"type":49,"tag":118,"props":2052,"children":2054},{"className":2053},[],[2055],{"type":55,"value":2056},"icons=\"thumbs\"",{"type":55,"value":1078},{"type":49,"tag":118,"props":2059,"children":2061},{"className":2060},[],[2062],{"type":55,"value":2063},"icons=\"smileys\"",{"type":49,"tag":114,"props":2065,"children":2066},{},[2067,2072,2073,2077,2078],{"type":49,"tag":67,"props":2068,"children":2069},{},[2070],{"type":55,"value":2071},"Text only",{"type":55,"value":719},{"type":49,"tag":556,"props":2074,"children":2075},{"href":2045},[2076],{"type":55,"value":2048},{"type":55,"value":2050},{"type":49,"tag":118,"props":2079,"children":2081},{"className":2080},[],[2082],{"type":55,"value":2083},"icons=\"none\"",{"type":49,"tag":114,"props":2085,"children":2086},{},[2087,2092,2093,2099,2100,2105,2106],{"type":49,"tag":67,"props":2088,"children":2089},{},[2090],{"type":55,"value":2091},"Sentiment only",{"type":55,"value":719},{"type":49,"tag":556,"props":2094,"children":2096},{"href":2095},"references\u002FInlineFeedback.tsx",[2097],{"type":55,"value":2098},"InlineFeedback.tsx",{"type":55,"value":2050},{"type":49,"tag":118,"props":2101,"children":2103},{"className":2102},[],[2104],{"type":55,"value":2056},{"type":55,"value":1078},{"type":49,"tag":118,"props":2107,"children":2109},{"className":2108},[],[2110],{"type":55,"value":2063},{"type":49,"tag":58,"props":2112,"children":2113},{},[2114],{"type":55,"value":2115},"These templates use inline styles and SVG icons so they work without any CSS framework or icon library. When the project has a design system, replace template elements with its primitives:",{"type":49,"tag":892,"props":2117,"children":2118},{},[2119,2135],{"type":49,"tag":896,"props":2120,"children":2121},{},[2122],{"type":49,"tag":900,"props":2123,"children":2124},{},[2125,2130],{"type":49,"tag":904,"props":2126,"children":2127},{},[2128],{"type":55,"value":2129},"Template element",{"type":49,"tag":904,"props":2131,"children":2132},{},[2133],{"type":55,"value":2134},"Replace with",{"type":49,"tag":915,"props":2136,"children":2137},{},[2138,2157,2182,2216,2246],{"type":49,"tag":900,"props":2139,"children":2140},{},[2141,2152],{"type":49,"tag":922,"props":2142,"children":2143},{},[2144,2146],{"type":55,"value":2145},"Inline ",{"type":49,"tag":118,"props":2147,"children":2149},{"className":2148},[],[2150],{"type":55,"value":2151},"style={{...}}",{"type":49,"tag":922,"props":2153,"children":2154},{},[2155],{"type":55,"value":2156},"Project's CSS approach (Tailwind classes, CSS modules, styled-components, etc.)",{"type":49,"tag":900,"props":2158,"children":2159},{},[2160,2169],{"type":49,"tag":922,"props":2161,"children":2162},{},[2163],{"type":49,"tag":118,"props":2164,"children":2166},{"className":2165},[],[2167],{"type":55,"value":2168},"\u003Cbutton>",{"type":49,"tag":922,"props":2170,"children":2171},{},[2172,2174,2180],{"type":55,"value":2173},"Design system's ",{"type":49,"tag":118,"props":2175,"children":2177},{"className":2176},[],[2178],{"type":55,"value":2179},"\u003CButton>",{"type":55,"value":2181}," component",{"type":49,"tag":900,"props":2183,"children":2184},{},[2185,2198],{"type":49,"tag":922,"props":2186,"children":2187},{},[2188,2190,2196],{"type":55,"value":2189},"Positioned ",{"type":49,"tag":118,"props":2191,"children":2193},{"className":2192},[],[2194],{"type":55,"value":2195},"\u003Cdiv>",{"type":55,"value":2197}," popover",{"type":49,"tag":922,"props":2199,"children":2200},{},[2201,2202,2208,2209,2215],{"type":55,"value":2173},{"type":49,"tag":118,"props":2203,"children":2205},{"className":2204},[],[2206],{"type":55,"value":2207},"\u003CPopover>",{"type":55,"value":1078},{"type":49,"tag":118,"props":2210,"children":2212},{"className":2211},[],[2213],{"type":55,"value":2214},"\u003CDropdown>",{"type":55,"value":2181},{"type":49,"tag":900,"props":2217,"children":2218},{},[2219,2228],{"type":49,"tag":922,"props":2220,"children":2221},{},[2222],{"type":49,"tag":118,"props":2223,"children":2225},{"className":2224},[],[2226],{"type":55,"value":2227},"\u003Ctextarea>",{"type":49,"tag":922,"props":2229,"children":2230},{},[2231,2232,2238,2239,2245],{"type":55,"value":2173},{"type":49,"tag":118,"props":2233,"children":2235},{"className":2234},[],[2236],{"type":55,"value":2237},"\u003CTextArea>",{"type":55,"value":1078},{"type":49,"tag":118,"props":2240,"children":2242},{"className":2241},[],[2243],{"type":55,"value":2244},"\u003CInput>",{"type":55,"value":2181},{"type":49,"tag":900,"props":2247,"children":2248},{},[2249,2254],{"type":49,"tag":922,"props":2250,"children":2251},{},[2252],{"type":55,"value":2253},"Inline SVG icons",{"type":49,"tag":922,"props":2255,"children":2256},{},[2257],{"type":55,"value":2258},"Project's icon library (Lucide, Heroicons, MUI icons, etc.)",{"type":49,"tag":58,"props":2260,"children":2261},{},[2262,2264,2270],{"type":55,"value":2263},"Always use ",{"type":49,"tag":118,"props":2265,"children":2267},{"className":2266},[],[2268],{"type":55,"value":2269},"fill=\"currentColor\"",{"type":55,"value":2271}," (not hardcoded hex colors) in SVG icons so they inherit the parent's text color.",{"type":49,"tag":58,"props":2273,"children":2274},{},[2275,2287,2289,2295],{"type":49,"tag":67,"props":2276,"children":2277},{},[2278,2280,2286],{"type":55,"value":2279},"Do NOT use find-and-replace for ",{"type":49,"tag":118,"props":2281,"children":2283},{"className":2282},[],[2284],{"type":55,"value":2285},"PROMPT_TO_REPLACE",{"type":55,"value":1555},{"type":55,"value":2288}," Instead, make ",{"type":49,"tag":118,"props":2290,"children":2292},{"className":2291},[],[2293],{"type":55,"value":2294},"prompt",{"type":55,"value":2296}," a string prop on the component. This makes the widget reusable across flags without code duplication. Pass the user's prompt text from Step 2 as a prop when rendering.",{"type":49,"tag":58,"props":2298,"children":2299},{},[2300,2305],{"type":49,"tag":67,"props":2301,"children":2302},{},[2303],{"type":55,"value":2304},"Standard UX pattern",{"type":55,"value":2306}," (follow this regardless of design system):",{"type":49,"tag":110,"props":2308,"children":2309},{},[2310,2322,2397,2415],{"type":49,"tag":114,"props":2311,"children":2312},{},[2313,2315,2320],{"type":55,"value":2314},"A ",{"type":49,"tag":67,"props":2316,"children":2317},{},[2318],{"type":55,"value":2319},"trigger button",{"type":55,"value":2321}," with a speech-bubble icon and \"Give feedback\" label (for popover styles)",{"type":49,"tag":114,"props":2323,"children":2324},{},[2325,2326,2331,2333],{"type":55,"value":2314},{"type":49,"tag":67,"props":2327,"children":2328},{},[2329],{"type":55,"value":2330},"popover",{"type":55,"value":2332}," that opens on click, containing:\n",{"type":49,"tag":110,"props":2334,"children":2335},{},[2336,2341,2392],{"type":49,"tag":114,"props":2337,"children":2338},{},[2339],{"type":55,"value":2340},"A text area with the prompt text as its placeholder",{"type":49,"tag":114,"props":2342,"children":2343},{},[2344,2346],{"type":55,"value":2345},"Sentiment controls matching the style chosen in Step 2:\n",{"type":49,"tag":110,"props":2347,"children":2348},{},[2349,2359,2369],{"type":49,"tag":114,"props":2350,"children":2351},{},[2352,2357],{"type":49,"tag":67,"props":2353,"children":2354},{},[2355],{"type":55,"value":2356},"Thumbs up \u002F thumbs down",{"type":55,"value":2358}," — two icon buttons toggling positive\u002Fnegative",{"type":49,"tag":114,"props":2360,"children":2361},{},[2362,2367],{"type":49,"tag":67,"props":2363,"children":2364},{},[2365],{"type":55,"value":2366},"Smiley-face scale",{"type":55,"value":2368}," — three icon buttons for positive (smile), neutral (meh), negative (frown)",{"type":49,"tag":114,"props":2370,"children":2371},{},[2372,2377,2379,2385,2387],{"type":49,"tag":67,"props":2373,"children":2374},{},[2375],{"type":55,"value":2376},"Text-only",{"type":55,"value":2378}," — no sentiment buttons; omit the ",{"type":49,"tag":118,"props":2380,"children":2382},{"className":2381},[],[2383],{"type":55,"value":2384},"sentiment",{"type":55,"value":2386}," field from ",{"type":49,"tag":118,"props":2388,"children":2390},{"className":2389},[],[2391],{"type":55,"value":221},{"type":49,"tag":114,"props":2393,"children":2394},{},[2395],{"type":55,"value":2396},"A submit button",{"type":49,"tag":114,"props":2398,"children":2399},{},[2400,2405,2407,2413],{"type":49,"tag":67,"props":2401,"children":2402},{},[2403],{"type":55,"value":2404},"After submission:",{"type":55,"value":2406}," Track a ",{"type":49,"tag":118,"props":2408,"children":2410},{"className":2409},[],[2411],{"type":55,"value":2412},"submitted",{"type":55,"value":2414}," state. Replace the widget with a \"Thanks for your feedback!\" confirmation message. Do not just close the popover silently — the user needs to know their feedback was received.",{"type":49,"tag":114,"props":2416,"children":2417},{},[2418,2423],{"type":49,"tag":67,"props":2419,"children":2420},{},[2421],{"type":55,"value":2422},"Quick thumbs \u002F inline smileys",{"type":55,"value":2424}," (no popover): inline prompt text with sentiment buttons; sends feedback immediately on click with no text input. After click, replace with a thank-you message.",{"type":49,"tag":58,"props":2426,"children":2427},{},[2428,2433],{"type":49,"tag":67,"props":2429,"children":2430},{},[2431],{"type":55,"value":2432},"Placement:",{"type":55,"value":2434}," Use the location chosen in Step 2. Do not add multiple feedback entry points on the same screen.",{"type":49,"tag":394,"props":2436,"children":2438},{"id":2437},"wire-the-component-into-the-target",[2439],{"type":55,"value":2440},"Wire the component into the target",{"type":49,"tag":58,"props":2442,"children":2443},{},[2444],{"type":55,"value":2445},"After building the widget, add it to the target location from Step 2:",{"type":49,"tag":185,"props":2447,"children":2448},{},[2449,2459,2500],{"type":49,"tag":114,"props":2450,"children":2451},{},[2452,2457],{"type":49,"tag":67,"props":2453,"children":2454},{},[2455],{"type":55,"value":2456},"Find the target file.",{"type":55,"value":2458}," Search the codebase for the page or component matching the placement chosen in Step 2. State the file path you found and ask the user to confirm it's correct before modifying it. If they say no, ask for clarification and try again.",{"type":49,"tag":114,"props":2460,"children":2461},{},[2462,2467,2469,2475,2477,2482,2484,2490,2492,2498],{"type":49,"tag":67,"props":2463,"children":2464},{},[2465],{"type":55,"value":2466},"Import and render.",{"type":55,"value":2468}," Import the feedback component into the confirmed target file. Render it and pass the required props: ",{"type":49,"tag":118,"props":2470,"children":2472},{"className":2471},[],[2473],{"type":55,"value":2474},"flagKey",{"type":55,"value":2476}," string and ",{"type":49,"tag":118,"props":2478,"children":2480},{"className":2479},[],[2481],{"type":55,"value":2294},{"type":55,"value":2483}," string. For React SDK projects, the component should use the ",{"type":49,"tag":118,"props":2485,"children":2487},{"className":2486},[],[2488],{"type":55,"value":2489},"useLDClient()",{"type":55,"value":2491}," hook internally rather than accepting ",{"type":49,"tag":118,"props":2493,"children":2495},{"className":2494},[],[2496],{"type":55,"value":2497},"ldClient",{"type":55,"value":2499}," as a prop.",{"type":49,"tag":114,"props":2501,"children":2502},{},[2503,2507,2509,2514,2515,2520],{"type":49,"tag":67,"props":2504,"children":2505},{},[2506],{"type":55,"value":1985},{"type":55,"value":2508}," Search the target component to confirm it imports and renders the feedback component with the required props (",{"type":49,"tag":118,"props":2510,"children":2512},{"className":2511},[],[2513],{"type":55,"value":2474},{"type":55,"value":495},{"type":49,"tag":118,"props":2516,"children":2518},{"className":2517},[],[2519],{"type":55,"value":2294},{"type":55,"value":2521},"). If the import or render is missing, fix before proceeding.",{"type":49,"tag":394,"props":2523,"children":2525},{"id":2524},"framework-specific-approach",[2526],{"type":55,"value":2527},"Framework-specific approach",{"type":49,"tag":58,"props":2529,"children":2530},{},[2531,2535],{"type":49,"tag":67,"props":2532,"children":2533},{},[2534],{"type":55,"value":944},{"type":55,"value":2536}," — Start from the template, then adapt to the project's design system using the table above.",{"type":49,"tag":58,"props":2538,"children":2539},{},[2540,2544,2546,2551],{"type":49,"tag":67,"props":2541,"children":2542},{},[2543],{"type":55,"value":1011},{"type":55,"value":2545}," — Wire up DOM elements to the ",{"type":49,"tag":118,"props":2547,"children":2549},{"className":2548},[],[2550],{"type":55,"value":221},{"type":55,"value":2552}," function:",{"type":49,"tag":1529,"props":2554,"children":2556},{"className":1531,"code":2555,"language":18,"meta":1533,"style":1533},"submitButton.addEventListener('click', () => {\n    sendFeedback(client, flagKey, feedbackInput.value, selectedSentiment, promptText);\n});\n",[2557],{"type":49,"tag":118,"props":2558,"children":2559},{"__ignoreMap":1533},[2560,2613,2682],{"type":49,"tag":1539,"props":2561,"children":2562},{"class":1541,"line":1542},[2563,2568,2572,2577,2581,2585,2590,2594,2598,2603,2609],{"type":49,"tag":1539,"props":2564,"children":2565},{"style":1546},[2566],{"type":55,"value":2567},"submitButton",{"type":49,"tag":1539,"props":2569,"children":2570},{"style":1552},[2571],{"type":55,"value":1555},{"type":49,"tag":1539,"props":2573,"children":2574},{"style":1558},[2575],{"type":55,"value":2576},"addEventListener",{"type":49,"tag":1539,"props":2578,"children":2579},{"style":1546},[2580],{"type":55,"value":1566},{"type":49,"tag":1539,"props":2582,"children":2583},{"style":1552},[2584],{"type":55,"value":1571},{"type":49,"tag":1539,"props":2586,"children":2587},{"style":1574},[2588],{"type":55,"value":2589},"click",{"type":49,"tag":1539,"props":2591,"children":2592},{"style":1552},[2593],{"type":55,"value":1571},{"type":49,"tag":1539,"props":2595,"children":2596},{"style":1552},[2597],{"type":55,"value":1585},{"type":49,"tag":1539,"props":2599,"children":2600},{"style":1552},[2601],{"type":55,"value":2602}," ()",{"type":49,"tag":1539,"props":2604,"children":2606},{"style":2605},"--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA",[2607],{"type":55,"value":2608}," =>",{"type":49,"tag":1539,"props":2610,"children":2611},{"style":1552},[2612],{"type":55,"value":1590},{"type":49,"tag":1539,"props":2614,"children":2615},{"class":1541,"line":1593},[2616,2621,2625,2629,2633,2638,2642,2647,2651,2656,2660,2665,2669,2674,2678],{"type":49,"tag":1539,"props":2617,"children":2618},{"style":1558},[2619],{"type":55,"value":2620},"    sendFeedback",{"type":49,"tag":1539,"props":2622,"children":2623},{"style":1597},[2624],{"type":55,"value":1566},{"type":49,"tag":1539,"props":2626,"children":2627},{"style":1546},[2628],{"type":55,"value":1549},{"type":49,"tag":1539,"props":2630,"children":2631},{"style":1552},[2632],{"type":55,"value":1585},{"type":49,"tag":1539,"props":2634,"children":2635},{"style":1546},[2636],{"type":55,"value":2637}," flagKey",{"type":49,"tag":1539,"props":2639,"children":2640},{"style":1552},[2641],{"type":55,"value":1585},{"type":49,"tag":1539,"props":2643,"children":2644},{"style":1546},[2645],{"type":55,"value":2646}," feedbackInput",{"type":49,"tag":1539,"props":2648,"children":2649},{"style":1552},[2650],{"type":55,"value":1555},{"type":49,"tag":1539,"props":2652,"children":2653},{"style":1546},[2654],{"type":55,"value":2655},"value",{"type":49,"tag":1539,"props":2657,"children":2658},{"style":1552},[2659],{"type":55,"value":1585},{"type":49,"tag":1539,"props":2661,"children":2662},{"style":1546},[2663],{"type":55,"value":2664}," selectedSentiment",{"type":49,"tag":1539,"props":2666,"children":2667},{"style":1552},[2668],{"type":55,"value":1585},{"type":49,"tag":1539,"props":2670,"children":2671},{"style":1546},[2672],{"type":55,"value":2673}," promptText",{"type":49,"tag":1539,"props":2675,"children":2676},{"style":1597},[2677],{"type":55,"value":458},{"type":49,"tag":1539,"props":2679,"children":2680},{"style":1552},[2681],{"type":55,"value":1832},{"type":49,"tag":1539,"props":2683,"children":2684},{"class":1541,"line":1622},[2685,2689,2693],{"type":49,"tag":1539,"props":2686,"children":2687},{"style":1552},[2688],{"type":55,"value":1823},{"type":49,"tag":1539,"props":2690,"children":2691},{"style":1546},[2692],{"type":55,"value":458},{"type":49,"tag":1539,"props":2694,"children":2695},{"style":1552},[2696],{"type":55,"value":1832},{"type":49,"tag":58,"props":2698,"children":2699},{},[2700,2705,2707,2712],{"type":49,"tag":67,"props":2701,"children":2702},{},[2703],{"type":55,"value":2704},"Vue \u002F Angular \u002F Svelte",{"type":55,"value":2706}," — Translate the React component pattern into the framework's idiom. The ",{"type":49,"tag":118,"props":2708,"children":2710},{"className":2709},[],[2711],{"type":55,"value":221},{"type":55,"value":2713}," function is framework-agnostic; only the UI wrapper changes.",{"type":49,"tag":281,"props":2715,"children":2717},{"id":2716},"step-7-verify",[2718],{"type":55,"value":2719},"Step 7: Verify",{"type":49,"tag":58,"props":2721,"children":2722},{},[2723,2728],{"type":49,"tag":67,"props":2724,"children":2725},{},[2726],{"type":55,"value":2727},"Pre-condition check:",{"type":55,"value":2729}," Before verifying, confirm that all prior steps produced their expected outputs:",{"type":49,"tag":110,"props":2731,"children":2732},{},[2733,2745,2750],{"type":49,"tag":114,"props":2734,"children":2735},{},[2736,2738,2743],{"type":55,"value":2737},"(a) The ",{"type":49,"tag":118,"props":2739,"children":2741},{"className":2740},[],[2742],{"type":55,"value":221},{"type":55,"value":2744}," utility file exists (or an existing one was reused from Check 4).",{"type":49,"tag":114,"props":2746,"children":2747},{},[2748],{"type":55,"value":2749},"(b) The feedback widget component file exists.",{"type":49,"tag":114,"props":2751,"children":2752},{},[2753],{"type":55,"value":2754},"(c) The widget is imported and rendered in the target location with the required props.",{"type":49,"tag":58,"props":2756,"children":2757},{},[2758],{"type":55,"value":2759},"If any are missing, go back and complete the relevant step before proceeding.",{"type":49,"tag":58,"props":2761,"children":2762},{},[2763],{"type":55,"value":2764},"Walk the user through validation step by step:",{"type":49,"tag":185,"props":2766,"children":2767},{},[2768,2778,2788,2798,2814,2831],{"type":49,"tag":114,"props":2769,"children":2770},{},[2771,2776],{"type":49,"tag":67,"props":2772,"children":2773},{},[2774],{"type":55,"value":2775},"Run the build.",{"type":55,"value":2777}," Execute the project's build or lint command. If it fails, fix the errors before continuing.",{"type":49,"tag":114,"props":2779,"children":2780},{},[2781,2786],{"type":49,"tag":67,"props":2782,"children":2783},{},[2784],{"type":55,"value":2785},"Start the app locally.",{"type":55,"value":2787}," Ask the user to run their dev server (or run it yourself if you can). Confirm it starts without errors.",{"type":49,"tag":114,"props":2789,"children":2790},{},[2791,2796],{"type":49,"tag":67,"props":2792,"children":2793},{},[2794],{"type":55,"value":2795},"Navigate to the feedback location.",{"type":55,"value":2797}," Tell the user to open the page where the widget was placed. Ask them to confirm the \"Give feedback\" button (or inline thumbs) is visible and styled correctly.",{"type":49,"tag":114,"props":2799,"children":2800},{},[2801,2806,2808,2813],{"type":49,"tag":67,"props":2802,"children":2803},{},[2804],{"type":55,"value":2805},"Submit test feedback.",{"type":55,"value":2807}," Walk the user through: click the trigger → enter test text → select a sentiment → click Send. Ask them to open the browser's Network tab and confirm a POST to the LaunchDarkly events endpoint fired containing ",{"type":49,"tag":118,"props":2809,"children":2811},{"className":2810},[],[2812],{"type":55,"value":231},{"type":55,"value":1555},{"type":49,"tag":114,"props":2815,"children":2816},{},[2817,2822,2824,2829],{"type":49,"tag":67,"props":2818,"children":2819},{},[2820],{"type":55,"value":2821},"Check the dashboard.",{"type":55,"value":2823}," Provide a direct link to the flag's ",{"type":49,"tag":67,"props":2825,"children":2826},{},[2827],{"type":55,"value":2828},"Feedback",{"type":55,"value":2830}," tab in the LaunchDarkly dashboard. Tell the user to wait ~1 minute and then refresh — their test feedback should appear.",{"type":49,"tag":114,"props":2832,"children":2833},{},[2834,2839,2841,2846,2848,2853],{"type":49,"tag":67,"props":2835,"children":2836},{},[2837],{"type":55,"value":2838},"Session replay (if applicable).",{"type":55,"value":2840}," If ",{"type":49,"tag":118,"props":2842,"children":2844},{"className":2843},[],[2845],{"type":55,"value":880},{"type":55,"value":2847}," is configured, ask the user to check for a ",{"type":49,"tag":67,"props":2849,"children":2850},{},[2851],{"type":55,"value":2852},"Replay",{"type":55,"value":2854}," button next to the feedback entry in the dashboard.",{"type":49,"tag":58,"props":2856,"children":2857},{},[2858],{"type":55,"value":2859},"After the user confirms everything works, mention:",{"type":49,"tag":110,"props":2861,"children":2862},{},[2863,2881],{"type":49,"tag":114,"props":2864,"children":2865},{},[2866,2868,2872,2874,2879],{"type":55,"value":2867},"They can subscribe Slack channels to receive feedback notifications: go to the flag's ",{"type":49,"tag":67,"props":2869,"children":2870},{},[2871],{"type":55,"value":2828},{"type":55,"value":2873}," tab → ",{"type":49,"tag":67,"props":2875,"children":2876},{},[2877],{"type":55,"value":2878},"Subscribe",{"type":55,"value":2880}," → select Slack channels (requires the LaunchDarkly Slack app).",{"type":49,"tag":114,"props":2882,"children":2883},{},[2884],{"type":55,"value":2885},"Provide the direct link to the flag's Feedback tab so they can bookmark it for monitoring.",{"type":49,"tag":90,"props":2887,"children":2889},{"id":2888},"edge-cases",[2890],{"type":55,"value":2891},"Edge Cases",{"type":49,"tag":892,"props":2893,"children":2894},{},[2895,2911],{"type":49,"tag":896,"props":2896,"children":2897},{},[2898],{"type":49,"tag":900,"props":2899,"children":2900},{},[2901,2906],{"type":49,"tag":904,"props":2902,"children":2903},{},[2904],{"type":55,"value":2905},"Situation",{"type":49,"tag":904,"props":2907,"children":2908},{},[2909],{"type":55,"value":2910},"Action",{"type":49,"tag":915,"props":2912,"children":2913},{},[2914,2932,2949,2966,2986,3018,3031,3051,3064],{"type":49,"tag":900,"props":2915,"children":2916},{},[2917,2922],{"type":49,"tag":922,"props":2918,"children":2919},{},[2920],{"type":55,"value":2921},"No LD SDK found",{"type":49,"tag":922,"props":2923,"children":2924},{},[2925,2930],{"type":49,"tag":67,"props":2926,"children":2927},{},[2928],{"type":55,"value":2929},"STOP",{"type":55,"value":2931}," — handled by Check 1",{"type":49,"tag":900,"props":2933,"children":2934},{},[2935,2940],{"type":49,"tag":922,"props":2936,"children":2937},{},[2938],{"type":55,"value":2939},"Server-side SDK only, no client SDK",{"type":49,"tag":922,"props":2941,"children":2942},{},[2943,2947],{"type":49,"tag":67,"props":2944,"children":2945},{},[2946],{"type":55,"value":2929},{"type":55,"value":2948}," — handled by Check 2",{"type":49,"tag":900,"props":2950,"children":2951},{},[2952,2957],{"type":49,"tag":922,"props":2953,"children":2954},{},[2955],{"type":55,"value":2956},"SDK version \u003C 3.0",{"type":49,"tag":922,"props":2958,"children":2959},{},[2960,2964],{"type":49,"tag":67,"props":2961,"children":2962},{},[2963],{"type":55,"value":2929},{"type":55,"value":2965}," — handled by Check 3",{"type":49,"tag":900,"props":2967,"children":2968},{},[2969,2981],{"type":49,"tag":922,"props":2970,"children":2971},{},[2972,2974,2979],{"type":55,"value":2973},"Existing ",{"type":49,"tag":118,"props":2975,"children":2977},{"className":2976},[],[2978],{"type":55,"value":221},{"type":55,"value":2980}," function found",{"type":49,"tag":922,"props":2982,"children":2983},{},[2984],{"type":55,"value":2985},"Reuse it, skip Step 5 — handled by Check 4",{"type":49,"tag":900,"props":2987,"children":2988},{},[2989,3006],{"type":49,"tag":922,"props":2990,"children":2991},{},[2992,2994,2999,3000,3005],{"type":55,"value":2993},"React SDK (",{"type":49,"tag":118,"props":2995,"children":2997},{"className":2996},[],[2998],{"type":55,"value":438},{"type":55,"value":809},{"type":49,"tag":118,"props":3001,"children":3003},{"className":3002},[],[3004],{"type":55,"value":449},{"type":55,"value":458},{"type":49,"tag":922,"props":3007,"children":3008},{},[3009,3011,3016],{"type":55,"value":3010},"Access client via ",{"type":49,"tag":118,"props":3012,"children":3014},{"className":3013},[],[3015],{"type":55,"value":2489},{"type":55,"value":3017}," hook instead of a direct reference",{"type":49,"tag":900,"props":3019,"children":3020},{},[3021,3026],{"type":49,"tag":922,"props":3022,"children":3023},{},[3024],{"type":55,"value":3025},"Flag doesn't have client-side availability",{"type":49,"tag":922,"props":3027,"children":3028},{},[3029],{"type":55,"value":3030},"User must enable it in the flag's Advanced Controls",{"type":49,"tag":900,"props":3032,"children":3033},{},[3034,3039],{"type":49,"tag":922,"props":3035,"children":3036},{},[3037],{"type":55,"value":3038},"Observability not installed",{"type":49,"tag":922,"props":3040,"children":3041},{},[3042,3044,3049],{"type":55,"value":3043},"Skip the ",{"type":49,"tag":118,"props":3045,"children":3047},{"className":3046},[],[3048],{"type":55,"value":1942},{"type":55,"value":3050}," field; session replay won't be available",{"type":49,"tag":900,"props":3052,"children":3053},{},[3054,3059],{"type":49,"tag":922,"props":3055,"children":3056},{},[3057],{"type":55,"value":3058},"No design system detected",{"type":49,"tag":922,"props":3060,"children":3061},{},[3062],{"type":55,"value":3063},"Use the template component with minimal inline styles as a starting point",{"type":49,"tag":900,"props":3065,"children":3066},{},[3067,3072],{"type":49,"tag":922,"props":3068,"children":3069},{},[3070],{"type":55,"value":3071},"Multiple flags need feedback",{"type":49,"tag":922,"props":3073,"children":3074},{},[3075,3077,3082],{"type":55,"value":3076},"Create separate ",{"type":49,"tag":118,"props":3078,"children":3080},{"className":3079},[],[3081],{"type":55,"value":221},{"type":55,"value":3083}," calls per flag; each widget targets one flag key",{"type":49,"tag":90,"props":3085,"children":3087},{"id":3086},"what-not-to-do",[3088],{"type":55,"value":3089},"What NOT to Do",{"type":49,"tag":110,"props":3091,"children":3092},{},[3093,3098,3103,3122,3127],{"type":49,"tag":114,"props":3094,"children":3095},{},[3096],{"type":55,"value":3097},"Don't ship the unstyled template component to production — always adapt to the project's design system.",{"type":49,"tag":114,"props":3099,"children":3100},{},[3101],{"type":55,"value":3102},"Don't add multiple feedback widgets on the same screen.",{"type":49,"tag":114,"props":3104,"children":3105},{},[3106,3108,3113,3115,3121],{"type":55,"value":3107},"Don't forget to call ",{"type":49,"tag":118,"props":3109,"children":3111},{"className":3110},[],[3112],{"type":55,"value":2007},{"type":55,"value":3114}," after ",{"type":49,"tag":118,"props":3116,"children":3118},{"className":3117},[],[3119],{"type":55,"value":3120},"client.track()",{"type":55,"value":1555},{"type":49,"tag":114,"props":3123,"children":3124},{},[3125],{"type":55,"value":3126},"Don't hardcode flag keys — use the project's existing constant\u002Fconfig pattern for flag keys.",{"type":49,"tag":114,"props":3128,"children":3129},{},[3130],{"type":55,"value":3131},"Don't send feedback from server-side code — this is a client-side feature only.",{"type":49,"tag":90,"props":3133,"children":3135},{"id":3134},"templates",[3136],{"type":55,"value":3137},"Templates",{"type":49,"tag":58,"props":3139,"children":3140},{},[3141,3143,3147],{"type":55,"value":3142},"Code templates live in ",{"type":49,"tag":556,"props":3144,"children":3145},{"href":1149},[3146],{"type":55,"value":1149},{"type":55,"value":3148}," alongside the SDK lists:",{"type":49,"tag":892,"props":3150,"children":3151},{},[3152,3168],{"type":49,"tag":896,"props":3153,"children":3154},{},[3155],{"type":49,"tag":900,"props":3156,"children":3157},{},[3158,3163],{"type":49,"tag":904,"props":3159,"children":3160},{},[3161],{"type":55,"value":3162},"File",{"type":49,"tag":904,"props":3164,"children":3165},{},[3166],{"type":55,"value":3167},"Description",{"type":49,"tag":915,"props":3169,"children":3170},{},[3171,3194,3229],{"type":49,"tag":900,"props":3172,"children":3173},{},[3174,3182],{"type":49,"tag":922,"props":3175,"children":3176},{},[3177],{"type":49,"tag":556,"props":3178,"children":3179},{"href":1518},[3180],{"type":55,"value":3181},"sendFeedback.ts",{"type":49,"tag":922,"props":3183,"children":3184},{},[3185,3187,3192],{"type":55,"value":3186},"Utility that sends the ",{"type":49,"tag":118,"props":3188,"children":3190},{"className":3189},[],[3191],{"type":55,"value":231},{"type":55,"value":3193}," tracking event, with session replay support",{"type":49,"tag":900,"props":3195,"children":3196},{},[3197,3204],{"type":49,"tag":922,"props":3198,"children":3199},{},[3200],{"type":49,"tag":556,"props":3201,"children":3202},{"href":2045},[3203],{"type":55,"value":2048},{"type":49,"tag":922,"props":3205,"children":3206},{},[3207,3209,3214,3215,3221,3222,3228],{"type":55,"value":3208},"Popover with text area + configurable sentiment icons (",{"type":49,"tag":118,"props":3210,"children":3212},{"className":3211},[],[3213],{"type":55,"value":2056},{"type":55,"value":809},{"type":49,"tag":118,"props":3216,"children":3218},{"className":3217},[],[3219],{"type":55,"value":3220},"\"smileys\"",{"type":55,"value":809},{"type":49,"tag":118,"props":3223,"children":3225},{"className":3224},[],[3226],{"type":55,"value":3227},"\"none\"",{"type":55,"value":458},{"type":49,"tag":900,"props":3230,"children":3231},{},[3232,3239],{"type":49,"tag":922,"props":3233,"children":3234},{},[3235],{"type":49,"tag":556,"props":3236,"children":3237},{"href":2095},[3238],{"type":55,"value":2098},{"type":49,"tag":922,"props":3240,"children":3241},{},[3242,3244,3249,3250,3255],{"type":55,"value":3243},"Inline one-click sentiment buttons (",{"type":49,"tag":118,"props":3245,"children":3247},{"className":3246},[],[3248],{"type":55,"value":2056},{"type":55,"value":809},{"type":49,"tag":118,"props":3251,"children":3253},{"className":3252},[],[3254],{"type":55,"value":3220},{"type":55,"value":458},{"type":49,"tag":58,"props":3257,"children":3258},{},[3259],{"type":55,"value":3260},"All templates are TypeScript — for JavaScript projects, adapt by removing type annotations. Templates include inline SVG icons and work without external icon libraries. Adapt them to the project's design system and pass the user's prompt text as a prop.",{"type":49,"tag":90,"props":3262,"children":3264},{"id":3263},"references",[3265],{"type":55,"value":3266},"References",{"type":49,"tag":110,"props":3268,"children":3269},{},[3270,3281,3291],{"type":49,"tag":114,"props":3271,"children":3272},{},[3273],{"type":49,"tag":556,"props":3274,"children":3278},{"href":3275,"rel":3276},"https:\u002F\u002Flaunchdarkly.com\u002Fdocs\u002Fsdk\u002Ffeatures\u002Fuser-feedback",[3277],"nofollow",[3279],{"type":55,"value":3280},"Official Docs: User feedback SDK",{"type":49,"tag":114,"props":3282,"children":3283},{},[3284],{"type":49,"tag":556,"props":3285,"children":3288},{"href":3286,"rel":3287},"https:\u002F\u002Flaunchdarkly.com\u002Fdocs\u002Fhome\u002Freleases\u002Fuser-feedback",[3277],[3289],{"type":55,"value":3290},"Official Docs: Viewing feedback",{"type":49,"tag":114,"props":3292,"children":3293},{},[3294],{"type":49,"tag":556,"props":3295,"children":3298},{"href":3296,"rel":3297},"https:\u002F\u002Flaunchdarkly.com\u002Fdocs\u002Ftutorials\u002Fcollect-qualitative-user-feedback-homepage",[3277],[3299],{"type":55,"value":3300},"Tutorial: Collecting user feedback",{"type":49,"tag":90,"props":3302,"children":3304},{"id":3303},"example-flows",[3305],{"type":55,"value":3306},"Example Flows",{"type":49,"tag":58,"props":3308,"children":3309},{},[3310],{"type":55,"value":3311},"These show how the decision tree plays out for common scenarios.",{"type":49,"tag":58,"props":3313,"children":3314},{},[3315,3320,3322,3327,3329,3335,3337,3342,3344,3349,3351,3357,3359,3365,3367,3373,3374,3379],{"type":49,"tag":67,"props":3316,"children":3317},{},[3318],{"type":55,"value":3319},"Happy path — React + TypeScript, new flag, thumbs popover:",{"type":55,"value":3321},"\nStep 0 → welcome. Step 1 → finds ",{"type":49,"tag":118,"props":3323,"children":3325},{"className":3324},[],[3326],{"type":55,"value":438},{"type":55,"value":3328},", React + Tailwind, no existing feedback. Step 2 → user picks a new flag ",{"type":49,"tag":118,"props":3330,"children":3332},{"className":3331},[],[3333],{"type":55,"value":3334},"checkout-redesign",{"type":55,"value":3336},", prompt \"How do you feel about the new checkout?\", thumbs style, placed below the order summary. Step 3 → creates flag via ",{"type":49,"tag":118,"props":3338,"children":3340},{"className":3339},[],[3341],{"type":55,"value":145},{"type":55,"value":3343},". Step 4 → user approves. Step 5 → creates ",{"type":49,"tag":118,"props":3345,"children":3347},{"className":3346},[],[3348],{"type":55,"value":3181},{"type":55,"value":3350}," in ",{"type":49,"tag":118,"props":3352,"children":3354},{"className":3353},[],[3355],{"type":55,"value":3356},"lib\u002Fld\u002F",{"type":55,"value":3358},". Step 6 → creates ",{"type":49,"tag":118,"props":3360,"children":3362},{"className":3361},[],[3363],{"type":55,"value":3364},"FeedbackPopover.tsx",{"type":55,"value":3366}," adapted to Tailwind, wires it into ",{"type":49,"tag":118,"props":3368,"children":3370},{"className":3369},[],[3371],{"type":55,"value":3372},"CheckoutPage.tsx",{"type":55,"value":2050},{"type":49,"tag":118,"props":3375,"children":3377},{"className":3376},[],[3378],{"type":55,"value":2489},{"type":55,"value":3380},". Step 7 → build passes, event fires.",{"type":49,"tag":58,"props":3382,"children":3383},{},[3384,3389,3391,3397,3399,3404,3406,3411,3413,3418],{"type":49,"tag":67,"props":3385,"children":3386},{},[3387],{"type":55,"value":3388},"Existing sendFeedback — reuse and skip:",{"type":55,"value":3390},"\nStep 1 → Check 4 finds ",{"type":49,"tag":118,"props":3392,"children":3394},{"className":3393},[],[3395],{"type":55,"value":3396},"src\u002Futils\u002FsendFeedback.ts",{"type":55,"value":3398}," already calling ",{"type":49,"tag":118,"props":3400,"children":3402},{"className":3401},[],[3403],{"type":55,"value":717},{"type":55,"value":3405},". Records the import path. Step 2 → gathers requirements normally. Steps 3–4 → as usual. Step 5 → ",{"type":49,"tag":67,"props":3407,"children":3408},{},[3409],{"type":55,"value":3410},"skipped",{"type":55,"value":3412}," (reuses existing function). Step 6 → builds widget, imports ",{"type":49,"tag":118,"props":3414,"children":3416},{"className":3415},[],[3417],{"type":55,"value":221},{"type":55,"value":3419}," from the existing path. Step 7 → build passes, event fires.",{"type":49,"tag":58,"props":3421,"children":3422},{},[3423,3428,3430,3436,3438,3444,3446],{"type":49,"tag":67,"props":3424,"children":3425},{},[3426],{"type":55,"value":3427},"Server-side SDK — early STOP:",{"type":55,"value":3429},"\nStep 1 → Check 1 finds ",{"type":49,"tag":118,"props":3431,"children":3433},{"className":3432},[],[3434],{"type":55,"value":3435},"@launchdarkly\u002Fnode-server-sdk",{"type":55,"value":3437},". Check 2 → it's in ",{"type":49,"tag":118,"props":3439,"children":3441},{"className":3440},[],[3442],{"type":55,"value":3443},"server-side-sdk-list.md",{"type":55,"value":3445},", no client SDK present. → Informs user that qualitative feedback requires a client-side SDK. ",{"type":49,"tag":67,"props":3447,"children":3448},{},[3449],{"type":55,"value":3450},"STOP.",{"type":49,"tag":58,"props":3452,"children":3453},{},[3454,3459,3461,3466],{"type":49,"tag":67,"props":3455,"children":3456},{},[3457],{"type":55,"value":3458},"No design system — minimal styles:",{"type":55,"value":3460},"\nStep 1 → finds ",{"type":49,"tag":118,"props":3462,"children":3464},{"className":3463},[],[3465],{"type":55,"value":416},{"type":55,"value":3467}," v3.2, no React, no Tailwind, no component library. Step 6 → uses the template with inline styles as the baseline, adapts to the project's vanilla JS patterns and existing CSS conventions.",{"type":49,"tag":3469,"props":3470,"children":3471},"style",{},[3472],{"type":55,"value":3473},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"items":3475,"total":3561},[3476,3493,3502,3516,3527,3539,3547],{"slug":3477,"name":3477,"fn":3478,"description":3479,"org":3480,"tags":3481,"stars":26,"repoUrl":27,"updatedAt":3492},"agent-graphs","create and manage agent graphs","Create and manage agent graphs — directed graphs of configs connected by edges with handoff logic. Use when building multi-agent workflows where configs route to each other.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3482,3485,3488,3489],{"name":3483,"slug":3484,"type":15},"Agents","agents",{"name":3486,"slug":3487,"type":15},"Architecture","architecture",{"name":9,"slug":8,"type":15},{"name":3490,"slug":3491,"type":15},"Multi-Agent","multi-agent","2026-07-28T05:33:33.709407",{"slug":3494,"name":3494,"fn":3495,"description":3496,"org":3497,"tags":3498,"stars":26,"repoUrl":27,"updatedAt":3501},"aiconfig-agent-graphs","manage agent graphs","DEPRECATED redirect — this skill was renamed to agent-graphs. Do not use this skill; invoke agent-graphs instead. Kept only so old references to aiconfig-agent-graphs still point users to the new name.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3499,3500],{"name":3483,"slug":3484,"type":15},{"name":3486,"slug":3487,"type":15},"2026-05-22T06:55:56.527064",{"slug":3503,"name":3503,"fn":3504,"description":3505,"org":3506,"tags":3507,"stars":26,"repoUrl":27,"updatedAt":3515},"aiconfig-ai-metrics","manage built-in AI metrics","DEPRECATED redirect — this skill was renamed to built-in-metrics. Do not use this skill; invoke built-in-metrics instead. Kept only so old references to aiconfig-ai-metrics still point users to the new name.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3508,3511,3512],{"name":3509,"slug":3510,"type":15},"Analytics","analytics",{"name":9,"slug":8,"type":15},{"name":3513,"slug":3514,"type":15},"Metrics","metrics","2026-05-22T06:55:53.858749",{"slug":3517,"name":3517,"fn":3518,"description":3519,"org":3520,"tags":3521,"stars":26,"repoUrl":27,"updatedAt":3526},"aiconfig-create","redirect to configs-create skill","DEPRECATED redirect — this skill was renamed to configs-create. Do not use this skill; invoke configs-create instead. Kept only so old references to aiconfig-create still point users to the new name.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3522,3523],{"name":9,"slug":8,"type":15},{"name":3524,"slug":3525,"type":15},"Reference","reference","2026-05-22T06:55:41.790591",{"slug":3528,"name":3528,"fn":3529,"description":3530,"org":3531,"tags":3532,"stars":26,"repoUrl":27,"updatedAt":3538},"aiconfig-custom-metrics","configure custom metrics in LaunchDarkly","DEPRECATED redirect — this skill was renamed to custom-metrics. Do not use this skill; invoke custom-metrics instead. Kept only so old references to aiconfig-custom-metrics still point users to the new name.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3533,3534,3537],{"name":3509,"slug":3510,"type":15},{"name":3535,"slug":3536,"type":15},"Feature Flags","feature-flags",{"name":9,"slug":8,"type":15},"2026-05-22T06:55:57.84851",{"slug":3540,"name":3540,"fn":3541,"description":3542,"org":3543,"tags":3544,"stars":26,"repoUrl":27,"updatedAt":3546},"aiconfig-migrate","redirect to migrate skill","DEPRECATED redirect — this skill was renamed to migrate. Do not use this skill; invoke migrate instead. Kept only so old references to aiconfig-migrate still point users to the new name.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3545],{"name":3524,"slug":3525,"type":15},"2026-05-22T06:55:44.464733",{"slug":3548,"name":3548,"fn":3549,"description":3550,"org":3551,"tags":3552,"stars":26,"repoUrl":27,"updatedAt":3560},"aiconfig-online-evals","run online evaluations","DEPRECATED redirect — this skill was renamed to online-evals. Do not use this skill; invoke online-evals instead. Kept only so old references to aiconfig-online-evals still point users to the new name.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3553,3556,3557],{"name":3554,"slug":3555,"type":15},"Evals","evals",{"name":9,"slug":8,"type":15},{"name":3558,"slug":3559,"type":15},"Testing","testing","2026-05-22T06:55:55.179617",50,{"items":3563,"total":3561},[3564,3571,3576,3582,3587,3593,3597,3603,3614,3623,3633,3642],{"slug":3477,"name":3477,"fn":3478,"description":3479,"org":3565,"tags":3566,"stars":26,"repoUrl":27,"updatedAt":3492},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3567,3568,3569,3570],{"name":3483,"slug":3484,"type":15},{"name":3486,"slug":3487,"type":15},{"name":9,"slug":8,"type":15},{"name":3490,"slug":3491,"type":15},{"slug":3494,"name":3494,"fn":3495,"description":3496,"org":3572,"tags":3573,"stars":26,"repoUrl":27,"updatedAt":3501},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3574,3575],{"name":3483,"slug":3484,"type":15},{"name":3486,"slug":3487,"type":15},{"slug":3503,"name":3503,"fn":3504,"description":3505,"org":3577,"tags":3578,"stars":26,"repoUrl":27,"updatedAt":3515},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3579,3580,3581],{"name":3509,"slug":3510,"type":15},{"name":9,"slug":8,"type":15},{"name":3513,"slug":3514,"type":15},{"slug":3517,"name":3517,"fn":3518,"description":3519,"org":3583,"tags":3584,"stars":26,"repoUrl":27,"updatedAt":3526},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3585,3586],{"name":9,"slug":8,"type":15},{"name":3524,"slug":3525,"type":15},{"slug":3528,"name":3528,"fn":3529,"description":3530,"org":3588,"tags":3589,"stars":26,"repoUrl":27,"updatedAt":3538},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3590,3591,3592],{"name":3509,"slug":3510,"type":15},{"name":3535,"slug":3536,"type":15},{"name":9,"slug":8,"type":15},{"slug":3540,"name":3540,"fn":3541,"description":3542,"org":3594,"tags":3595,"stars":26,"repoUrl":27,"updatedAt":3546},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3596],{"name":3524,"slug":3525,"type":15},{"slug":3548,"name":3548,"fn":3549,"description":3550,"org":3598,"tags":3599,"stars":26,"repoUrl":27,"updatedAt":3560},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3600,3601,3602],{"name":3554,"slug":3555,"type":15},{"name":9,"slug":8,"type":15},{"name":3558,"slug":3559,"type":15},{"slug":3604,"name":3604,"fn":3605,"description":3606,"org":3607,"tags":3608,"stars":26,"repoUrl":27,"updatedAt":3613},"aiconfig-projects","manage AI configuration projects","DEPRECATED redirect — this skill was renamed to projects. Do not use this skill; invoke projects instead. Kept only so old references to aiconfig-projects still point users to the new name.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3609,3612],{"name":3610,"slug":3611,"type":15},"Configuration","configuration",{"name":9,"slug":8,"type":15},"2026-05-22T06:55:48.522229",{"slug":3615,"name":3615,"fn":3616,"description":3617,"org":3618,"tags":3619,"stars":26,"repoUrl":27,"updatedAt":3622},"aiconfig-snippets","manage AI configuration snippets","DEPRECATED redirect — this skill was renamed to snippets. Do not use this skill; invoke snippets instead. Kept only so old references to aiconfig-snippets still point users to the new name.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3620,3621],{"name":3610,"slug":3611,"type":15},{"name":9,"slug":8,"type":15},"2026-05-22T06:55:47.16557",{"slug":3624,"name":3624,"fn":3625,"description":3626,"org":3627,"tags":3628,"stars":26,"repoUrl":27,"updatedAt":3632},"aiconfig-targeting","configure LaunchDarkly targeting rules","DEPRECATED redirect — this skill was renamed to configs-targeting. Do not use this skill; invoke configs-targeting instead. Kept only so old references to aiconfig-targeting still point users to the new name.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3629,3630,3631],{"name":3610,"slug":3611,"type":15},{"name":3535,"slug":3536,"type":15},{"name":9,"slug":8,"type":15},"2026-05-22T06:55:49.845445",{"slug":3634,"name":3634,"fn":3635,"description":3636,"org":3637,"tags":3638,"stars":26,"repoUrl":27,"updatedAt":3641},"aiconfig-tools","redirect to tools skill","DEPRECATED redirect — this skill was renamed to tools. Do not use this skill; invoke tools instead. Kept only so old references to aiconfig-tools still point users to the new name.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3639,3640],{"name":9,"slug":8,"type":15},{"name":3524,"slug":3525,"type":15},"2026-05-22T06:55:39.13373",{"slug":3643,"name":3643,"fn":3644,"description":3645,"org":3646,"tags":3647,"stars":26,"repoUrl":27,"updatedAt":3650},"aiconfig-update","redirect to configs-update skill","DEPRECATED redirect — this skill was renamed to configs-update. Do not use this skill; invoke configs-update instead. Kept only so old references to aiconfig-update still point users to the new name.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3648,3649],{"name":9,"slug":8,"type":15},{"name":3524,"slug":3525,"type":15},"2026-05-22T06:55:40.464884"]