Skip to content
TODD BROWN
« Writing

Sadyr: blueprint to production in twelve days, and what it answers from

Sadyr is a revenue agent for company websites. It answers pre-sales questions from approved sources only, qualifies visitors, and hands sales reps a briefed lead. The platform is live — it's been running in production since 30 June 2026 — and it also runs two working demonstrations for prospects: a plan explainer for an insurance provider and a rulebook assistant for a national amateur sports league's managers. Nobody pays for it yet, so the status word is demo.
The build took twelve days from blueprint to production: first commit 18 June, live 30 June, 63 commits across eight working days. Claude Code wrote the code, tests and documentation; I directed, decided and validated. It's three apps — API, operator console, website widget — and 17 packages.

Most website chatbots will answer anything, which is the problem. A revenue agent that invents a price or a policy is worse than no agent. Sadyr is built on one principle: own the center; wrap, rent, or swap the edges.

The Architecture in Plain Words

A small kernel owns the business logic: qualification, routing, scoring, policy, and audit. The CRM, the scheduler, the chat channel and the knowledge store sit behind adapters, each with a mock. HubSpot is the first adapter, not the spine. Each client is one configuration file.

That's why one platform can serve both demonstrations — the public insurance explainer and the gated managers' assistant — with no re-architecting. Documents carry an audience field, surfaces carry a policy, and public surfaces decline cleanly on manager-only content.

The sports league's knowledge base holds 98 approved, synced documents: 89 tagged audience "all" and 9 tagged "managers." The managers surface answered real ruling questions from manager-only handbook content with titled sources; the public surfaces abstained, with no manager-only content leaking across the boundary.

Standing up that second, sign-in-gated audience didn't require a second platform or a fork of the codebase. It required a data model change — an audience field on each document — and a configuration block — surfaces per client. If a knowledge platform needs a schema change and a new codebase every time an audience is added, the platform boundary is in the wrong place. The audience control belongs on the document, not on the deployment.

What Broke and How I Fixed It

The answer gate that divided by word count

Sadyr decides whether it's confident enough to answer by checking a retrieval confidence score against a threshold. Somewhere in the build, the gate picked up a heuristic: divide the top retrieval score by the number of words in the question.

Against Sadyr's mock retrieval adapter, that heuristic looked correct. The mock returned a raw count of matching words rather than a normalized score, so every test passed.

The problem surfaced once real OpenAI embeddings went live for the insurance demo on 14 September. Real cosine similarity scores land in the range of about 0.4 to 0.6. Divided by a multi-word question's token count, those scores fell to roughly 0.03 to 0.05 — well under the gate's threshold of 0.62. Every multi-word question abstained.

Every one of Sadyr's tests passed the entire time the bug was live, because the whole suite ran against the mock adapter, which faithfully reproduced the same wrong assumption the runtime made.

The bug was found on the first live run against real embeddings. The fix landed the same day: every adapter — the mock included — now returns a normalized score between 0 and 1, and the runtime compares that score as-is, with no query-length division. The contract for what a "score" means was written down in the codebase so the mock and the real adapters couldn't drift apart again. The diffstat: 3 files changed, 15 insertions, 6 deletions.

When agents write both the code and the tests, a passing test suite verifies that the code agrees with itself — not that it agrees with reality. The gap only shows up when the real system runs, with someone watching. My habit since: run the real adapter early, and check the mock's behavior before trusting any test suite an agent has written.

The booking that wasn't

My first chat on staging got a confident "You're booked" with no email, no calendar and no choice of time. The rule since: a scheduler that isn't real never confirms a meeting, and nobody gets booked without leaving an email.

Booking now runs through HubSpot Meetings and offers real open slots in production; the first real booking is still waiting on a CRM permission fix, so it is not called live yet.

Tests, Mocks and Pressure

The platform carries 2,816 automated tests, a figure recorded from the Sadyr README and not re-run for this article. Tests run on mocks by default, which is why the answer-gate bug survived them all.

I also built a headless evaluation battery that pressure-tests the hosted agent with realistic conversations. That's the gate: Sadyr doesn't talk to anyone until it's answered a battery of hard questions correctly, with real embeddings, against real business logic.

What It Answers From

This started with a question: could Sadyr answer visitors on Adroit's own site from Adroit's own approved knowledge base, published from Content Ops? It does now, using 24 approved public documents synced from Content Ops, embedded, and answering on the production API. Twenty-six warm-tier documents — pieces held for review or marked do-not-use — are deliberately held back, and the chat abstains on them.

That end-to-end proof is what made the two client demos credible: if it works on my own knowledge base, under my own policy, it can work on theirs.

What's Next

Sadyr supports the sales rep and hands off a briefed lead. It never replaces a person — that framing is deliberate and stays with the product.

The next gate is a paying customer. Until someone pays for it, it stays a demonstration, no matter how well it runs. The platform is ready; the business model is the open question.

You can see the full receipts — test counts, commit dates, architecture diagrams — on the site. Everything I claim, I show.