Find the genuinely best flight — cash or points — by ranking every option against what a mile is actually worth to you.
- 🧠 Build your own with Claude Code →
GUIDE.md - 🛠 Run the code → below
- 🚀 Just use it → hosted version (coming soon)
Award availability and cash fares live in a dozen places and change by the hour. flight-finder pulls both — cash fares (via Google Flights) and award space (via the seats.aero Pro API) — then ranks every option using your per-program cents-per-mile valuations and travel preferences. It also enriches each option with seat-quality detail from AeroLOPA — cabin layout, seat counts, and the actual seat map for the specific aircraft (tail-number matched) — so you're comparing the seat you'll actually sit in, not just the price. "Is this a good deal?" becomes a number, not a vibe. And it runs as an MCP server, so you can plan trips conversationally in Claude Code: "find me SEA→Tokyo in business under 120k points."
uv sync
cp .env.example .env # add SEATS_AERO_API_KEY (+ optional AEROLOPA_API_ID / AEROLOPA_API_SECRET for seat maps)
# edit config/profile.yaml + config/programs.yaml (home airports, point balances, cpm values)
uv run ff search --from SEA --to FCO --depart 2026-11-21 --cabin BUSINESS
uv run ff awards --from SEA --to FCO --start 2026-11-18 --end 2026-11-23 --cabin business
uv run ff plan trips/example-trip.yaml --out trips/example-shortlist.mdclaude mcp add flight-finder --scope user \
-- uv --directory /path/to/flight-finder run python -m flight_finder.mcp_serverTools: search_cash_one_way, search_cash_round_trip, search_awards, find_positioning_flights, get_seat_map, plan_trip.
src/flight_finder/
offer.py # normalized Offer (cash or award) + Segment
config.py # profile + programs + env
cash/ # Google Flights wrapper + multi-origin × date fan-out
awards/ # seats.aero Pro client
strategy/scorer.py # cpm-based cost + preference-aware ranking ← the core idea
seatmaps/ # AeroLOPA enrichment: cabin product + seat map per aircraft (tail-matched)
planner.py # combines it all behind a TripSpec
cli.py · mcp_server.py
The interesting decision: a single normalized Offer for cash and award, so the scorer can compare them on one axis — your dollar value — instead of apples-to-oranges price vs. miles.
The hard part wasn't the model — it was the valuation layer. The same award seat is a steal or a trap depending on which points you hold, what you value, and even which seat you'll actually sit in. Encoding that judgment is what turns a search into a recommendation. It's true of most useful AI products: the model is the commodity; the context and the scoring are the moat.
Built nights and weekends, mostly by talking to Claude — scaffolded, iterated, and tested through Claude Code.
MIT