DEV Community

Cover image for Your most polite customers are the ones you’re about to lose.
Kshitij
Kshitij

Posted on Originally published at github.com

Your most polite customers are the ones you’re about to lose.

Think of the last time you said an app was “fine.”

You still have it on your phone. You still open it when you’re tired. You would not recommend it to a friend. You also would not write to support. Support is for a missing order. “Fine” is quieter than that. “Fine” means you order less, then you stop.

This review is that moment:

“It’s not bad but I’m comparing every food order to getting downstairs 10 floors. The convenience tax is getting loud.”

— 3 stars

In plain English: skipping 10 floors of stairs used to be worth the extra fee. Now walking is starting to win. The person still has manners. They even left stars in the middle.

A normal sentiment tool reads “not bad,” sees 3 stars, and calls it okay. Maybe even positive. Green on the dashboard.

What happens next is not a complaint. It is fewer orders. Then the app comes off the phone.

That is the whole product: the review that looks okay and means goodbye.

What Resonance is

Resonance reads a sheet of reviews and tells you what people felt, not what they performed. It scores eight emotions. It notices when the words and the feelings disagree. It names the groups hiding in the 3- and 4-star pile. It writes a Hidden Ask — the need nobody filed as a ticket. Then it waits. It will not invent a product roadmap until you say yes.

Two minutes. Then keep reading — the rest is what the clip doesn’t show.

Resonance

Customer emotion archaeology powered by Plutchik's Wheel

Live demo License: MIT

Resonance does not classify reviews as positive, negative, or neutral. It scores each review on Plutchik's eight emotions, flags cognitive dissonance, maps an unmet Maslow need, clusters the emotion vectors in a TrueForge sandbox, names psychological archetypes, writes Hidden Asks — then pauses for a human before any product-roadmap recommendation is emitted.

Built for The Agent Harness Hackathon on the TrueForge harness (filesystem MCP, Exa web search, Daytona sandbox, ask_user_question).

Live demo: https://graphics-newsletters-usr-simplified.trycloudflare.com

Always-on Oracle Always Free ARM VM in Mumbai. Nothing runs on a laptop. The URL is a Cloudflare Quick Tunnel (*.trycloudflare.com); it can change if that tunnel process restarts.


Screenshots

Zomato demo run (Plutchik profile → HITL approval → roadmap).

Zomato — live analysis workbench

Eight-dimension Plutchik emotion profile   Psychological archetype segment card

Human-in-the-loop approval gate before recommendations   Roadmap recommendations after approval

Hidden Asks — unmet needs no review filed as a ticket   Cognitive dissonance red flags on individual reviews

Executive summary with PDF export   Light-mode workbench

Upload a CSV → watch the Plutchik wheel fill in real time → approve the analysis → export a dark-theme PDF.


Sample analysis









Product Dataset Report





Built for The Agent Harness Hackathon (WeMakeDevs × TrueForge × Qodo). The live URL is a Cloudflare tunnel on a small always-on VM. If that process restarts, the hostname can change. The repo and the video stay.

Drop a CSV. Watch the wheel fill. Approve or decline. Download a PDF.

The job I gave the agent

A product manager already has a spreadsheet. Their dashboard says “mostly positive.” They need the people hiding in the polite ratings.

The job, in order:

  1. Read the file. Don’t make me paste reviews into a chat.
  2. Learn what the product is, so “I love it” on food is not “I love it” on a bank.
  3. Score every row: eight emotions, whether the words fight the feeling, one unmet need.
  4. Group similar emotion patterns with real math — not a guess.
  5. Name the groups. Write the Hidden Asks.
  6. Ask me before any “you should build X.”

The eight emotions are Plutchik’s, not happy / sad / meh. Politeness is not joy.

Eight-emotion wheel for the Zomato run. Sadness and anger sit high. Joy is low.

This is the job: a shape of feeling, not a thumbs-up.

TrueForge: the harness in the middle

A chatbot answers. An agent has to reach a file, run code somewhere safe, and stop before it does something you can’t undo. I didn’t want to spend the week building that machinery. TrueForge is the layer between the model and everything it touches.

You (browser)  →  workbench  →  TrueForge agent
                                   ├ filesystem (the CSV)
                                   ├ web research (what is this product?)
                                   └ sandbox (the clustering script)
Enter fullscreen mode Exit fullscreen mode

What the harness handled:

  • Files — the agent reads the upload by name and writes results. It doesn’t get the rest of the disk.
  • A specialist — one helper looks up the product. Scoring and the wait stay on the main agent.
  • A sandbox — grouping runs in a sealed machine, not on my laptop.
  • A pause — after Hidden Asks, TrueForge stops and asks. Roadmap items stay empty until Approve. Decline ends there.

I wrote the screen, the parser, and the PDF. The harness wrote the loop, the tools, the sandbox, and the wait.

TrueForge paused on ask_user_question — waiting for Approved or Decline.

Live analysis after a finished run. The activity log shows TrueForge paused, waiting for Approve or Decline.

The wait is not a fake button. The session actually stops.

What broke

Stage 1 — the model vanished. The first provider ran out of quota. I moved the agent to OpenRouter: one model first, a second if the first turn fails. A run stays on one model until you approve. Unsexy. Why the demo still works.

Stage 2 — the sealed room had no door. I told it to run the clustering script on the scored file. The sandbox had never seen that file. I had to copy the script and the data in. After that, it was just a tool.

Stage 3 — the answer got cut in half. Long replies died mid-stream. The UI said done. The wheel was empty. I stopped asking the model to “be complete” and started only drawing what I could actually read.

Stage 4 — the first model got tired. Same job, second model, more room. Not a second opinion.

Stage 5 — the small computer had opinions. The app had to listen for the real visitor IP behind the tunnel. The harness on that machine had to listen on all network interfaces or Docker couldn’t talk to it. The public URL is a tunnel. The only open door is SSH.

That’s the messy middle. That’s also why a stranger can click the link.

Qodo from the first PR

Every real change went through a pull request. Qodo read it before it landed. That was the way the repo grew, not a polish pass at the end.

Example: PR #4 — the approval step. The dangerous part of this product is emitting a roadmap. Qodo caught a High bug: if the pause data failed to parse, Approve would fake a local replay, mark the run done, and never send the answer back to TrueForge. The wait would look real. The harness would never hear you.

I stopped inventing a fake replay id. Approve only continues when the pause is a real TrueForge interrupt.

I don’t merge because the bot is green. I merge when the note is fixed, or the thread says why we skipped it.

All merged work: the PR list.

One Zomato run

I uploaded zomato_reviews.csv. Fifty reviews. No extra chat window — the file is the input.

First, the polite ones that don’t mean polite.

Review cards. One says “not bad” and is tagged praise masking pain, 3 stars.

Same quote as the opening. Now you can see the tag.

Then the group that still opens the app.

Segment card: Fee-Fatigued Loyalists. 22 reviews. 44% of the set. Esteem.

They stay because discovery still works. One bad bill and they don’t.

Then the need that never became a ticket.

Hidden Ask card: “A path back to a real human.” Belonging. High.

Not “make the bot nicer.” A person who can undo a wrong charge.

Then it waits. The roadmap side is blank on purpose.

Approve recommendations modal, Hidden Asks listed, Decline and Approve buttons.

Approve continues. Decline stops here. I tried both.

Only after Approve:

Roadmap card: one-tap “talk to a person” after two failed chat loops.

Same ask, now as something you could ship. That sentence did not exist before a human said yes.

Go try it

Open the live link at the top, or clone the repo, and hit Load demo dataset. Approve once. Decline once. The interesting screen is the one where the roadmap is still empty.

Top comments (0)