Google Maps gets you to the parking lot. Indoor wayfinding kiosks start at the front door. The walk in between is where patients get lost and miss their appointment. Medical Wayfinder closes that gap with a fine-tuned Gemma 4 E2B that runs on the patient's phone. It speaks English and Spanish and works at any facility without an enterprise contract.
Two audiences. Two ways in.
iOS first; Android in test. Voice-first and multilingual, with accessibility on by default. The model and five facility packs ship inside the app — it works in airplane mode.
Author your facility in an afternoon. The editor sits on top of OSM and satellite tiles, with a Street View edge-walker for ground truth and GitHub OAuth for team access. Sign in, edit, publish.
Tap the mic. Say it however you'd say it — "the kids' doctor," "lo del corazón," "where they take blood." The model figures out which department you mean. A plain shortest-path algorithm then walks the facility map (no LLM involved in the routing). The model writes the resulting steps back in the patient's language with landmark and accessibility cues.
That split is deliberate. Routing is a solved problem and we don't ask the model to solve it. The model handles the parts only a model can — figuring out what someone meant, replying in their language, and holding to a strict JSON contract. It also turns down medical questions outside its scope.
▸ Model output · five-block contract// validated client-side; drops invalid blocks silently [ { "type": "destination", "department": "Lab / Blood Draw", "building": "Atrium", "floor": "1" }, { "type": "steps", "steps": [ { "text": "Enter via the main entrance, 800 Washington St.", "accessibility": "automatic_doors" }, { "text": "Walk past Au Bon Pain; right at Information.", "accessibility": null } ] }, { "type": "arrival", "check_in": "Kiosk at the front desk; bring photo ID." } ]
Watch the same pipeline handle two turns of one session. The first locates the patient at the main entrance. The second handles a real-world wrinkle: they got distracted and ended up at the cafeteria. Everything below happens on the device, no round-trip to a server.
// model output [ { type: "destination", department: "Blood Draw", building: "Atrium", floor: "1" }, { type: "steps", steps: [{ text: "Main entrance, 800 Washington.", accessibility: "automatic_doors" }, … ] } ]
// re-orient detected, // origin = cafeteria_node [ { type: "guide_text", text: "Got it from the cafeteria you're three minutes out." }, { type: "steps", steps: [{ text: "Exit cafeteria, turn right at the elevator bank.", accessibility: "elevator" }, … ] } ]
The model figures out what the patient meant (English or Spanish, colloquial or clinical) and emits a five-block JSON contract. The actual routing runs on a shortest-path algorithm over the facility's 11–30-node map. Keeping the model out of the routing is what makes the whole thing small, fast, and reliable.
Hospital wayfinding is an under-measured cost, and it lands hardest on the patients nobody designs navigation for. Each number below comes from a peer-reviewed study or federal data.
Atlas is the tool a clinic uses to map its own building. It runs in a browser — Vite + React + TypeScript on the frontend, FastAPI and Redis on the backend, GitHub OAuth for sign-in, plus a Street View edge-walker for ground-truth checks.
5 facilities · 99 nodes · 79 edges · 60 departments. Mini-map cards, region filters, status pills.
Map-first editing over OSM + satellite, node inspector, Street View edge-walker for ground-truth, LLM bootstrap of department aliases.
App-faithful render of the model contract before publish. Closes the loop without round-tripping a Flutter build.
Same production prompt, only the LoRA toggles. Every delta is attributable to the fine-tune alone, not to prompt engineering. Judge model is gpt-oss-120b, JSON-schema-constrained, scoring five criteria 1–5.
| Configuration | Mean (1–5) | Strict pass | Soft pass | English | Spanish |
|---|---|---|---|---|---|
| Base Gemma 4 E2B + production prompt | 3.62 | 28% | 47% | 3.57 | 3.92 |
| + LoRA (cp78), same prompt | 3.98 | 38% | 56% | 3.94 | 4.17 |
| Δ · attributable to fine-tune alone | +0.36 | +10 pp | +9 pp | +0.37 | +0.25 |
Training pipeline, eval suite, Flutter app, Atlas dashboard, facility data, deck, this site. Built to be forkable.
A monorepo with three pieces that stay in sync through a shared system prompt and a strict five-block JSON contract.