Models sound just as certain when they're wrong as when they're right. So when I plan through places I've never been, I treat what the AI tells me as a lead to check, and keep the facts that matter — distances, ferries, what's actually open — coming from sources I trust.
The name is deliberate. A planned route is only a theory. The AI and I draft it together, but the deciding is mine: shaping it, prompting carefully, confirming the facts before I rely on them out there. A route only proves out once it's ridden and logged — what worked, what didn't. The plan is a guess; the ride is the evidence. That's why it's a log, not a planner.
01 — The problem
The map can't lie when you're 40km from anywhere
A real two-person cycle tour, Berlin to Copenhagen along EuroVelo 7, planned in a shared spreadsheet. The spreadsheet worked at the kitchen table and failed on the road: no offline access, no map, no way to tap a stop and navigate to it when the signal dropped somewhere in rural Mecklenburg. The wedge was the constraints of cycle touring — real distances, ferry timetables, accommodation that may or may not be open in shoulder season.
Those constraints are exactly where general-purpose travel AI fails. Travel-planning LLMs hallucinate hotels, invent ferry schedules, and fabricate distances. Building on a model as the primary source of physical-world facts would be irresponsible for a tool you actually rely on mid-trip. So the architecture draws a hard line — and the line is the interesting part.
Deterministic · ground truth
AI · language & reasoning
Routing, distances, elevation
Eliciting constraints from plain language
Accommodation & ferry schedules
Critiquing a plan, finding the gaps
Pricing, opening hours, seasonality
"What if we had an extra day?" reasoning
Where things physically are
Synthesis ("stock up before Møn")
This is the split at runtime: when the AI needs a fact, it calls a tool, and the tool returns ground truth. AI did more behind the scenes — drafting the structured trip data while building the app — but every generated record is validated against a strict schema before it's trusted.
02 — How the work was run
Each phase shippable, validated on a real trip
The project moves in phases, each independently useful even if work stopped at its end. Decisions are captured as Architecture Decision Records before anything hard-to-reverse is written; work is tracked on a GitHub Projects board with issues titled by their roadmap ID. Solo, but run like a team — and pointed at a hard external deadline.
- 0FoundationRepo, docs, ADRs, CI, Vercel + Supabase plumbingDone
- 1Static PWAHardcoded Berlin → Copenhagen, offline, mobile, used on the tripCurrent
- 2Editable & collaborativeAuth, sync, two people editing one planPlanned
- 3Trip criticOne-shot AI review of a plan against its constraintsPlanned
- 4What-if assistantScoped chat, diff-based modifications to a tripPlanned
- 5GeneralisationUseful beyond trip one — speculativeFuture
Phase 1 is "done" only when it is installed on both phones, works with no signal, and is the thing actually reached for during the trip — late August. Real-world use, not a green CI badge, is the acceptance test.
03 — Key decisions
Every decision audited against the road
Governing constraint · Offline-First
"It has to work with no signal, on a phone, in the rain."
One real-world constraint governs the project, and every decision is judged against it rather than against what's convenient to build. Local-first storage, a PWA that installs without an app store, pre-computed routes that don't need a live API — none of these are technical preferences. They're the consequences of taking the trip seriously as the acceptance test.
The decisions build on one another: the offline-first posture everything inherits, the split between the plan and the ridden run, the rule that the app surfaces facts to verify rather than inventing them, and one decision that isn't about code at all. A coherent log that evolves — not standalone documents.
AI Layer Design record LLM orchestration
Is this an AI app? At runtime, no — in the making, very much
The running app is deterministic: when the model needs a fact it calls a tool that returns ground truth rather than generating one, and the planned features (critic, what-if, generator) share one orchestration substrate, with API keys only in edge functions. Deterministic backbone, AI on top. But AI did real work building it — generating the day and contingency data the app runs on — and every generated record passes through a deterministic script that validates it against a strict schema before it's committed and trusted. Those generation scripts are kept as an audit trail.
Why it mattersThe discipline is restraint, not avoidance. AI earns the jobs it's reliable at — language, reasoning, drafting structured data — and hits a hard wall everywhere facts matter: distances, schedules and prices never come from a model in a tool you trust on the road, and nothing it generates is trusted until a deterministic check has passed. Right-sizing the intelligence — a real collaborator, on a short leash — is the same judgment across the portfolio.
ADR-0004 Accepted Trip Runs as the unit of lived experience
The plan is a guess; the run is what happened
A trip is the plan — route, days, stops. A run is one rider's attempt at it, with its own dates and a per-day log of what actually happened: real distance, where you slept, the weather, notes. One trip can have many runs. The plan stays clean; the run carries the reality.
Why it mattersThis is the "log, not a planner" idea made structural. The plan is what's intended; the run is what's lived, and they're modelled as separate things so neither corrupts the other. Day logs stay anchored to the plan's days even when the plan is edited later, so the record of what happened never quietly drifts.
ADR-0003 Accepted Contingencies as a first-class concept
Surface the options; let the rider decide
A contingency is anything that helps you abandon, shorten or rescue a day — the nearest bike shop, a train that takes bikes, a bed to bail to. They're a first-class part of the model, and the app's job is to surface them with enough detail to verify and act on — never to recommend, book, or predict. Each one carries notes on how to check it (say, how to confirm bike-carriage rules on a given train).
Why it mattersIt's the same discipline as the AI layer, in the data model: lay out real, checkable options and be honest about what still needs confirming, rather than pretending to know which one will save the day. The kind of contingency is free text, so a new sort can be added the moment a trip surfaces a gap — no schema migration, no guessing the full list up front.
Decision record Accepted Repository visibility
The decision that isn't about code
The repository stays private, with the case study and selected artefacts — ADRs, roadmap, project board — published separately as redacted copies. The driver wasn't technical: it was a deliberate choice to curate what goes public rather than expose a working repo wholesale, so the portfolio reads as a considered presentation, not a code dump.
Why it mattersTreating repository visibility as a decision to record — not a default to drift into — is a judgment made above the architecture. Publishing redacted artefacts on request keeps control over what represents the work while still giving reviewers the full reasoning. Choosing curation over convenience is the unglamorous, senior call.
Also in the log: ADR-0001 (PWA over native) — a web app, not a native build, so two people can install one offline tool without app-store friction; ADR-0002 (Supabase over Firebase) — predictable pricing, Postgres, magic-link auth; ADR-0005 (persistence) — the backend decision deliberately deferred from day one until the first feature that actually needed to write data, then settled on the lowest-cost option that covers every later phase. The map and routing stack (MapLibre, BRouter) are deliberate tooling picks rather than headline decisions. Full set available to reviewers on request.