About GridGPT
Overview
GridGPT is an open-source, real-time monitoring dashboard for Ontario's electricity grid. It ingests public data from the Independent Electricity System Operator (IESO) and presents it in a dense, analyst-grade interface across nine pricing zones. The dashboard covers zonal pricing, provincial demand, generation by fuel type, intertie flows to neighbouring jurisdictions, weather overlays, and a text-to-SQL AI chatbot that can query any of the underlying data using natural language.
The project is a full-stack engineering portfolio piece built to demonstrate real-time data pipeline design, time-series analytics, and AI-augmented data exploration. Every layer — from the Python producer that parses IESO XML feeds, to the ClickHouse OLAP storage, to the SSE-streamed chat interface — is designed for low-latency observability of a complex, always-on system.
Why Blueprint.js?
Blueprint.js was chosen as the component library because it was purpose-built for data-dense enterprise applications — exactly the kind of interface an electricity grid dashboard needs.
- Data-dense layouts — Blueprint is designed for complex dashboards with tables, trees, and multi-panel views, not consumer landing pages. It doesn't waste space on oversized padding or rounded cards.
- Dark-first design — A native dark theme ships out of the box. No CSS override hacks, no theme provider workarounds. The dark theme is a first-class citizen.
- TypeScript native — Full type definitions for every component and prop, matching the strict TypeScript configuration used throughout this project.
- 500+ icons — A comprehensive icon system for status indicators, navigation, fuel types, and controls without pulling in a separate icon library.
System Architecture
Data flows through a streaming pipeline from IESO's public report servers into the dashboard. Each stage is designed for reliability and low latency.
Data Pipeline
force-dynamic for real-time data.Deployed on Vercel (serverless)A separate WMS connection to Environment and Climate Change Canada (ECCC) feeds weather overlays (temperature, cloud cover, precipitation) directly into the map component via GDPS forecast layers.
Dashboard Panels
The dashboard is built around six panels, each showing a different facet of Ontario's grid in real time.
Fuel Mix
v_generator_output aggregated by fuel typeThree views of Ontario's current generation: a donut chart showing the percentage split between fuel types (nuclear ~60%, hydro ~25%, gas, wind, solar, biofuel), a detailed table with per-fuel output and capability numbers, and a radar chart for comparing fuel contributions. The inner ring shows the energy flow direction.
Generation by Resource
v_generator_output per plantArea charts for each major generating station (Bruce, Darlington, Pickering, and more), grouped by fuel type with color coding. Each section — Renewables, Nuclear, Hydro, Gas — shows individual plant contributions. This table can lag ~2 hours behind other data sources.
Ontario Zone Map
v_zonal_prices + v_intertie_flow + v_generator_output + ECCC WMSAn interactive Leaflet map with a pricing zone GeoJSON overlay using a 12-tier color scale, generation site markers sized by output, animated intertie chevrons showing flow direction, and ECCC weather WMS layers for temperature, cloud cover, and precipitation. A time scrubber allows historical replay of all map layers simultaneously.
Market Overview
v_da_ozp + v_zonal_prices + v_zonal_demand + v_adequacyA dual-axis Recharts chart with demand, supply, and grid load on the left MW axis and price on the right $/MWh axis. Includes a day-ahead overlay for both the current day (D) and tomorrow (D+1), plus a peak demand display. Supports 1-hour and full-day time ranges.
Grid AI
All ClickHouse tables via /api/chatA text-to-SQL chatbot powered by the Claude API. Users ask natural language questions like “What was the average price in Toronto this morning?” and the system generates validated SQL, executes it against ClickHouse, and streams back the answer with a strategy explanation. Chat history persists in localStorage.
Grid AI: Text-to-SQL Architecture
Grid AI is a context-grounded query assistant that translates natural language into validated ClickHouse SQL. Rather than relying on the LLM's general knowledge, every query is anchored in domain expertise assembled from four context layers.
Context Layers
Tool Loop
The chat API uses Claude's tool-use capability with a query_clickhouse tool. On each turn, the model generates SQL plus a plain-English strategy explanation. The SQL passes through a safety validator (SELECT-only, LIMIT required, no system table access) before executing against ClickHouse. If the query returns an error or empty results, the model can retry with corrected SQL for up to 5 iterations.
SSE Streaming
Results stream to the browser via Server-Sent Events. The frontend receives four event types: tool_use (SQL + strategy), tool_result (row count + duration), text_delta (chunked natural language response), and done. The Grid AI component renders tool badges, strategy text, markdown-formatted answers, and persists conversations in localStorage.
Grid AI Pipeline
API Reference
The Next.js API layer exposes 19 routes organized into five categories. All routes query ClickHouse directly and use force-dynamic for real-time data.
Core (6)
- /api/prices Latest zonal prices
- /api/demand Current demand
- /api/fuel-mix Fuel mix breakdown
- /api/generators Generator output
- /api/interties Intertie flows
- /api/weather Weather by zone
Historical (6)
- /api/prices/history
- /api/demand/history
- /api/supply/history
- /api/fuel-mix/history
- /api/generators/history
- /api/market/history
Day-Ahead (2)
- /api/market/day-ahead DA forecasts
- /api/peak-demand Peak forecasts
Time-Scrub (4)
- /api/prices/at-time
- /api/weather/at-time
- /api/interties/at-time
- /api/interties/prices
AI (1)
- /api/chat Text-to-SQL via Claude
Weather Integration
The Ontario Zone Map displays weather overlays sourced from ECCC's Global Deterministic Prediction System (GDPS) via WMS tile layers. Three layers are available: surface temperature, cloud cover, and total precipitation.
Weather frames are snapped to 3-hour forecast boundaries (00Z, 03Z, 06Z, etc.) to match GDPS model runs. The map uses a double-buffering technique: the next forecast image loads in a hidden layer while the current one displays, so transitions between time steps are smooth instead of flickering.
Next.js Techniques
- Dynamic imports for Leaflet — The map component uses
next/dynamicwithssr: falseto avoidwindow is not definederrors during server-side rendering. Leaflet requires a browser environment. force-dynamicon all API routes — Every API route exportsexport const dynamic = 'force-dynamic'to ensure fresh ClickHouse queries on every request rather than serving stale cached responses.- Revalidation on ClickHouse fetch — The ClickHouse HTTP client uses
next: { revalidate: 5 }to allow brief caching while keeping data near-real-time. - Client-side hydration for suggested questions — The Grid AI panel renders a deterministic set of suggested questions on the server, then randomizes them client-side after hydration to avoid mismatch errors.
Hosting & Infrastructure
The system is split across two hosting providers, optimized for cost and reliability:
- Frontend on Vercel — The Next.js app runs as serverless functions for API routes and uses Vercel's edge CDN for static assets. This handles bursty user traffic with auto-scaling at near-zero idle cost.
- Backend on Hetzner VPS — A single VPS runs Docker Compose with 5 services: Redpanda, Redpanda Console, ClickHouse, Redis, and init-kafka. The Python producer runs on a cron schedule on the same machine. This provides persistent, always-on infrastructure for 24/7 data ingestion at ~$5–10/month.
The split rationale: Vercel handles user-facing traffic cheaply with auto-scaling, while Hetzner provides the stable, long-running services (Kafka, ClickHouse, Redis) that need to be online continuously regardless of user traffic.
Built with Claude Code
GridGPT was developed using Claude Code as the primary development tool. The project leveraged several MCP (Model Context Protocol) integrations and custom Skills to accelerate development:
- ClickHouse direct queries — A custom
/querySkill for running ad-hoc SQL against the live database during development, validating schema designs and query patterns in real time. - Context7 for documentation — Used for looking up Blueprint.js component APIs, Recharts configuration, Leaflet plugin patterns, and Next.js App Router conventions.
- Sequential Thinking for complex logic — Applied to multi-step problems like the text-to-SQL context assembly, timezone conversion strategy, and deduplication view design.
- Custom Skills —
/dev(start all infrastructure),/query(run ClickHouse SQL), and/ingest(trigger a producer run) provided one-command workflows during development.
Tech Stack
| Layer | Technology |
|---|---|
| Frontend | Next.js 14 (App Router), Blueprint.js 5.x, Recharts, Nivo, Leaflet |
| Language | TypeScript (strict), Python 3.11 |
| API | Next.js API routes, Server-Sent Events (SSE) |
| Database | ClickHouse (columnar OLAP) |
| Streaming | Redpanda (Kafka-compatible) |
| Cache | Redis |
| AI | Claude API (claude-sonnet-4, tool use) |
| Weather | ECCC GDPS via WMS |
| Maps | Leaflet + react-leaflet, GeoJSON, WMS tiles |
| Producer | Python 3.11, aiohttp, confluent-kafka, Pydantic v2 |
| Infrastructure | Docker Compose, Vercel, Hetzner VPS |
| Dev Tools | Claude Code, Context7, Sequential Thinking |
Quick Start
# Start infrastructure
docker compose up -d
# Start frontend dev server
cd frontend && npm run dev
# Start producer (separate terminal, activate venv)
cd producer && source venv/bin/activate && python main.py
# Query ClickHouse directly
docker exec -it clickhouse clickhouse-client \
-q "SELECT zone, price FROM ieso.v_zonal_prices \
ORDER BY timestamp DESC LIMIT 9"IESO Data Sources
All data comes from IESO's public report server. These reports are freely available and require no authentication.
| Report | Format | Frequency | URL |
|---|---|---|---|
| RealtimeZonalEnergyPrices | XML | 5-min | Link |
| RealtimeDemandZonal | CSV | 5-min | Link |
| GenOutputCapability | XML | 5-min | Link |
| GenOutputbyFuelHourly | XML | Hourly | Link |
| IntertieScheduleFlow | XML | Hourly | Link |
| DayAheadOntarioZonalPrice | XML | Daily | Link |
| DayAheadIntertieLMP | XML | Daily | Link |
| RealtimeIntertieLMP | XML | 5-min | Link |
| AdequacyDay | XML | Daily | Link |
Glossary
Plain-language definitions for terms used throughout this page.
- Intertie
- A power line that connects Ontario's electricity grid to another region like Quebec or Michigan. Power can flow in or out through these connections.
- Pricing Zone
- An area of Ontario where electricity costs the same amount. Ontario has 9 pricing zones with names like TORONTO, OTTAWA, and NORTHWEST.
- IESO
- Independent Electricity System Operator. The organization that runs Ontario's power grid and shares public data about it.
- Megawatt (MW)
- A unit of power. One megawatt can power about 1,000 homes at the same time.
- $/MWh
- Dollars per megawatt-hour. This is how electricity prices are measured — like a “price per gallon” for electricity.
- Fuel Mix
- The combination of energy sources used to make electricity right now — things like nuclear, water (hydro), natural gas, wind, and solar.
- Day-Ahead Market
- A market where electricity prices are set one day before the power is actually used. This helps the grid plan ahead.
- DA-OZP
- Day-Ahead Ontario Zonal Price. The official price for electricity, decided one day in advance. This is what consumers actually pay.
- Settlement Price
- The final, official price used for billing. In Ontario, this is the DA-OZP — not the real-time 5-minute price.
- Real-Time Price
- The live electricity price, updated every 5 minutes. Used for watching the grid, but not for billing.
- Baseload
- Power plants that run all the time, like nuclear plants. They provide steady, low-cost power around the clock.
- Peaker Plant
- A power plant that only turns on when lots of people need electricity at the same time. Usually gas-powered and more expensive.
- ClickHouse
- A very fast database built for analyzing large amounts of data over time. GridGPT stores all IESO data here.
- Redpanda
- A streaming platform that moves data in real-time — like a conveyor belt carrying information from the producer to the database.
- Text-to-SQL
- Turning a plain English question (like “What's the price in Toronto?”) into a database query that finds the answer.
- Context-Grounded
- An AI approach that uses specific domain knowledge (like IESO rules) instead of relying on general knowledge alone.
- SSE
- Server-Sent Events. A way for the server to push live updates to your browser without you needing to refresh the page.
- OLAP
- Online Analytical Processing. A type of database designed for fast, complex queries on historical data — perfect for time-series energy data.
- Blueprint.js
- A design system made for building data-heavy dashboards. It provides ready-made dark theme components like tables, icons, and buttons.
- Materialized View
- A saved database query that updates itself automatically when new data arrives. Used to move data from Kafka into ClickHouse tables.
- Dedup View
- A database view that removes duplicate rows. When the producer re-fetches data, these views make sure you only see one copy of each record.
- WMS
- Web Map Service. A standard way to serve map images over the internet. GridGPT uses this for weather overlays from Environment Canada.
- ECCC
- Environment and Climate Change Canada. The government agency that provides weather forecast data used on the map.
- Double-Buffering
- A technique where the next image loads in the background before being shown, so transitions look smooth instead of flickering.
- Hydration
- The process where a web page that was already drawn by the server becomes interactive once JavaScript loads in your browser.