Bazza
Bazza is a restaurant platform: mobile ordering, a POS, tables, inventory, cash. Somewhere in the middle of building it the interesting problem stopped being the screens and became the assistant. Something a manager can talk to on a Saturday night, hands full, and have it actually close the register.
The context is not in the prompt
The usual way to make an agent "know your app" is to describe the app in the system prompt. Then it invents a product id and writes to the wrong tenant.
Here the tools are built with the session already inside them:
const tools = [
...createAnalyticsTools(session),
...createPosTools(session),
...createInventoryTools(session),
// 19 modules, all the same shape
]Every tool is a closure over the authenticated session: organization, store, role, currency, timezone. The model never passes a store id, because there is no store id parameter to get wrong. And the tools call the same services the dashboard calls, so there is no second version of the truth to keep in sync.
One rule on top: never invent numbers. Any quantitative claim has to come out of a tool call.
Propose, then create
When the assistant thinks you should add a product, it does not add a product. It calls propose_product, the dashboard renders a preview card with the fields and the reasoning behind each one, and only after you accept does create_product run. The business profile works the same way.
A confident wrong guess becomes a card you dismiss instead of a row you have to find and delete. The model is allowed to be wrong where being wrong is cheap. And when it is missing a value it asks, typed: an amount asks for an amount, a choice renders as options.
The close-day ritual
You say "cierra la caja". If more than one drawer is open it asks which, with the expected amount next to each name. Then it computes what the drawer should hold from every order, payment and movement of the day, and tells you.
It does not ask you to count the cash. It only asks for a physical count if you say there is a difference. That is the test I keep coming back to: the default path has zero questions, and a question appears only where the human knows something the database cannot.
Underneath
Google ADK, Gemini 2.5 Flash, tools as FunctionTool with Zod parameters, inside the same Elysia server as everything else. Bun and Moon, Postgres, Drizzle, a Vite dashboard.
It is at bazza.cloud
