You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The repo has two independent weather scripts — weather.nu (wttr.in) and meteo.nu (Open-Meteo) — each with its own copy of the same helper functions. Adding a third API means a third copy. At that point the duplication is worth fixing properly.
This refactor may also be a good opportunity to move the module into its own repo (nu_mod_weather). A five-command module with shared helpers, a geocoding layer, and its own cache strategy is no longer really a "scripts" folder drop-in — it's a package. A dedicated repo also keeps the original standalone scripts available for people who just want something simple, without mixing two different installation models in the same place. That decision doesn't need to be made upfront, but it's worth keeping in mind as the scope grows.
Problems with the current structure
format-temp, beaufort-scale, beaufort-icon, wind-dir-icon, resolve-cache-dir, is-cache-valid, and http-get-with-retry are duplicated verbatim across both scripts. A bug fix has to be applied twice.
Location resolution works differently in each: weather.nu defers to wttr.in's opaque lookup, meteo.nu calls Open-Meteo's geocoding endpoint. The same input string can resolve to different results.
The imperial/metric decision uses country-name string matching, and the logic is slightly inconsistent between the two scripts.
The scripts can't share data or call each other's internals without going through the CLI layer.
weather.nu is named after its command rather than its source, which will look inconsistent once the other source-named scripts exist.
Minimum Nushell version
0.111.0
Naming rationale
weather.nu is renamed to wttr.nu so all source files are named after their API, not their command. The weather command name moves to wx.nu, which is the most useful command in the module and the natural default for someone who just wants the weather. Individual backends are still available by name for scripts or when you want a specific source.
Migration note
Existing users calling weather "New York" will get the combined wx output after upgrading instead of wttr.in specifically. This is a superset of the old behaviour, but worth a note in the README. Users of weather.nu who have Nerd Fonts enabled will also see emoji by default after migration unless $env.NERD_FONTS = "1" is set.
weather becomes the combined command. Users who want a specific backend can call wttr, meteo, yr, or nws directly.
Shared geocoding layer
Geocoding moves out of the individual scripts and into helpers.nu. Every command gets the same canonical location record — coordinates, display name, country code — rather than resolving the city string on its own.
Returns country code, which drives the imperial/metric decision
Needs a User-Agent header and stays under 1 req/sec — the existing 15-minute cache handles this automatically
Fallback chain if a geocoder fails:
Nominatim → Photon → Open-Meteo geocoder → error
Photon (photon.komoot.io) is also OSM-based, no key, and more typo-tolerant. Open-Meteo's geocoder is already in meteo.nu and serves as the last resort before giving up. If all three fail, the error should name all three and suggest the user check their connection rather than just reporting whichever one failed last.
Geocoding cache
Geocoding gets its own cache directory (nu_geocode_cache) with a much longer TTL than weather data. City coordinates don't change, so caching them for days is fine.
Unified data flow
flowchart TD
A[city string] --> B[Nominatim geocode\nhelpers.nu]
B --> C[name / country_code / lat / lon]
C --> D[wttr.nu]
C --> E[meteo.nu]
C --> F[yr.nu]
C --> G{US location?}
G -->|yes| H[nws.nu]
G -->|no| I[skip]
D --> J[weather\nwx.nu]
E --> J
F --> J
H --> J
Loading
Country code from Nominatim becomes the single source of truth for units, replacing the country-name string matching in both current scripts.
Cache layout
Each source keeps its own cache directory under $nu.cache-dir, which is the standard location for this in Nushell 0.111.0+. The old /tmp fallback in the current scripts gets dropped.
Each command keeps its own --clear-cache flag for clearing just that source. The weather command gets an additional --clear-all-caches flag that wipes every directory the module owns, including nu_geocode_cache. This matters because the geocoding cache has a long TTL — if a city resolves to bad coordinates, --clear-cache on an individual source won't help since the bad geocode result will just get reused. --clear-all-caches is the escape hatch for that.
Default city configuration
Each command resolves its default city in priority order: source-specific variable first, shared fallback second, then auto-detect from IP.
Most users only need to set $env.WEATHER_CITY once and every command picks it up. The per-source variables exist for edge cases — an airport code that resolves better in one API than another, or a coastal location where you want yr to default to a slightly different point. Existing users who already have $env.WTTR_CITY or $env.METEO_CITY set don't need to change anything.
Icon mode
The two current scripts handle icons inconsistently — weather.nu defaults to Nerd Fonts, meteo.nu defaults to plain text. The module standardises this:
Default: emoji, since it works without any font setup
Nerd Font mode: opt-in via $env.NERD_FONTS = "1", consistent with how meteo.nu already handles it
Plain text: -t / --text flag as before
Raw mode
--raw defaults to text mode since most pipe targets (JSON, scripts, clipboard) don't want icons or ANSI. Icon flags and a new --color flag still apply when passed explicitly — to_gui supports emoji/Nerd Font glyphs, ANSI colour, and ANSI hyperlinks. Full priority:
--raw alone → text, no icons, no ANSI
--raw --emoji → emoji glyphs, no ANSI
--raw --nerd → Nerd Font glyphs, no ANSI
--raw --color → text, no icons, ANSI colour + hyperlinks preserved
--raw --emoji --color → emoji glyphs, ANSI colour + hyperlinks preserved
--raw --nerd --color → Nerd Font glyphs, ANSI colour + hyperlinks preserved
--color enables both ANSI colour and ANSI hyperlinks together — the location field links to the relevant source URL (e.g. https://wttr.in/New+York), which to_gui can render as a clickable link. --color has no effect outside of --raw since the normal display path always renders colour and links.
APIs: MET Norway and NWS
If the module is getting built out anyway, adding a fourth API isn't much more work — the shared geocoding and helpers do the heavy lifting; each script is just the fetch and display logic for that source. Four also makes for a more complete picture than three, since these cover meaningfully different strengths:
Command
Source
Strength
Gap
wttr
wttr.in
Moon/astronomy, broad format support
Opaque, no real alerts
meteo
Open-Meteo
AQI, UV, snowfall, fast
No moon data
yr
MET Norway
Best non-US precision, real alerts
Needs User-Agent care
nws
NOAA / NWS
Best US alerts, most authoritative for the US
US-only
MET Norway (api.met.no) — the backend behind Yr.no. No API key, just a User-Agent header, global coverage. The main reason to add it is real alert data. wttr.nu infers severity from weather codes, which is a rough approximation. MET Norway has an actual alert endpoint. It also has better precision at high latitudes and marine/coastal data neither current script exposes.
NWS (api.weather.gov) — US-only, but the most authoritative source for US alerts by a wide margin. No API key. The US-only limitation is handled automatically: weather checks the country code from Nominatim and skips the NWS column for non-US locations. Users outside the US never see it; users inside the US get it for free.
Combined command: weather
weather (exported from wx.nu) calls the four internal build functions directly (not the CLI commands), gets structured records back, then compares or merges them.
This only works cleanly once the scripts share a geocoding step and return structured records from internal functions — which is the other reason to do this refactor.
Comparison mode (default)
All sources side by side. Where they disagree is useful information in itself. The NWS column appears automatically for US locations and is omitted everywhere else — weather knows from the geocoded country code and doesn't need to be told.
wttr.in Open-Meteo MET Norway NWS
────────────────────────────────────────────────────────
Temperature 72°F 70°F 73°F 71°F
Feels Like 68°F 67°F 69°F 68°F
Wind 15 mph NW 13 mph NW 16 mph NW 14 mph NW
Rain 0.1 in 0.08 in 0.1 in 0.09 in
Consensus mode (--consensus flag)
Merges into a single record. Numeric fields are averaged across whichever sources are active; source-specific fields come from wherever they're actually available:
Field
Source
Temperature, wind, precip
Average of all active sources
Moon / astronomy
wttr only
AQI
Open-Meteo only
Weather alerts
NWS (US) or MET Norway (everywhere else)
Precipitation probability
Most conservative (highest value)
An --uncertainty flag could add a stddev column to numeric fields.
--source flag
Each backend is callable directly (wttr, meteo, yr, nws), so --source is technically redundant. Worth adding anyway — it keeps everything accessible through the single weather entry point without needing to remember which individual commands exist, and it makes source-pinning explicit in scripts and aliases rather than relying on knowing the module internals.
weather--sourcewttr"Tokyo"weather--sourcemeteo"Tokyo"weather--sourceyr"Tokyo"weather--sourcenws"Tokyo"# errors outside the US
Valid values: wttr, meteo, yr, nws. Passing an unrecognised value should error with the list of valid options rather than silently falling back to the combined view.
Latency
Four sequential HTTP calls would be slow. Two options: use par-each for parallel fetches (error handling is limited in Nushell), or lean on warm caches. If the individual commands have run recently, weather costs almost nothing since the caches are already populated.
Source failures
If a weather source fails during a weather fetch, it is skipped and noted in the output rather than taking down the whole command. A failed NWS fetch in the US shows the remaining three columns with a nws: failed note.
Geocoding uses a fallback chain (Nominatim → Photon → Open-Meteo) so a single geocoder outage is handled silently. If all three geocoders fail, that is the one unrecoverable error — every weather source depends on coordinates, so there is nothing sensible to show. The error should name all three failed geocoders and suggest checking the user's connection.
Checklist
Extract shared helpers into helpers.nu
Add Nominatim geocoding to helpers.nu with fallback chain (Nominatim → Photon → Open-Meteo) and long-TTL cache
Implement $env.WEATHER_CITY shared fallback with per-source variable priority order
Standardise icon mode: emoji default, Nerd Fonts via $env.NERD_FONTS = "1", text default for --raw unless icon flag explicitly passed; add --color flag to preserve ANSI and hyperlinks in raw mode for to_gui
Rename weather.nu to wttr.nu and update its exported command name to wttr
Refactor wttr.nu to use shared geocoding and helpers
Refactor meteo.nu to use shared geocoding and helpers
Implement yr.nu against MET Norway API
Implement nws.nu against NWS API (gracefully skips outside the US)
Write wx.nu exporting weather — comparison and consensus modes, --source flag, --clear-all-caches, NWS column conditional on country code, skip-and-note on source failure
Update mod.nu to re-export all five commands
Update README with new installation instructions, command rename note, icon mode change, and weather usage
Add privacy note to README covering IP exposure via ipapi.co, city string logging by geocoders, coordinate exposure to weather APIs, and wttr.in opacity
Update TESTING.md with wttr, yr, nws, and weather test cases
The repo has two independent weather scripts —
weather.nu(wttr.in) andmeteo.nu(Open-Meteo) — each with its own copy of the same helper functions. Adding a third API means a third copy. At that point the duplication is worth fixing properly.This refactor may also be a good opportunity to move the module into its own repo (
nu_mod_weather). A five-command module with shared helpers, a geocoding layer, and its own cache strategy is no longer really a "scripts" folder drop-in — it's a package. A dedicated repo also keeps the original standalone scripts available for people who just want something simple, without mixing two different installation models in the same place. That decision doesn't need to be made upfront, but it's worth keeping in mind as the scope grows.Problems with the current structure
format-temp,beaufort-scale,beaufort-icon,wind-dir-icon,resolve-cache-dir,is-cache-valid, andhttp-get-with-retryare duplicated verbatim across both scripts. A bug fix has to be applied twice.weather.nudefers to wttr.in's opaque lookup,meteo.nucalls Open-Meteo's geocoding endpoint. The same input string can resolve to different results.weather.nuis named after its command rather than its source, which will look inconsistent once the other source-named scripts exist.Minimum Nushell version
0.111.0
Naming rationale
weather.nuis renamed towttr.nuso all source files are named after their API, not their command. Theweathercommand name moves towx.nu, which is the most useful command in the module and the natural default for someone who just wants the weather. Individual backends are still available by name for scripts or when you want a specific source.Migration note
Existing users calling
weather "New York"will get the combinedwxoutput after upgrading instead of wttr.in specifically. This is a superset of the old behaviour, but worth a note in the README. Users ofweather.nuwho have Nerd Fonts enabled will also see emoji by default after migration unless$env.NERD_FONTS = "1"is set.Proposed module layout
Single entry in
config.nu:weatherbecomes the combined command. Users who want a specific backend can callwttr,meteo,yr, ornwsdirectly.Shared geocoding layer
Geocoding moves out of the individual scripts and into
helpers.nu. Every command gets the same canonical location record — coordinates, display name, country code — rather than resolving the city string on its own.Preferred geocoder: Nominatim (
nominatim.openstreetmap.org)User-Agentheader and stays under 1 req/sec — the existing 15-minute cache handles this automaticallyFallback chain if a geocoder fails:
Photon (
photon.komoot.io) is also OSM-based, no key, and more typo-tolerant. Open-Meteo's geocoder is already inmeteo.nuand serves as the last resort before giving up. If all three fail, the error should name all three and suggest the user check their connection rather than just reporting whichever one failed last.Geocoding cache
Geocoding gets its own cache directory (
nu_geocode_cache) with a much longer TTL than weather data. City coordinates don't change, so caching them for days is fine.Unified data flow
flowchart TD A[city string] --> B[Nominatim geocode\nhelpers.nu] B --> C[name / country_code / lat / lon] C --> D[wttr.nu] C --> E[meteo.nu] C --> F[yr.nu] C --> G{US location?} G -->|yes| H[nws.nu] G -->|no| I[skip] D --> J[weather\nwx.nu] E --> J F --> J H --> JCountry code from Nominatim becomes the single source of truth for units, replacing the country-name string matching in both current scripts.
Cache layout
Each source keeps its own cache directory under
$nu.cache-dir, which is the standard location for this in Nushell 0.111.0+. The old/tmpfallback in the current scripts gets dropped.Each command keeps its own
--clear-cacheflag for clearing just that source. Theweathercommand gets an additional--clear-all-cachesflag that wipes every directory the module owns, includingnu_geocode_cache. This matters because the geocoding cache has a long TTL — if a city resolves to bad coordinates,--clear-cacheon an individual source won't help since the bad geocode result will just get reused.--clear-all-cachesis the escape hatch for that.Default city configuration
Each command resolves its default city in priority order: source-specific variable first, shared fallback second, then auto-detect from IP.
Most users only need to set
$env.WEATHER_CITYonce and every command picks it up. The per-source variables exist for edge cases — an airport code that resolves better in one API than another, or a coastal location where you wantyrto default to a slightly different point. Existing users who already have$env.WTTR_CITYor$env.METEO_CITYset don't need to change anything.Icon mode
The two current scripts handle icons inconsistently —
weather.nudefaults to Nerd Fonts,meteo.nudefaults to plain text. The module standardises this:$env.NERD_FONTS = "1", consistent with howmeteo.nualready handles it-t/--textflag as beforeRaw mode
--rawdefaults to text mode since most pipe targets (JSON, scripts, clipboard) don't want icons or ANSI. Icon flags and a new--colorflag still apply when passed explicitly —to_guisupports emoji/Nerd Font glyphs, ANSI colour, and ANSI hyperlinks. Full priority:--colorenables both ANSI colour and ANSI hyperlinks together — the location field links to the relevant source URL (e.g.https://wttr.in/New+York), whichto_guican render as a clickable link.--colorhas no effect outside of--rawsince the normal display path always renders colour and links.APIs: MET Norway and NWS
If the module is getting built out anyway, adding a fourth API isn't much more work — the shared geocoding and helpers do the heavy lifting; each script is just the fetch and display logic for that source. Four also makes for a more complete picture than three, since these cover meaningfully different strengths:
wttrmeteoyrnwsMET Norway (
api.met.no) — the backend behind Yr.no. No API key, just aUser-Agentheader, global coverage. The main reason to add it is real alert data.wttr.nuinfers severity from weather codes, which is a rough approximation. MET Norway has an actual alert endpoint. It also has better precision at high latitudes and marine/coastal data neither current script exposes.NWS (
api.weather.gov) — US-only, but the most authoritative source for US alerts by a wide margin. No API key. The US-only limitation is handled automatically:weatherchecks the country code from Nominatim and skips the NWS column for non-US locations. Users outside the US never see it; users inside the US get it for free.Combined command:
weatherweather(exported fromwx.nu) calls the four internal build functions directly (not the CLI commands), gets structured records back, then compares or merges them.This only works cleanly once the scripts share a geocoding step and return structured records from internal functions — which is the other reason to do this refactor.
Comparison mode (default)
All sources side by side. Where they disagree is useful information in itself. The NWS column appears automatically for US locations and is omitted everywhere else —
weatherknows from the geocoded country code and doesn't need to be told.Consensus mode (
--consensusflag)Merges into a single record. Numeric fields are averaged across whichever sources are active; source-specific fields come from wherever they're actually available:
An
--uncertaintyflag could add a stddev column to numeric fields.--sourceflagEach backend is callable directly (
wttr,meteo,yr,nws), so--sourceis technically redundant. Worth adding anyway — it keeps everything accessible through the singleweatherentry point without needing to remember which individual commands exist, and it makes source-pinning explicit in scripts and aliases rather than relying on knowing the module internals.Valid values:
wttr,meteo,yr,nws. Passing an unrecognised value should error with the list of valid options rather than silently falling back to the combined view.Latency
Four sequential HTTP calls would be slow. Two options: use
par-eachfor parallel fetches (error handling is limited in Nushell), or lean on warm caches. If the individual commands have run recently,weathercosts almost nothing since the caches are already populated.Source failures
If a weather source fails during a
weatherfetch, it is skipped and noted in the output rather than taking down the whole command. A failed NWS fetch in the US shows the remaining three columns with anws: failednote.Geocoding uses a fallback chain (Nominatim → Photon → Open-Meteo) so a single geocoder outage is handled silently. If all three geocoders fail, that is the one unrecoverable error — every weather source depends on coordinates, so there is nothing sensible to show. The error should name all three failed geocoders and suggest checking the user's connection.
Checklist
helpers.nuhelpers.nuwith fallback chain (Nominatim → Photon → Open-Meteo) and long-TTL cache$env.WEATHER_CITYshared fallback with per-source variable priority order$env.NERD_FONTS = "1", text default for--rawunless icon flag explicitly passed; add--colorflag to preserve ANSI and hyperlinks in raw mode forto_guiweather.nutowttr.nuand update its exported command name towttrwttr.nuto use shared geocoding and helpersmeteo.nuto use shared geocoding and helpersyr.nuagainst MET Norway APInws.nuagainst NWS API (gracefully skips outside the US)wx.nuexportingweather— comparison and consensus modes,--sourceflag,--clear-all-caches, NWS column conditional on country code, skip-and-note on source failuremod.nuto re-export all five commandsweatherusagewttr,yr,nws, andweathertest cases