/voc-source-chat — Mine Internal Chat for Customer Voice
Your team already does VoC work. They paste customer quotes into channels named things like
#wins, #churn-risk, #feature-requests and #sales-questions, where the quote gets four
emoji reactions and is never seen again.
This is the highest-yield source per unit of setup effort in the whole pipeline, and it is the one every VoC tool ignores because it is not a customer-facing system.
Requires
| What | Value |
|---|---|
| Chat MCP server | Slack, Discord, Teams — whatever your team uses |
| Config | context/product-context.md → chat_channels |
| Cost | Free. |
Wiring the tools
This skill deliberately does not hardcode chat MCP tool names. They vary by server, and a skill that declares a tool name your server does not expose fails at its first step while looking like it ran.
To connect yours:
- Add your chat MCP server to
.mcp.json(see.mcp.json.example) - Run
/mcpin Claude Code to list the tool names your server actually exposes - Add those names to this file's
allowed-tools
If you skip step 2 and guess, you will get a skill that reads no messages and reports no error.
Execution
Step 1 — Resolve channels
Read chat_channels from your context file. Each entry:
chat_channels:
- name: "#wins"
signal_type: praise
reliability: high
- name: "#sales-questions"
signal_type: objection
reliability: medium
If unconfigured, ask which channels carry customer quotes. Do not scan every channel — most chat volume is internal coordination and scanning it wastes tokens and buries the signal.
Step 2 — Pull the window
Read messages from the configured window. Include thread replies: the quote is often in the parent and the crucial context in a reply three deep.
Step 3 — Separate quote from relay
This is the work, and it is where naive implementations fail. Chat contains three things:
| Type | Example | Keep? |
|---|---|---|
| Direct quote | Customer said: "we can't get the data out fast enough" |
Yes, verbatim |
| Paraphrase | Northwind is frustrated with export speed |
Yes, but mark paraphrased: true |
| Internal chatter | has anyone seen the deck for tomorrow |
No |
Preserve the distinction all the way through. A paraphrase is real signal about a real conversation, but it is your colleague's words, and it must never be published as a customer quote. Downstream skills rely on this flag.
Extract quoted spans precisely. Look for text inside quotation marks, after said: /
told me: / their words:, and inside blockquote formatting. When a message mixes relay and
quote, keep only the quoted span as verbatim and put the rest in context.
Step 4 — Attribute
For each signal, resolve:
- Company — usually named in the message or its thread. If absent, check the channel topic and the surrounding messages before giving up.
- Who relayed it — the team member. Useful for follow-up, and useful for spotting when one enthusiastic rep is generating a disproportionate share of your "signal."
- Date — the message timestamp, not the date of the underlying conversation. Note the difference when it is knowable; chat relays often lag the call by days.
Unattributable signals still get written. They become tier U at the profiling step and are excluded from confirmation counts automatically.
Step 5 — Write
One JSON per signal to outputs/voc/sources/chat/<date>-<slug>.json:
{
"channel": "chat",
"chat_channel": "#wins",
"verbatim": "we can't get the data out fast enough",
"paraphrased": false,
"context": "relayed after the QBR",
"company": "Northwind Trading",
"relayed_by": "person who posted",
"message_date": "2026-04-22",
"permalink": "...",
"signal_type": "pain"
}
Report counts by channel and by signal type, plus how many were unattributable.
What this gets wrong
- Relay bias is real and large. You hear what your team found notable enough to paste. Quiet problems and boring-but-common complaints never make it to chat.
- Enthusiasm skews the sample. One rep who posts every customer comment will dominate the
corpus. Check the
relayed_byspread before treating volume as prevalence. - Paraphrase drift compounds. By the time a customer's comment reaches a channel it has passed through one person's memory and framing. This is why the flag matters.
- Chat is a lagging indicator. Something posted Friday may have been said the previous week. Date arithmetic on this source is approximate.
- Reading team channels is a trust matter. Tell your team this is running. A tool that silently harvests colleagues' messages is a bad thing to be discovered doing, even when the intent is benign.