Project Info
This project did not submit a demo video on Devpost.
Inspiration
Every group trip we've planned hits the same wall: a group chat with eight people throwing out preferences, someone volunteering to "look into flights," and three days later nothing's booked. We wanted an agent that could actually do that comparison work — check real prices, not just suggest a vibe.
What it does
TripSync collects trip preferences from a group via a shareable link — budget, vibe, dates, must-haves. Once enough people respond, the organizer hits "Generate Trip Plan" and the agent takes over: it reconciles everyone's input, brainstorms candidate destinations, browses real flight prices, hotel rates, and local activities for each, then scores and ranks them against the group's stated preferences. Output: one report with ranked destination cards and a plain-English "why this fits" for each.
How we built it
A small Express server handles live group input — shareable trip codes, QR links, real-time response tracking. That triggers a four-stage pipeline: aggregate group responses into one preference set, brainstorm candidates (pure LLM reasoning), research each via real Browserbase sessions (flights, hotels, activities), then score and rank against the group's actual preferences. Every reasoning step uses forced tool calls for structured output instead of prompting for JSON — far more reliable across a multi-step chain. Each stage also runs standalone for isolated testing.
Challenges we ran into
Google Flights and Booking.com are dense, frequently-changing pages — getting reliable extraction took real iteration, plus fallbacks (Skyscanner) so one site's quirks couldn't sink a destination's results. Keeping multi-device form submissions race-condition-free took some care, solved by Node's single-threaded handling as long as nothing awaits between reading and writing state.
Accomplishments we're proud of
Our activities step originally pulled a full Wikivoyage page through Stagehand's extractor every run — ~70k tokens to find a "things to do" list. We rewrote it to grab only the relevant sections via a lightweight DOM script first, cutting that to ~2.6k tokens (~27x), with a fallback to full extraction if a page's structure ever changes. Small fix, big difference for a pipeline meant to run repeatedly.
What we learned
The biggest lever for cost and reliability was separating "the agent should reason here" from "we already know where this data lives" — Claude reasons where it adds value (reconciling preferences, scoring tradeoffs), and gets pre-mapped extraction everywhere else.
What's next
Two-way Google Calendar sync for the winning destination, group voting on final picks instead of one organizer deciding, and more research sources for larger or pickier groups.
TripSync
A group trip planner agent built for CalHacks AI Hackathon (Browserbase track).
Describe a group's trip preferences — budget, dates, vibe, must-haves, deal-breakers — and TripSync:
- Brainstorms 2-3 candidate destinations with Claude (pure reasoning, no browsing).
- Researches each candidate live in a real browser via Browserbase +
Stagehand:
- Flight price range from Google Flights (falls back to Skyscanner if extraction fails)
- Lodging price range from Booking.com
- Top activities/things to do from Wikivoyage
- Scores each destination against the original preferences (budget fit, vibe match, deal-breaker violations) using Claude with structured tool-use output.
- Renders a visual HTML report with ranked destination cards.
Setup
npm install
cp .env.example .env # fill in your keys
Required environment variables (.env, gitignored):
ANTHROPIC_API_KEY=
BROWSERBASE_API_KEY=
BROWSERBASE_PROJECT_ID=
Running
Run the full pipeline (edit the example preferences in src/main.ts to change the trip):
npx tsx src/main.ts
Output is written to output/results.html — open it in a browser to see the ranked destination
cards.
Running each stage in isolation
Each stage is independently testable:
npx tsx src/brainstorm.ts # Step 1: destination brainstorm
npx tsx src/research.ts # Step 2: Browserbase + Stagehand research for one destination
npx tsx src/score.ts # Step 3: scoring against preferences
Architecture
| File | Purpose |
|---|---|
src/types.ts | Shared types for preferences, candidates, research, and scores |
src/brainstorm.ts | Step 1 — Claude tool-use call to suggest candidate destinations |
src/research.ts | Step 2 — Stagehand browser automation for flights, lodging, activities |
src/score.ts | Step 3 — Claude tool-use call to score and rank candidates |
src/render.ts | Step 4 — renders the ranked results as a static HTML report |
src/main.ts | CLI orchestrator that runs all four steps end to end |
Step 0: live group-preference form
Before the pipeline above runs, the organizer collects each group member's preferences through a live multi-device form. Express server + in-memory store (no database needed for a single demo event), plain HTML/JS frontend (mobile-friendly).
npm run server
This prints both a localhost URL and a LAN URL (e.g. http://192.168.x.x:3000) — use the LAN
URL on phones.
Flow:
- Organizer opens
http://localhost:3000, clicks Create Trip → gets a short code (e.g.A4EJ6) and a shareable link/trip/A4EJ6. - Each group member opens that link on their own phone and submits name, budget, vibe (multi-select), dates (or "flexible"), and free-text notes.
- Organizer opens
/trip/A4EJ6/resultsto watch responses arrive live (polls every 3s). - Once ≥2 people have responded, the organizer enters a departure city + airport code for
the group and clicks Generate Trip Plan. This triggers the full pipeline on the server:
src/aggregate.tssynthesizes all respondents into oneTripPreferencesobject (Claude tool-use call — reconciles budgets, dates, and vibes, and pulls must-haves/deal-breakers out of free-text notes)- then Steps 1-4 (
brainstorm.ts→research.ts→score.ts→render.ts) run exactly as described above
- The results page polls
/api/trips/:tripId/planfor status and shows a View Trip Plan button once done. The finished report is also saved tooutput/<tripId>.html.
This takes 1-2 minutes per destination (real browser research via Browserbase), so 3 candidates can take 3-5 minutes total — the UI shows a "generating" state throughout.
Testing the multi-device flow locally
- Make sure your laptop and phone(s) are on the same WiFi network.
- Run
npm run serverand note theNetwork:URL it prints (e.g.http://192.168.86.29:3000). - On your laptop, open that URL and click Create Trip to get a code like
A4EJ6. - On each phone's browser, go to
http://192.168.86.29:3000/trip/A4EJ6and submit the form. - Watch
http://192.168.86.29:3000/trip/A4EJ6/resultson your laptop update within ~3 seconds of each submission.
If a phone can't reach the laptop, check that your Mac's firewall isn't blocking incoming connections to Node, and that the phone isn't on a "guest"/isolated WiFi network (some routers/venues block device-to-device traffic on guest networks — use a personal hotspot as a fallback).
Analysis
View
Metric
- 3
Figures cover GitHub contributors during the hackathon window. A co-authored commit counts in full for each author, so per-member totals add up to more than the whole-team figures.
Technology
- AnthropicIn code
- CSSIn code
- ExpressIn code
- HTMLIn code
- JavaScriptIn code
- TypeScriptIn code
6 of 6 appear in the indexed code.
AI coding agents
No AI coding agent signals were found in this repository.
Detected from committed agent config files and commit authorship. Absence of a signal is not proof an agent was unused.
Codebase size
Source size
128 KB
Source files
21
Counts recognized source files only; vendored directories, binaries and lockfiles are excluded, so this is smaller than the repository on disk.
Repository
deionchaudhary1/TripSync
27 files · 257 KB · @ 41e473d
Structure
API & routing
5 files · 19%Request entry points: routes, handlers and controllers.
Application logic
8 files · 30%Domain rules, services and shared utilities.
Supporting
Layers are inferred from where files sit in the tree, not from reading the code. A project that names its directories unconventionally will read oddly here — open the file browser to check anything the diagram implies.
Languages
- JavaScript51%
- TypeScript37%
- HTML4%
- CSS4%
- Markdown4%
Share of indexed source by file size. Binary and vendored files are excluded.
Dependencies
package.json
npm · 10- @anthropic-ai/sdk
- @browserbasehq/sdk
- @browserbasehq/stagehand
- dotenv
- express
- zod
- +4 more
Declared in the repository’s manifests at the indexed commit. A declared package is not proof it is used, and runtime dependencies are listed first.
Feature verification
Aggregation of group responses into one preference set via Claude tool-useVerified
Agent reconciles everyone's input (budgets, dates, vibes) and pulls must-haves/deal-breakers from free text, using a forced Claude tool call
Claimed on readmehigh confidencesrc/aggregate.ts:63— aggregatePreferences calls anthropic.messages.create with tool_choice forced to submit_preferences, synthesizing budget/dates/vibe/mustHaves/dealBreakers
Brainstorm 2-3 candidate destinations via pure LLM reasoningVerified
Claude brainstorms 2-3 candidate destinations with pure reasoning, no browsing
Claimed on readmehigh confidencesrc/brainstorm.ts:43— brainstormDestinations calls Claude with forced submit_candidates tool, minItems 2 / maxItems 3, no browser calls
Each pipeline stage independently testable via CLIVerified
Each stage runs standalone for isolated testing (npx tsx src/brainstorm.ts, research.ts, score.ts, aggregate.ts)
Claimed on readmehigh confidencesrc/brainstorm.ts:83— Standalone test block guarded by import.meta.url check runs brainstormDestinations with example datasrc/research.ts:380— Same standalone-test pattern for researchDestinationsrc/score.ts:134— Same standalone-test pattern for scoreDestinationssrc/aggregate.ts:113— Same standalone-test pattern for aggregatePreferences
Four-stage pipeline orchestration end-to-end on the serverVerified
A four-stage pipeline (aggregate -> brainstorm -> research -> score/render) runs automatically when the organizer generates a plan, with status polling and a finished HTML report saved per trip
Claimed on readmehigh confidencesrc/server/pipeline.ts:40— generatePlanHtml calls aggregatePreferences, brainstormDestinations, researchDestination (looped), scoreDestinations, renderResultsHtml in sequencesrc/server/pipeline.ts:20— Writes output/<tripId>.html and updates plan status to donesrc/server/app.ts:171— GET /api/trips/:tripId/plan exposes plan status for client polling
Generate Trip Plan trigger requiring minimum 2 respondentsVerified
Once at least 2 people respond, the organizer clicks Generate Trip Plan to trigger the pipeline
Claimed on readmehigh confidencesrc/server/app.ts:149— generate endpoint rejects requests with fewer than 2 respondentspublic/results.js:3— MIN_RESPONDENTS = 2 gates the Generate button in the UI
Live multi-device group preference form with real-time response trackingVerified
Group members submit preferences (budget, vibe, dates, notes) via a mobile-friendly form; organizer watches responses arrive live (polls every 3s)
Claimed on readmehigh confidencesrc/server/app.ts:77— POST /api/trips/:tripId/responses validates and stores respondent submissionspublic/results.js:2— POLL_INTERVAL_MS = 3000 and pollRespondents() polls /api/trips/:tripId every 3ssrc/server/store.ts:59— addRespondent stores respondent data in an in-memory Map
Optimized DOM-script activity extraction (27x token reduction) with fallback to full extractionVerified
Rewrote activities extraction to grab only relevant Wikivoyage sections via a lightweight DOM script, cutting ~70k tokens to ~2.6k, with fallback to full page extraction if structure changes
Claimed on Devposthigh confidencesrc/research.ts:109— WIKIVOYAGE_SECTION_EXTRACTOR is an in-browser script that extracts only the Do/See sectionssrc/research.ts:332— Fallback to stagehand.extract() over the whole page if the section text is too short/missing
Race-condition-free multi-device form submissions via Node single-threaded handlingVerified
Concurrent form submissions across devices are kept safe because nothing awaits between reading and writing state
Claimed on readmemedium confidencesrc/server/store.ts:59— addRespondent reads trip and synchronously pushes to trip.respondents.push with no await in between, consistent with the claimed single-threaded safety approach
Real browser research of flights, hotels, activities via Browserbase + StagehandVerified
Agent browses real flight prices (Google Flights, Skyscanner fallback), hotel rates (Booking.com), and activities (Wikivoyage) via real Browserbase sessions
Claimed on Devposthigh confidencesrc/research.ts:15— buildStagehand() configures Stagehand with env BROWSERBASE and Browserbase API key/project IDsrc/research.ts:172— getFlightPriceRange scrapes Google Flights and falls back to Skyscanner on failuresrc/research.ts:254— getLodgingPriceRange scrapes Booking.com for nightly pricessrc/research.ts:312— getActivities scrapes Wikivoyage for activities
Scoring and ranking destinations against group preferences using Claude structured tool-useVerified
Agent scores each destination against budget fit, vibe match, and deal-breaker violations using Claude with structured tool-use, then ranks
Claimed on readmehigh confidencesrc/score.ts:69— scoreDestinations forces submit_scores tool call producing budgetFitScore, vibeMatchScore, dealBreakerViolations, overallScoresrc/score.ts:125— Results are sorted by overallScore descending, i.e. ranked
Shareable trip link and QR code for group preference collectionVerified
Group members join a trip via a shareable link and QR code, with short trip codes
Claimed on readmehigh confidencesrc/server/ids.ts:6— generateTripCode() creates short trip codes like A4EJ6src/server/app.ts:35— GET /trip/:tripId serves the shareable link routepublic/home.js:24— Generates a QR code (qrcode(0, 'M')) pointing to the trip form URL
Structured tool-use forced output instead of prompted JSON across all reasoning stepsVerified
Every reasoning step uses forced tool calls for structured output instead of prompting for JSON
Claimed on Devposthigh confidencesrc/aggregate.ts:90— tool_choice: { type: 'tool', name: 'submit_preferences' } forces structured tool outputsrc/brainstorm.ts:66— tool_choice forced to submit_candidatessrc/score.ts:112— tool_choice forced to submit_scores
Visual HTML report with ranked destination cards and plain-English rationaleVerified
Output is one report with ranked destination cards and a plain-English why this fits for each
Claimed on Devposthigh confidencesrc/render.ts:92— renderResultsHtml sorts candidates by score and renders ranked cards with rank badges, scores, and a whyItFits writeupsrc/render.ts:79— Card includes 'Why it fits' text sourced from Claude's whyItFits field
CLI orchestrator running full pipeline end to end (src/main.ts)Code-supported
Run the full pipeline via npx tsx src/main.ts, writing output to output/results.html
Claimed on readmemedium confidencesrc/main.ts:1— File exists as described in the architecture table as the CLI orchestrator, but was not read in full to confirm every step matches the README exactly
Group voting on final destination pickClaimed only
What's next: group voting on final picks instead of one organizer deciding
Claimed on readmehigh confidenceTwo-way Google Calendar sync for winning destinationClaimed only
What's next: two-way Google Calendar sync for the winning destination
Claimed on readmehigh confidence
An AI agent derived these features from the project’s Devpost page and readme, then searched the code for each one. Verified features are backed by cited code; claimed-only features had no supporting code, which is not by itself proof a feature is missing.
Export this project's context (description, README, evidence, key source files) to chat with an AI agent elsewhere.