-
Notifications
You must be signed in to change notification settings - Fork 5
feat(self-driving): Self-driving setup skills for Wizard #192
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
bcd51e2
a5b5be7
b08cebd
4fea255
634c620
2550ee9
3dcb03e
3e10a6e
901140c
a9f2d00
e6b98f7
d10f51a
dae4dd0
3d36929
8af2177
efb250e
0924d1e
4e6b24f
d02da70
63b1448
e7788ad
83ca4c9
e0c238f
df498c8
bf143f6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| type: skill | ||
| template: description.md | ||
| description: Set up PostHog Self-driving — enable the right signal sources, connect GitHub, tune the scout fleet, and design custom scouts | ||
| tags: [signals, self-driving] | ||
| references: | ||
| preamble: "**Read ONLY this file.** Do not read any other reference file until this one tells you to." | ||
| variants: | ||
| - id: setup | ||
| display_name: PostHog Self-driving | ||
| docs_urls: [] | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| # PostHog Self-driving setup | ||
|
|
||
| This skill configures PostHog Signals for a project that already has PostHog installed: it switches on the signal sources (the inbox's "Responders") that match what the product actually uses, makes sure the GitHub integration is connected so Signals can research and fix issues in code, tunes the scout fleet, designs custom scouts for the watchable surfaces the canonical fleet doesn't cover (always proposed to the user first). Organization-level AI data processing approval — which everything downstream depends on — is enforced by the wizard itself before this skill runs. | ||
|
|
||
| The wizard's run prompt supplies the project URLs (integrations settings, organization AI settings, new warehouse source, Signals inbox). Use those exact URLs whenever a step sends the user to the browser. | ||
|
|
||
| ## Workflow | ||
|
|
||
| The setup runs as an 8-step chain: | ||
|
|
||
| {workflow} | ||
|
|
||
| Each step file points to the next. Run them in order. **Start by reading `references/1-check-access.md`** (relative to this skill's directory — typically `.claude/skills/self-driving-setup/references/1-check-access.md`). Don't read ahead. Don't re-read a step once you've passed it. Don't re-read SKILL.md. | ||
|
|
||
| ## Ground rules | ||
|
|
||
| - **Trust the setup report.** `./posthog-setup-report.md` is ground truth for what is instrumented. Scan the codebase only for what the report won't cover. | ||
| - **Every write must be idempotent.** List before you create. A duplicate `inbox-source-configs-create` returns 400 — recover by finding the existing row's `id` and calling `inbox-source-configs-partial-update` with `enabled: true`. | ||
| - **Never disable a source the user already enabled.** You only switch things on (and tune scouts off); existing enabled rows are someone's deliberate choice. | ||
| - **Never enable a connected-tool source the user hasn't confirmed they use.** GitHub Issues, Linear, Zendesk, and pganalyze are ask-then-connect, never blind. | ||
| - **Stay off the internal surfaces.** Don't call `signals-scout-emit-signal` or any scratchpad-write tool, and don't change a scout's `emit` flag or `run_interval_minutes` — on configs, this skill only flips `enabled`. **Canonical scout bodies are never edited.** New scout skills are created in exactly one place: step 6b, and only ones the user approved there. | ||
| - **Batch your questions.** `wizard_ask` has a small per-run budget; one multi-select beats four yes/nos. | ||
| - **Decline goes first.** Every `wizard_ask` that offers choices must include a plain-language decline option (skip / none / "keep what's there"), and it must be the **first** option so it is the default highlight — an accidental `enter` then declines instead of committing the user to something. The **one exception is step 3's GitHub gate**: the run cannot proceed without GitHub, so there the affirmative ("Done — I've installed it") stays first and the decline ("I can't connect right now", which aborts) stays last. | ||
|
|
||
| ## Live activity — `[STATUS]` | ||
|
|
||
| The "Working on …" banner reads from `[STATUS]` lines you emit in plain text. Each step file lists the exact string to emit when it starts. Use them — they're cheap. Don't invent your own. | ||
|
|
||
| ## Abort statuses | ||
|
|
||
| Report aborts with `[ABORT]`-prefixed messages. The wizard catches these, renders a friendly explanation, and stops the run — don't halt yourself. The exact strings (the wizard matches them verbatim): | ||
|
|
||
| - `[ABORT] self-driving is not available for this project` | ||
| - `[ABORT] github connection declined` | ||
| - `[ABORT] requires-interactive-mode` | ||
|
|
||
| Tool failures on individual sources or scouts are **not** abort conditions — record them as follow-ups and keep going. Only the three cases above end the run. | ||
|
sortafreel marked this conversation as resolved.
|
||
|
|
||
| ## Framework guidelines | ||
|
|
||
| {commandments} | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| --- | ||
| next_step: 2-read-context.md | ||
| --- | ||
|
|
||
| # Step 1 — Check access | ||
|
|
||
| Verify the Signals API is available for this project before touching anything. Self-driving is in beta and enabled per team by PostHog; there is no flag you can read, so the API itself is the probe. | ||
|
|
||
| ## Status | ||
|
|
||
| Emit: | ||
|
|
||
| ``` | ||
| [STATUS] Checking Self-driving access | ||
| ``` | ||
|
|
||
| ## Tools | ||
|
|
||
| Load via `ToolSearch select:mcp__posthog-wizard__inbox-source-configs-list` (subsequent steps load their own tools). | ||
|
|
||
| ## Do | ||
|
|
||
| 1. Call `inbox-source-configs-list`. | ||
| 2. **Success — including an empty list** — means the API is reachable: proceed. (The probe can't prove beta enrollment — the wizard's detect step and the beta flags own that — but it's the strongest signal available to you.) Keep the returned rows: step 2 and step 4 use them as the already-enabled baseline. Mark your access task completed and continue. | ||
|
Comment on lines
+23
to
+24
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, but the endpoint powering No reason, other than the scope not being available, but that would not mean "self-driving is not available for this project", that would means that something is wrong with authentication. What's this whole step for then?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Initially it was about FFs, but we decided to drop all FFs. I still find it valuable, as it checks that MCP works, sources configs are pulled, and so on, before we do any edits. Plus, I 100% can imagine us adding new stuff that we would want FF in the future, so I'll keep it. |
||
| 3. A permission error (403), not-found (404), or "scope" error means Self-driving is not available to this caller. Emit exactly: | ||
|
|
||
| ``` | ||
| [ABORT] self-driving is not available for this project | ||
| ``` | ||
|
|
||
| and stop — the wizard renders the explanation. | ||
|
|
||
| Do not retry the probe more than once; a transient network failure is worth one retry, an authorization error is not. | ||
|
|
||
| A 5xx error after a retry is also not access denial — abort is wrong there. Surface it as a plain error instead: report the failure and stop without the `[ABORT]` marker so the wizard treats it as an error, not a clean refusal. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| --- | ||
| next_step: 3-github.md | ||
| --- | ||
|
|
||
| # Step 2 — Read context | ||
|
|
||
| Build a picture of what this product uses so every later decision (which sources to enable, which scouts to keep) is grounded in evidence, not guesses. **Read-only step** — no writes anywhere. | ||
|
|
||
| ## Status | ||
|
|
||
| Emit: | ||
|
|
||
| ``` | ||
| [STATUS] Reading project context | ||
| ``` | ||
|
|
||
| ## Tools | ||
|
|
||
| Load via `ToolSearch select:Read,Glob,Grep,mcp__posthog-wizard__signals-scout-project-profile-get,mcp__posthog-wizard__query-session-recordings-list,mcp__posthog-wizard__survey-list,mcp__posthog-wizard__error-issue-list`. | ||
|
|
||
| ## Do | ||
|
|
||
| 1. **Read `./posthog-setup-report.md`.** It is ground truth for what the base integration instrumented **in this repo**: events, error tracking, feature flags. Do not re-derive what it already states. It is NOT authority over project-level facts — session replay in particular may be instrumented in another repo or via the snippet, so the report can rule replay in but never out (step 4 probes the server for that). | ||
|
Comment on lines
+22
to
+23
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Worth clarifying that this won't be present if the codebase was set up with PostHog a while ago. (Or never)
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yup, updated. |
||
|
|
||
| 2. **Call `signals-scout-project-profile-get`.** It returns products in use, connected integrations, warehouse sources, and the signal source configs split enabled/disabled — one call instead of four. **Tolerate failure**: it can 404 or error on a team without a profile yet. If it fails, fall back to the step-1 source list and the report; do not retry more than once and do not abort. **Note "profile unavailable" in your checklist** — a profile 404 is expected on a first-run team, so any later decision that relies only on the profile must record "unknown", not a confident negative. | ||
|
|
||
| 3. **Server-side product usage.** The run prompt's "Project state" block is authoritative for the opt-ins it lists (session replay recording, exception autocapture, surveys): **opt-in ON = product enabled**, even if no data has arrived yet. Where the block says OFF/unknown and the repo gave no signal, spend ONE cheap probe each for usage evidence (tolerate 403/404 → record "unknown"): | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe I'm being a bad LLM here:
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Each wizard run has a prompt ( |
||
| - `query-session-recordings-list` — any recording → replay in use | ||
| - `survey-list` — any survey → surveys in use | ||
| - `error-issue-list` — any issue → error tracking in use, even when this repo doesn't instrument it | ||
|
|
||
| 4. **Light scan for what the report, profile, and server state won't cover.** Targeted lookups only — package manifests, config files, a grep or two. You are answering these questions: | ||
| - **Revenue**: is there a payment SDK (Stripe, Paddle, LemonSqueezy, RevenueCat…) or revenue events? | ||
| - **Surveys**: does the code or profile show PostHog surveys in use? | ||
| - **AI/LLM**: are there `$ai_*` events, an LLM SDK, or LLM analytics in the profile? | ||
| - **Logs**: is the PostHog logs product in use (per the profile)? | ||
| - **CSP**: is a Content-Security-Policy with PostHog CSP reporting configured? | ||
| - **Support**: does the team use PostHog support/conversations (per the profile)? | ||
| - **Issue trackers**: any hints of Linear, Zendesk, or pganalyze (you will still ask in step 5 — hints only shape the question, they never authorize enabling). | ||
|
Comment on lines
+32
to
+39
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think error tracking, replay, and analytics are all worth including in the code scan as well, as you might e.g. not yet have errors in PostHog, but indeed have error tracking hooked up
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fair enough, not sure what "analytics" means (general scout should cover regular analytics), but added bias toward error tracking/replay. |
||
|
|
||
| Do NOT crawl the whole source tree. If a question can't be answered cheaply, record "unknown" and move on — unknowns default to asking the user about sources; for surface-specific scouts, an unconfirmed surface is not justification to keep them on (step 6 disables them without evidence). | ||
|
|
||
| 5. **Write down your working checklist** (in your own notes, not a file): candidate native sources, candidate connected tools, candidate scout disables, GitHub status if the profile revealed it. Steps 4–6 consume this. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| --- | ||
| next_step: 4-sources.md | ||
| --- | ||
|
|
||
| # Step 3 — Connect GitHub (required) | ||
|
|
||
| The GitHub integration gives Signals code access: it is how findings get researched against the actual repository and how Self-driving opens fixes. **Setup cannot finish without it.** This is the GitHub App *integration* — distinct from the optional "GitHub Issues" warehouse source in step 5. | ||
|
|
||
| ## Status | ||
|
|
||
| Emit: | ||
|
|
||
| ``` | ||
| [STATUS] Checking GitHub connection | ||
| ``` | ||
|
|
||
| ## Tools | ||
|
|
||
| Load via `ToolSearch select:mcp__posthog-wizard__integrations-list,mcp__wizard-tools__wizard_ask`. | ||
|
|
||
| ## Do | ||
|
|
||
| 1. Call `integrations-list`. If any integration has `kind: "github"`, the team is already connected — record it and continue to step 4. (If step 2's project profile already showed a GitHub integration, this call just confirms it.) | ||
|
sortafreel marked this conversation as resolved.
|
||
|
|
||
| 2. If absent, build the **one-click install link** from the run prompt's project URLs — same host, project id as a path segment (the same pattern Linear uses in step 5b): | ||
|
|
||
| ``` | ||
| <posthog host>/api/environments/<project id>/integrations/authorize?kind=github | ||
| ``` | ||
|
|
||
| Opening it in the user's logged-in browser runs the GitHub App install flow directly — no settings-page hunting. Then ask: | ||
|
|
||
| ``` | ||
| { | ||
| id: "github-connect", | ||
| prompt: "Self-driving needs GitHub access to investigate findings in your code and open fixes — setup can't finish without it.\n\nOpen this link to install the PostHog GitHub App in one click, then approve access. Grant it the repos you want Self-driving to work with — include this project's repo so step 5 can also watch its issues:\n\n<github authorize URL>\n\nThen come back here.\n\n(Need to re-link an existing installation instead? Use your integrations settings: <integrations settings URL>.)", | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A couple of things about this:
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh, I see you tackled problem 2 (link wrapping) in the Wizard PR – but this didn't seem to work for me in Cursor 🤔
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Removed the re-link, noted the polling, will iterate. |
||
| kind: "single", | ||
| options: [ | ||
| { label: "Done — I've installed it", value: "done" }, | ||
| { label: "I can't connect right now", value: "cant" } | ||
| ] | ||
| } | ||
| ``` | ||
|
|
||
| 3. On **done**: call `integrations-list` again. | ||
| - GitHub present → continue to step 4. | ||
| - Still absent → tell the user it hasn't appeared yet (the install may take a few seconds to land) and re-ask with the same two options. Verify after each "done". Give this **at most 3 rounds**; on the third miss, ask one final time whether to keep waiting or exit. | ||
|
|
||
| 4. On **cant** (at any point): emit exactly: | ||
|
|
||
| ``` | ||
| [ABORT] github connection declined | ||
| ``` | ||
|
|
||
| and stop. Never continue setup without GitHub, and never leave it "half-finished" — the abort happens before this step makes any writes, and the source/scout writes only happen after GitHub is verified. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| --- | ||
| next_step: 5-connected-tools.md | ||
| --- | ||
|
|
||
| # Step 4 — Enable native signal sources | ||
|
|
||
| Switch on the PostHog-native sources (the inbox's "Responders") that match what this product actually uses, per your step-2 checklist. Conditional means conditional: a source for a surface the product doesn't have just adds noise. | ||
|
|
||
| ## Status | ||
|
|
||
| Emit: | ||
|
|
||
| ``` | ||
| [STATUS] Enabling signal sources | ||
| ``` | ||
|
|
||
| ## Tools | ||
|
|
||
| Load via `ToolSearch select:mcp__posthog-wizard__inbox-source-configs-create,mcp__posthog-wizard__inbox-source-configs-partial-update,mcp__posthog-wizard__inbox-source-configs-list`. | ||
|
|
||
| ## The write recipe (use for every source here and in step 5) | ||
|
|
||
| 1. Check the baseline list (from step 1; refresh with `inbox-source-configs-list` if you're unsure it's current). | ||
| 2. Row exists and `enabled: true` → leave it alone, record "already enabled". | ||
| 3. Row exists and `enabled: false` → `inbox-source-configs-partial-update` with `{ enabled: true }`. | ||
| 4. No row → `inbox-source-configs-create` with `{ source_product, source_type, enabled: true }`. A 400 about uniqueness means a row appeared since you listed — fall back to 3. | ||
| 5. Any other failure → record it as a follow-up and move on; a single failed source never stops the run. | ||
|
|
||
| ## Enable | ||
|
|
||
| | Source | When | Payload | | ||
| |---|---|---| | ||
| | Scout gate | **Always** — it lets the step-6 fleet's findings reach the inbox | `signals_scout` / `cross_source_issue` | | ||
| | Error tracking | Error tracking is in use anywhere: instrumented in this repo (report), exception autocapture ON (project-state block), or error issues exist (step-2 probe) | **All three rows**: `error_tracking` / `issue_created`, `error_tracking` / `issue_reopened`, `error_tracking` / `issue_spiking` — the product UI treats them as one switch | | ||
| | Session replay | Replay is enabled for the **project**: recording opt-in ON (project-state block) OR recordings exist (step-2 probe) OR the report says this repo instruments it. Opt-in ON with zero recordings still counts (recordings just haven't arrived yet). Skip only when all three say no/unknown, with reason "replay not enabled for this project" | `session_replay` / `session_analysis_cluster` — don't pass a `config`; the server injects the default sample rate. A 400 mentioning AI approval is unexpected (approval is enforced upstream) → skip this source and record a follow-up | | ||
| | Support | The team uses PostHog support/conversations (per the profile). If the profile was unavailable (step 2), don't record a confident skip — record "unknown — profile unavailable" + a follow-up to enable Support manually if they use it | `conversations` / `ticket` | | ||
|
|
||
| ## Skip — do not create | ||
|
|
||
| - `llm_analytics` (internal-only, not a user-facing responder) | ||
| - `logs` (not a v1 responder) | ||
| - Anything with `source_type` `evaluation` or `alert_state_change` | ||
| - The connected-tool sources (`github`, `linear`, `zendesk`, `pganalyze`) — those are step 5, ask-first. | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thinking we should def also ask them about non-signal sources, but ones we can connect via MCP, and are context-rich. E.g. Notion is a prime suspect here
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yup, surely need to be one of the next iterations. |
||
|
|
||
| Record every enable/skip decision with its reason — the report needs them. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,62 @@ | ||
| --- | ||
| next_step: 6-scouts.md | ||
| --- | ||
|
|
||
| # Step 5 — Connected-tool sources (ask, then connect) | ||
|
|
||
| External tools can feed the inbox too: GitHub Issues, Linear, Zendesk, and pganalyze. Each needs a **data warehouse source** before its signal source produces anything — a source row without the warehouse connection is dormant: harmless, but silent until the source syncs. Never enable one the user hasn't confirmed. | ||
|
|
||
| Two of these the run can connect **itself**: GitHub Issues, and Linear via a one-click OAuth link (dedicated connector files below). The other two — Zendesk and pganalyze — need API credentials this run never collects, so the run does **not** send the user to the UI and does **not** check whether they connected: it just arms the dormant responder and records a follow-up. The user finishes those later (a downstream reminder prompts them). | ||
|
|
||
| ## Status | ||
|
|
||
| Emit: | ||
|
|
||
| ``` | ||
| [STATUS] Offering issue-tracker integrations | ||
| ``` | ||
|
|
||
| ## Tools | ||
|
|
||
| Load via `ToolSearch select:mcp__wizard-tools__wizard_ask,mcp__posthog-wizard__external-data-sources-list` (the source-config tools from step 4 stay loaded). | ||
|
|
||
| ## Do | ||
|
|
||
| 1. Ask **once**, multi-select. **"None of these" is the first option** (the safe default — an accidental `enter` declines); order the *tools* after it, seeding with any step-2 hints so a tool you saw evidence of comes first among them: | ||
|
sortafreel marked this conversation as resolved.
|
||
|
|
||
| ``` | ||
| { | ||
| id: "connected-tools", | ||
| prompt: "Self-driving can also watch your other tools and pull their issues into the inbox. Which of these do you use?", | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: I feel "<...> and pull their issues into the inbox" undersells it a bit – something like this would be more active framing: "Self-driving can also address problems surfaced in your other tools." I do definitely believe an option like "I don't see a tool in this list" would provide really interesting data. Probs needs a wizard change to support that.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good point. updated the copy. As for custom options - yup, noted. |
||
| kind: "multi", | ||
| options: [ | ||
| { label: "None of these", value: "none" }, | ||
| { label: "GitHub Issues", value: "github-issues" }, | ||
| { label: "Linear", value: "linear" }, | ||
| { label: "Zendesk", value: "zendesk" }, | ||
| { label: "pganalyze", value: "pganalyze" } | ||
| ] | ||
| } | ||
| ``` | ||
|
|
||
| 2. Call `external-data-sources-list` once (step 2's project profile also lists warehouse sources when it exists). For each picked tool whose source already exists (`source_type` `Github` / `Linear` / `Zendesk` / `PgAnalyze`): record "already connected" — no connector flow needed, just enable its responder row (step 4 below). | ||
|
sortafreel marked this conversation as resolved.
|
||
|
|
||
| 3. Dispatch each picked tool that's still missing: | ||
|
|
||
| - **GitHub Issues** → read `references/5a-github.md` and follow it. | ||
| - **Linear** → read `references/5b-linear.md` and follow it. | ||
| - **Zendesk / pganalyze** → this run can't create their sources (it never collects the API credentials they need), so **don't ask the user to connect them and don't verify**. Just enable the dormant responder (step 4 below) and record "picked but not connected" with a follow-up. A downstream reminder prompts the user to add the warehouse source later; the responder stays dormant (harmless) and starts emitting once that source syncs. | ||
|
|
||
| 4. Enable the source row (step 4's write recipe) for every tool the user picked — created, verified, and picked-but-not-connected alike (a dormant row is harmless and saves a later trip): | ||
|
|
||
| - GitHub Issues → `github` / `issue` | ||
| - Linear → `linear` / `issue` | ||
| - Zendesk → `zendesk` / `ticket` | ||
| - pganalyze → `pganalyze` / `issue` | ||
|
|
||
| 5. Record each picked tool's final class honestly — the report consumes these verbatim: | ||
|
|
||
| - **connected by this setup** — the connector flow created the source (you have its id; the first sync starts automatically) | ||
| - **already connected** / **verified connected** — the source row was seen in `external-data-sources-list` | ||
| - **picked but not connected** — the user picked the tool but no live warehouse source exists: Zendesk / pganalyze (never connected in-run), Linear when its integration didn't land, or a GitHub Issues fallback the user skipped. **Enable the dormant responder and add a "Connect <tool>…" follow-up** — this is harmless, because a responder only emits once its warehouse source actually syncs, so a dormant row just saves the user a later trip. Record it honestly — never write that the user "confirmed connecting" and never "not used". Phrase it as "you selected <tool>, but no warehouse source was detected — the responder is enabled and stays dormant until you add the source and it starts syncing", plus the follow-up with the new-warehouse-source URL | ||
| - **not used** — the tool was **not picked** in the connected-tools multi-select. No responder, no follow-up; record "skipped (not used)". | ||
Uh oh!
There was an error while loading. Please reload this page.