Awareness
Live Lookups
Edge-stateless weather & news, fetched within a single turn — keyless, and with no new persistent state.
Situation
Mallory could hold context and dig deep, but had no live view of the outside world. Phase 3 gives him weather and news as tools used within one turn, flipping live to built:true in the capability registry.
These are stateless external fetches — the same category as the Anthropic / Whisper / ElevenLabs calls already on the hot path. The edge-local invariant holds because the Worker never calls the Hub or the Tower; delegation home is the forbidden direction, not all I/O. Providers hit hardcoded hostnames only, so unlike the URL-unfurler there is no SSRF surface.
Key decisions
Providers (v1)
Weather + News. Traffic and markets are fast-follow — the framework absorbs them without touching the turn pipeline.
Keyless sources
Open-Meteo (forecast + geocoding) and BBC RSS — both keyless, so no new secrets.
Classifier-triggered
A live: string[] dimension is added to the classifier JSON, validated against LIVE_PROVIDERS, mirroring how signals works. One streamed pass.
Server-side card assembly
The weather/news fences are an internal contract the model never emits — built deterministically from fetched data to guarantee fidelity (no silent "14°C → 15°C").
Short KV cache
Results cached under a live: prefix with per-provider TTLs and stale-on-error so a flaky upstream degrades gracefully.
Default location
LIVE_HOME_LOCATION = "Milton Keynes" in [vars], overridable per-message via a liveLocation hint.
Architecture
A new self-contained edge module, src/live/, whose loadLive is the direct analogue of loadSignals: fetch in parallel behind timeouts, return a ## Live prose block for the model plus structured cards for the web.
LIVE_PROVIDERS set + loadLive(env, providers, opts, waitUntil) → { block, cards, unavailable }.parseRss(xml) (Workers has no DOMParser); returns [] on garbage, never throws. Fixture-tested.timedFetch with a 2.5s AbortController + size cap (never throws); live: KV helpers with TTLs and stale-on-error.weatherFence / newsFence — deterministic, unit-testable fence builders.live/liveLocation/liveTopic; runTurn injects the block and appends cards post-stream (before any trailing chips).Risks & guardrails
A live fetch fails
That provider is omitted from the block, produces no card, and is named in a one-line liveNote. The turn classifies, assembles and streams normally — no live failure can fail a turn.
Data fidelity
Cards are built from fetched values, not the LLM's paraphrase, so the figure shown is exactly what Open-Meteo / BBC returned.
Misrouting
An explicit classifier guard keeps "what's the news" as live:[...] with investigate:none, so it is never mistaken for an async dig.
Voice double-reading
toSpeech() already strips all fences, so voice reads the prose summary and ignores the card.
Delivery
Edge module + classifier
Build src/live/* behind tests (rss, weather, cards, loadLive), then extend the classifier with the validated live dimension.
runTurn integration
Thread ctx.waitUntil, inject ## Live + note, append card fences post-stream via a unit-tested appendCards, and fix the push teaser to exclude fence JSON.
Web rendering (additive)
Extend replyBlocks with weather/news, add WeatherCard / NewsCard (+ wmoCodeMap), wire two branches into MessageView.
Capability flip + evals
Flip live to built with an honest claim/label, update capabilities.test.ts, and add classifier-intent eval cases run before/after.
Deploy (gated)
No D1 migration; add the [vars] entry; PR-only — Alex reviews, merges, deploys.
Out of scope
docs/superpowers/specs/2026-06-21-live-lookups-design.mdplan ·
docs/superpowers/plans/2026-06-21-live-lookups.md