Inspiration

I have a friend group spread across different jobs, different parts of the city, different schedules. Most of us are in our mid twenties doing the corporate thing now. Which means by the time the weekend comes, everyone is tired and nobody wants to be the person who has to organize something.

So the planning happens over WhatsApp. Someone sends "guys what are we doing this weekend" on a Thursday. Half the group sees it during a meeting and thinks they will reply later. Later never comes. By Saturday morning there are four unread messages, two suggestions that nobody responded to, and someone asking "so is anything happening or not."

And even when people do reply, nobody actually knows everyone else well enough to make a decision. Some people in these groups are friends of friends. I do not actually know if one person eats non veg. I do not know someone else's budget situation right now. Asking feels awkward. So everyone just says "whatever works" and nothing gets decided.

That is the real problem. Not that people do not want to hang out. They do. It is that the coordination is exhausting and nobody has full information and someone always has to chase everyone else.

Pakt tries to fix that. Each person sets up their profile once with their preferences, schedule, budget range, and the things they would never do. Then when someone wants to plan something, the agents step in and handle it. Nobody has to be the organizer. Nobody has to ask awkward questions. The agents already know, and they talk it out among themselves.

How I Built It

The core is one agent per person. Each agent knows its user and speaks in turns, reading what the previous agent said before it responds. That last part matters more than it sounds.

I almost built it the wrong way. My first instinct was to have all agents respond at once. Faster, everyone talks simultaneously. But then I caught myself. If they all go at the same time, none of them can actually react to each other. You get three people talking past each other, which is exactly what happens in the WhatsApp chat I was trying to fix. So they go one at a time, each one reading everything before it speaks.

Before any negotiation even starts, the system checks whether the person who started planning actually gave the agents enough information to work with. Things like the date, the general area, or what the group is in the mood for. If something important is missing, negotiation never begins. Instead the chat displays a small inline form asking only for the missing details. I did not want agents quietly making assumptions when simply asking the user would lead to a much better result. That follows the same philosophy as the rest of the product. Stop assuming and just ask.

I also gave the agents real information to work with. When they suggest a movie they have looked it up. When they recommend somewhere to go they first perform a shared real time web search so every agent is working with current information. A plan built on made up details is just a different kind of mess.

The piece I did not plan but ended up being my favourite is the memory layer. After every confirmed plan, each agent stores what happened, what everyone agreed to, and what got rejected. Next time the group plans something, that history comes back. During testing an agent referenced a plan from a completely separate session in its very first message of a new negotiation without being asked. That felt like it was actually working.

One thing I also paid attention to was cost. Every incoming chat message first passes through a lightweight classifier that decides whether the message is actually related to planning. Messages that are just casual conversation or unrelated questions never trigger a full negotiation. That keeps the system responsive while avoiding unnecessary AI calls.

What I Built It With

The frontend runs on Next.js deployed on Vercel. The three main screens including onboarding, the dashboard, and the group chat were scaffolded using v0 which saved a lot of time on the UI side and let me focus on what actually makes the application interesting. Confirmation is not a separate page. It appears naturally inside the chat once the agents reach consensus.

The database is DynamoDB with six tables. Five cover users, groups, messages, negotiation state, and polls. The sixth exists purely to enforce unique usernames. The messages table has DynamoDB Streams enabled which is what makes the real time workflow possible. Every new message automatically triggers a Lambda function where the negotiation engine runs.

Negotiation state and long term memory are stored separately. The negotiation state table tracks the current session including rounds, proposals, votes, and consensus. Long term memory lives in Amazon S3 Vectors and stores information across previous planning sessions so each user's agent can remember past experiences.

The negotiation engine itself is built with LangGraph running on Python inside AWS Lambda. Each agent is represented as a node in the graph with rules that determine whether negotiation should continue, move to voting, or stop and ask a human to make the final decision. OpenAI GPT 4o powers every agent. Movie recommendations come from TMDB while other activities use a shared real time web search step so every agent works with current information.

Real time communication between the backend and frontend uses Server Sent Events. As every agent finishes its turn, the backend streams that message directly to the browser, allowing users to watch the negotiation happen live.

Challenges

The worst bug I hit was accidentally building something that kept calling itself forever. Every time the backend wrote a message into the chat it immediately triggered itself to write another one which triggered it again and again. I only noticed because I checked the logs and saw things moving much faster than they should. The fix ended up being a single condition that I had completely forgotten to add.

Getting the agents to actually negotiate was much harder than getting them to talk. Early versions had agents that simply stated their preferences and then agreed with whatever anyone else suggested. Nobody challenged ideas. Nobody compromised naturally. I had to teach them when to stand their ground, when to negotiate, and when changing their opinion actually made sense.

The early conversations also sounded terrible. They were formal, robotic, and felt more like a report than a group chat. I rewrote prompts over and over until the messages became short, conversational, and felt like something real friends would actually send each other.

The memory system took much longer than expected. Saving memories was easy. Getting the agents to naturally use those memories in future negotiations without sounding forced required a lot of experimentation. Eventually I found a balance where past experiences subtly influenced decisions without dominating the conversation.

The real time chat also failed in a way that was difficult to notice. If the connection dropped and later reconnected, users would sometimes see duplicate messages or miss messages that arrived during the interruption. It looked completely fine on the surface and took several hours to trace back to the synchronization logic.

What I Learned

The biggest lesson was that slower is sometimes the better solution. I kept trying to make the agents respond simultaneously because it felt more efficient. But the moment I did that, the negotiation stopped feeling real. Reading and reacting to previous messages is what makes the conversation work.

The second lesson was about keeping the architecture simple. The frontend and backend never communicate directly. They both simply read from and write to the same database. That one decision made debugging dramatically easier because every problem could be isolated to a single part of the system instead of chasing requests across multiple services.

Building AI products also taught me that good user experience often comes from knowing when not to use AI. Asking users for missing context, filtering out irrelevant messages before they reach expensive models, and keeping the agents grounded in real information made the application noticeably more reliable.

Accomplishments I'm Proud Of

The memory system genuinely surprised me. I built it, ran a test, and watched an agent begin a brand new negotiation by referencing something that happened in a completely different planning session days earlier. Nobody instructed it to do that. It simply remembered.

I am also proud that this runs on actual AWS infrastructure rather than a demo setup. Real Lambda functions, real DynamoDB tables, real Amazon S3 Vectors, and a complete end to end negotiation pipeline. I successfully ran four negotiation rounds where agents disagreed, compromised, reached consensus, wrote the confirmed plan, and stored memories for future sessions.

Seeing the entire pipeline working together from validating user input through negotiation, streaming every message in real time, saving memories, and producing a final plan made the project feel like a real product instead of just another AI demo.

Finally, getting the agents to stop sounding like robots took far more effort than I expected. There was no technical shortcut. It simply required countless prompt revisions until the conversations felt genuinely human.

What's Next for Pakt

Movies and restaurants are only the beginning. The same negotiation framework can easily support concerts, weekend trips, sporting events, house parties, and many other shared activities. The preference system already supports expansion and only needs additional tools and onboarding questions for each category.

Another major step is completing the entire planning journey. Today the agents successfully agree on the activity, location, and time, but users still need to complete bookings themselves. Connecting directly with booking providers would allow the entire experience to happen inside Pakt.

The current version already includes a simple subscription model. Anyone can start with the free plan, which includes their own AI planning agent and up to five new Pakts each day for groups of up to four people. Pakt Pro removes the daily limit through a monthly subscription, making it a better fit for friend groups that plan frequently. I wanted to validate that the product could support a sustainable business model instead of existing only as a hackathon prototype.

The long term vision is for Pakt to become the layer between deciding and booking. Today the agents help groups reach a decision. Tomorrow they should also complete it. Once users no longer need to leave Pakt to reserve a table, buy movie tickets, or order food, the product becomes dramatically more useful.

That also creates a natural monetization path beyond subscriptions. I plan to integrate with restaurants, movie theatres, ticket booking platforms, event providers, and online food delivery services through affiliate partnerships and revenue sharing. Since the agents already recommend where to go and what to do, completing those bookings inside Pakt creates value for users while providing a sustainable revenue model for the platform.

Looking further ahead, I see opportunities to partner with restaurants, movie theatres, ticket booking platforms, and online food delivery services through affiliate programs and revenue sharing. Since the agents already help users decide what to do and where to go, completing the booking and earning through trusted partners feels like a natural extension of the product.

A mobile application is another obvious next step. This is fundamentally a problem people experience on their phones where their group chats already exist. Bringing Pakt directly into that environment would make it much more natural to use.

I also want to make the negotiation process more transparent. Right now users mainly see the final outcome. Showing the complete discussion, the arguments each agent made, and where compromises happened would make the experience feel more collaborative while helping users better understand how the final decision was reached.

Complete Demo Video

https://youtu.be/MWd6BCIEKqc

Built With

Share this project:

Updates