BACK_TO_BLOG
·3 min read·AI / Building / Engineering

Switchback: a content engine for motorcycle roads

89 commits into kickstand-web this week — what started as a POI catalog turned into an AI-grounded programmatic-SEO engine with a buildout orchestrator.

Most of the week was one repo: kickstand-web, the web side of Switchback (formerly Kickstand). It's the motorcycle-roads project I've been quiet about. The commit log is loud enough now that it's worth a paragraph.

The shape of it

Switchback started as a flat catalog of points of interest — Tail of the Dragon, Beartooth, Going-to-the-Sun. Six hand-seeded routes, hero photos from Unsplash, a Next.js detail page. A normal CMS-shaped thing.

That isn't what it is anymore.

This week the repo grew an OSM ingestion pipeline (feat(routes): pure Overpass parser with way-stitching + haversine length), a generative-art layer that renders deterministic SVG route posters keyed by content hash (feat(art): content-hash cache key with recipe-version invalidation), a per-POI YAML authoring format with a pnpm poi:upsert orchestrator, and — the actual interesting piece — an AI-driven state buildout orchestrator that takes a curated seed list of 150–250 routes, resolves each one against OSM, enumerates verified nearby places, and generates rider-to-rider prose grounded only in things that actually exist.

The grounding constraint is the part I care about. The system prompt forbids the model from naming any business, landmark, or feature that isn't either in the verified OSM places list or in the curated seed notes (see #4, feat(ai): body_mdx may name verified OSM places OR curated seed names only). No hallucinated diner names. No fake scenic overlooks. If it isn't in OpenStreetMap or in my notes, the model can't write it.

The guards that matter

A buildout pipeline that writes to a public-facing DB needs cheap, correct skip logic. Three commits this week were entirely about not doing the wrong thing:

  • #7 — already-covered geographic guard: skip a candidate route if an existing published POI's polyline already covers it (shorter-probe overlap test). Prevents cross-source duplicates.
  • #10 — run the guard before place enumeration: the original guard ran after Overpass had already paid for dozens of place-enumeration calls. Moving it before the enumeration cut per-route cost by an order of magnitude on already-covered routes.
  • #11 — never overwrite an existing POI on slug collision: when the AI slugified going-to-the-sun-road identically to the curated one, upsertPoi would clobber the hand-written content. Now it skips. We can't distinguish a curated POI from a re-run, so we never overwrite.

These are the unglamorous commits. They're also the ones that decide whether the pipeline can be left to run unattended.

What's actually shipped

Three new POIs landed in the DB from a real buildout run (#8): Highway 36 Fortuna→Red Bluff, Sonora Pass, and the Pintler Veterans Memorial Scenic Highway in Montana — all assembled from OSM ways via the osm-ways-ref route source (which required widening a CHECK constraint that the dry-run tests had never exercised, #9).

The rider profile system also went in (#15, #16) — bikes, badges, iconic-roads tracking — plus the auth foundation (#14) and an admin gate that closes the previously-open badge-studio and route-studio internal tools (#17). And a CSP that doesn't break static rendering (#20), because the Next 16 nonce-based recipe forces every page dynamic and would kill the ISR that the SEO surface depends on.

Elsewhere

TwoOps got a README refresh through Sprint 18 — drift detection, BYOK multi-provider AI, Polar usage billing, 1,800+ tests across 240+ files. No code this week; that one's been in a quieter polish phase. The personal site got Switchback added to the projects list.

Mostly: one repo, one pipeline, one bet. Curated seeds in, OSM-grounded prose out, no hallucinated landmarks. We'll see how it scales.