Skip to content

Releases: galjos/pitstop-cli

v1.0.1 (metadata fix)

10 Jun 08:24

Choose a tag to compare

Metadata-only patch. The 1.0.0 wheel on PyPI was built before the GitHub repo was renamed pitstoppitstop-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

10 Jun 07:43

Choose a tag to compare

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 --help

For 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

02 Jun 11:44

Choose a tag to compare

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 Venise all resolve to the Italian dataset keys via a curated EN/FR/DE map.
  • pitstop stats / MCP get_stats — macro price statistics (median/min/max/count) per provincia, plus a national aggregate, per fuel.
  • GeoJSON output--geojson on both stations and chargers produces a standard FeatureCollection (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 errorsfetch_elements and find_chargers return (data, error); the response envelope carries an error field on failure while keeping the rest of the schema. Lets callers distinguish "no chargers found" from "service unavailable".
  • Centroid-first coord validationquery_stations prefers 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_chargers now also calls normalize_comune, so agents using the MCP path can use comune="Bozen" (or any other bilingual form) the same way the CLI does.
  • MCP find_chargers error responses now use the full response_envelope shape (with disclaimer, source_url, etc.), not a partial dict.
  • BILINGUAL_MAP de-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

01 Jun 07:59

Choose a tag to compare

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

01 Jun 06:51

Choose a tag to compare

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-power kW, --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

30 May 09:17

Choose a tag to compare

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 outlier if 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-outliers CLI flag and drop_outliers MCP parameter. MCP find_cheapest now defaults drop_outliers=True so the agent gets clean cheapest answers without having to interpret the flag.

v0.5.0

30 May 08:46

Choose a tag to compare

Adds price-outlier detection — a direct answer to "is this price real?".

  • Every price now carries regional_median, deviation_pct, and an outlier flag (true when >15% below the median for its fuel in that provincia). Computed from the dataset itself, no extra source.
  • New --max-deviation-pct N flag (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

30 May 08:11

Choose a tag to compare

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.py module: 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_stations flags coordinate_suspect when 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).
  • --near excludes stations whose declared comune is outside radius + 30 km of the query point. "Agip Tankstelle Rasen" no longer pollutes "near Bolzano" searches.
  • --no-comune-validate flag to disable.

v0.3.0

29 May 21:51

Choose a tag to compare

Self-contained mitigation for the mis-geocoded-station class of bugs.

  • New coordinate_suspect flag 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.
  • --near skips 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

29 May 21:40

Choose a tag to compare

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). pitstop now reads each price's updated timestamp.
  • --fresh-within-days N on pitstop stations; max_age_days on the MCP tools. MCP find_cheapest defaults to a 90-day window so stale records can't win "cheapest".
  • New UPDATED column in the stations table.
  • Documents a related data caveat: some stations are mis-geocoded in the registry.