Inspiration
I built Yaler around a simple problem: independent cafés, restaurants, and food operators can lose £1,000s when critical kitchen equipment goes down — refrigeration, extraction hoods, grease traps, etc.
But the broken equipment isn't the only problem. Finding, vetting, negotiating with, and supervising a local technician can take hours of a manager's busiest shift, often while service is running and stock is spoiling.
I kept coming back to one question: why is anyone doing this manually?
It's a multi-step job with clear constraints — budget, postcode, deadline, equipment category — yet the usual outcome is a phone number and a vague promise.
So I didn't want to build an agent that could just talk about the problem. I wanted to see if an agent could actually do the whole job.
What it does
Yaler turns one spoken or typed sentence into a completed, verifiable repair job.
A manager says: "My commercial fridge is down in N1, budget £500, need it before lunch."
Yaler:
- Extracts a mandate — Gemini 3.5 Flash turns the request into editable budget, area, deadline, and category chips.
- Enforces the rules — a deterministic Go policy engine checks every action against budget, postcode, and safety constraints.
- Sources suppliers — three independent Gemini agents generate quotes from different supplier personas, then a buyer agent ranks them.
- Books within the rules — the best in-budget offer is committed. If nothing fits, Yaler refuses to overspend and escalates.
- Verifies the work — Gemini checks completion photos against the agreed scope and redacts PII.
- Creates proof — a shareable thermal-print receipt with a verified stamp closes the mission.
The UI is deliberately a paper receipt, not a chatbot — kitchen-friendly language, an optional N1 rehearsal, and AI traces hidden until needed.
How we built it
The core principle was:
Gemini proposes. Go decides.
Gemini lives in internal/gemini/ and can only return typed proposals. It never mutates state. A pure-function policy engine in internal/policy/ validates every action before Go writes it.
That gives Gemini the jobs it's good at — extraction, ranking, negotiation, and evidence — while deterministic code handles budgets, postcodes, state transitions, and auditability.
I built the project spec-first using a Kiro loop: requirements → design → tasks. The requirements became actual architecture, from the mandate editor and immutable event log to the state machine and policy boundaries.
Production execution uses Cloud Tasks + OIDC + Cloud Run, with idempotency keys and expected-version checks so retries can't double-commit or duplicate events.
The frontend is Astro + React islands with Nanostores, Tailwind, and GSAP.
Stack: Go, Cloud Run, Cloud Tasks, Firestore, Cloud Storage, Astro/React, Gemini 3.5 Flash, Vapi, ElevenLabs, Exa, Apify, and Netlify.
Challenges we ran into
- Keeping Gemini from becoming the source of truth. I enforced a hard boundary: Gemini proposes → policy decides → Go writes.
- Making the demo reliable. Cloud Run cold starts and flaky supplier calls are risky during a live demo, so I built
/rehearsalwith static fixtures and/replay/<id>for deterministic mission playback. - Making it feel like a product. Kitchen managers don't want a dashboard, so I built the experience around a physical-looking receipt with thermal-print animation and a verified stamp.
- Idempotency. Cloud Tasks retries needed to be completely safe, which led to version-checked writes and idempotency keys throughout the workflow.
Accomplishments that we're proud of
- The over-budget stop. Yaler refuses to spend beyond the mandate instead of blindly complying. It's the strongest demo moment and the product's moral centre.
- Real multi-agent sourcing. The three supplier quotes are independent Gemini calls with different personas, so their prices and terms genuinely differ.
- Mandate-as-data. Showing budget, area, and deadline before execution makes the policy boundary obvious and builds trust.
- Durable async execution. Append-only events, version checks, idempotency, and a 14-state machine make this feel like a production system rather than a scripted demo.
What we learned
The abstraction that survived was:
mandate as data, policy as a pure function.
It's testable, auditable, and lets me add rules without touching the model layer.
I also learned that trust is a UX problem, not just a model problem. The receipt and the refusal to overspend did more for credibility than prompt engineering alone.
Multi-agent sourcing also felt more convincing because independent supplier voices create real negotiation tension.
Voice turned out to be polish rather than the core — the text path is more reliable, so I treated Vapi as an enhancement rather than a dependency.
Finally, seed data became the backbone of the demo. The 12 seeded missions covering the lifecycle are what make replay useful.
What's next for yaler
- Real supply-side reach — turn the
/opsconcierge into a pilot with verified engineers via a WhatsApp-in / typed-out workflow. - Auth and permissions — separate buyer, supplier, and operator roles.
- Google ADK — layer in richer tool-calling orchestration.
- Outbound notifications — milestone calls and SMS updates for engineers.
- Better evidence verification — deeper image interpretation with preserved source evidence and confidence, while keeping human confirmation in the loop.
The goal is to take Yaler from a convincing end-to-end prototype to something that can actually take a broken piece of kitchen equipment and make the problem disappear.
Log in or sign up for Devpost to join the conversation.