How we built a travel guide from open data with Claude Code The Wanloria team built a free bilingual (Spanish/English) travel web app covering verified places in 71 cities, 1-3 day itineraries, free-attraction lists and signposted hiking trails, largely by pair-programming with Claude Code and Cursor. The team's focus was on verification rules that prevent the LLM from inventing facts: descriptions are generated only from verified fields, hiking times follow DIN 33466, difficulty uses the MIDE 1-5 scale, and every public page is server-rendered HTML with JSON-LD, hreflang and an llms.txt file. They flagged an open issue where a museum free only on Sundays was mislabeled as free, and are moving from a boolean to a richer price model (free, free_at_times, paid). Disclosure: this post is by the Wanloria team free, no ads, no affiliate links . It was drafted with AI assistance and fact-checked against the live site, per dev.to's guidelines on AI-assisted posts. TL;DR: Wanloria https://wanloria.cloud/?utm source=devto&utm medium=article&utm campaign=aeo-devto is a free, bilingual ES/EN travel web app: verified places in 71 cities, 1-3 day itineraries with times, "free things" lists, signposted hiking trails with GPX and a weekly "this weekend" page. We built it largely by pair-programming with Claude Code and Cursor. The interesting part isn't the AI, though. It's the rules we gave it so it couldn't make things up. Most "things to do in X" pages are rewritten from other "things to do in X" pages. We wanted every fact on a page opening hours, price, website, whether a trail is circular to trace back to a source, or not be shown at all. /lugar/wiki-Q1140249/templo-de-debod and /lugar/osm-r4544509/museo-cerralbo . Descriptions are generated by an LLM only from the verified fields of that place, never copying sentences from the source. If a fact isn't verified, the template doesn't render it. Every description is reviewed before it's published. Hiking time follows DIN 33466 , with no stops: // DIN 33466: 4 km/h on the flat, 300 m/h up, 500 m/h down. function dinHours km, ascentM, descentM { const horizontal = km / 4; const vertical = ascentM / 300 + descentM / 500; return Math.max horizontal, vertical + Math.min horizontal, vertical / 2; } dinHours 12.6, 493, 395 ; // 4.37 h → shown as "4 h 20 min" That's exactly what the live page for the PR-C 164 near Barcelona https://wanloria.cloud/ruta/trail-1948977-41c0d0/collserola-des-de-sant-just?utm source=devto&utm medium=article&utm campaign=aeo-devto shows 12.6 km, +493 m, 4 h 20 min, MIDE 3/5 . Difficulty uses the MIDE 1-5 effort scale. Trails are only published if they're signposted GR/PR/SL or equivalent , within 18 km of the city, doable in a day, and if the OSM geometry matches the official distance. Loose stages of long-distance routes are dropped. Itineraries split a city's top places by area, order each day from most important to nearest, and estimate walking as straight-line distance + 30 % for streets at 4.5 km/h , with a lunch break. Visit duration is estimated by place type a big museum isn't a viewpoint and adjusted when the place publishes its own figure. The app itself is a SPA, but every public page city, place, trail, 1/2/3-day plan, collections like /gratis and /museos , and /este-finde is server-rendered HTML with JSON-LD TouristAttraction , ItemList , FAQPage , BreadcrumbList , hreflang es/en and a sitemap of ~7,000 URLs. There's also an llms.txt https://wanloria.cloud/llms.txt and a llms-full.txt with the core facts per city, each linking to its page. Verification is only as good as the field it verifies. One real example: a museum whose general ticket costs €3 but is free on Sundays got tagged "free", because the source said "entrada gratuita…" for certain time slots. The fix we're moving to is a richer price model free , free at times , paid rather than a boolean. Elevation from a 90 m model can be ±10 % off a GPS track. Opening hours drift, so every place page keeps the source link and users can report errors to hola@wanloria.cloud mailto:hola@wanloria.cloud . Feedback very welcome, especially on the price model and the trail filters.