# How we turn NPS responses into clear themes

Once a week our Machine agent reads new NPS and CSAT answers from a Google Sheet, sorts the comments into themes with sentiment and detractor drivers, and posts the score trend and real quotes to Slack.

Canonical page: https://themachine.myapps.ai/use-cases/nps-analysis

Every survey answer comes with a little story attached, and almost nobody reads
it. The score ends up on a dashboard. The comment beside it, the bit that
explains why this customer gave you a 4 and not a 9, sits alone in a
spreadsheet row. It never gets added up with the hundred other people saying
the very same thing. When a pattern is finally loud enough for someone
scrolling the sheet to notice, it has usually been growing for months.

So an agent on Machine now reads the week's new responses and posts the
themes, the mood and the main reasons for detractors in our customer-success
Slack channel, together with how the score shifted since last week. The survey
sheet is read and never changed. The Slack message is the one and only thing
it produces. That's how our own NPS program avoids becoming a spreadsheet no
one opens.

- **Team:** Machine
- **Runs on:** A schedule that fires once a week
- **Connected systems:** Google Sheets · Slack
- **Mode:** Reads only · a single Slack post each week

## The problem

Each NPS or CSAT answer tells you two things: a score and a comment. Scores
are the easy half, and your survey tool probably graphs them already. The
comment holds the reason, and that's the half that disappears. Written
feedback stacks up in an export, one line per person, and nobody gets through
all of it each week. Twelve detractors can raise the same gripe and it still
never gets counted as one issue.

The usual fixes fall short. A dashboard tells you the number moved but not
why. A person skimming the sheet notices the angriest comment rather than the
most frequent one, and reads a little differently each week. And since no one
tracks themes over time, a problem that has been building for a month looks
exactly like one that showed up once and vanished.

## What we built

A weekly cron wakes an agent on Machine. Each run gets a fresh, isolated cloud
computer, or sandbox, that can read (and only read) the Google Sheet our
survey tool exports into. The agent goes through the entire response history,
groups the written comments into themes, labels each answer with its sentiment
and score band, picks out what is really pushing detractors down this week,
and works out the week-over-week change in the score. It sends a single
summary to Slack with typical quotes. Nothing is written back to the sheet.

## How it works

### Fire once a week

A **cron trigger** is a timer, and this one goes off weekly. Each time,
Machine starts a new **session**: a clean sandbox just for that run. No memory
is kept from the week before. The sheet is the record, so the agent rebuilds
the themes, the sentiment and the score trend from every response, every time.

### Spell out how to read the feedback

Our approach to grouping comments and reading the score is kept as **skills**
and **memory**, the playbook the agent brings into every run. It explains how
a real detractor driver differs from a one-off moan, how to choose a quote
that fairly stands for a theme, where the promoter, passive and detractor
bands begin and end, and how to describe a change from one week to the next.
Once we sharpen our idea of a good theme and write it down, the following run
uses it.

### Connect the survey sheet and Slack

Each tool is reached through a **connector**, a narrow link whose keys stay on
our servers, so the model never handles a raw token. With it, the agent:

- **Reads answers from Google Sheets.** The whole export of NPS and CSAT
scores, comments and timestamps, with read access only.
- **Posts in Slack.** One summary a week: the score and where it's heading,
the biggest themes with quotes and counts, and the top detractor drivers.

### Set the limits

On the survey sheet the agent is **read-only**. It won't change a row, add a
column or write back a score, and it never gets in touch with anyone who
answered the survey. The one thing it produces is the Slack message, which is
a report, not an action. Credentials are stored encrypted in the **Secrets
Manager** and only handed to the agents you grant them to.

### Post the weekly summary

Once that's set up, Monday brings a single Slack message. It shows the latest
NPS and CSAT score and how far it moved since last week, the themes behind the
comments with a typical quote and a count for each, and what's dragging
detractors down this week. The customer-success team reads it and chooses what,
if anything, to do next.

> **The pattern**
> Once a week a **cron** starts a clean session with a read-only **connector**
> into the survey Google Sheet. The rules for grouping and scoring live in the
> agent's **skills** and **memory**. It reads the whole history on every run
> and writes nothing except the Slack post.

## Guardrails

The agent works from a live survey export, so its access is narrow and flows
one way:

- **Isolation.** Each run has a sandbox to itself and can reach only the sheet
  it was given. The Slack post is the only thing that leaves.
- **Scoped secrets.** The Google Sheets and Slack keys are stored encrypted in
  the **Secrets Manager** and only handed to the agents you grant them to, when
  the sandbox starts.
- **Read-only, report-only.** Its link to the survey sheet can only read. It
  can't edit an answer, insert a row or write back a score, and it never
  contacts a respondent. It reports and stops there.
- **Everything is code.** Grouping rules, skills and the permissions for each
  system are versioned files in the repo, changed only through a reviewed
  **change request**, never a dashboard toggle.

## The outcome

- **Every week:** Themes and the score trend rebuilt from every response so far
- **Read-only:** The survey sheet is never written to
- **1 post:** Score trend, themes and detractor drivers in a single Slack message

Comments that used to gather dust in a spreadsheet now show up every week as
named themes with quotes and counts, right next to the real week-over-week
change in the score and the reasons behind it. The agent reads and reports,
nothing more. Deciding what to do about each theme is still the team's job.
