I live at 3,200 feet in the Sierra Nevada foothills. When a winter storm rolls in, the difference between rain and a foot of snow is about 800 feet of elevation. The National Weather Service issues forecasts for broad regions โ "snow levels dropping to 2,500 feet" โ but my house sits right in that transition zone where every hundred feet matters.
So I built 4 cron jobs to monitor the storm in real time. They caught snow levels dropping faster than NWS predicted, thunderstorms that weren't in the original warning, and accumulation that exceeded the initial forecast. Total cost: about $0.50/day during the storm.
The Problem
Standard weather apps give you a temperature and a precipitation percentage. That's useless at my elevation. What I need to know:
- Snow level: Is precipitation falling as rain or snow at my elevation?
- Road conditions: Can I drive to work tomorrow? (50+ mile mountain commute)
- Power status: Is PG&E reporting outages in my area?
- Hazard trees: Any emergency alerts for fallen trees or road closures?
I check these manually during storms. That means refreshing NWS, checking Caltrans, watching local Facebook groups. During a multi-day event, that's a lot of mental overhead for something a cron job can do every hour.
The 4 Crons
1. Snow Level Tracker
The core monitor. Runs every hour during the storm. Compares current NWS forecast data against a baseline (the original Winter Storm Warning) and only alerts if conditions deviate.
{
"name": "Storm Monitor - Snow Level Tracker",
"schedule": {
"kind": "every",
"everyMs": 3600000
},
"payload": {
"kind": "agentTurn",
"message": "Check current NWS forecast for Oakhurst, CA (3,200 ft elevation, coords 37.32/-119.60). Use web_search to find the latest NWS Area Forecast Discussion from Hanford (HNX) and the point forecast. Compare snow levels, accumulation totals, and timing against this baseline: Winter Storm Warning, snow levels 4,000 ft dropping to 2,500 ft by Wednesday, 4-8 inches at 3,200 ft. ONLY alert if conditions have materially changed from this baseline. If everything is tracking as expected, reply NO_REPLY.",
"model": "anthropic/claude-sonnet-4-5"
},
"sessionTarget": "isolated",
"delivery": { "mode": "announce" }
}
The key design decision: baseline comparison. Without it, every hourly check would send me the same forecast rephrased. With it, I only hear about changes. The agent compares against the original warning and stays silent unless something shifted.
2. Road Conditions Monitor
Checks Caltrans and local road status. Critical because my commute is 50+ miles each way through mountain highways.
{
"name": "Storm - Road Conditions",
"schedule": { "kind": "every", "everyMs": 3600000 },
"payload": {
"kind": "agentTurn",
"message": "Check road conditions for Highway 41 between Oakhurst and Madera, CA. Use web_search for Caltrans QuickMap, CHP incidents, and chain control status. Only report if there are closures, chain requirements, or significant incidents. If roads are clear, reply NO_REPLY.",
"model": "anthropic/claude-sonnet-4-5"
},
"sessionTarget": "isolated",
"delivery": { "mode": "announce" }
}
3. Power Outage Monitor
Watches for PG&E outages in my area. This one has a problem I'll get to.
{
"name": "Storm - Power Outage Monitor",
"schedule": { "kind": "every", "everyMs": 3600000 },
"payload": {
"kind": "agentTurn",
"message": "Check for PG&E power outages in Oakhurst / Madera County, CA. Use web_search for outage reports and Downdetector. Only alert if outages are reported. If no outages found, reply NO_REPLY.",
"model": "anthropic/claude-sonnet-4-5"
},
"sessionTarget": "isolated",
"delivery": { "mode": "announce" }
}
4. Tree Damage / Emergency Monitor
Checks for fallen trees, road closures, and emergency alerts specific to the area.
{
"name": "Storm - Tree Damage/Emergency",
"schedule": { "kind": "every", "everyMs": 3600000 },
"payload": {
"kind": "agentTurn",
"message": "Search for emergency alerts, fallen trees, or road closures in the Oakhurst / Bass Lake / Madera County area. Use web_search. Only alert on confirmed incidents. Reply NO_REPLY if nothing found.",
"model": "anthropic/claude-sonnet-4-5"
},
"sessionTarget": "isolated",
"delivery": { "mode": "announce" }
}
What Broke
The power outage monitor failed every single time. Downdetector returns a 403 to server-side fetches โ it requires a real browser with JavaScript rendering. The agent tried, got blocked, and couldn't find outage data from any other source either.
PG&E's own outage map is also JavaScript-heavy and doesn't expose a clean API. So the power monitor was effectively dead on arrival.
web_search or web_fetch. Many outage trackers and government sites require browser rendering. If you need those sources, you'll need to use the browser tool instead โ which is heavier and more expensive.
The other three worked well. The snow level tracker was the star โ it correctly identified when conditions deviated from the baseline and stayed silent when they didn't.
The Numbers
| Cron | Model | Runs/Day | ~Cost/Run | ~Cost/Day |
|---|---|---|---|---|
| Snow Level Tracker | Sonnet | 24 | $0.008 | $0.19 |
| Road Conditions | Sonnet | 24 | $0.006 | $0.14 |
| Power Outage | Sonnet | 24 | $0.004 | $0.10 |
| Tree/Emergency | Sonnet | 24 | $0.004 | $0.10 |
| Total | 96 | ~$0.53 |
About 53 cents a day for continuous monitoring during a storm event. The snow level tracker is the most expensive because it pulls the most data (full NWS Area Forecast Discussion + point forecast), but even that is under 20 cents.
Design Decisions
Temporary, not permanent. These crons get killed when the storm passes. They're not running year-round. I created them when the Winter Storm Warning was issued and I'll delete them when conditions clear. No cost creep.
Baseline comparison, not raw reporting. The prompt includes the original forecast as a baseline. The agent compares against it and only speaks when something changes. This is the difference between getting 24 messages a day and getting 3-4 that actually matter.
Isolated sessions with announce delivery. Each run is its own isolated session that delivers results to my Telegram. If a run fails, it doesn't pollute my main conversation history. If it has nothing to say, it replies NO_REPLY and I never see it.
Sonnet, not Opus or Haiku. Haiku would be cheaper but struggles with the nuance of "has this materially changed?" โ it tends to either alert on everything or miss real changes. Opus would be better at analysis but costs 5x more per run. Sonnet hits the sweet spot for monitoring tasks.
Real Results
The storm started Sunday night. By Monday evening, the snow level tracker had identified three deviations from the original warning:
- Snow levels dropping lower than forecast โ 2,000-2,500 ft vs. the original 2,500 ft floor
- Thunderstorms added โ not in the original Winter Storm Warning, appeared in updated forecasts
- Extended duration โ accumulation now expected through Thursday morning, original warning only covered through Wednesday
That third one directly affected my work planning. I'd planned to work from home Wednesday only. With accumulation extending into Thursday, I added a second telework day.
The snow started falling earlier than forecast too โ I walked outside Monday evening and my car was already coated. The monitors had been hinting at faster-than-expected snow level drops for two hours before I saw it myself.
What's Next
The power outage monitor needs a browser-based approach or a different data source. I'm looking at PG&E's PSPS (Public Safety Power Shutoff) notification system โ they send emails for planned outages, which could be caught by an email-monitoring cron instead.
For the next storm, I'll also add a cron that checks road cameras. Caltrans has CCTV feeds on Highway 41 that show actual conditions โ worth a screenshot capture every hour.
Read next: My AI Texted My Wife โ what happens when you enable a channel without a whitelist.