The Planning Loop
This page owns the planning workflow: how the AI planning agent receives context, writes a bounded plan, journals the hypothesis, and lets the dispatcher hand safe setpoints to the ESP32. It should not become the tunable catalog, the climate dashboard, or the safety page.
The exact runtime contract for triggers, payloads, accepted outputs, tunable writes, midnight review, and automatic site publishing lives on Planner Contract and AI Tunables.
At solar milestones, band transitions, forecast deltas, and deviation checks, the AI planning agent receives a structured greenhouse context window. The prompt carries a trigger ID, planner-instance stamp, MCP tool contract, current scorecard context, recent lessons, and the greenhouse state needed for that trigger.
Crop profiles define the target bands. The dispatcher derives the whole-house firmware band. The AI planning agent chooses bounded tactics inside that envelope. MCP validates the write. The ingestor dispatcher pushes changed values. The ESP32 firmware owns the physical relay state machine.
Live Planner State
The live panels here answer two narrow questions: is the planner healthy, and what plan is active now?
The Closed Loop
Assemble context from sensors, forecast, crop bands, equipment, lessons, scorecards, prior plans, and static greenhouse documentation.
Score the previous plan and extract a lesson when reality diverged from the hypothesis.
Deliver each trigger with the same MCP allowlist, audit banner, and trigger-scoped context.
Balance temperature, VPD, water, fog, heat, light, cost, lessons, and retrieved context against the next 72 hours.
Write time-based tactical waypoints, each with a hypothesis and expected outcome.
Every 5 minutes, push changed setpoints to the ESP32; firmware enforces physical state locally.
Post the operator-facing Slack summary: what changed, why it changed, and what a human should watch.
Logged outcomes become scorecard data and validated lessons for the next planning cycle.
What The AI Planning Agent Reads
The planner assembles a bounded context packet rather than a generic prompt:
Zone climate, VPD, humidity, CO2, lux, outdoor weather, equipment state, active mode, alerts, and tunable readbacks.
Forecast pressure, solar context, crop bands, firmware-band projection, and expected stress windows.
Previous plans, scorecard outcomes, validated lessons, recent failures, and operator notes.
Curated site pages for structure, equipment, crops, safety, physical constraints, operating rules, and build notes.
The crop target source lives on Crop Profiles. Current climate panels live on Climate Control.
Context Window And Prompts
The AI planning agent does not plan from a generic greenhouse prompt. Every planning event gets a generated context window that describes the current room, the active plan, recent outcomes, forecast pressure, crop targets, equipment state, lessons, and data-health caveats.
The context window is built before the AI planning agent plans. MCP tools validate writes; the ESP32 enforces the physical state machine.
Dynamic Data Window
scripts/gather-plan-context.sh builds the live greenhouse packet. It reads TimescaleDB views, Home Assistant state where needed, and current ESP32/forecast data. The packet is plain text so the same context can move through both local and cloud planner routes.
Representative sections include:
| Section | Planning role | Data |
|---|---|---|
| System health | Trust inputs or degrade | Data-health and dependency completeness. |
| Active plan | Avoid stale posture | Future transitions and Tier 1 values. |
| Zone conditions | Diagnose current stress | Temperature, RH, VPD, CO2, outdoor weather, water, and enthalpy. |
| ESP32 state | Separate intent from mode | Current firmware state when available. |
| 24h hourly pattern | Ground forecast reasoning | Temperature, VPD, RH, CO2, and lux over the prior day. |
| Planner scorecard | Connect decisions to outcomes | Today’s score and recent trend. |
| Compliance | Find binding failure mode | 24h zone band percentages for temperature and VPD. |
| DIF and DLI | Avoid sensor overreach | Day/night differential and light estimates with known limitations. |
| Hydro and irrigation | Keep water context visible | Water quality, schedules, and history. |
| Equipment runtime | Spot churn and cost drivers | Relay/equipment hours and transitions. |
| Energy and water | Make tradeoffs visible | kWh, therms, watts, and water trend. |
| Crops and observations | Tie goals to plants | Active crops and growing context. |
| Previous plan review | Grade the last hypothesis | Governing plan, outcome fields, and validation state. |
| Structured hypothesis | Compare belief to reality | Typed predicted conditions and stress windows. |
| Tunable constraints | Prevent impossible writes | Firmware min/max/step readbacks. |
| Forecast calibration | Separate bias from regime change | Bias-corrected weather priors and recent forecast accuracy. |
| Active lessons | Carry durable learning | Deduplicated high-value lessons. |
| Current setpoints | Fill unchanged waypoints | Latest effective values. |
| Forecast alerts | Turn weather into tactics | Heat, VPD, frost, overcast, cold-front, and stress-window signals. |
| Guardrail-aware audits | Keep nudges inside rules | Recent transitions, stress windows, and constraint checks. |
| Context completeness | Expose missing data | Reachability and staleness of dependencies. |
Static Site Context
scripts/gather-static-context.sh builds /srv/verdify/state/planner-static-context.md. It concatenates public Markdown pages from the site, excluding generated daily plans, dashboards, static assets, and scripts. The planner context packet embeds that file with a SHA-256 digest, byte count, and line count, so the public site contract and the planner payload are tied to the same source tree.
Generated daily plan pages are handled by source records instead of copied HTML or Markdown. The site renders plan_journal, plan_delivery_log, setpoint-plan rows, scorecards, lessons, and daily summaries into /plans/YYYY-MM-DD; the planner receives those same records directly in the dynamic context packet.
This gives the AI planning agent the greenhouse documentation in the same form public readers see it:
- structure, equipment, zones, crops, and physical constraints
- safety architecture and data model
- planning loop and AI Tunables Traceability
- resource accounting, evidence, and build notes
- lessons and FAQ language that constrain public claims
Static context keeps the planner anchored to this greenhouse’s actual hardware and physical limitations.
Prompt Family
ingestor/iris_planner.py has a tailored prompt builder for each planning event:
| Trigger | Role | Expected output |
|---|---|---|
SUNRISE | Morning tactical plan | Full set_plan with 5-8 compact waypoints for the next daylight and overnight period. |
SUNSET | Overnight posture | Full set_plan with 3-5 overnight waypoints for cold and disease control. |
MIDNIGHT | End-of-day review and reset | Required plan_evaluate pass for completed prior-day plans, followed by a fresh set_plan to start the new local day. |
SOLAR_MAX | Solar-noon checkpoint | set_tunable or acknowledge_trigger before the afternoon dry window. |
TRANSITION | Stress checkpoint | set_tunable or acknowledge_trigger at peak-stress or decline points. |
FORECAST_DEVIATION | Forecast miss | Immediate bounded correction or explanation after a sigma-gated observed-vs-forecast miss. |
MANUAL | Operator request | Whatever the operator asked, still within MCP bounds. |
Each event gets the same safety contract, the same writable tunable limits, and the same audit headers. The difference is how much change the event is expected to make. DEVIATION remains as a backward-compatible alias for old in-flight deliveries, but new trigger paths use FORECAST_DEVIATION.
Prompt Contract
The stable prompt contract is public-safe to summarize:
READ: scorecard, climate, forecast, active plan, crop bands, lessons, alerts.
DIAGNOSE: identify the binding compliance axis and stress type.
DECIDE: apply safety first, then validated lessons, then forecast reasoning.
ACT: write bounded tunables or a full plan through MCP tools only.
REPORT: summarize decisions and tradeoffs for the operator.The standing directives also require:
- use MCP tools only
- do not run shell, direct SQL, or Docker commands
- include
trigger_idandplanner_instanceon every write - do not acknowledge required MIDNIGHT/SUNRISE/SUNSET full-plan cycles unless validation mode is active
- call
acknowledge_triggerfor routine no-op cycles so SLA monitoring can close them honestly - write compact plans and avoid broad read tools during routine no-op or transition checks
Context Trim Policy
The planner route is designed for bounded, event-scoped context. Trigger-scoped sessions prevent chat history from growing without limit, but the generated packet still needs an explicit trim policy so required full plans stay focused.
Firmware safety split, tunable bounds, audit headers, and current setpoints. Never trim from required planning events.
Current climate, equipment state, active alerts, forecast pressure, and active plan; avoid broad historical dumps.
Last plan hypothesis, scorecard, stress windows, and resource use, with links to plan/archive rows.
Active curated lessons and high-confidence constraints.
Architecture, safety, known limits, crops, zones, and equipment summaries with canonical links.
Old plans, raw extraction rows, and full dashboard prose unless the event specifically needs them.
The practical rule is: routine events should receive enough context to make a bounded tactical decision, not a full copy of the website and history. Larger reviews can carry more context, but they still use the same MCP write boundary.
Audit Header
Every delivered prompt ends with an audit banner:
trigger_id=<uuid>
planner_instance="local" | "opus"The planner must pass those values into set_plan, set_tunable, or acknowledge_trigger. That is how Verdify correlates:
plan_delivery_log -> planner delivery -> MCP write -> plan_journal/setpoint_changes -> public archiveIf any link is missing, the failure should be visible. Missed cycles remain in the planning archive because planner availability is part of the system being audited.
What The AI Planning Agent Writes
The AI planning agent writes tactical intent, not direct actuator commands. In production that means two MCP write paths:
set_planMulti-waypoint planWrites future rows to setpoint_plan, deactivates older future plan waypoints, and records a hypothesis in plan_journal.
set_tunableOne-shot adjustmentWrites a current tactical row for a planner-pushable parameter when a trigger needs a narrow correction.
Parameter names, bounds, trigger IDs, planner instance, structured hypotheses, and required routine-plan fields are checked before DB writes land.
The generated AI Tunables Traceability page owns the exact parameter names, bounds, defaults, current values, readbacks, and firmware references. This page intentionally does not duplicate that table.
Dispatch And Readback
The ingestor runs the setpoint dispatcher every 300 seconds, with an immediate reconciliation path after ESP32 reconnect. The dispatcher reads the active plan, resolves the latest applicable value for each parameter, compares it with current readbacks, and pushes only changed values through the ESPHome API. Final writes are logged in setpoint_changes; setpoint_snapshot stores the firmware cfg_* readbacks that confirm what the controller actually accepted.
Between dispatcher runs, the ESP32 keeps running locally from its current configured values. Failure behavior and relay ownership live on Safety Architecture.
Journal And Learning
Every plan is a hypothesis. plan_journal stores the plan ID, trigger metadata, hypothesis, experiment, expected outcome, conditions summary, and changed parameters. Later evaluation writes the outcome and score back to the same record.
Useful findings become rows in planner_lessons; they are not model self-modification. Future prompts can read validated lessons as ordinary database memory.
Planner outcome proof lives on the Scorecard. The generated lesson list lives on Lessons Learned.
Page Boundaries
The public story: crop targets, AI-assisted tactics, ESP32 control, scorecards, and why the testbed is useful.
Generated registry, bounds, readbacks, ownership, and firmware references.
Trigger schedule, payload shape, accepted outputs, tunable writes, midnight review, automatic site publishing, and reliability checks.
Scorecards, compliance, stress hours, forecast-vs-band-vs-actual, and lessons live with the public proof layer.
Live temperature, VPD, forecast, zone, and firmware-band evidence.
Lighting, biological activity, direct-wet windows, irrigation, and fertigation policy.
Utility timing, rates, daily cost, seasonal cost, and solar-alignment accounting.
ESP32 relay ownership, hard rails, and failure behavior.
Human-readable briefs, forecast-deviation messages, reminders, and the operator task queue.
Full dashboards: Controller ↗ · Planning ↗