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:

  1. Extracts a mandate — Gemini 3.5 Flash turns the request into editable budget, area, deadline, and category chips.
  2. Enforces the rules — a deterministic Go policy engine checks every action against budget, postcode, and safety constraints.
  3. Sources suppliers — three independent Gemini agents generate quotes from different supplier personas, then a buyer agent ranks them.
  4. Books within the rules — the best in-budget offer is committed. If nothing fits, Yaler refuses to overspend and escalates.
  5. Verifies the work — Gemini checks completion photos against the agreed scope and redacts PII.
  6. 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 /rehearsal with 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 /ops concierge 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.

Built With

  • apify
  • astro
  • cloud-run
  • cloud-storage
  • cloud-tasks
  • elevenlabs
  • exa
  • firestore
  • gemini
  • go
  • gsap
  • react
  • tailwind-css
  • vapi
Share this project:

Updates

Submission history