6.6 KiB
Report Templates
Purpose
This guide describes the implemented Markdown report template surface for
weatherreporter. It is for maintainers editing embedded report templates,
especially the hourly report template.
Templates are Go text/template files. The current implemented template is:
internal/reporttemplate/templates/hourly.md.tmpl
The hourly template is rendered from a curated HourlyRenderContext, not from
the raw prompt data package. Weather data selection, derivation, module
execution, LLM generation, and artifact paths are handled before template
rendering.
Editing Rules
- Use Go
text/templatesyntax. - Keep templates focused on Markdown layout, headings, ordering, and simple conditional display.
- Do not put weather derivation, source selection, or path construction logic in templates.
- Missing template keys are errors. A misspelled variable will fail rendering.
- No custom template functions are currently registered.
- Optional strings can be guarded with
{{ with .Field }}...{{ end }}. - Slices can be rendered with
{{ range .Items }}...{{ else }}...{{ end }}.
Hourly Template Variables
These are the complete variables currently available to
internal/reporttemplate/templates/hourly.md.tmpl.
Report Metadata
| Variable | Type | Description |
|---|---|---|
.ReportTitle |
string | Display title for the report. Currently Hourly Report. |
.LocationName |
string | Prompt/report location label, such as Brentwood, MO. Falls back to source location if configured location metadata is unavailable. |
.ValidPeriod |
string | Friendly local valid period label, such as 2026-05-29 at 8:30 AM to 2026-05-29 at 2:30 PM. |
.GeneratedAt |
string | Friendly local generation time label. |
GeneratedText
These fields are written by Scriptorium as structured JSON, validated by weatherreporter, and then inserted into the render context.
| Variable | Type | Description |
|---|---|---|
.GeneratedText.Summary |
string | Required short prose summary. |
.GeneratedText.Timing |
string | Required prose about timing of notable weather changes or hazards. |
.GeneratedText.Impacts |
string | Required prose about practical near-term impacts. |
.GeneratedText.Confidence |
string | Optional confidence or uncertainty note. Empty when omitted by the LLM. |
Example:
## Summary
{{ .GeneratedText.Summary }}
{{ with .GeneratedText.Confidence }}
## Confidence
{{ . }}
{{ end }}
Current Conditions
| Variable | Type | Description |
|---|---|---|
.CurrentConditions |
string | Deterministic one-line current conditions summary. May include condition text, temperature, apparent temperature, humidity, and wind. |
Example value:
Partly cloudy; 74 F; feels like 76 F; humidity 71%; wind S 8 mph.
Hourly Forecast
| Variable | Type | Description |
|---|---|---|
.HourlyForecast |
[]HourlyForecastRow | Ordered rows for the hourly report valid period. |
.HourlyForecast[].Time |
string | Friendly local period start time, or the source period name if no start label is available. |
.HourlyForecast[].Summary |
string | Hourly text description, falling back to the period name. |
.HourlyForecast[].Temperature |
string | Rounded temperature label such as 75 F, or empty. |
.HourlyForecast[].Precipitation |
string | Rounded precipitation probability label such as 70% precipitation, or empty. |
.HourlyForecast[].Wind |
string | Wind label such as wind S 10 mph, gusts 18 mph, or empty. |
Example:
## Hourly Forecast
{{ range .HourlyForecast }}
- {{ .Time }}: {{ .Summary }}{{ with .Temperature }}; {{ . }}{{ end }}{{ with .Precipitation }}; {{ . }}{{ end }}{{ with .Wind }}; {{ . }}{{ end }}
{{ else }}
- No hourly forecast rows available.
{{ end }}
Precipitation Timing
| Variable | Type | Description |
|---|---|---|
.PrecipitationTiming |
string | Deterministic precipitation timing summary. May include peak probability, precipitation windows, and thunder mention. |
Example value:
Peak precipitation probability 70% at 10 AM; 2026-05-29 at 10:00 AM to 2026-05-29 at 12:00 PM (max 70% at 10 AM); Thunder is mentioned in the forecast.
Alerts
| Variable | Type | Description |
|---|---|---|
.Alerts |
[]string | Alert labels for active alerts overlapping the report period. Empty when there are no relevant alert overlaps. |
Example:
## Alerts
{{ range .Alerts }}
- {{ . }}
{{ else }}
- No active alert overlaps for this report period.
{{ end }}
SPC Outlooks
| Variable | Type | Description |
|---|---|---|
.SPCOutlooks |
[]string | SPC convective outlook labels overlapping the report period. Empty when there are no overlapping outlooks. |
Example value:
Slight Risk from 2026-05-29 at 7:00 AM to 2026-05-29 at 3:00 PM
Forecast Discussion
| Variable | Type | Description |
|---|---|---|
.ForecastDiscussion.KeyMessages |
[]string | AFD key messages included for the hourly report. |
.ForecastDiscussion.ShortTerm |
string | AFD short-term discussion text, or empty if unavailable. |
Example:
## Forecast Discussion
{{ range .ForecastDiscussion.KeyMessages }}
- {{ . }}
{{ end }}{{ with .ForecastDiscussion.ShortTerm }}
{{ . }}
{{ end }}
SPC Discussion
| Variable | Type | Description |
|---|---|---|
.SPCDiscussions |
[]string | SPC discussion labels retained for overlapping qualifying outlook periods. Empty when there is no relevant SPC discussion. |
Example:
## SPC Discussion
{{ range .SPCDiscussions }}
- {{ . }}
{{ else }}
- No overlapping SPC discussion.
{{ end }}
Weather Story
| Variable | Type | Description |
|---|---|---|
.WeatherStory |
string | Weather story title and description, or No weather story available. |
Common Patterns
Use with for optional strings:
{{ with .GeneratedText.Confidence }}
## Confidence
{{ . }}
{{ end }}
Use range with else for optional lists:
{{ range .SPCOutlooks }}
- {{ . }}
{{ else }}
- No overlapping SPC outlooks.
{{ end }}
Keep punctuation outside optional blocks when possible:
- {{ .Time }}: {{ .Summary }}{{ with .Temperature }}; {{ . }}{{ end }}
Validation
After editing a template, run:
go test ./internal/reporttemplate ./internal/generatedtext ./internal/app
For a full check, run:
go test ./...
go run ./cmd/weatherreporter --help
git diff --check
Template render tests currently exercise the hourly template through
internal/generatedtext/render_context_test.go.