Metadata-Version: 2.4
Name: hermes-weather-agent
Version: 0.5.8
Summary: Standalone Weather MCP server powered by rustwx for model maps, satellite, radar, meteograms, cross sections, and research workflows.
Author: Fahrenheit Research
License-Expression: MIT
Project-URL: Homepage, https://github.com/FahrenheitResearch/hermes-weather-agent
Project-URL: rustwx, https://github.com/FahrenheitResearch/rustwx
Project-URL: wxstore, https://github.com/FahrenheitResearch/wxstore
Keywords: mcp,weather,hrrr,ecape,rustwx,wxstore,agent
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Science/Research
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering :: Atmospheric Science
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Requires-Dist: rustwx>=0.5.8
Requires-Dist: mcp>=1.0.0
Requires-Dist: requests>=2.28
Requires-Dist: numpy>=1.24
Requires-Dist: Pillow>=10.0
Provides-Extra: dev
Requires-Dist: pytest>=7; extra == "dev"
Requires-Dist: ruff>=0.5; extra == "dev"

﻿# Hermes Weather Agent

**A standalone Weather MCP server powered by rustwx and WxStore.**

Hermes Weather Agent gives Hermes Agent, Claude, and any MCP-speaking client direct access to [`rustwx`](https://github.com/FahrenheitResearch/rustwx), a pure-Rust weather workspace, and [`wxstore`](https://github.com/FahrenheitResearch/wxstore), the MIT temporal store for 2-D and 3-D weather data. It is meant to be a general weather engine for agents: model maps, satellite imagery, radar products, meteograms, soundings, cross sections, latest-run discovery, local cache management, temporal-store queries, and severe-weather research tools from one server.

The compute and rendering live in `rustwx`. PNG output goes through the pure-Rust `rustwx-render` contour engine: no matplotlib for maps, no ANSI rendering, and no Python in the hot path. WRF NetCDF4 reads use `netcrust` (pure-Rust, feature-gated) so **no `netcdf.dll` runtime is required for the standard agent workflows.**

Hermes defaults RustWx renders to the current fast operational plot style by setting `RUSTWX_PLOT_STYLE=operational_fast` when no explicit style is configured. The Rust CLI also accepts `operational-fast`; use `HERMES_RUSTWX_PLOT_STYLE` or `RUSTWX_PLOT_STYLE` to override it.

## Why this matters

* **One MCP server for weather work.** Agents can request maps, satellite, radar, meteograms, soundings, cross sections, cache status, and background jobs without a custom web app.
* **Latest data by default.** HRRR requests resolve against advertised forecast-hour availability; longer-range HRRR requests use the newest synoptic cycle with the requested hours.
* **Efficient local data use.** rustwx uses `.idx` byte-range fetches where possible, and Hermes exposes data-pack guidance so users can choose how much disk to reserve.
* **Temporal stores for shared weather data.** Hermes can query a running WxStore service, sample WXA grids and WXP pressure-profile stores, search object lanes, and materialize RustWx grids into durable WxStore WXA caches so repeated plotting and point sampling stay fast.
* **Live product discovery.** Product support is read from the installed `rustwx` wheel so the agent can pick slugs the active model actually advertises; optional workspace binaries expose deeper catalog metadata for local development.
* **rustwx 0.5 model compatibility.** Hermes now understands the broadened rustwx model set: HRRR/HRRR-AK, GFS/GDAS/GEFS/HGEFS, AIGFS/AIGEFS, ECMWF Open Data, AIFS/Earth2, RAP, NAM, HIRESW/HREF/SREF, RTMA/URMA, NBM, RRFS-A/RRFS-Public/REFS/RRFS-FireWx, and WRF/GDEX-style local workflows.
* **Composite and grid-plot vocabulary.** Agents can ask for built-in fill-plus-isopleth recipes, contour labels, ensemble member/stat selectors, and schema-stable grid-overlay requests such as value grids, EBS-style scalar grids, and hodograph glyph grids. Generic custom grid overlays are reserved in the schema and return a clear rustwx error until the generic renderer lands.
* **Fast regular renders by default.** Hermes keeps direct and light-derived non-ECAPE products in one shared RustWx pass so ordinary HRRR plot packs avoid repeated decode work, while heavy ECAPE, generic, and windowed requests still use guarded chunking when needed. Set `chunk_size` for explicit chunk control or `chunk_large_requests=false` / `chunk_size=0` to force one pass.
* **Advanced severe-weather research when needed.** ECAPE maps, profile probes, profile sweeps, ratio maps, and severe panels are available as regular tools, not as a separate research-only app.

## What an agent can do with this

```
"Render latest HRRR 2 m temperature and 10 m wind over Los Angeles."
"Show me the latest GOES-West GeoColor image with GLM overlay for southern California."
"Make a point meteogram for Redding for the next 18 hours."
"Render KTLX base reflectivity and dual-pol products."
"Cross-section theta-e from Amarillo to Chicago at f06 using the HRRR VolumeStore."
"What does the latest CONUS QPF look like at f24?"
"Export latest HRRR temperature, wind, and CAPE grids into WxStore."
"Materialize latest HRRR severe grids into WxStore, then render f000-f002 operational maps from the WXA cache."
"Sample the WxStore temporal sounding lane near Norman and include severe diagnostics."

"Render MLECAPE and 0-3 km SRH over the southern plains for the latest HRRR."
"Render HRRR DCAPE over Oklahoma City."
"Probe the ECAPE profile at Norman, OK at the latest f01."
"Build a 7-day dataset of MLECAPE / SRH 0-3 / STP renders for southern-plains."
"What's currently in the cache, and what would a 400 GB eviction free?"
```

## Advanced Research Mode

The general weather tools are the main surface area. On top of that, Hermes Weather Agent includes ECAPE and severe-weather research tools for deeper work:

* full-parcel ECAPE and DCAPE maps at HRRR-grid scale
* per-profile ECAPE diagnostics from the Rust solver
* random/target/stress profile sweeps
* severe-weather panels and ECAPE/CAPE ratio products
* multi-day render/probe datasets for verification workflows

The ECAPE path is strong for exploratory and product-triage research, not yet calibrated forecast skill. Calibration is downstream of the verification work these tools enable.

## Install

```bash
pip install -U rustwx hermes-weather-agent
weather-mcp --doctor
```

That's it for every map-rendering tool â€” the rustwx PyPI wheel ships the `rustwx-agent-v1` Python API used by this plugin (no Rust toolchain, no separate binaries, no `netcdf.dll`). `rustwx>=0.5.8` is recommended for the current public release.

`weather-mcp --doctor` should report `rustwx_module_available: true`, `agent_api: rustwx-agent-v1`, `plot_style: operational_fast`, and a nonzero `domain_count`.

### Optional specialty tools

A small set of tools sit *outside* the agent-v1 contract today and need rustwx workspace binaries to be built locally:

- `wx_sounding` (skew-T renderer)
- `wx_cross_section` / `wx_volume_cross_section` (HRRR pressure VolumeStore renderer; all non-smoke wxsection styles)
- `wx_radar` (NEXRAD Level-II renderer)
- `wx_native_dataset_plan` / `wx_native_dataset_run` (Rust-native HRRR/GOES/MRMS/Level-II training-data plans and shards)
- `wx_native_obs_preview` (quicklook PNGs from local GOES, MRMS, or Level-II files)
- `wx_goes_native_sequence` (native-grid GOES crops, time-window sequences, and GIF loops)
- `wx_ecape_profile` (single-point ECAPE probe)
- `wx_ecape_grid` (full-grid ECAPE swath research)
- `wx_wxstore_grid_export` (RustWx to WxStore dense-grid manifest export)
- `wx_wxstore_grid_import` (WxStore CLI import of one or more exported manifests)
- `wx_wxstore_grid_materialize` (one-call RustWx export plus WxStore WXA import)
- `wx_wxstore_grid_plot` (fast static PNG rendering from cached WXA grids)

If you want those too:

```bash
git clone https://github.com/FahrenheitResearch/rustwx
cd rustwx
cargo build -p rustwx-cli --release \
  --bin sounding_plot \
  --bin hrrr_pressure_volume_store \
  --bin volume_store_cross_section_render \
  --bin radar_export \
  --bin native_dataset_plan \
  --bin native_dataset_runner \
  --bin native_obs_preview \
  --bin goes_native_sequence \
  --bin hrrr_ecape_profile_probe \
  --bin hrrr_ecape_grid_research \
  --bin rustwx_grid_export \
  --bin wxstore_wxa_showcase

export HERMES_RUSTWX_BIN_DIR="$(pwd)/target/release"
```

To import exported grids into WxStore, also build the WxStore CLI and point Hermes at it:

```bash
git clone https://github.com/FahrenheitResearch/wxstore
cd wxstore
cargo build --release
export HERMES_WXSTORE_BIN_DIR="$(pwd)/target/release"
export HERMES_WXSTORE_URL="http://127.0.0.1:8897"
```

These will fold into the agent-v1 contract or service APIs as they stabilize; until then, the corresponding MCP tools degrade with a clear "build the binary" or "service unavailable" error rather than blocking the rest of the plugin.

## Configure

```yaml
# Hermes Agent â€” ~/.hermes/config.yaml
mcp_servers:
  weather:
    command: weather-mcp
    env:
      HERMES_RUSTWX_BIN_DIR: /path/to/rustwx/target/release
      HERMES_WXSTORE_BIN_DIR: /path/to/wxstore/target/release
      HERMES_WXSTORE_URL: http://127.0.0.1:8897
      HERMES_RUSTWX_PLOT_STYLE: operational_fast
      HERMES_CACHE_DIR: /path/to/weather-cache         # default: ./cache/rustwx
      HERMES_OUT_DIR:   /path/to/weather-outputs       # default: ./outputs
```

```json
// Claude Desktop / generic MCP â€” claude_desktop_config.json
{
  "mcpServers": {
    "weather": {
      "command": "weather-mcp",
      "env": { "HERMES_RUSTWX_BIN_DIR": "/path/to/rustwx/target/release" }
    }
  }
}
```

## CLI

```bash
weather-mcp --list      # every MCP tool with one-line descriptions
weather-mcp --doctor    # binary discovery + product catalog state
weather-mcp --test      # smoke-test render
```

## Tools (49 total)

### Discovery
| Tool | Purpose |
|---|---|
| `wx_models` | Available models, sources, products, forecast horizons |
| `wx_products` | Product slugs advertised by the installed `rustwx` wheel, filterable by kind/model/status/search |
| `wx_recipes` | Compact recipe summary (live with fallback mirror) |
| `wx_regions` | rustwx region presets |
| `wx_doctor` | Local install diagnostics |
| `wx_latest` | Resolve the latest available run for a model |
| `wx_data_packs` | HRRR-first local storage tiers: what works without more downloads at 1/5/10/50 GB style budgets |

Hermes is HRRR-first for local operational use. Tool defaults use `run="latest"` and resolve against advertised forecast-hour availability; requests for f019-f048 use the newest HRRR synoptic cycle that actually has those hours. Local data-pack tiers are cache/retention guidance: rustwx uses `.idx` byte-range fetches wherever the requested fields can be safely subset, while larger tiers simply retain more warmed hours, routes, and artifacts.

### Direct & derived rendering
| Tool | Purpose |
|---|---|
| `wx_fetch` | Fetch model GRIB2 data via rustwx with idx-byte-range selective download by default |
| `wx_render_recipe` | Render any combination of direct / derived / windowed / heavy recipes (auto-routes to the right binary) |
| `wx_composite` | Built-in composite/isopleth recipe helper plus schema-stable custom composite/grid-overlay requests |
| `wx_cape` | SBCAPE / MLCAPE / MUCAPE shortcut |
| `wx_ecape` | First-class ECAPE map (sbecape / mlecape / muecape) |
| `wx_srh` | 0-1 km or 0-3 km SRH |
| `wx_shear` | 0-1 km or 0-6 km bulk shear |
| `wx_stp` | Fixed-layer Significant Tornado Parameter |
| `wx_windowed` | Time-window products: full HRRR QPF/UH/surface-extrema family, plus cross-model `qpf_total` for validated v0.5 indexed-GRIB models |
| `wx_severe_panel` | Multi-product severe + ECAPE plate from one shared heavy thermo load |

### ECAPE specialists
| Tool | Purpose |
|---|---|
| `wx_ecape_profile` | Per-profile ECAPE diagnostics at a (lat, lon) â€” sub-millisecond Rust solver |
| `wx_ecape_grid` | Full-grid ECAPE research over a swath (background) |
| `wx_ecape_ratio_map` | MLECAPE filled + ECAPE/CAPE ratio contours w/ magnitude mask |

### Vertical / observations
| Tool | Purpose |
|---|---|
| `wx_cross_section` | Compatibility alias for HRRR pressure VolumeStore cross sections |
| `wx_volume_cross_section` | HRRR pressure VolumeStore cross sections; builds a short-lived 1-3 hour local store and renders PNG/WebP for all non-smoke wxsection styles |
| `wx_satellite` | Latest GOES satellite imagery via `rustwx.render_goes_satellite_json`; supports GeoColor, GLM overlay, RGB composites, and ABI Bands 1-16 |
| `wx_meteogram` | Point forecast time series via `rustwx.sample_point_timeseries_json`, or a warmed store when `store_id` is supplied |
| `wx_meteogram_warm_store` | Warm a point-timeseries grid store for repeated meteogram sampling |
| `wx_radar` | Native rustwx NEXRAD Level-II rendering via `radar_export`: base, dual-pol, SRV, VIL, echo tops, and feature JSON |
| `wx_sounding` | Skew-T at (lat, lon) rendered by rustwx's native `sounding_plot` binary; supports `sample_method="box-mean"` with `box_radius_km` |
| `wx_native_obs_preview` | Quicklook PNG from a local GOES, MRMS, or Level-II file before it becomes a training shard; Level-II velocity supports rustwx dealiasing |
| `wx_goes_native_sequence` | Fast GOES ABI image/loop generator for arbitrary lat/lon boxes, full disk, CONUS, or mesoscale sectors; can return PNG frames and an animated GIF |

### WxStore temporal stores
| Tool | Purpose |
|---|---|
| `wx_wxstore_status` | Check WxStore service health and local binary discovery |
| `wx_wxstore_catalog` | Query WxStore status, model/product/variable catalogs, latest runs, observation sources, satellite/radar layers, and vertical-render status |
| `wx_wxstore_forecast` | Sample WxStore WXA spatial lanes as Open-Meteo-style point forecasts |
| `wx_wxstore_sample` | Sample one WxStore grid variable at a lat/lon or named location |
| `wx_wxstore_temporal_sounding` | Query WxStore WXP temporal pressure-profile lanes, optionally with diagnostics |
| `wx_wxstore_objects` | Search WxStore observation, model, static-plot, evidence, satellite, radar, and source objects |
| `wx_wxstore_mesoanalysis` | Query WxStore mesoanalysis innovation status, targeted station/source checks, and watchlists |
| `wx_wxstore_grid_export` | Export RustWx direct, derived, or windowed grids into WxStore-importable WXA manifests |
| `wx_wxstore_grid_import` | Import one or more exported manifests into a WxStore spatial root and optionally publish latest |
| `wx_wxstore_grid_materialize` | Export RustWx grids and import them into a durable WXA spatial cache in one call |
| `wx_wxstore_grid_plot` | Render operational-fast static PNGs directly from cached WXA grids |

### Research mode
| Tool | Purpose |
|---|---|
| `wx_research_profile_sweep` | Multi-point ECAPE sweep across (point Ã— date Ã— cycle Ã— fhour). Modes: `targets` / `random` / `stress`. Aggregated CSV with timing breakdown |
| `wx_build_dataset` | Multi-day batch renders or profile probes (background) |
| `wx_native_dataset_plan` | Write a selectable HRRR/GOES/MRMS/Level-II training-data plan |
| `wx_native_dataset_run` | Fetch/materialize a native training-data plan into shards |

### Cache & jobs
| Tool | Purpose |
|---|---|
| `wx_cache_status` | Disk usage + top consumers + per-subdir totals |
| `wx_cache_evict` | LRU eviction to bring cache below `target_gb` (dry-run by default) |
| `wx_job_status` / `wx_job_list` / `wx_job_cancel` | Background-job control |

## Showcase gallery

The repo ships a one-shot script that exercises every tool against a single canonical run, captures per-call timing, and emits a self-contained HTML gallery:

```bash
python examples/showcase_full.py        # ~3 min with warm cache, ~5 min cold
python examples/showcase_html.py        # builds outputs/showcase/index.html
```

The showcase includes HRRR VolumeStore cross sections, the GOES18 product set, direct point meteograms, warmed point-timeseries store sampling, and native rustwx radar export. Open `outputs/showcase/index.html` after running.

Top wall-time consumers from the canonical run:

```
42.7 s  HRRR derived  â€” 44 recipes / one shared decode    72 PNGs
41.3 s  HRRR severe panel (heavy_panel_hour)              24 PNGs
35.1 s  ECAPE/CAPE ratio display (background)              6 PNGs
 8.0 s  mini research dataset (1 cycle Ã— 2 recipes)
 7.9 s  HRRR windowed â€” 8 QPF/UH products                  6 PNGs
 6.6 s  HRRR direct â€” 52 recipes / one shared decode      72 PNGs
 6.6 s  ECAPE grid research (background)
 5.9 s  stress profile sweep (10 curated points)
 5.1 s  GFS derived (sbcape/mucape/lapse)                  6 PNGs
 4.7 s Ã—5  cross sections (4 routes + 1 city pair)
```

The HRRR direct + derived passes each render dozens of products from one shared thermodynamic decode â€” that's where the per-product cost approaches zero. A focused HRRR CONUS benchmark with the default smart chunk policy produced 81 regular non-ECAPE PNGs (52 direct + 29 light-derived) in 27.27 s warm-cache for one hour, and 162 PNGs in 56.27 s warm-cache for two hours.

## Programmatic use (without an LLM)

Every tool is also a plain Python function:

```python
from hermes_weather.rustwx import discover
from hermes_weather.tools import (
    render, ecape, volume_cross_section,
    satellite, meteogram, radar, catalog, wxstore,
)

env = discover()

# Single first-class ECAPE map
out = render.ecape(env, parcel="ml", region="southern-plains",
                   run_str="latest", forecast_hour=0)
print(out["pngs"])

# Per-profile ECAPE in <1ms (Rust kernel)
prof = ecape.profile(env, location="Norman, OK",
                     run_str="latest", forecast_hour=1,
                     include_input_column=True)
print(prof["diagnostics"]["parcels"][1]["ratio_ecape_to_undiluted_cape"])

# HRRR VolumeStore cross sections: temporary 1-hour SoCal cube,
# all non-smoke wxsection styles, PNG + WebP outputs.
fast_xs = volume_cross_section.volume_cross_section(
    env, products=["all"], route="socal-coast-desert",
    run_str="latest", forecast_hour=0,
)

# GOES satellite set, short point meteogram, and native radar export.
sat = satellite.satellite(env, products=satellite.DEFAULT_PRODUCTS)
met = meteogram.meteogram(env, location=(34.0522, -118.2437),
                          forecast_hour_start=0, forecast_hour_end=3)
rad = radar.radar(env, site="KTLX", products="all")

# Discover what every recipe is and where it works
products = catalog.products(env, kind="derived", search="ecape")
for p in products["products"]:
    supported_models = [s["model"] for s in p["support"] if s["status"] == "supported"]
    print(f"{p['slug']:35s} {p['maturity']:14s} {supported_models}")

# Query WxStore if a service is running
store = wxstore.catalog(env, endpoint="latest", model="hrrr", domain="conus")
print(store)

# Cache-first WXA workflow: pay the GRIB -> grid cost once, then plot quickly.
mat = wxstore.grid_materialize(
    env,
    products=["vpd_2m", "dewpoint_depression_2m", "heat_index_2m", "stp_fixed"],
    forecast_hours="0-2",
    region="conus",
    jobs=4,
)
plots = wxstore.grid_plot(env, products=["stp_fixed"], forecast_hours="0-2")
print(mat["spatial_root"], plots["png_count"])
```

## Speed reality check (ECAPE-RS validation paper, April 2026)

| Operation | Python (`ecape-parcel` + MetPy) | Rust (`rustwx-calc`) | Speedup |
|---|---|---|---|
| ECAPE per HRRR profile (one parcel/config) | 2.8â€“6.1 s | 0.45â€“0.65 ms | **5,600â€“13,000Ã—** |
| ECAPE full-grid (272,955 HRRR cells / forecast hour) | impractical | 17.6â€“18.4 s | â€” |

Per-profile ECAPE is essentially free; full-grid is the heavy one. Heavy tools (`wx_ecape_grid`, `wx_ecape_ratio_map` for CONUS, `wx_research_profile_sweep` over many cycles) run as background jobs. Profile-sweep results separate `raw_fetch_s` / `profile_extract_s` / `parcel_solver_s` / `render_s` so you can attribute time honestly.

## License

MIT.

## Acknowledgements

Built on top of [`rustwx`](https://github.com/FahrenheitResearch/rustwx) (Rust meteorology workspace, Fahrenheit Research), [`wxstore`](https://github.com/FahrenheitResearch/wxstore) (MIT temporal stores for weather data), and the public `ecape-parcel` reference implementation. Validation methodology described in *Validation and Acceleration of an ecape-parcel-Compatible Solver for HRRR-Scale Entraining-CAPE Diagnostics*, ECAPE-RS Project, April 2026.
