I Built AI Agents That Plan Weekends So My Friends Don't Have to Reply in WhatsApp
There is always that one group chat.
Every Thursday someone sends,
"Guys... weekend plans?"
Then nothing.
Three people read it. Two forget about it. Someone finally replies on Saturday afternoon asking if the plan is still happening. By then everyone has already made other plans or decided staying home sounds better.
It happens every single week.
I don't blame my friends. We're all busy. Work, college, deadlines, family stuff. Planning something with four or five people somehow ends up feeling like a full time job.
Even if someone actually tries, the questions never stop.
Which movie?
Which theatre?
Who's vegetarian?
Who's free after six?
What's everyone's budget?
Is this place too far?
By the time you've answered everything, the weekend is basically over.
After watching this happen for months I had one thought.
What if everyone had someone to do the planning for them?
Not another chatbot sitting in a group chat throwing random suggestions around.
An actual personal AI agent.
One agent per person.
It knows your preferences, your budget, your schedule, the places you've hated before, and it argues on your behalf while you're busy doing something else.
The agents negotiate with each other.
You come back later.
There's already a plan waiting.
That became Pakt.
This is how I built it.
Why "Pakt"?
The name came surprisingly early.
It's based on the word pact, a mutual agreement between people.
That's exactly what the app is trying to create.
Friends don't need another recommendation engine.
They need help reaching an agreement.
Changing the C to a K made it a little more memorable.
It also works nicely as a verb.
"Let's Pakt tonight."
That sounded good enough to stick.
The First Decisions
Before writing any code I spent a surprising amount of time deciding what not to build.
The hackathon required using AWS databases, so I had three options.
Aurora PostgreSQL.
Aurora DSQL.
DynamoDB.
For a chat application where multiple AI agents constantly write messages, DynamoDB felt like the obvious choice.
High write throughput.
Simple schema.
And one feature that ended up becoming the backbone of the entire application.
DynamoDB Streams.
More on that in a bit.
For the frontend I went with Next.js hosted on Vercel.
Most of the UI started life inside v0.
Honestly, it saved me an unbelievable amount of time.
Instead of spending days aligning buttons and tweaking layouts, I could focus on building the actual product.
The onboarding flow, dashboard and chat interface all started there before I customized everything.
For the AI side I used GPT 4o.
Every user gets their own agent powered by the same model.
The interesting part isn't the model.
It's the system prompt.
Every agent has a different personality because every agent represents a different person.
Someone who loves action movies shouldn't suddenly recommend romantic comedies just because everyone else likes them.
The prompts had to make the agents feel like actual people instead of copies of each other.
Finally there was LangGraph.
That ended up becoming the brain of the whole application.
The Multi Agent Problem Nobody Warns You About
Whenever people talk about multi agent systems, they usually focus on making agents smarter.
Better prompts.
Better tools.
Better memory.
Nobody talks about the real problem.
How do you make them stop talking?
Seriously.
If you give four AI agents a shared goal and tell them to figure it out, they'll happily keep discussing forever.
They'll agree.
Then disagree.
Then agree again.
Then revisit a point from three rounds ago.
LLMs don't naturally know when a conversation is finished.
They need rules.
That's exactly what LangGraph gave me.
Instead of one long unpredictable conversation, I could define the negotiation as a graph.
An agent speaks.
The next agent responds.
After everyone has spoken, another node checks whether they've reached consensus.
If they have, great.
Publish the plan.
Finish.
If not, start another round.
If they've gone around in circles four times, stop the negotiation and ask the actual humans to decide.
Without that hard stop, the app would have been one very expensive infinite conversation.
The Decision That Changed Everything
One design choice completely changed how the app felt.
Originally I wanted every agent to run in parallel.
It sounded perfect.
Everyone responds at the same time.
Collect the responses.
Done.
Fast.
Efficient.
Then I realised something.
If Agent Two starts thinking before Agent One finishes speaking, Agent Two never actually reacts to anything.
The same goes for everyone else.
What I built wasn't a negotiation.
It was four independent opinions dumped into a chat window.
It felt less like friends making plans and more like filling out a Google Form.
Real conversations don't work like that.
People react.
They change their minds.
They compromise.
Sometimes they completely disagree.
That only happens if everyone can hear what everyone else has already said.
So I changed the graph.
Every agent now runs one after another.
Agent Two reads Agent One's response.
Agent Three reads both.
By the time the fourth person speaks, the conversation has actually evolved.
Yes, it's slower.
But the slowness is exactly what makes it feel real.
Sometimes good software isn't about making something faster.
It's about making it feel natural.
How Everything Actually Works
This is probably my favourite part of the project.
Not because it's the most complicated.
Because it's surprisingly simple once you see the pieces working together.
The frontend never talks to the AI directly.
The AI never talks back to the frontend.
Everything happens through DynamoDB.
Here's what happens when someone sends a message.
The frontend writes the message into the Messages table.
That's it.
Its job is done.
Now DynamoDB Streams notices that something new has been written.
Think of Streams like a doorbell.
Every time a new record appears, it rings automatically.
That event wakes up an AWS Lambda function.
Inside that Lambda is the entire LangGraph workflow.
The function loads everyone's preferences, fetches memories, starts the negotiation, and lets each agent speak one after another.
Every time an agent finishes its turn, Lambda immediately writes that response back into DynamoDB.
It doesn't wait until the whole negotiation is finished.
Each message appears as soon as it's generated.
Back on the frontend there's a Server Sent Events connection quietly listening for anything new.
The moment another message lands in DynamoDB, it's streamed straight into the chat.
Watching the app feels surprisingly natural.
One agent starts typing.
A second later another replies.
Then someone disagrees.
Then another person suggests a compromise.
It feels much closer to watching four friends text each other than watching an AI generate a giant wall of text.
One thing I really liked about this architecture is that every component has exactly one responsibility.
The frontend writes data.
Lambda thinks.
DynamoDB stores everything.
That separation made debugging much easier because whenever something broke I already knew roughly where to start looking.
Giving Every Agent a Memory
Making agents remember your favourite movie sounds impressive.
Honestly, that's the easy part.
The interesting challenge is deciding what they should remember.
Pakt uses two different kinds of memory.
The first is short term memory.
This lives inside DynamoDB and only exists during an active negotiation.
Things like which round we're on, what restaurants have already been suggested, whether someone has voted, whether consensus has been reached.
Once the negotiation ends, that state disappears.
The second is long term memory.
That's stored in Amazon S3 Vectors.
Whenever a plan is accepted or rejected, every user's agent writes a small memory about what happened.
Maybe someone rejected a restaurant because parking was terrible.
Maybe the group loved a particular theatre.
Maybe everyone agreed never to suggest horror movies again.
Those memories are embedded into vector storage and kept completely separate for each user.
When a new conversation starts, the agent searches through those memories before it begins negotiating.
The first time I saw this working properly genuinely caught me off guard.
I started a completely new group.
Nobody had mentioned restaurants yet.
One of the agents immediately said something along the lines of,
"We didn't really enjoy that restaurant last time. Maybe we should try somewhere else."
That information came from a completely different conversation days earlier.
Nobody told the model to mention it.
It simply remembered.
That was one of those moments where the project stopped feeling like a demo and started feeling like an actual product.
The Weirdest Bug I Ran Into
Most bugs are predictable.
This one wasn't.
No matter what group I created, the agents somehow kept suggesting the exact same restaurant.
Someone would reject it because it was too far away.
Another negotiation round would begin.
The same restaurant came back.
Again.
And again.
Then things got even stranger.
My reviewer agent confidently explained that one of the restaurants was in Thrissur.
The address wasn't in Thrissur.
It was actually a mock address in Bangalore.
The model wasn't reading location data.
It was guessing based on the restaurant name.
That sent me down a very long debugging session.
Eventually I realised the problem wasn't the agent at all.
It was my architecture.
The venue search tool wasn't configured with a real Google Places API key yet.
Every search quietly returned the exact same mock dataset regardless of what city anyone searched for.
Every agent was independently calling the same tool.
Every agent received the same fake data.
And because there were no real addresses available, my reviewer agent had nothing concrete to compare.
It had a venue name and a lot of confidence.
That's a dangerous combination.
The fix ended up changing the architecture quite a bit.
Instead of letting every agent search for venues independently, I moved venue search into its own shared step inside the graph.
Now venue search runs once per negotiation round.
It performs a real search.
The results are cached for that round.
Any venue that was rejected gets filtered out before the next search.
Every agent now negotiates using exactly the same list of real places.
Nobody is guessing anymore.
Even better, the reviewer agent now receives the actual address of the selected venue along with every group member's address.
Checking whether somewhere is too far is no longer a guess.
It's just distance calculations.
That one bug completely changed how I thought about multi agent systems.
Shared information beats independent guesses every single time.
Guardrails Aren't Just About Safety
Another lesson I learned was that guardrails save money just as much as they improve reliability.
Originally every single message sent inside a group triggered a full negotiation.
It didn't matter what the message said.
Someone could paste a programming question.
Ask for today's weather.
Type complete nonsense.
The app would still launch an entire LangGraph workflow.
That meant multiple GPT 4o calls for absolutely no reason.
The fix was surprisingly small.
Before a message even gets written into DynamoDB, a tiny GPT 4o mini classifier checks whether it's actually related to planning.
The prompt is tiny.
The token limit is tiny.
If the message isn't about planning, it never reaches Lambda.
No negotiation.
No unnecessary API calls.
No wasted money.
I also added another guardrail after integrating real venue search.
Google Places isn't free.
If something went wrong and negotiations kept restarting forever, the app could quietly burn through API credits.
To avoid that, every search increments a shared counter stored in DynamoDB.
Once the daily limit is reached, the app simply falls back to mock data instead of breaking completely.
Hopefully nobody ever notices that fallback.
But it means I don't wake up to an unexpectedly large bill either.
Teaching Humans How to Talk to Agents
One thing became obvious during testing.
Humans are terrible at giving useful information.
Someone would create a group and type,
"Let's do something this weekend."
That's it.
No date.
No time.
No area.
No activity.
No budget.
The agents would spend the next few rounds asking questions instead of actually planning.
Technically it worked.
Practically it felt slow.
So I added another small step before negotiations begin.
The first message gets checked against a simple schema.
Depending on the activity type, the app looks for things like the date, preferred time, search area, movie genre or cuisine.
If enough information is missing, the chat doesn't even start negotiating.
Instead it renders a small form directly inside the conversation asking only for the missing details.
Once that's filled in, the agents finally have enough context to do something useful.
I made a similar change during onboarding.
Originally adding your home location was optional.
Almost nobody filled it in.
Which meant the distance calculations I had spent so much time building quietly stopped working for most users.
Now it's required.
Locality.
District.
State.
Pincode.
Everything gets geocoded into latitude and longitude during onboarding.
From that point onwards, every venue recommendation actually considers how far everyone has to travel.
That tiny onboarding change ended up making the recommendations feel dramatically smarter without changing the agents themselves.
Making Memory Visible
I realised something after building long term memory.
Users had no idea what their agent actually remembered.
They just had to trust me.
I didn't like that.
So I added a Memory page to the dashboard.
Every memory the agent stores is visible there.
Users can browse through them, see why they were saved, and delete anything they don't want anymore.
It doesn't make the AI smarter.
It makes the product feel more trustworthy.
I think that's just as important.
People are much more comfortable with AI remembering things when they can actually see what those things are.
What Pakt Looks Like Today
After weeks of building, rebuilding, debugging and questioning my own decisions, Pakt finally feels like a real product instead of a collection of AI experiments glued together.
The experience is intentionally simple.
You sign up once.
Tell the app a little about yourself.
Your favourite movies.
Food preferences.
Budget.
Your general schedule.
Where you live.
That's all the setup you need.
From there everything happens inside the group chat.
Create a group.
Invite your friends.
The moment everyone joins, their agents get to work.
Nobody has to tell the agents to start.
Nobody has to type "any suggestions?"
The conversation begins automatically.
The agents discuss different options, recommend movies from TMDB, find restaurants using Google Places, remember what the group enjoyed before, and slowly work towards something everyone is happy with.
Sometimes they agree almost immediately.
Sometimes they don't.
When there's a genuine split between two good options, Pakt creates a vote inside the chat.
Real people vote.
The agents take that result and continue negotiating from there.
Humans stay in control.
The agents just remove all the exhausting back and forth.
And if someone suddenly joins the conversation halfway through and says,
"I can't stay out too late tonight."
or
"I'm not really in the mood for pizza anymore."
The agents immediately adjust the negotiation around that new information.
Nothing has to restart.
The conversation simply continues.
Once everyone reaches an agreement, the chat ends with a plan card containing everything the group needs.
The venue.
The time.
The people joining.
And eventually, I want that card to include the actual booking as well.
A Few Small Things That Made a Big Difference
Not every improvement involved complicated architecture.
Some of my favourite fixes were tiny.
One of the first things I noticed during demos was that GPT naturally writes Markdown.
Lists.
Bold text.
Headers.
The chat wasn't rendering any of it.
Instead people saw a screen full of random asterisks.
It looked broken.
One Markdown renderer later, the entire conversation suddenly felt polished.
Another surprisingly important improvement involved the demo accounts.
Originally they all had empty profiles or random addresses.
The agents would recommend places that made absolutely no sense because nobody actually lived anywhere.
Before recording demos, I replaced those with real nearby locations.
Suddenly the recommendations became believable.
Sometimes the smallest details make the biggest difference when you're showing a product to someone for the first time.
Under the Hood
The final architecture ended up being much bigger than I originally expected.
There are six DynamoDB tables.
Users.
Groups.
Messages.
Negotiation state.
Polls.
And one extra table that exists for one reason only.
Making sure usernames stay unique using transactional writes.
The AI workflow runs inside AWS Lambda.
Each execution gets a 300 second timeout, which is far more than a normal negotiation ever needs.
To avoid cold starts during demos, EventBridge pings the function every few minutes.
Nobody watching a live demo wants to wait while Lambda wakes up.
Some engineering decisions exist purely because you've been embarrassed once.
That was one of them.
What I Want To Build Next
I think Pakt solves the hardest part of planning.
Getting people to agree.
But there's still one obvious gap.
Right now the agents decide where everyone should go.
The humans still have to book the movie tickets.
Reserve the restaurant.
Buy the event tickets.
I want the conversation to end with the booking already completed.
The agents shouldn't just recommend something.
They should finish the job.
The second thing I want to build is a proper mobile app.
This problem lives on phones.
Every group chat lives on phones.
People aren't sitting at a laptop wondering what they're doing on Saturday night.
They're checking WhatsApp while waiting for a bus or standing in a queue somewhere.
The experience belongs on mobile.
Longer term, movies and restaurants are just the beginning.
Weekend trips.
Concerts.
Sports.
Road trips.
Coffee catch ups.
Game nights.
The negotiation engine doesn't really care what it's planning.
It just needs different tools and different questions.
That part is surprisingly scalable.
What This Project Actually Taught Me
When I started building Pakt, I thought the hardest part would be getting the AI to make good decisions.
It wasn't.
The AI was probably the easiest part.
The difficult part was everything around it.
Designing the architecture.
Making sure every agent had the same information.
Knowing when a negotiation should stop.
Making sure memory actually helped instead of confusing the conversation.
Keeping costs under control.
Building guardrails.
Handling failures without breaking the experience.
Those ended up being the real engineering problems.
One lesson stood out more than anything else.
I originally thought running every agent in parallel would make the app feel smarter.
Instead it made the conversation feel fake.
The moment I switched to sequential negotiation, everything changed.
The agents actually started responding to each other.
Compromises appeared naturally.
Arguments felt believable.
The conversation slowed down.
Ironically, that slower experience felt much more human.
Sometimes making software feel intelligent isn't about making it faster.
It's about making it behave the way real people do.
Final Thoughts
Pakt started because my friends couldn't decide where to go on weekends.
Somewhere along the way it turned into one of the most enjoyable projects I've ever built.
Not because of the technologies.
Not because of the hackathon.
But because it kept forcing me to rethink how AI systems should actually work.
I went into this project thinking I was building a chatbot.
I came out of it thinking much more about orchestration, memory, shared context, architecture and trust than prompts or models.
That's probably the biggest lesson I took away.
If you're building multi agent applications, spend less time trying to make individual agents smarter.
Spend more time thinking about the system they live inside.
Shared context.
Clear responsibilities.
Good orchestration.
Reliable memory.
Those matter far more than another clever prompt.
And if your group chat still spends three days deciding where to eat every weekend, hopefully Pakt can save you from reading another message that says,
"So... are we doing anything or not?"
JoelJaison394
/
Pakt
AI agents that negotiate your social plans, so you don't have to.
Pakt
AI agents that negotiate your social plans, so you don't have to.
Each user has a personal AI agent that knows their tastes, schedule, and budget. When a group wants to plan a movie night or dinner, their agents negotiate with each other in a shared chat — proposing, compromising, polling, and converging on a single confirmed plan — with the real humans able to jump in and override at any point.
Built for H0: Hack the Zero Stack (AWS DynamoDB + Vercel + Next.js) — deadline 30 June 2026.
The Problem
Planning leisure time with friends is broken — not because people don't want to hang out, but because of the coordination overhead:
- "Can we do Saturday?" starts a 40-message thread that takes 3 days to resolve.
- Everyone has different schedules, budgets, food preferences, and movie tastes.
- Someone always says "IDK, up to you" — decision paralysis…
Built for the H0 Hack the Zero Stack Hackathon.
Stack
- Next.js
- Vercel
- AWS Lambda
- Amazon DynamoDB
- DynamoDB Streams
- LangGraph
- OpenAI GPT 4o
- Amazon S3 Vectors
- TMDB API










Top comments (0)