01

Dental chain: phone first, front desk unburdened

The first lesson from a multi-location dental chain: patients don't choose between “web chat” and “a phone call” — they choose whatever is at hand first. The phone wins almost every time. Our job wasn't to change that, but to take the phone seriously: multilingual greeting, appointment reshuffling by voice, strict escalation on pain or trauma.

Technically that runs on FreeSWITCH, a local SIP instance inside the practice network. Three handoff targets: reception Berggasse (Mo–Th 08:30–17:00), reception Gunertweg (Mo–Th 08:30–17:00, Fr 07:30–14:00), and an emergency physician on extension 1001, always reachable. A simple LLM-classifier guardrail blocks non-urgent cases that would otherwise take the emergency route.

Call
FreeSWITCH
Triage
Booking
Insurance
Ext. 1001
One graph, three roles, one emergency button.
02

Tourism concierge: one agent, three skills

In the second engagement — a cruise and shore-experience operator — the temptation was to build every role as its own agent: “Trip Planner”, “Restaurant Advisor”, “Shore Expert”. We did the opposite. One agent, three skills. A skill is a workflow spec with tool dependencies — not a separate graph node, not a separate handoff.

The reason: all three tasks share the same tone, the same persona, the same tool permissions. A skill-based approach saves a turn (no handoff), saves cost (no second prompt), and is easier for editors to maintain. The Persona Wizard extracted the voice from the operator's website in 30 seconds — which, honestly, was the biggest surprise of the setup.

Skills are agents that grew up — they skip the dramatic handoff because the agent already knows the role.

03

B2B SaaS: MCP tools and structured answers

The third case, a B2B SaaS support desk, is technically the most interesting. The agent talks to the user through a ticket system (Zendesk) — but the actual workplace is an MCP server exposing status APIs, changelog data, and migration guides as tools. One MCP endpoint, twelve tools, not a single webhook manually configured.

What makes it interesting: instead of free-form text, the agent emits a structured JSON response — reply_text, confidence, category, escalate. The ticket system parses it, posts it as a comment, and escalates on low confidence or an explicit flag. The same agent graph also serves the web widget on the documentation site, where it streams markdown instead. One infrastructure, two faces.

json
{
  "reply_text": "API rate limit for Tier Pro is 600/min. Details in the linked doc.",
  "citations": ["https://docs.example.com/rate-limits"],
  "confidence": 0.88,
  "category": "api_limits",
  "escalate": false
}
04

What all three share

Despite different surfaces, the same backbone runs through all three: a triage agent with a clear routing task, specialists with narrow vocabularies and few tools, a guardrail set per role, and an audit log that isolates everything at the tenant level. What changes is the channel — not the architecture.

  • Tenant isolation down to the query layer (dedicated Qdrant collection, tenant-scoped Mongo records)
  • Per-end-user memory with GDPR-compliant deletion paths
  • Snapshots of the agent graph with second-scale rollback
  • The same retrieval backend — only the content differs
  • The same model registry — models maintained centrally, assigned per agent
3
Industries
medical, tourism, SaaS
1
Platform
one codebase
4
Channels
web, phone, ticket, API
20k+
Conversations / month
as of today
05

The uncomfortable lesson

When three such different industries can live on the same platform, that's either a sign of real architectural leverage — or a common denominator so small it explains nothing. We think it's the former. The common denominator is that every real conversation eventually branches, eventually touches a system outside the chat, and eventually someone is accountable for it. That's not an industry question. That's a product definition.