Find the cheapest fuel near you in Sydney after your discounts, see where prices sit in the price cycle, and check whether to use a 7-Eleven fuel lock.
Live at tanks.seankoji.com. Tanks collects NSW FuelCheck prices every 20 minutes, ranks more than 700 Sydney stations by the price you would actually pay, and shows 24-hour and 7-day outlooks beside the observed prices. The forecasts come from an experimental statistical model. The site labels them that way, next to every number, and sends no alerts from them. Treat them as one input to a decision, never as a promise.
Screenshot from the live site, 15 October 2026. Prices move; the honesty labels stay.
- Prices (
/): suburb, postcode or device-location search, 2–25 km or all-Sydney distance, fuel choice, discount programs (no account needed) and tank size with live full-tank totals. Stations are ranked by the price you pay, with price tiers, members-only and unmanned badges, directions and a map. The search circle follows the reader: a saved home suburb, a browser-detected location, or the original Sydney centre, in that order of preference. - Region (
/region): the regional median and spread, matched-cohort change between buckets, where prices sit in the recent range, and the model outlook with the cohort detail behind it. - Lock advice (
/advice): the cheapest 7-Eleven to lock today for each fuel and a browser-only calculator that compares your lock, Telstra Plus and the cheapest nearby station. - Compare (
/compare) and Forecast results (/results): grades side by side, and the forecast record scored against what prices actually did. - Station pages (
/stations) with step-series history (imported and collected), gaps shown as gaps, a data table and separate 24-hour and 7-day E10 forecasts. - Optional Google sign-in to sync programs and watchlists, account deletion, and web push with at most one combined alert per user per Sydney day.
- A FuelCheck price-history importer (docs/history-import.md).
flowchart LR
A["NSW FuelCheck API<br/>every 20 minutes"] --> C["Collector<br/>validate and normalise"]
B["CKAN monthly history<br/>2016 onward"] --> D["History importer"]
C --> E[("PostgreSQL<br/>evidence ledger")]
D --> E
E --> F["Station and region aggregates<br/>medians, spreads, cohorts"]
F --> G["Experimental forecasts<br/>24 hours and 7 days"]
F --> H["Web app (Hono)<br/>prices, maps, lock advice"]
G --> H
H --> I["Reader<br/>buy now, or wait?"]
Prices are stored as an evidence ledger first and aggregated second, so a median can always be traced back to the observations behind it. Grades are never mixed, stations with no observation in a bucket are excluded and counted, and missing history reads as unknown rather than zero. The stack is TypeScript with Hono and PostgreSQL, deployed as a Docker container on a Raspberry Pi. Start with Architecture and stack and Operations.
pnpm install --frozen-lockfile
pnpm build
pnpm start:fixture # http://localhost:4173, labelled synthetic test dataDevelopment: pnpm dev. All commands, the browser matrix and the evidence bundle are described in docs/testing.md.
- Product specification, definition of done, accepted discovery, handoff and provenance (provenance describes the specification package, not the application)
- Architecture and stack · Projection contract with petrol-watch
- Release gates decision record · Client-readiness redesign · Station chart display · Source rights
- Operations · Tests and evidence
- Repository ownership, development and deployment
- Requirement traceability
Check the specification package with python3 tools/check_specs.py (part of pnpm validate).

