Inspiration

Every few years a beloved product gets quietly reformulated, a cheaper oil, a new sweetener, a tweaked chocolate, and the internet notices before the company admits anything. Toblerone widened its gaps. Cadbury changed its recipe. Reese's. The pattern is always the same: the brand ships the change silently, and within weeks thousands of people are posting "this tastes different now" across Reddit, Amazon reviews, and news comment sections. But those complaints are scattered. No single team owns the question "is anyone upset about our recipe change right now?" By the time it shows up in a quarterly sales review, the damage is done.

We wanted to build the early-warning system that doesn't exist: point it at a product, and it tells you whether a reformulation is quietly going wrong, dated to the moment it broke, with a citation behind every claim.

What it does

Give Basket a product name. An orchestrator runs five specialist agents over live web data:

  1. Date-Finder (Tavily) figures out when the product was reformulated, from the product name alone, by finding the earliest credible coverage.
  2. Retrieval (Tavily) searches and cleans complaint mentions across news, the web, and forums.
  3. Classifier (Prometheux) rule-classifies each complaint (taste, texture, etc.) with a literal, traceable reason chain back to the source text.
  4. Aggregator/Detector (ClickHouse) rolls complaints up by week and category and detects the spike against the pre-reformulation baseline.
  5. Publisher (cited.md) ships a sourced alert when an inflection is found.

The output isn't a sentiment score. It's a dated, cited claim: "complaints spiked the week of the reformulation, here is the rule that connects them, here is every source." That's what lets a category manager act in week two instead of at the quarterly review.

How we built it

The system is a pipeline of five agents behind one /run contract, so each piece could be built and tested independently and still snap together.

  • Tavily is what makes this a real web agent and not a script over a static file. We run source-biased searches: news gives us reliable publication dates (the backbone of the spike chart), while forum and review searches give us volume. The Date-Finder pools several query angles and takes the earliest in-window coverage as the proxy for when the reformulation surfaced.
  • Prometheux carries the explainability moat. We encoded an ontology of product variants and complaint markers as declarative Vadalog rules: entity resolution (rule A), marker classification by precedence (rule B), and a date-relative join that only counts a complaint as post-reformulation if its date is on or after the reformulation date (rule C). The engine emits not just a label but the rule trace, so a judge can see exactly why a complaint was counted.
  • ClickHouse does real-time aggregation over a single complaints MergeTree table. The week × category rollup and the inflection detection both run as SQL and recompute as complaints stream in. Ingestion is idempotent via uniqExact(source_url), so re-running the pipeline never double-counts.
  • cited.md publishes the action as a sourced report where every claim links back to its origin.

The spike detector is deliberately simple and explainable rather than a black-box model. For a category with a pre-reformulation weekly baseline $\bar{c}{\text{pre}}$ and a peak post-reformulation week $c{\max}$, we flag an inflection when

$$\frac{c_{\max}}{\bar{c}_{\text{pre}} + 1} \geq \tau$$

with the $+1$ guarding against a zero baseline. Every input to that ratio is a row you can click through to its source.

Challenges we ran into

  • The reformulation date is the genuinely hard part. A product name carries no date, and naive search will happily hand you the brand's founding year. We recency-bound the search window and take the earliest credible coverage, but this is the fragile joint of the whole system and where we spent the most judgment.
  • Tavily doesn't return dates for every source. Forum results came back with great text but no publication date. We added a fallback that fetches the thread's own JSON to recover the timestamp, so one undated source can't break the spike chart.
  • The Prometheux engine is single-slot and stateful. Live runs hit ENGINE_BUSY (one job at a time, so we added exponential backoff with retry), NO_ACTIVE_COMPUTE (the compute machine has to be started before a run), and PATH_NOT_FOUND (results don't persist unless you pass persist_outputs=True). Each one was a small mystery solved against the live engine.
  • Learning the live response shape. The engine's fetch_results returns facts nested several levels deep with pagination, not the flat list we first assumed. We wrote a smoke test to learn the real shape before building on it.
  • Keeping the demo alive under failure. Any live dependency can flake mid-demo. The classifier degrades gracefully: if the real engine is unreachable, a deterministic in-Python implementation of the exact same rules takes over, so the pipeline always produces output.

What we learned

  • Explainability is a feature, not overhead. The instinct is to reach for a model that scores sentiment. But "sentiment dropped" isn't actionable, "the recipe changed on this date and here's the rule connecting it to the spike, with citations" is. Building on a declarative reasoning engine forced every claim to be traceable, and that traceability is the product.
  • Live web agents live or die on the messy edges: missing dates, busy engines, paginated responses, flaky sources. The interesting engineering wasn't the happy path, it was making the agent robust to a web that doesn't cooperate.
  • A frozen contract between agents pays for itself. Fixing the data shape between the five agents early meant we could build and verify each in isolation and trust them to compose.

What's next for Basket

Tighten the hardest joint: reformulation dating. Today the Date-Finder takes the earliest credible coverage as a proxy for when a reformulation broke. Next we want to corroborate that across multiple independent sources and surface a confidence band, so the date the whole pipeline pivots on is defensible, not a single best guess.

Broaden the signal. More sources (TikTok, YouTube comments, retailer Q&A), more complaint categories (price, shrinkflation, packaging), and a continuous watch mode that re-runs on a schedule and alerts the moment an inflection crosses threshold, rather than only when someone asks.

Built With

  • cited.md
  • clickhouse
  • cursor
  • prometheux
  • python
  • senso
  • tavily
Share this project:

Updates