I ask for something for a headache. The agent does not tell me what to take. It tells me what this pharmacy has on the shelf, what is in it, and offers to get me a pharmacist.
That is not the agent being careful. That is the product.
Most agent demos are one model and one prompt. That holds up until the answer has to be true. A support bot that is wrong sends you to the wrong help page. A pharmacy agent that is wrong tells a person to take a drug.
So not one fact in here comes from the model. Stock, ingredients, interactions — all of it comes out of a database. The model's job is to ask the right question and to know when to stop.
That is the integration problem, and that is what this is about.
The project was a take-home task in a six-round interview process (separate article). The company and its brief stay unnamed: this is a reference implementation, not the submission.
The system prompt
It is called a system prompt, but it reads like a policy document. It has three sections:
- What the agent may say.
- What it must never say.
- Which data exists in the database and must never reach the user.
The third section is the one people need. The first is the one people skip.
The agent can see supplier data and purchase prices, because it queries the same database the pharmacy uses. So it has to be told explicitly: being able to see something is not permission to say it.
A few of the rules in that file:
- No announcements.
- No medical advice.
- Start directly with the answer.
- One to two short sentences, maximum.
More of that file is about refusing than about answering.
Six tools
- Medication information
- Find something for a symptom
- Check stock
- Get alternatives
- Check interactions
- Transfer to a pharmacist
Five of them are reads against the database. The model never guesses whether something is in stock. It calls the stock tool, and that goes through Prisma to PostgreSQL. If the row says zero, the answer is zero. There is no path where the model gets to be optimistic about inventory.
The sixth is the interesting one: transfer to a pharmacist is a tool, not an error handler. Most agents treat a handoff as a failure — the thing that happens when nothing worked. Here it is a capability the model can pick like any other. And some inputs trigger it immediately, before the model gets a turn.

Two answer formats
Same agent, same tools, two output shapes.
The chat answer has structure: lists, bold, dosage on its own line. The voice answer has none of that, because nobody wants a bulleted list read out loud to them.
That is not styling. It sits in the system prompt — which means the model writes a different sentence depending on which channel asked.
In chat
"What helps with headaches?" The agent does not reason about pharmacology. It calls the tool, gets rows back, and reports what exists here.
"Do you have ibuprofen in stock?" — "Interaction between aspirin and ibuprofen?" — "Alternatives to paracetamol?" Severity and recommendation come out of the database too, not out of the model.
And then the edge case: "I have had chest pain since this morning. What should I take?" That is where the handoff fires.
By voice
Same agent underneath. Microphone in, Deepgram turns it into text, Claude answers, ElevenLabs speaks it back. Four services in one round trip — and you can hear what that costs.
Three languages
English, German, and a right-to-left language. The third is the only one that costs real work: the layout mirrors, not just the strings. Every flex direction, every icon that points somewhere, every margin that assumed a left edge.
Seven pieces
| Piece | Role |
|---|---|
| Next.js and React | The interface |
| API routes | The backend |
| PostgreSQL | The source of truth |
| Prisma | The way in |
| Claude | The only part that reasons |
| Deepgram, ElevenLabs | Speech in, speech out |
| Docker | So it runs the same on my machine and on the server |
The source of truth is a schema: medications, ingredients, stock levels, interactions. Ordinary tables with ordinary columns.
There is no retrieval step in this and no embeddings. The agent does not search for a probable answer. It reads a row.
And the rule that kept this from turning into spaghetti is one sentence:
Every component has exactly one job, and exactly one of them is allowed to improvise.
The database is never uncertain. The speech services are never creative. The model is the only thing that improvises — and it may only improvise about wording, never about facts, because every fact has to come back through a tool.
Draw that line early and the rest of the integration is plumbing.
Three limits
A demo that does not name its limits is not a demo, it is an ad.
- It runs on a seeded data set, not on a live pharmacy inventory.
- There is no pharmacist on the other end of the handoff. The handoff is real; the human is not.
- It is not a medical device. It is not certified, and nothing in it is advice.
Three rules
One: the model may be uncertain about words, never about facts. Every fact goes through a tool.
Two: the handoff is a feature. Build it first, not last.
Three: write down what the agent must never do before you write what it should do. The prohibitions are the product.
Takeaway
The point is not the pharmacy. The point is that turning five services into one honest answer is a boundary problem, not a model problem.



