flight-finder
by nstevens
README.md
# flight-finder
> Find the genuinely best flight β cash *or* points β by ranking every option against what a mile is actually worth to *you*.
### Three ways to use this
- π§ **Build your own** with Claude Code β [`GUIDE.md`](./GUIDE.md)
- π **Run the code** β below
- π **Just use it** β hosted version (coming soon)
## What it does
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](https://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](https://www.aerolopa.com)** β 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."*
## Quickstart
```bash
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.md
```
## MCP (Claude Code)
```bash
claude mcp add flight-finder --scope user \
-- uv --directory /path/to/flight-finder run python -m flight_finder.mcp_server
```
Tools: `search_cash_one_way`, `search_cash_round_trip`, `search_awards`, `find_positioning_flights`, `get_seat_map`, `plan_trip`.
## How it works
```
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.
## What I learned building this
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 with Claude Code
Built nights and weekends, mostly by talking to Claude β scaffolded, iterated, and tested through Claude Code.
## License
MIT
TDQS
B3.2/5.0
Scored across 6 tools
Disambiguation5/5
Each tool targets a distinct aspect of flight finding: positioning flights, seat maps, trip planning, award search, and cash search (one-way and round trip). No overlaps.
Naming Consistency5/5
All tool names follow a consistent verb_noun pattern with snake_case (e.g., find_positioning_flights, get_seat_map, search_awards).
Tool Count5/5
Six tools cover the core functionality of a flight finder without excess. The scope is well-scoped and manageable.
Completeness4/5
The set covers major flight search types (award, cash) and trip planning, but lacks tools for flight status, booking management, or filtering by amenities. Minor gaps exist.
Maintenance
ActivitySlowing
ResponsivenessSyncing