Back to DevLog

Adding weather data to Foreman with Open-Meteo and focus variants

2 min read

I added Foreman's first external data tool: weather via Open-Meteo. It's free, keyless, and requires no signup. I classified it as SAFE because it's read-only external data from a single fixed source.

Setting the pattern for external tools

This establishes the pattern for all future external tools: one named tool, one fixed source, read-only access. Not general web access. The tool is an honest registry entry, not a capability the router can use to reach arbitrary endpoints.

I added a new tools/weather.py that reads from Open-Meteo using stdlib urllib with a 10-second timeout. It returns a calm {"error":"weather unavailable"} on any failure. It includes a WMO weather_code to plain words dictionary and user-editable LATITUDE/LONGITUDE/TIMEZONE constants set to Appleton, Wisconsin.

Making answers shape to the question

Weather answers now shape to the question. "Is it going to rain today?" gets an authored yes/no verdict plus numbers. "What's the weather?" gets the general two-sentence summary.

I threaded an optional focus enum through the router with values "general" and "rain". The router picks the shape via the enum. Every number and the yes/no verdict come straight from the tool dict via fixed templates. The model cannot invent a temperature or a verdict.

Rain verdict thresholds: precipitation chance below 20% gets "No rain expected", 20-60% gets "Maybe", above 60% gets "Likely". I verified the boundaries at 19, 20, 60, and 61.

Known limits

The forecast is today-only. "Will it rain tomorrow?" routes to get_weather with focus set to rain, but answers for today. I documented this as a known limit rather than leaving it silently wrong.

I added a keyword-fallback route for weather, forecast, and rain so degraded mode can still reach the weather tool when the router is offline.

Git hook collision

The repo's git-guard hook blocked my commit because I included a Co-Authored-By trailer, which violates a hard rule in the global CLAUDE.md. I recommitted without it. This will recur unless I stop adding the trailer up front.

Share this post