Fresh session each run. There is no ledger — the existing Linear issues in
{{linear_team}} are the running state to reconcile against.
Step 1 — Read the existing themes in Linear first
Before touching any source, pull the current state of {{linear_team}} so new
feedback is reconciled, not duplicated:
- List open issues in {{linear_team}}, with their title, description, and
current quote/count body.
- Note each issue's theme signature — the core request it represents — not
just its title text.
Step 2 — Gather support threads from Plain (read-only)
Pull recent threads (since the last run's approximate window, or the last
24–48h if that's unknown). For each thread, extract:
- The specific request or complaint, in the user's own words.
- A candidate quote — the clearest single sentence expressing it.
- Enough context (account, thread link) to trace it back later.
Ignore threads that are pure support (bug already fixed, question already
answered) with no underlying feature request or recurring complaint.
Step 3 — Gather public reviews (read-only)
Fetch the current reviews from {{review_sources}} (G2, app-store listings, or
whatever is configured). For each new review since the last visible one:
- Extract the specific ask or complaint, not star-rating alone.
- Take the reviewer's own phrase as the candidate quote.
- Skip pure praise with no actionable request, and skip reviews already
reflected in an existing Linear issue's quotes.
Step 4 — Gather messages from the feedback channel (read-only)
Read {{feedback_channel}} for messages where a team member is relaying
something they heard from a user (not internal chatter). Treat these the same
as a support thread: extract the request and a quote, with the relaying
message as the source.
Step 5 — Cluster into themes
Group everything gathered in Steps 2–4 into themes. Two mentions are the
same theme when they ask for the same underlying capability or fix, even
if:
- The wording is completely different ("can't bulk export" vs. "no way to
download everything at once").
- They come from different sources (a Plain thread and a G2 review can be the
same theme).
- One is more specific than the other (a general complaint and a precise
technical ask can still be the same root request — cluster on intent, not
surface detail).
Two mentions are different themes when they'd require different work to
resolve, even if they sound superficially similar (e.g. "slow page load" on
the dashboard vs. "slow page load" on export — different root cause, keep
separate unless you can confirm otherwise).
Step 6 — Pick the representative quote and title
For each theme:
- Quote — the clearest, most specific verbatim quote from any mention in
the theme. Prefer a quote that names the concrete capability over a vaguer
one.
- Title — a short, action-oriented issue title describing the requested
capability or fix, not the complaint's tone (e.g. "Bulk export for
workspace data", not "Users are annoyed about exporting").
Step 7 — Reconcile against Linear
For each theme from Step 5:
- Matches an existing issue (same theme signature from Step 1): add the
new quote(s) to its quote list, increment its mention count, and note the
new source(s). Don't create a duplicate.
- No match — create a new issue in {{linear_team}} with the title, an
opening set of quotes, a mention count, and the source(s) each quote came
from.
Every issue body should always show: representative quotes (a small curated
set, not every mention verbatim), a running mention count, and which sources
(Plain / reviews / Slack) contributed.
Step 8 — Stop
Report the set of Linear issues created or updated this run. Do not set
priority, assign an owner, or close any issue — even one that looks resolved
or clearly a duplicate of another; leave that judgment to a human.
1---2name: feedback-clustering3description: Turns feedback from Plain, public reviews, and a Slack channel into deduplicated, quantified themes, and reconciles each theme against one Linear issue in {{linear_team}} — never prioritizing, assigning, or closing.4---56<skill name="feedback-clustering">78<overview>9Feedback about the same underlying request shows up worded differently in10Plain support threads, public reviews, and a Slack channel, and never gets11counted together. This skill turns a run's raw feedback into themes —12deduplicated, quantified, and backed by real quotes — and reconciles each13theme against exactly one Linear issue in {{linear_team}}, so a request a14hundred people made looks different from a one-off.1516Fresh session each run. There is no ledger — the existing Linear issues in17{{linear_team}} are the running state to reconcile against.18</overview>1920<when-to-load>21- The scheduled cron fires the feedback sweep.22- A human asks for the current feedback themes, or why a piece of feedback did23 or didn't land in a given theme.24</when-to-load>2526<workflow>2728## Step 1 — Read the existing themes in Linear first2930Before touching any source, pull the current state of {{linear_team}} so new31feedback is reconciled, not duplicated:3233- List open issues in {{linear_team}}, with their title, description, and34 current quote/count body.35- Note each issue's theme signature — the core request it represents — not36 just its title text.3738## Step 2 — Gather support threads from Plain (read-only)3940Pull recent threads (since the last run's approximate window, or the last4124–48h if that's unknown). For each thread, extract:4243- The specific request or complaint, in the user's own words.44- A candidate quote — the clearest single sentence expressing it.45- Enough context (account, thread link) to trace it back later.4647Ignore threads that are pure support (bug already fixed, question already48answered) with no underlying feature request or recurring complaint.4950## Step 3 — Gather public reviews (read-only)5152Fetch the current reviews from {{review_sources}} (G2, app-store listings, or53whatever is configured). For each new review since the last visible one:5455- Extract the specific ask or complaint, not star-rating alone.56- Take the reviewer's own phrase as the candidate quote.57- Skip pure praise with no actionable request, and skip reviews already58 reflected in an existing Linear issue's quotes.5960## Step 4 — Gather messages from the feedback channel (read-only)6162Read {{feedback_channel}} for messages where a team member is relaying63something they heard from a user (not internal chatter). Treat these the same64as a support thread: extract the request and a quote, with the relaying65message as the source.6667## Step 5 — Cluster into themes6869Group everything gathered in Steps 2–4 into themes. Two mentions are the70**same theme** when they ask for the same underlying capability or fix, even71if:7273- The wording is completely different ("can't bulk export" vs. "no way to74 download everything at once").75- They come from different sources (a Plain thread and a G2 review can be the76 same theme).77- One is more specific than the other (a general complaint and a precise78 technical ask can still be the same root request — cluster on intent, not79 surface detail).8081Two mentions are **different themes** when they'd require different work to82resolve, even if they sound superficially similar (e.g. "slow page load" on83the dashboard vs. "slow page load" on export — different root cause, keep84separate unless you can confirm otherwise).8586## Step 6 — Pick the representative quote and title8788For each theme:8990- **Quote** — the clearest, most specific verbatim quote from any mention in91 the theme. Prefer a quote that names the concrete capability over a vaguer92 one.93- **Title** — a short, action-oriented issue title describing the requested94 capability or fix, not the complaint's tone (e.g. "Bulk export for95 workspace data", not "Users are annoyed about exporting").9697## Step 7 — Reconcile against Linear9899For each theme from Step 5:100101- **Matches an existing issue** (same theme signature from Step 1): add the102 new quote(s) to its quote list, increment its mention count, and note the103 new source(s). Don't create a duplicate.104- **No match** — create a new issue in {{linear_team}} with the title, an105 opening set of quotes, a mention count, and the source(s) each quote came106 from.107108Every issue body should always show: representative quotes (a small curated109set, not every mention verbatim), a running mention count, and which sources110(Plain / reviews / Slack) contributed.111112## Step 8 — Stop113114Report the set of Linear issues created or updated this run. Do not set115priority, assign an owner, or close any issue — even one that looks resolved116or clearly a duplicate of another; leave that judgment to a human.117118</workflow>119120<guardrails>121- **Read-only sources.** Plain, the review sources, and {{feedback_channel}}122 are read-only. The only write in this skill is creating or updating a123 Linear issue.124- **One issue per theme.** Never file a second issue for a theme that already125 has one — reconcile against Step 1's list first, every run.126- **People decide priority.** The agent never sets priority, assigns an127 owner, or closes an issue. It quantifies and describes; humans weigh themes128 against the roadmap.129- **Quotes over volume.** Keep a curated set of representative quotes per130 issue, not an ever-growing dump of every mention.131- **Scoped secrets.** Plain, review-source, Slack, and Linear access is132 brokered server-side; no raw credential is ever pasted into chat.133- **No memory between runs.** Each run is a fresh session; the current state134 of {{linear_team}} in Linear is the only carryover, not an internal ledger.135</guardrails>136137</skill>