Problem
The bundled embedded weather skill (forge-skills/local/embedded/weather/SKILL.md) can never work as shipped. Its egress_domains allow only:
egress_domains:
- api.openweathermap.org
- api.weatherapi.com
Both require an API key — but the skill declares no key at all:
env:
required: []
one_of: []
optional: []
So the two hosts the egress gate permits are exactly the two that reject an unauthenticated request. On top of that the tool bodies are prose-only (## Tool: weather_current … no runnable command / endpoint), so there is nothing wired to call even if a key existed. Net result: the skill is dead on arrival for every user who hasn't signed up for OpenWeather/WeatherAPI and manually threaded a key in — which the skill gives no way to do.
Fix
Repoint the skill at a weather service that needs no API key for at least a reasonable amount of free traffic, and give the tools an actual runnable curl invocation against that endpoint. Two good options:
Option A — wttr.in (simplest drop-in) ⭐ recommended
- Single host:
wttr.in. Accepts a city name directly (wttr.in/London?format=j1 → JSON), so it maps 1:1 to the skill's existing location (string) input — no geocoding step.
- Keyless, free for reasonable traffic.
- Already blessed in-repo: the Skill Builder UI suggestion at
forge-ui/static/app.js:2902 literally proposes "Create a weather lookup skill that uses curl to fetch weather data from wttr.in."
egress_domains: [wttr.in].
Option B — open-meteo.com (structured, more robust)
- Forecast:
https://api.open-meteo.com/v1/forecast?latitude=..&longitude=..¤t=temperature_2m,relative_humidity_2m,wind_speed_10m&daily=temperature_2m_max,temperature_2m_min.
- City name → coordinates needs the separate geocoding host:
https://geocoding-api.open-meteo.com/v1/search?name=London.
- Keyless, generous free tier for non-commercial use; clean structured JSON (better for the
weather_forecast 1–7 day tool).
egress_domains: [api.open-meteo.com, geocoding-api.open-meteo.com] (two hosts, because of the geocoding call).
Recommendation: wttr.in for the drop-in fix (single domain, city-name input, already referenced by our own UI). If we want reliable structured multi-day forecasts, use open-meteo and add the geocoding host.
Blast radius — the two domains are hard-coded in several places, keep them in sync
| File |
What to change |
forge-skills/local/embedded/weather/SKILL.md |
egress_domains + add runnable curl bodies to the two tools |
forge-cli/internal/tui/steps/egress_step.go:187-188 |
the "api.openweathermap.org"/"api.weatherapi.com" → "weather skill" allowlist hints |
forge-skills/local/scanner_test.go:41 |
fixture asserts api.openweathermap.org |
.claude/skills/forge.md:1102 |
doc example uses egress_domains: [api.openweathermap.org] |
(forge-plugins/channels/markdown/markdown_test.go also mentions openweathermap.org, but only as an unrelated example link in a Markdown-conversion test — leave it.)
Acceptance
Problem
The bundled embedded weather skill (
forge-skills/local/embedded/weather/SKILL.md) can never work as shipped. Itsegress_domainsallow only:Both require an API key — but the skill declares no key at all:
So the two hosts the egress gate permits are exactly the two that reject an unauthenticated request. On top of that the tool bodies are prose-only (
## Tool: weather_current… no runnable command / endpoint), so there is nothing wired to call even if a key existed. Net result: the skill is dead on arrival for every user who hasn't signed up for OpenWeather/WeatherAPI and manually threaded a key in — which the skill gives no way to do.Fix
Repoint the skill at a weather service that needs no API key for at least a reasonable amount of free traffic, and give the tools an actual runnable
curlinvocation against that endpoint. Two good options:Option A — wttr.in (simplest drop-in) ⭐ recommended
wttr.in. Accepts a city name directly (wttr.in/London?format=j1→ JSON), so it maps 1:1 to the skill's existinglocation (string)input — no geocoding step.forge-ui/static/app.js:2902literally proposes "Create a weather lookup skill that uses curl to fetch weather data from wttr.in."egress_domains: [wttr.in].Option B — open-meteo.com (structured, more robust)
https://api.open-meteo.com/v1/forecast?latitude=..&longitude=..¤t=temperature_2m,relative_humidity_2m,wind_speed_10m&daily=temperature_2m_max,temperature_2m_min.https://geocoding-api.open-meteo.com/v1/search?name=London.weather_forecast1–7 day tool).egress_domains: [api.open-meteo.com, geocoding-api.open-meteo.com](two hosts, because of the geocoding call).Recommendation: wttr.in for the drop-in fix (single domain, city-name input, already referenced by our own UI). If we want reliable structured multi-day forecasts, use open-meteo and add the geocoding host.
Blast radius — the two domains are hard-coded in several places, keep them in sync
forge-skills/local/embedded/weather/SKILL.mdegress_domains+ add runnablecurlbodies to the two toolsforge-cli/internal/tui/steps/egress_step.go:187-188"api.openweathermap.org"/"api.weatherapi.com" → "weather skill"allowlist hintsforge-skills/local/scanner_test.go:41api.openweathermap.org.claude/skills/forge.md:1102egress_domains: [api.openweathermap.org](
forge-plugins/channels/markdown/markdown_test.goalso mentionsopenweathermap.org, but only as an unrelated example link in a Markdown-conversion test — leave it.)Acceptance
egress_domainslists only the keyless host(s) actually called; the two key-gated domains are gone.curlcommand against the chosen endpoint (not prose alone).egress_step.gohints,scanner_test.gofixture, and theforge.mdexample updated to match.gofmt+golangci-lintclean;forge-skills+forge-clisuites green.