Two of Our Three Demos Failed Live. We Still Placed Third.
What the Sea × OpenAI Codex Hackathon taught me about why judges remember the story, not the stack.
We placed third at the Sea × OpenAI Regional Codex Hackathon in Singapore. Forty teams, 300-plus applicants, one day to build.
The project was Shopee Live Producer: an agent that works backstage during a live commerce stream. Not a chatbot. Something more specific than that.
The ranking matters less than what got us there. I’ve done enough hackathons now to notice a pattern. The teams that place well don’t just build fast. They scope clearly, tell a clean story, and don’t fall apart when the demo gets messy. We did most of those things. The parts we didn’t do are where the actual lessons are.
The problem was worth building
Shopee Live hosts are doing several things at once. Selling. Answering buyer questions in a chat that moves faster than anyone can read. Keeping the energy up. Not accidentally making product claims that the platform doesn’t allow.
That last one is easy to overlook, but it matters. In live commerce, a host saying something unverified mid-stream, like an exaggerated health claim or a price guarantee they can’t back, creates real problems after the fact. When you’re live with hundreds of people watching, the wrong answer is out before you’ve thought it through.
A chatbot doesn’t fix this. A chatbot answers everything it can, and that’s the wrong behaviour for a live room.
What we wanted was closer to a producer. An agent that sits behind the host, not in front of the buyer. The difference matters more than it sounds. A chatbot responds to whoever talks to it. An agent works toward a goal on someone’s behalf, and it can choose not to act. Ours read each incoming question and picked one of four moves: answer, escalate, warn, or stay quiet. The host stayed in control. The agent just gave them better information, faster.
Producer, not chatbot. That distinction was what we kept coming back to, and it’s what we tried to make the architecture actually reflect.
How it actually worked
On every incoming buyer message, the agent ran the same four steps.
Classify first. Each message gets bucketed into one of four actions: AUTO_REPLY, ESCALATE, WARN, or NO_ACTION. Spam gets dropped. A policy-risky claim from the host triggers a warning. A genuine product question moves to the grounding step.
Ground before replying. This was the part I cared most about getting right. We seeded a product catalogue where every fact (spec, price, policy) had its own ID. Before the agent generated a reply, it had to tie that reply to a specific fact ID in the catalogue. If it couldn’t, it escalated instead of guessing. No made-up product specs going out to a live room.
Remember what the host answered. When a host manually resolved an escalated question, that answer went into the session store. Next time the same question came in, the agent could answer it directly using the host’s confirmed words instead of escalating again. It got better at the job as the stream went on.
Coach the sale. On top of the question loop, the host console surfaced prompts: a flag when the same feature kept coming up, or a nudge when the host could lean harder on something buyers clearly wanted. The agent wasn’t only answering buyers. It was helping the host sell.
We wired it together with LangChain, and Supabase Realtime kept the buyer view and the host console in sync. Every decision the agent made was visible to the host, and every one could be overridden before it reached the buyer.
That was the system on paper. Building it in a day, with three people in the same codebase at the same time, was something else.
The build broke an hour before submission
About an hour before the deadline, we hit merge conflicts bad enough to break the build. Three of us had been working in parallel: the buyer view, the host console, and the grounding gate. We’d drifted. Different people in the same files. Integration assumptions nobody had said out loud.
Here’s the part that usually gets skipped in write-ups like this. We didn’t patch and pray. We stopped, triaged, cut the branches that weren’t essential to the demo loop, resolved the conflicts cleanly, and reran the whole thing from scratch before submitting. What we shipped was working and coherent, not something we were quietly hoping wouldn’t fall over in front of the judges.
Merge conflicts in a hackathon aren’t the story. What you ship when the dust clears is.
The first presentation got us into the finals
We went in without everything wired up. Session memory was partial. The coaching layer was barely stubbed. But the core loop was solid enough to show: classify, ground, decide, display.
It was enough. The problem was clear, the user was clear, and why it wasn’t a chatbot was clear. The judges could follow the logic without the full thing running in front of them.
This is what I’ve had to learn across several hackathons: story before polish. If you can’t explain the problem in two sentences, more features won’t save it. Getting to the finals told us the core narrative worked. It also meant a shorter slot, higher stakes, and a room far louder than anything we’d rehearsed in.
The final demo didn’t go to plan
We’d planned to show three things: the grounding gate, the session memory, and the coaching layer.
We got through the first cleanly. The other two didn’t happen.
Session memory failed in the room. The venue was loud, and whatever we’d set up to trigger that part of the demo didn’t register. I remember the exact second I knew it wasn’t going to work. That feeling of recalibrating on the spot while trying to keep it off your face. I kept moving. Stopping to fumble with it would have been worse.
The coaching layer got cut because we ran out of time before we reached it.
Here’s what I noticed while pushing through: the judges were still with us. The core loop still landed. Buyer asks, agent classifies and grounds, host sees the call and can step in. That’s the product. The memory and the coaching extend it, but they aren’t what make it make sense. The judges didn’t need to see all of it to get what we were building.
We should have rehearsed in noise. We should have timed it more tightly. The missing features were on us. But the logic held well enough that losing two of them didn’t lose the room.
What actually won it
It wasn’t the stack. Next.js 15, TypeScript, LangChain, Supabase Realtime, and the OpenAI API. Solid, but plenty of teams had solid stacks.
What won it was being able to sell the user journey.
I mean that exactly. We could walk through every step from “buyer types a question” to “host knows what to do with it,” and say why each piece existed. The grounding gate is there because the alternative is a fake spec going out live. The classifier is there because not every message deserves a reply. The host console is there because the agent’s job is to inform, not to decide.
Judges see a lot of projects in a short window. The ones they keep are the ones where the logic feels inevitable. You get what it does, why it’s built that way, and who it’s for. That kind of clarity doesn’t come from picking the right framework. It comes from actually understanding the workflow you’re building inside.
What I’d do differently
The hardest moment of the day wasn’t the merge conflicts. It was clocking, mid-demo, that session memory wasn’t going to fire in that room, and having to decide right there whether to chase it or move on. I moved on. I think it was right. Part of me still isn’t sure.
The rest of what I’d change is less philosophical:
- Three features for a five-minute slot is one too many.
- Rehearse in noisy conditions, not ideal ones.
- Protect the last hour. Stabilising only, no new work.
- Write the demo script before the build, not after.
And the thing I’m taking into the next one: ship something you can stand behind, and keep the core loop legible even when the edges aren’t done. Know the problem well enough that when features fall away, the story still holds.
This is the work I want to do. Agents that sit inside real workflows, not wrappers floating on top of them. Systems where the user journey is the product, not a thin layer over a model call.
Shopee Live Producer was a one-day build. Merge conflicts an hour before submission. Session memory, the room swallowed whole. A coaching layer that never got its moment on stage.
Polished MVP. Third place.
The code matters, but the story is what they remember.
