-
-
88% of Gen Z have a plan stuck in a group chat right now.
-
The quiet friend is asked privately; the answer lands back in the group.
-
Majority rules: Homi shows the tally, one person switches, nobody is steamrolled.
-
Drop the receipt and say "homi split the bill": Claude reads it, Homi splits it to the cent.
-
Three real Boston spots, two hearts, one address with a maps link.
Inspiration
Every group chat has the plan that died. Someone says "we should hang out!!", one person hearts it, somebody starts typing and stops, and three days later: "Hello?"
The numbers behind that feeling are not small. Americans aged 15–24 spent 153 minutes a day with friends in person in 2003 and 67 in 2019 (Kannan & Veazie 2023, American Time Use Survey). Ask one person for something and 36% reply; ask the same thing with 14 or more people copied and 14% do (Blair, Thompson & Wuensch 2005). In the average relationship one person is almost twice as likely to initiate contact, and the longer one side keeps initiating alone, the more likely the relationship is to end (Mollgaard & Mathiesen 2016). When a message is read and not answered, 42.8% of senders feel upset or angry (Hoyle et al., CHI 2017).
Put those together and you get the organizer: the one friend who proposes, follows up, picks the place, fronts the bill and chases the money. Every unanswered message lands on them. Nobody in a group feels responsible, so the organizer feels like they are nagging, and when they stop, the group stops meeting.
We wanted a friend who takes that job: one who lives in the chat you already have, carries the social cost of following up, decides fairly, and remembers only what a friend would.
What it does
Add Homi to the group. That is the whole setup. Then:
- "homi dinner friday 7pm." The person who named the time is in; everyone else taps ❤️ or answers in words ("fri works", "can't do thu", "I want to do earlier"). A window like "next week" gets three proposals. The lock happens when everyone has answered, or at the announced deadline.
- The quiet friend gets asked privately. After 30 seconds with no answer, Homi tells the group who is missing and messages them one to one: "does Fri Oct 23 · 7pm work for you for dinner? Reply yes, no, or a number." Their reply lands back in the plan as their vote. Nobody is called out, nobody has to chase. If only one person can make it, Homi says so and cancels instead of booking a dinner for one.
- The cuisine is decided by majority. "What are we feeling?" Each person's latest answer counts, so "ok thai then" moves a vote. Claude maps whatever people say ("pad thai sounds great") onto one of 15 cuisines; a split gets the tally ("No majority yet: Thai 1 · Japanese 1 · Pizza 1. Need 2 of 3 on one"); "surprise us" ends it. Then three real Boston spots, a vote, and an address with a maps link.
- The bill. Send the receipt photo and say "homi split the bill" (or "3 ways", "between ana ben me", "paid by ana"). Claude reads the total off the photo and Homi does the math to the cent. Itemized splits with tax, tip and several payers, and "homi settle up" for who pays whom, are built in.
- It remembers like a friend. "homi I'm Ana" is kept for the chat, so the next plan greets Ana by name. On a dedicated iMessage line it knows who is in the group before anyone speaks. It keeps the plan, the running bill and the group's settings, encrypted; never your messages.
- It forgets on schedule and on command. A plan deletes itself 24 hours after the event. "homi what do you know" shows everything it holds; "homi forget" deletes the plan; "homi stop" deletes everything and Homi leaves.
- It always answers when you talk to it, and leaves everything else in the chat alone.
Also in the engine: show-up pledges where the group agrees first where no-show money goes (Homi moves no real money in this build), a members-only photo album, trip planning with labeled cost estimates, reminders, calendar invites and a phone call to the quiet friend who opted in.
How we built it
- Surfaces. Photon spectrum-ts for iMessage (a dedicated line for groups, shared lines for 1:1), Telegram groups over the Bot API, and Photon 2.0 SIP for the phone call (Retell voice agent, one question only). Thin adapters translate each platform to typed events and declare capabilities, so features degrade gracefully: tapbacks become numbered replies become plain text.
- Engine. A pure state machine:
applyEvent(state, event, ctx) → {state, actions}, no I/O, no clock reads. The same code runs in the offline chat, under the eval and on every live surface, and every rule has a test (533 passing). - Language. A closed-vocabulary reply grammar (replies are matched against the options Homi itself posted, never free-form date parsing), chrono-node for date words, a small naive-Bayes intent model on our own phrases, and Claude (Haiku 5.5) first for everything addressed to Homi: intent, cuisine mapping, receipt reading. Names, handles, numbers and links are replaced with placeholders before anything leaves the machine.
- Places. A curated Boston list for the 15 cuisines, a bundled OpenStreetMap snapshot with opening hours evaluated locally, and optional Google Places for everywhere else.
- Storage. SQLite (
node:sqlite); each plan sealed as one AES-256-GCM blob; member ids HMAC'd per group; at-most-once scheduler jobs; a retention sweep; a redacting logger.
Challenges we ran into
- Groups on iMessage. Free Photon projects get shared lines, and shared lines cannot see group chats. We made the engine capability-driven and ran the demo on a dedicated line and on Telegram, where the group size comes from the member count instead of a roster.
- The bot that never replied. In our first live runs Homi stayed silent on messages it could not read, which in a group reads as being ignored, the exact feeling we set out to fix. Now anyone who addresses Homi always gets an answer, the open question again or an honest "not sure what you mean", and the Claude-first listener is not allowed to turn chatter into that reply.
- Whose plan is it. With one exact time proposed, counting the proposer as pending produced "Only 0 can make it". The person who names the time is in; the poll is for everyone else.
- No calendars, by choice. Free-form date parsing read "Fri or Sat works" as two different weeks. Interpreting replies only relative to the options Homi posted fixed it.
Accomplishments that we're proud of
- The private follow-up: the quiet friend gets asked one to one and their answer lands back in the group, with nobody chasing and nobody shamed.
- Deliberation that ends: majority rules, each person's latest answer counts, and a split gets a tally and a nudge instead of a stalemate.
- Measured, not vibes. Ten role-play chats written blind from the spec, replayed through the real stack: 133 of 135 day-cells read correctly (1.5% error), the right final date in 10 of 10, 100% precision on food talk, 175 of 183 message intents right (4.4% error), zero message text or phone numbers in 502 log lines or the database.
- An agent that can say "here's everything I know" and then actually forget it.
What we learned
- Recognition beats recall. People answer "Fri 7pm?" instantly and never answer "when are you free?".
- The social design (who sends the nudge, who gets blamed, who is counted as in) matters more than the NLP.
- Silence is the worst reply. A bot in a group chat must answer when spoken to, every time.
What's next
- WhatsApp and SMS follow-ups, and an email digest for the people who never open the chat.
- Interactive iMessage cards for one-tap date and place pickers.
- Live places beyond Boston by default, and the engine released as a reusable "group decision" library.
Built With
- anthropic
- claude
- imessage
- node.js
- openstreetmap
- photon
- retell
- sqlite
- telegram
- typescript
Log in or sign up for Devpost to join the conversation.