Transport for London in your terminal. Built for AI agents, still pleasant for humans.
tfl status # Is the Northern line running?
tfl route "waterloo" "king's cross" # How do I get there?
tfl arrivals "waterloo" # What's coming next?
tfl disruptions # What's broken right now?
tfl bikes "SE1 9SG" # Any bikes nearby?npm install -g tfl-cliOr from source:
git clone https://github.com/shan8851/tfl-cli.git
cd tfl-cli
npm install && npm run build
npm linktfl-cli works without any credentials. Anonymous TfL API access is enough for casual use.
For higher rate limits, grab a free key from the TfL API Portal and set it:
export TFL_APP_KEY=your_key
# or add to .env in your project directory| Command | What it does |
|---|---|
tfl status [line] |
Live line status β good service, delays, closures |
tfl disruptions [line] |
Current disruptions with detail |
tfl route <from> <to> |
Journey planning between stations, postcodes, or coordinates |
tfl arrivals <stop> |
Next arrivals at any stop or station |
tfl search stops <query> |
Find stops and stations by name |
tfl bikes <location> |
Santander bike availability nearby |
Supports station names, postcodes (SE1 9SG), coordinates (51.50,-0.12), and TfL stop IDs.
status and disruptions cover tube, overground, DLR, and Elizabeth line.
The CLI defaults to colorized text in a TTY and JSON when piped β no flag needed.
tfl route "SE1 9SG" "EC2R 8AH" --json # Explicit JSON
tfl arrivals "king's cross" | jq # Auto-JSON when piped
tfl --no-color status # Plain text without ANSI colors
tfl route "SE1 9SG" "EC2R 8AH" --output journeys.0.durationMinutesEvery response uses a stable envelope:
{
"ok": true,
"schemaVersion": "1",
"command": "status",
"requestedAt": "2026-03-21T22:00:00.000Z",
"data": { ... }
}Errors return ok: false with structured error.code, error.message, and error.retryable fields. Exit codes: 0 success, 2 bad input/ambiguity, 3 upstream failure, 4 internal error.
Use --output <path> on route, arrivals, and bikes when an agent only needs one field or subtree. Paths use dot notation with zero-based array indexes.
tfl route "SE1 9SG" "EC2R 8AH" --output journeys.0.durationMinutes
tfl arrivals "waterloo" --json --output arrivals.0.lineName
tfl bikes "SE1 9SG" --output bikePoints.0In text mode, scalar projections print just the value. Object and array projections print plain pretty JSON instead of the richer human formatter.
Works with OpenClaw, Claude Desktop MCP, or any agent that can shell out.
# Is the Jubilee line ok?
$ tfl status jubilee
Jubilee: Good Service
# Route from postcode to station
$ tfl route "SE1 9SG" "kings cross"
Walk to Waterloo (11 min)
Jubilee line to King's Cross St. Pancras (8 min)
Total: 19 min
# Next trains at Waterloo
$ tfl arrivals waterloo --limit 5
Northern | Edgware via CX | 2 min
Jubilee | Stanmore | 3 min
Bakerloo | Harrow & Wealdstone | 4 min
...
# Bikes near a postcode
$ tfl bikes "SE1 9SG"
Waterloo Station 3 | 15 bikes | 13 empty docks | 245m
Baylis Road | 8 bikes | 22 empty docks | 310m
...
# Agent-friendly projection
$ tfl arrivals "waterloo" --json --output arrivals.0.lineName
{
"ok": true,
"schemaVersion": "1",
"command": "arrivals",
"requestedAt": "2026-03-21T22:00:00.000Z",
"data": "Northern"
}MIT