Web App · Transit

Your commute,
in one sentence.

A self-hosted Swiss public-transit app that knows your personal routes and gives you a short, AI-written status — not a wall of departure times. Built as an installable progressive web app.


The idea

Less a timetable,
more a briefing.

Most transit apps hand you a list of connections and leave the interpreting to you. planlos flips that: it knows the routes you actually travel, checks them against live data, and writes a short natural-language briefing — is the train on time, is there a delay, would the alternative get you there sooner.

The facts are assembled deterministically first, so they are always correct. The local language model only rephrases that draft into something readable. It never invents times or lines — that separation is deliberate, and it is what keeps the briefing trustworthy.


Features

Three tabs,
built around real routes.

// TIMETABLE

Saved routes

The connections you care about as reorderable tiles. Tap one to see its live status — on time, delayed, or better via an alternative — with the relevant departure for today's weekday.

Drag to reorder Live status
// COMMUTE

The briefing

One commute per account, outbound and return. The return can be derived from the outbound automatically. An optional walking-distance station per direction is compared against the direct route to find the genuinely better option.

AI briefing Auto direction
// LIVE

Load & disruptions

Second-class carriage occupancy per connection, plus disruptions merged from two independent official feeds and deduplicated, so a single source going quiet does not hide a problem.

Occupancy Disruption merge

Architecture

Local backend,
official data sources.

The backend is a Python service with a PostgreSQL database, all running on local hardware. It pulls live timetable, real-time, occupancy, and disruption data from the official Swiss open-transport API, and merges a second disruption feed as a safety net.

The frontend is a lightweight progressive web app — no framework, installable on a phone's home screen, with offline-capable caching. The AI briefing is generated per user through a local language model; if the model is unreachable, the deterministic draft is shown unchanged.

Backend
Python · PostgreSQL
Frontend
Vanilla progressive web app
Data source
Official Swiss open-transport API
AI briefing
Local LLM, per-user access
Auth
Argon2 password hashing
Deployment
Ansible, HTTPS, login required

Lessons

Measured, not assumed.

Disruption data turned out to need two sources rather than one. The connection-precise feed and the network-wide safety-net feed use entirely different identifier systems, so they cannot be matched automatically by reference — they are merged by comparing the disruption text instead, with the connection-precise feed taking priority.

The disruption filter also had to be narrowed to the actual stops of each connection. An early version counted the entire line, which produced false alarms from the origin station of a train that never affected the route in question.

The AI step is intentionally limited to rephrasing. Letting a model generate the facts directly risks invented lines or mixed-up times; feeding it a correct draft and asking only for nicer wording removes that risk entirely.


On the horizon

Where it's going.

Planned additions include a morning push notification with the briefing shortly before the relevant departure, a compact occupancy symbol directly on each connection tile, live updates in the journey tab, and an optional weather hint. The project is being prepared for an open-source release under a copyleft license.