Inspiration
Planning a road trip with friends means:
- agreeing on the destination, dates and activities,
- ironing out the details (budgets, dietary needs, where to stop),
- and making sure everyone actually replies!
But there's a hidden task: one person has to become the "group leader" who organizes everything and everyone.
We've been that person many times, so we built Trippy 🚗 to automate that job. It makes group planning more democratic (everyone gets a say) and much faster.
What it does
Trippy is an AI group leader that lives in iMessage. Each traveler texts Trippy in their own DM. Trippy collects everyone's requirements, finds where the group disagrees, puts only those disagreements to a vote, and plans an itinerary built for real people.
- Start and join in one text.
new tripstarts a trip and sends a standalonejoin CODEmessage the host forwards to friends. Trippy reads each person's first name from their Photon user record, so nobody gets asked. - Three quick questions:
- 📍 Where? The host sets the starting point, and friends just pick a destination.
- 📅 When? e.g. "Oct 18–19".
- 💵🥗 Budget and dietary needs? e.g. "$300, halal".
Replies like Octobr 18 to 19 or 250, none are understood instantly. Gemini handles anything written as a full sentence.
- "Anything else?" in words or pictures. One reply adds a wish ("beach day", "seafood") or says "nope". Or send a photo: a screenshot of an Instagram post becomes "Visit The Chicken Joint, Myrtle Beach, SC", and a photo of a view becomes "stops similar to this".
- Nudges whoever the group is waiting on. "⏰ Hey Rameez — Cooper is waiting on you to respond (Cooper for 13 sec)", then again after 1, 4, 16 and 64 minutes. It only nudges when someone is actually waiting.
- Settles what it can on its own:
- the budget becomes the lowest one stated, so everyone can afford the trip;
- everyone's dietary needs are combined;
- "Wilmington" and "Wilmington, NC" count as the same place;
- wishes are checked to make sure they fit together.
- Polls only where people differ. The destination and dates go to a vote. Reply with a number or in your own words ("Asheville!"). A tie gets a revote.
- Plans while you vote. As soon as a poll opens, Trippy drafts a complete itinerary for every possible outcome with Gemini and live Google Search, so the plan arrives shortly after the last vote.
- Plans for people, not just places. Every itinerary is checked against the real drive times:
- meals at normal mealtimes (lunch around noon, dinner around 6) and never two in a row;
- a 15-minute "Stretch break near Dillon, SC" at least every 2 hours of driving, because sitting for hours is tiring and raises blood-clot risk;
- about 8 hours of driving a day at most, and no driving at night.
A 4-day trip comes back with every day filled: breakfast, sights, lunch, dinner and the hotel, with breaks and lunch on the drive home.
- The itinerary is a mini-app. "✅ Itinerary ready!" is followed by a Photon mini-app card with Trippy artwork that opens a trip dashboard inside iMessage, with Map, Schedule, Impact and Trip tabs.
- A send-off. Everyone gets a line that fits the destination ("🏖️ You're set for Myrtle Beach! … don't forget to pack sunscreen 🧴😎") and a dap GIF.
Live re-planning on the road:
- "we're 30 min late" shifts the rest of the day;
- "sushi instead of pizza" swaps a stop;
- a photo ("saw this on Instagram, can we eat here?") is added as a new stop for everyone;
- "can we add an extra day?" goes back to a quick group vote, and a tie keeps the plan;
- "I'm out" lets that person leave without holding up anyone else's votes or plans.
Everyone is notified, and every card updates in place. Trips stay within the US.
Optional review round, behind a setting. Each piece of feedback is classified and handled one of three ways:
- minor: applied automatically;
- material: everyone approves again;
- conflicting: goes to a vote.
How we built it
- Photon Spectrum (
spectrum-ts): iMessage DMs, photos (including a photo and its caption sent as one message), mini-app cards that are edited in place, typing indicators and GIF attachments, plus Photon's users API for first names. - Gemini 3.8 Flash (Interactions API): structured output with Google Search grounding to research itineraries, plus reading photos, free-form answers and live updates. Each task runs at its own thinking level.
- OpenAI Decisions API (
gpt-6-luna): fast choices from a fixed set of options, in about 150–300 ms. It maps free-text votes to poll options, sorts wishes, checks that wishes fit together and picks the destination's vibe. Gemini is the fallback for each. - Tiger Data (Postgres + TimescaleDB) with Drizzle ORM: stores trips, members, requirements, polls and every itinerary version, plus
chat_eventsandtrip_eventshypertables. The reminders read their timing straight from those hypertables. - OpenStreetMap: Leaflet tiles, Komoot Photon and Nominatim for geocoding, Photon reverse geocoding to name stretch-break towns, and OSRM for routing.
- TypeScript on Node 24 with a Hono HTTP server. Zod schemas check every contract and every LLM response.
- Plain HTML/CSS/JS for the dashboard, in a Frutiger Aero style, with Trippy the red-car mascot.
- Vitest + PGlite: 121 tests that run fully offline against the real database migrations.
Our design rule: Gemini decides what to do, and code computes every number. Distances, drive times, fuel, CO₂ and the schedule all come from OSRM and our own code, never from the model.
Challenges we ran into
- Photon Pro doesn't deliver group-chat messages to the agent, so Trippy can't sit in a group chat. Instead each traveler DMs Trippy, and Trippy coordinates the group across those DMs, starting with a forwardable join message.
- Native iMessage polls can be sent, but the votes never reach the agent. We switched to numbered replies plus free-text votes ("Asheville sounds better"), which OpenAI Decisions maps to the right option. We also built a poll mini-app; it's turned off to streamline the User Experience so people vote by texting within iMessage, requiring minimal number of user clicks.
- Gemini latency. Researching an itinerary with web search took 74–86 seconds at Gemini's default thinking level. What brought it down:
- a lower thinking level (about 11 s);
- a cap of 3 web searches (7–10 s);
- drafting the complete itinerary for every possible vote outcome while people vote.
In our rehearsals, a full multi-day itinerary arrived about 20–50 seconds after the final vote, including the human-schedule checks. The quicker everyone votes, the more of that work is left to do after the vote.
- AI itineraries ignored human needs. Early drafts had meals at 10:44 AM and 4:04 PM, and 4-hour drives home with no break. We wrote rules with sources into Gemini's instructions: AAA and the National Safety Council for breaks, the CDC on blood clots, and USDA time-use data for mealtimes. Then we check them in code against the real OSRM times. Our code adds stretch breaks and moves early meals; whatever's left goes back to Gemini once with the exact problems.
- Too many back-and-forth messages. Our first version needed about 12 messages per person. We cut it to about 6, most answered instantly, by:
- grouping the questions;
- reading answers with code first, which also catches misspelled months;
- taking names from Photon;
- letting the host set the starting point.
- Limits of Gemini's structured output. It rejects
oneOf, andminItems/maxItemson nested arrays return HTTP 400. We kept the schemas flat and enforce those rules with Zod after parsing. - Mini-app quirks:
- live cards render at text-bubble size, which was too cramped, so we send regular cards that open near-full-screen;
- every card edit returns a new handle that we have to store for the next edit;
- the in-app browser won't open new windows;
- free ngrok puts a warning page in front of the dashboard;
- the hackathon network blocked Cloudflare's quick tunnels.
- Finding real businesses on a map. OpenStreetMap geocoders happily return a same-name place in another city. A result only counts if its name and city match (or it's within 30 km). Otherwise the stop is marked "approx." or dropped, and dropped stops are listed on the dashboard.
Accomplishments that we're proud of
- A multi-user group-leader agent on iMessage that coordinates a whole group across separate DMs, from
new tripto a shared dashboard. - Itineraries that respect people: mealtimes, a stretch break every ~2 hours, sensible driving days and every day of the trip filled, all checked against real drive times rather than taken on the AI's word.
- Multimodal planning: send a screenshot or a photo while planning and it becomes a wish; send one on the road and it becomes a new stop for everyone.
- The Photon mini-app trip dashboard, designed by Pranav in Frutiger Aero, starring Trippy!
- Map: an interactive map of the route and stops, with Start and Whole route buttons.
- Schedule: an interactive schedule; tap a stop to jump to it on the map.
- Impact: sustainability metrics, including gas and money saved by carpooling, CO₂ per person compared with driving alone, and green stops.
- Trip: a traceability page showing the crew, every group decision with its vote count, and the itinerary version.
- Tiger Data for time-based tracking. Every message in and out is logged to a
chat_eventshypertable, which also filters out the duplicate deliveries Photon can send. Trip milestones (trip_created,member_joined,phase_changed,poll_closed,live_update,reminder_sent,member_left) go totrip_events. The reminders are computed entirely from these two tables. - Speed. Answers to the planning questions get instant replies, OpenAI Decisions responds in 150–300 ms, and the itinerary is drafted while people vote.
- Honest numbers. Every distance, time, fuel and CO₂ figure is calculated by code, and Gemini's price estimates are labeled as estimates.
- Privacy by design. Dashboards show only first names and group totals: no phone numbers, no individual requirements, and polls never show who suggested what. While planning, asking "where does Rameez wanna go?" gets "🤫 Everyone's picks stay secret until the vote!"
What we learned
- Our first idea and prototype needed a hard pivot once we found out that Photon Pro doesn't deliver group-chat messages.
- Claude Code alone couldn't search the Photon docs and build a working MVP to test our idea.
- So we refined the idea without AI, spending more than 2 hours on a design document covering the project idea, user flow and data flow. Pranav also designed the dashboard instead of asking Claude to come up with one from scratch.
- Giving Claude Code that design document produced a much better MVP, which only needed polish to improve the user experience.
- Measure before optimizing. Gemini's thinking level, not our prompt, was the biggest factor in its latency. And wherever plain code could read an answer, it replaced an LLM call.
- Don't trust the plan, check it. An AI itinerary can look fine and still schedule lunch at 4 PM; testing it against real drive times is what made it humane.
What's next for Trippy
- Group chat integration, once Photon supports group-chat messages.
- More multimodal input: voice notes and video (photos already work).
- More dashboard styles beyond Frutiger Aero.
- One-way trips and a separate starting point for each person. The planner already supports both; they're turned off for the demo to improve latency.
AI Usage
This project was built for HackNC 2026 with heavy help from AI coding tools, mainly Claude (through Claude Code). This section summarizes how we used it, and where people stayed in charge.
Specs first, then code
We spent a lot of time (over 2 hours!) on hand-written design documents before asking AI to generate any real code. They included:
- The pitch and user flow: what the agent does, phase by phase, from the first
newtriptext to re-planning on the road. - A data flow and spec: the requirement fields, the voting rules, the itinerary shape, and what the dashboard shows.
- Platform findings: notes from a hands-on probe of Photon's iMessage platform. These recorded what actually works (DMs, mini-app cards) and what doesn't (group-chat events, native poll votes).
These documents were the main input to code generation. Clear specs let Claude produce code that matched our intent, instead of guessing at it. When the implementation had to differ from the original pitch, we recorded the reason in a deviations table in CLAUDE.md. That way the specs and the code never silently drifted apart.
How we worked with Claude
- A shared project guide. CLAUDE.md is a living document that Claude reads at the start of every session. It holds the architecture, the conversation flow, the non-obvious platform rules, and the pitch deviations. We updated it as the project evolved, so each session started with the full context.
- Scaffolding and implementation. Claude generated most of the TypeScript from our specs. This covered the phase-by-phase agent engine, the database schema and queries, the Gemini, map and routing integrations, and the dashboard web pages.
- Probing before building. Before committing to a design, we had Claude write small experiments against the Photon platform. Their results shaped decisions like DM-only conversations and text-based voting.
- Tests alongside code. Claude wrote unit tests for the pure logic, such as vote tallying, scheduling and sustainability math. It also wrote integration tests that run against an in-memory database. We ran the tests, type checks and linting after each change.
- Iterating from real use. We tested on real iPhones and fed what we saw back to Claude: screenshots, error messages and things that felt wrong. Examples include a cramped inline card, hard-to-scroll tabs, and stray HTML entities in titles. Claude diagnosed each one and proposed a fix, and we verified it on device.
- Design polish. Claude helped refine the Frutiger Aero look of the dashboard, working from our screenshots and style direction.
What people decided
AI wrote much of the code, but the team made the product decisions. These included the overall concept and user flow, and which conflicts get a vote and which resolve automatically. The team also chose the privacy rules, the platform and tool choices, and the scope cuts. We reviewed the generated code, tested it on real devices, and rejected or redirected changes that didn't fit the spec.
AI inside the product
Separately from building it, the agent itself uses Google Gemini and OpenAI Decisions API at runtime. Gemini reads free-form messages and photos, drafts itineraries with web search, and classifies feedback and live updates. The Decisions API helps reduce latency during voting. We treat all AI output as untrusted. Everything is validated against strict schemas. Distances, drive times, fuel and CO₂ figures are always computed in code from OpenStreetMap routing, never taken from the model.
Built With
- css
- gemini
- html
- javascript
- photon
- timescaledb
- typescript
- zod
Log in or sign up for Devpost to join the conversation.