Grass Optimizer — Saskatchewan lawn watering and winter shutdown
prototypeA Martensville yard on a short prairie growing season still gets watered and mowed by feel — and the first hard freeze is the deadline that feeling always misses.
The problem
Cool-season turf in Saskatchewan does not fail in July; it fails in the last three weeks of fall. Cut wet grass before a rain, leave the deck at summer height under snow, or skip the final 25 mm soak and the sprinkler blowout, and the damage shows up in April. None of that is a chatbot paragraph. It is a water balance, a mower-deck notch, and a temperature trigger.
Why it mattered
One missed freeze night and the underground lines are done. One late wet mow and you spend spring fighting snow mold. The calendar is the product.
What I built
I built a daily job under 600 lines that replays 7 days of rain minus Hargreaves ET into a 25 mm soil profile, walks a 14-day forecast plus a freeze horizon, and snaps mower height to the real deck (1.25 / 1.5 / 2 / 2.5 / 3 / 3.5 / 4"). Code owns the arithmetic and the three-step SK winter protocol. Jev answers six typed questions in one call — growth low/medium/high, rain-in-48h, mow-now, rain-covers-water, freeze-blowout, mower regime — and code thresholds those probabilities. The public page is static HTML on the Saskatchewan wheat/evergreen kit; API keys never leave .env / Actions secrets.
-
Step 1Pull weather
7-day history + 14-day forecast at 52.29N, 106.67W, plus future probes until the first freeze.
-
Step 2Balance and winter steps in code
Replay rain − ET into a 25 mm profile; step deck 3.5" → 3.0" → 2.5"; lockdown on a ≤0°C night.
-
Step 3Ask Jev, then publish
Six typed questions in one call; merge at 0.65; write lawn_state.json for the static page.
Key decisions
Jev as six typed judgments vs. one free-form JSON blob. Jev is a System One model: Noul / Score / Choice, not a prose generator. I kept millimetres, dates, and ≤0°C lockdown in Python so a model cannot invent a soak amount, then asked Jev only for the calls that are actually judgments (is 1.56 mm a soaking rain? is growth medium given a 27°C weekend?).
Nearest deck notch, ties go longer. The winter spec wanted 2.75" then 2.25"; this mower does not have those holes. I snap 2.75→3.0 and 2.25→2.5 so the recommendation is something the deck can actually do.
Outcome
- Gut calendar → dated actions — next water 18 Sep (50 min @ 4 GPM = 8.15 mm), next mow 24 Sep, last soak and last cut 22 Oct, frost watch 28 Sep at 0.6°C.
- 14 tests, including pre-rain mow and freeze-in-7-day lockdown, all passing before the first live Jev call.
- Six Jev questions, one request — growth 1.05 (medium), rain-in-48h 0.02, freeze-now 0.18; none crossed the 0.65 action line, so hydrology stood.
- Zero keys in the public repo — snapshot JSON only; WeatherAPI and TypeSafe stay in Actions secrets.
What a production version needs
Personal yard tool, not a landscaping product. ET is Hargreaves × a prairie factor because WeatherAPI et0 is paid-only. The 22 Oct freeze is a sampled future day, not a dense 14-day forecast past September 30.