
The dish nobody eats keeps coming back: a food-waste agent on AWS that mess staff talk to in Hindi
Mess staff log each meal by answering a Hindi voice call. An AI agent on AWS Step Functions spots the dish that keeps getting wasted, a manager approves a change, and MessLoop measures whether waste really went down. Built for Environmental Hacks 2026.
Our hostel mess cooks the same amount every day. Five kilos of rice, whatever the attendance, whatever is on the menu. At the end of dinner the plates get scraped into a drum. Some of it goes to the bin and some to the animals behind the kitchen. The same unpopular sabzi comes back the next week, and nobody can say how much of it was thrown away last time, or why.
When we asked the mess staff about the leftover food in the cooking vessels, we learned something we hadn't expected: the workers take it home to their families. It isn't wasted at all. The real waste was on the plates, and nobody was measuring that either.
So we built MessLoop for Environmental Hacks 2026 (Waste & Energy track). It finds the dish that keeps getting wasted, lets an AI agent suggest a change, lets a human decide, and then measures whether waste actually went down. Its one rule:
AI recommends. Humans decide. Outcomes prove it.
- Live app: https://messloop-web-sitebucket-agfku78revhs.s3.us-east-1.amazonaws.com/index.html (tap a "Try the demo" button, no code needed)
- Demo video (2:55): https://youtu.be/1IT8X0xW6p8

The serverless app (S3, API Gateway, Lambda, DynamoDB), the agent (DynamoDB Streams, Step Functions, our own model on EC2), the voice call (Polly, Transcribe) and the alerts (SNS, EventBridge).
The first thing we tried failed
Before writing any code we made a Google Form for the student mess committee: what was cooked, how full the drum was, a photo of it. In a week, nobody filled it in once.
That failure became the design brief. If logging takes more than a few seconds, it won't happen. Mess staff are carrying vessels, not typing. So MessLoop lets them talk instead.
How it works, in four moments

1. "Bol ke batao": the worker just talks
The mess staff screens are entirely in Hindi. The worker taps बोल के बताओ ("Bol ke batao", say it out loud). The app runs it like a phone call: Amazon Polly asks five questions in Hindi, there's a beep, and it listens. When the worker stops talking, it moves to the next question on its own.
"Namaste! Aaj khane mein kya bana tha? Kul kitne kilo bana tha? Service ke baad bartanon mein kitne kilo bacha? Aaj kitne bacchon ne khaya? Aapke hisaab se khana kyun bacha?"
The first question asks what was cooked, not just which sabzi, so one answer can name the whole meal: "dal, chawal aur roti". MessLoop picks out every dish it hears from our hostel's real weekly menu (30 dishes, with their Hindi names).
Question 1 of 5 on a worker's phone. Each answer is transcribed while the next question plays, so the form is filled about two seconds after the call ends.
Each answer goes to Amazon Transcribe streaming (Hindi) the moment it ends. Simple rules read the numbers, because Transcribe usually writes them as digits ("50 kg बना था"). Our model only steps in when a rule can't read something. Then the worker sees a filled form with "सुना" (heard) and the words it heard under every field, and presses सेव करें (Save).
That last step matters. In testing, Transcribe heard "तेईस" (23) as "30". Speech-to-text will mishear numbers, so nothing is ever saved without a person checking it.

2. The agent wakes up by itself
Saving the meal writes to DynamoDB. A DynamoDB Stream sees the new record and starts our agent on AWS Step Functions. Nobody presses a button.
First, a fixed rule decides whether anything is wrong: over 35% left in at least 3 of a dish's last 5 meals. Not the AI. If the dish crosses the rule, the agent investigates. Our own model (Qwen3-4B, running on Amazon EC2 with llama.cpp) gets three tools and decides for itself what to look at:
The agent woke up when a meal was logged, chose its own evidence, wrote a suggestion, and paused for the manager.
The tools only return slices of evidence that code has already computed. The model never does arithmetic. Then a validator checks its answer: every number must come from evidence it actually looked at, vote shares must belong to the right dish, and comparisons like "lower waste than Chole" must match the data. If anything fails, a rule-based template is shown instead.
3. A real pause for a human
The agent can't change anything. Step Functions pauses the run on a task token until the manager approves, modifies or rejects. Here is that part of the state machine, from our AWS SAM template:
YAML
WaitForManager:Type: TaskComment: Human in the loop. Nothing changes until the manager approves, modifies or rejects.Resource: arn:aws:states:::lambda:invoke.waitForTaskTokenParameters:FunctionName: ${AgentFunctionArn}Payload:agentStep: awaitSK.$: $.SKtaskToken.$: $$.Task.TokenTimeoutSeconds: 1209600 # 14 daysNext: Decided
When the agent's suggestion is ready, it alerts the manager: on the dashboard, and by email through Amazon SNS. Every day at 3 pm, EventBridge Scheduler checks whether that day's meal was logged and reminds the committee if it wasn't.

4. Did it actually work?
After the change, every meal of the new dish wakes the agent again. Code computes the before and after; the agent writes one plain sentence about it; code always adds the caveat.
In the demo story, waste fell from 18.2 to 11.3 kg per 100 plates after Aloo Gobi was swapped for Chole. Simulated data, one meal, labelled as an observed change.
We show the result as kg per 100 plates, not raw kilos, so a low-attendance day doesn't look like success. Food saved is also shown as plates (about 28 here, worked out from what each student actually ate) and as an estimated CO₂e footprint (about 21 kg, using FAO's global average of roughly 2.5 kg CO₂e per kg of wasted food). Both carry an Estimated label.
Students have a screen too: "Aaj ki sabzi kaisi thi?" One tap for a rating and one for a reason ("bahut teekha", "thanda tha"). They can also vote for what should be cooked instead, choosing from dishes served at the same meal, or suggest a dish of their own. Students know the food best. Their reasons and votes go straight into the agent's evidence, and their ideas show up on the manager's dashboard.
Why each AWS service is there
Service | Its job in MessLoop | Why this one |
|---|---|---|
API Gateway (HTTP API) + Lambda | The whole API, in TypeScript | Pay per request; a mess logs a few meals a day |
DynamoDB | One table: meals, ratings, suggestions, trials | Single-digit-millisecond reads, nothing to manage |
DynamoDB Streams | Wakes the agent when a meal is logged | The agent reacts to data, not to a button |
Step Functions | Runs the agent: investigate, pause, measure | The human-approval pause is a real task token, visible in the console |
Amazon EC2 | Hosts our own model (Qwen3-4B, llama.cpp) | The evidence never leaves our AWS account |
Polly + Transcribe streaming | Asks in Hindi, transcribes each answer live | Hindi voices and Hindi speech-to-text, no audio stored |
SNS + EventBridge Scheduler | Emails alerts; the 3 pm daily check | The agent can reach people, not just a dashboard |
S3 | Hosts the React site | Static files, a few cents |
CloudWatch | Logs every request, agent run and AI call | One place to see what the agent did |
AWS SAM (open source) + CloudFormation | Every piece defined as code | One template, one deploy, judges can read it |
The EC2 model server is the only real cost, about $0.36 an hour on a c7i.2xlarge, so it gets stopped after the hackathon. Everything else rounds to almost nothing at mess scale.
Amazon Bedrock wasn't available on our new account (
NOT_AUTHORIZED ), and the organisers confirmed any inference hosted on AWS counts. So we self-hosted a small open model behind the same validation. The model sits behind one small module, so moving to Bedrock later means changing that module and nothing else.What fought back
Problem | What happened | Fix |
|---|---|---|
The 1.5B model got facts wrong | Qwen2.5-1.5B wrote "Aloo Gobi received 61% of votes". That 61% was Chole's. | Moved to Qwen3-4B, and taught the validator to tie each vote share to its dish |
Comparisons were the weakest spot | Qwen3-4B said Mixed Veg had "lower waste than Chole" (22% vs 14%) | A check that compares claims against the numbers, and a prompt that asks for each dish's own numbers instead |
API Gateway's 30-second limit | A CPU model answer takes about 25 s | The API stores a template suggestion at once; the agent replaces it in the background |
The voice call was slow | Batch Transcribe jobs started after the call and took 10–15 s each, about 25 s of waiting | Streaming Transcribe per answer during the call, plus rules before the model: about 2 s |
A race between two writes | The agent's pause token and the manager's decision could overwrite each other | DynamoDB update expressions on separate fields, conditional on status |
One bad deploy | cloudformation package ignored a CodeUri in SAM Globals , so both Lambdas deployed without code | CodeUri on each function; an end-to-end check after every deploy |
A judge couldn't log in | At the DTU build day the demo stopped at the login screen because the role codes hadn't been shared | One-click "Try the demo" buttons, safe because all demo data is simulated and resettable |
The engineering numbers in this post come from our own runs. The end-to-end check (24 steps: log a meal, agent wakes up, pause, approve, measure, report) passes on the live deployment, alongside 59 unit tests.
What we don't claim
- The meal data in the demo is simulated, and the app says so on every screen. The voice call, agent and alerts are real and running; the history behind the story is not.
- One meal after a change is an observed change, not proof. The app always shows how many meals the comparison is based on.
- The CO₂e figure is a global average, not a measurement of our mess.
What we learned
- Ask the people who do the work before you measure anything. The leftovers we planned to weigh weren't waste.
- If logging takes more than a few seconds, it won't happen. Talking beat typing.
- Let rules decide what's wrong and let the AI explain it. The alert is a fixed rule; the agent never decides on its own.
- Validate what the model looked at, not just what it said. Numbers it never fetched get rejected.
- A human-in-the-loop step should be a real pause. A task token is harder to skip than a button.
- Run the whole loop after every deploy. It caught a broken release within minutes.
Try it
Open the live app, tap Mess staff under "Try the demo", choose बोल के बताओ, and answer in Hindi. Then log in as Manager and watch the agent's activity fill in.
Built by Vipul Yadav, Vidushi Singh and Parth Negi for Environmental Hacks 2026 (Bharat Builds Tour). We used Claude Code as a coding assistant throughout.
Enjoyed reading this content? Let the author know!
Your likes, comments, shares, and saves help creators reach more builders.
Loading recommendations
Loading article