# A2A Travel Planner

Structured, verifiable data that AI agents read when planning trips in Japan. Phase 1 covers 10 cities. For each city the repo holds 20 historic but low-key attractions with coordinates, and public travel blog posts with photos about each attraction. Agents first, humans second.

**Status: milestone 1 (scaffold).** Schemas, validator, card and site builders, and agent docs are in place. No attraction data has been collected yet; Kyoto is the pilot city.

## Cities
Tokyo, Kyoto, Osaka, Nara, Kanazawa, Hiroshima, Nagoya, Fukuoka, Sapporo, Nagasaki (`data/cities.json`). Each city is its own folder under `cities/`, so swapping one is cheap. `data/queue.json` lists the 38 queued cities for later iterations (one per prefecture plus a second Hokkaido city), copied from the city-deck design; they are not part of phase 1.

### "Historic but low-key"
An attraction qualifies when it meets all of these:
- **Historic:** tagged `historic=*` or a heritage designation in OpenStreetMap, or listed in Wikidata with a heritage designation or an inception date before 1945.
- **Low-key:** not in the city's top tourist spots, has few Wikipedia language editions (5 or fewer, or no English article), and has no major crowd-management infrastructure.
- **Visitable:** open to the public or viewable from public land.
- **Spread out:** no more than 5 of the 20 in one ward or district.

## Data fields
- Attraction: `id, city, name_en, name_ja, lat, lng, osm_id, wikidata_id, category, era, designation, why_low_key, maps_url, retrieved_on, sources`, plus optional `district` and `coords_check` (second-source coordinate). See `schema/attraction.schema.json`.
- Blog post: `url, title, author, site, published, language, attraction_id, photos, licence, summary, retrieved_on`. See `schema/post.schema.json`.
- Intercity option: `from, to, mode, typical_minutes, transfers, notes, source, retrieved_on`. See `schema/intercity.schema.json`.

Coordinates come from free sources (OpenStreetMap, Wikidata). Google coordinates are not stored; each record carries a Google Maps link built from lat/lng, which needs no API. Blog posts and photos are **links and attribution only**: no copied images and no copied text.

## How to query
- Static files: `cities/<city>/attractions.json`, `posts.json`, `data/intercity.json`.
- A2A Agent Card: `/.well-known/agent-card.json`, generated from `server/tools.yaml`.
- The read-only A2A endpoint (`server/`) is scaffolded after the Kyoto pilot, so the skills match the real record shape.
- `llms.txt` and `AGENTS.md` for agents that do not speak A2A.

## Working in this repo
```bash
pip install -r requirements.txt
python scripts/validate.py            # schema, bbox, duplicates, maps_url, coordinate drift
python scripts/validate.py --strict   # release checks: 20 per city, posts, all 45 intercity pairs
python scripts/build_card.py --domain https://YOUR-DOMAIN --version v0.1.0
python scripts/build_site.py --domain https://YOUR-DOMAIN --version v0.1.0
python -m unittest discover tests
```
Kyoto pilot pipeline: `fetch_wikidata.py` -> `shortlist.py` -> `fetch_osm.py` (OSM candidates and a coordinate cross-check) -> hand curation. See `cities/kyoto/README.md`. `scripts/enrich_wikidata.py` is superseded by `fetch_wikidata.py` and is still a stub.

## Card photos
The flipped face of a city card can show a photo from Unsplash, hotlinked from `images.unsplash.com` with the photographer credited (nothing is copied into the repo). `data/city-image-picks.json` holds candidate photo ids; `python scripts/resolve_unsplash.py` checks each against the Unsplash API, pings the download endpoint as the API guidelines require, and writes `data/city-images.json`. The site shows a photo only for a city that is in that file, with a "Photo credits" list at the bottom. It needs an Unsplash Access Key: set `UNSPLASH_ACCESS_KEY`, or add it as a network secret for `api.unsplash.com` (header `Authorization`, value `Client-ID <key>`). A demo-mode key allows about 24 photos an hour; the script stops at the limit and resumes on the next run.

## Adding a city
`python scripts/new_city.py SLUG` creates the folder; the pipeline steps are listed in the new city's README. A city needs its `wikidata_id` in `data/cities.json`.

## Licensing and attribution
- **OpenStreetMap:** ODbL. Our `attractions.json` files are likely derivative databases, so the repo's data is intended to be published under the ODbL with attribution to OpenStreetMap contributors. Confirm against the OSM Licence and Legal FAQ before release; this is not legal advice.
- **Wikidata:** CC0, no attribution required. The Wikidata ID is recorded anyway for traceability.
- **Blog posts and photos:** links and attribution only; content stays with its authors.
- See `sources.md` for every source, licence and retrieval date.

Map data © OpenStreetMap contributors, ODbL.

## Corrections
Report a wrong coordinate or a dead link as an issue in this repo, with the attraction `id` and a source.
