Releases: galjos/pitstop-cli
v1.0.1 (metadata fix)
Metadata-only patch. The 1.0.0 wheel on PyPI was built before the GitHub repo was renamed pitstop → pitstop-cli, so its Project-URL entries still point at the old URLs. PyPI wheels are immutable, so 1.0.1 supersedes 1.0.0 with corrected URLs. No code changes.
v1.0.0 — first public release
First public release. No new features vs 0.9.0 — this is the stable-API milestone after nine months of iteration, MIT-licensed and PyPI-ready.
What pitstop is
A JSON-first CLI + MCP server for Italian fuel-station prices and EV charging stations, designed for AI agents and humans.
- Fuel — MIMIT Osservaprezzi Carburanti, ~23.8k stations, four layers of data-quality defense (placeholder floor, freshness, combined 15% + Tukey IQR outlier rule, ISTAT comune-coordinate validation). Cross-validated against MIMIT's own published regional averages and spritpreise.it — matches to within ~½ cent across all 21 regions.
- EV charging — OpenStreetMap via Overpass, with operator tariff-page URLs per result.
- CLI + MCP — same core, two surfaces. Five MCP tools:
list_fuels,find_stations,find_cheapest,find_chargers,get_stats. - Agent ergonomics — multi-fuel queries, international comune names (Rome / Bozen / Mailand / Venise / …), GeoJSON, navigation URLs, structured errors.
Install
pipx install pitstop # or:
uv tool install pitstop # or just run on-demand:
uvx pitstop --helpFor the MCP server: pipx install "pitstop[mcp]" then pitstop-mcp.
What changed since 0.9.0
- LICENSE (MIT).
- PyPI-ready packaging: classifiers, project URLs, license metadata.
- OpenClaw frontmatter on the agent skill so it's publishable to ClawHub.
- README intro rewritten for non-Italians.
38 tests, GitHub Actions CI, Python ≥ 3.10, stdlib-only runtime.
v0.9.0
Polish + breadth release. Focused on agent ergonomics: fewer round-trips, international city names, navigation links, and a stats view.
New
- Multi-fuel queries —
--fuel "Benzina,Gasolio"(comma-separated) on CLI and MCP. One call returns both. - International comune names —
--comune Rome,--comune Bozen,--comune Mailand,--comune Veniseall resolve to the Italian dataset keys via a curated EN/FR/DE map. pitstop stats/ MCPget_stats— macro price statistics (median/min/max/count) per provincia, plus a national aggregate, per fuel.- GeoJSON output —
--geojsonon bothstationsandchargersproduces a standardFeatureCollection(Point geometry, [lon,lat] order, properties without duplicated coords). - Navigation URLs — every station and charger in the JSON envelope now carries
navigation_url(Google Maps deep-link). The CLI table prints a "Top result map:" footer. - Structured Overpass errors —
fetch_elementsandfind_chargersreturn(data, error); the response envelope carries anerrorfield on failure while keeping the rest of the schema. Lets callers distinguish "no chargers found" from "service unavailable". - Centroid-first coord validation —
query_stationsprefers the data-derived comune centroid (robust for ≥3 stations) over the ISTAT reference; falls back to ISTAT for single-station comuni. Fixes occasional false-positive flags caused by ISTAT's center for Bolzano.
Fixed
- MCP
find_chargersnow also callsnormalize_comune, so agents using the MCP path can usecomune="Bozen"(or any other bilingual form) the same way the CLI does. - MCP
find_chargerserror responses now use the fullresponse_envelopeshape (withdisclaimer,source_url, etc.), not a partial dict. BILINGUAL_MAPde-duplicated; identity mappings removed.
Tests
38 passing (29 → 38). New coverage: multi-fuel comma list, bilingual normalization, fuel_stats shape, navigation_url format, both GeoJSON envelopes, error envelope, MCP bilingual end-to-end.
v0.8.0
EV operator tariff URLs. Each charger result now carries tariff_info_url pointing to the operator's official tariff page when the operator is recognized.
The honest finding from a thorough investigation:
- AFIR DATEX II (mandatory since 14 Apr 2026) is a CPO→NAP upload channel — no documented public consumer endpoint.
- Italy's PUN (piattaformaunicanazionale.it) is an ArcGIS SPA — no public REST API for tariffs.
- Chargeprice / Eco-Movement carry per-station tariffs but require paid licenses.
- OSM has
fee=yes/no(already surfaced), not actual €/kWh.
So per-station €/kWh prices are not openly machine-readable in Italy in mid-2026. The most useful + honest layer pitstop can add today is the operator's own canonical tariff page per result. Registry covers the major Italian CPOs: Alperia, Neogy, Enel X Way, Be Charge, Free To X, Ionity, Tesla, Plenitude, Atlante, Repower, A2A, Edison, Acea, EVway, and others.
When the user asks "how much will it cost?", the MCP tool now instructs the agent to surface tariff_info_url instead of guessing.
v0.7.0
First step into the EV domain. Adds pitstop chargers (CLI) and find_chargers (MCP), backed by OpenStreetMap via the Overpass API.
- Filter by
--operator,--socket(plug-type substring),--min-powerkW,--fast(≥50 kW),--ultra-fast(≥150 kW),--free,--public. - Search by
--comune NAME(resolved via the comune-coords reference) or--near "lat,lon". - Per-charger output: operator, plug types & counts, max kW, fee, access, distance.
- 7-day on-disk cache for Overpass results.
Open Charge Map's API now requires a registered key (HTTP 403 without); OSM Overpass is fully open and well-covered for EU chargers. Pricing isn't in this dataset yet — AFIR NAP / DATEX II is the planned next layer.
v0.6.0
Tightens outlier detection — found by cross-checking against spritpreise.it.
- New Tukey IQR rule combined with the existing 15% deviation rule. A price is now flagged
outlierif it is more than 15% below the median or below the Tukey lower fence (Q1 − 1.5·IQR). Catches borderline misreports in tight markets — e.g. BZ Gasolio €1.787 at −14.9% slipped past v0.5.0's percent rule but is well below the €1.949 fence. - New
--drop-outliersCLI flag anddrop_outliersMCP parameter. MCPfind_cheapestnow defaultsdrop_outliers=Trueso the agent gets clean cheapest answers without having to interpret the flag.
v0.5.0
Adds price-outlier detection — a direct answer to "is this price real?".
- Every price now carries
regional_median,deviation_pct, and anoutlierflag (true when >15% below the median for its fuel in that provincia). Computed from the dataset itself, no extra source. - New
--max-deviation-pct Nflag (CLI + MCP) drops prices more than N% below the local median — opt-in; off by default to preserve fidelity. The CLI table marks outliers with?. - Catches misreports like Q8 Verona's €1.638 (vs €2.06 VR median, −20%) and ENI Rome's €1.639 (vs €2.07 RM median, −21%) that survived every prior filter.
v0.4.0
First multi-source release. Adds ISTAT-derived comune-coordinate validation as a second data source, which finally fixes the single-station mis-geocoded class of bugs (the original Rasen case).
- New
geocoding.pymodule: runtime-fetch + 30-day cache of comune→(lat, lon) from opendatasicilia/comuni-italiani (ISTAT-derived). 97.5% comune-name match against MIMIT. Graceful fallback to self-contained heuristics if upstream is unreachable. query_stationsflagscoordinate_suspectwhen a station's stored coord is >30 km from its declared comune's true location (works for single-station comuni that the centroid method couldn't reach).--nearexcludes stations whose declared comune is outsideradius + 30 kmof the query point. "Agip Tankstelle Rasen" no longer pollutes "near Bolzano" searches.--no-comune-validateflag to disable.
v0.3.0
Self-contained mitigation for the mis-geocoded-station class of bugs.
- New
coordinate_suspectflag on stations whose registry coordinate is outside Italy's bounding box, or more than 30 km from the median of their comune's other stations. Surfaced in JSON; marked*in the table. Flags ~1% of stations (211/23.8k) on real data. --nearskips coordinates outside Italy.- Limit: single-station comuni (e.g. RASUN-ANTERSELVA) cannot be flagged this way. The robust fix needs a second data source (ISTAT comune coordinates) — tracked as the next step in the roadmap.
v0.2.0
Adds price freshness filtering — prompted by a user catch that a €1.749 result was wrong.
- Stale-price fix: a 2023 "Gasolio Alpino" at €1.749 was ranking as the cheapest diesel near Bolzano, although that station's current diesel is €2.115 and the national self-service average was ~€2.03 (2026-05-29).
pitstopnow reads each price'supdatedtimestamp. --fresh-within-days Nonpitstop stations;max_age_dayson the MCP tools. MCPfind_cheapestdefaults to a 90-day window so stale records can't win "cheapest".- New
UPDATEDcolumn in the stations table. - Documents a related data caveat: some stations are mis-geocoded in the registry.