Files
weatherreporter/docs/templates.md

24 KiB

Report Templates

Purpose

This guide describes the implemented Markdown report template surface for weatherreporter. It is for maintainers editing embedded report templates, especially generated-text-template reports.

Templates are Go text/template files. The implemented top-level templates are:

  • internal/reporttemplate/templates/daily.md.tmpl
  • internal/reporttemplate/templates/today.md.tmpl
  • internal/reporttemplate/templates/tomorrow.md.tmpl
  • internal/reporttemplate/templates/hourly.md.tmpl

Shared named partials live under internal/reporttemplate/templates/partials/:

  • alert_digest.md.tmpl, used by Daily, Today, Tomorrow, and Hourly for the combined Alerts and Risk Products section
  • daypart_forecast.md.tmpl, used by Daily and Tomorrow
  • today_daypart_forecast.md.tmpl, used by Today
  • precipitation_timing.md.tmpl, used by Daily, Today, Tomorrow, and Hourly

Templates are rendered from structured contexts such as DailyRenderContext, TodayRenderContext, TomorrowRenderContext, and HourlyRenderContext. Weather data collection, derivation, module execution, generated text validation, and artifact paths are handled before template rendering.

Editing Rules

  • Use Go text/template syntax.
  • 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 registered.
  • Named partials are invoked with {{ template "name" . }}. Pass the current render context (.) unless the partial is intentionally designed for a narrower value.
  • Optional module stanzas are pointers and should be guarded with {{ with .Modules.WeatherStory }}...{{ end }}.
  • Slices can be rendered with {{ range .Items }}...{{ else }}...{{ end }}.

Hourly Context

The hourly template receives five top-level values:

Variable Type Description
.Report HourlyReportContext Display metadata and friendly labels for the rendered report.
.GeneratedText Hourly Structured text returned by Scriptorium.
.Modules HourlyTemplateModules Preferred deterministic template surface, keyed by module purpose.
.Collected facts.CollectedFacts Normalized upstream facts for advanced template use.
.Derived facts.DerivedFacts Shared derived facts for advanced template use.

Prefer .Modules for normal template edits. .Collected and .Derived are available when a template needs lower-level facts, but templates should still avoid nontrivial derivation.

Report

Variable Type Description
.Report.Title string Display title. Currently Hourly Report.
.Report.LocationName string Prompt/report location label, such as Brentwood, MO.
.Report.GeneratedAt time.Time Canonical generation timestamp.
.Report.GeneratedAtLabel string Friendly local generation time label.
.Report.ValidPeriod timeutil.Period Canonical valid period.
.Report.ValidPeriodLabel string Friendly local valid period label, such as 2026-05-29 at 8:30 AM to 2026-05-29 at 2:30 PM.
.Report.Timezone string Effective report timezone.

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.ForecastDiscussion string Required prose for the Forecast Discussion section.
.GeneratedText.PrecipitationTiming string Optional prose rendered after deterministic precipitation windows.
.GeneratedText.Confidence string Optional confidence or uncertainty note. Empty when omitted by the LLM; not rendered by the current hourly template.

Example:

{{ .GeneratedText.Summary }}

## Forecast Discussion

{{ .GeneratedText.ForecastDiscussion }}

Tomorrow Context

The Tomorrow template receives five top-level values:

Variable Type Description
.Report TomorrowReportContext Display metadata and friendly labels for the rendered report.
.GeneratedText Tomorrow Structured text returned by Scriptorium.
.Modules TomorrowTemplateModules Preferred deterministic template surface, keyed by module purpose.
.Collected facts.CollectedFacts Normalized upstream facts for advanced template use.
.Derived facts.DerivedFacts Shared derived facts for advanced template use.

Tomorrow report metadata includes .Report.Title, .Report.ForecastDate, .Report.ForecastDateLabel, .Report.ForecastDayName, .Report.GeneratedAt, .Report.GeneratedAtLabel, .Report.ValidPeriod, and .Report.Timezone.

Tomorrow generated text uses the same .GeneratedText.Summary, .GeneratedText.PrecipitationTiming, and .GeneratedText.Confidence fields as Hourly. .GeneratedText.ForecastDiscussion is a slice of paragraphs and should be rendered with range.

Tomorrow uses the shared alert_digest, daypart_forecast, and precipitation_timing partials.

Tomorrow modules include the Hourly module fields plus:

Variable Type Description
.Modules.DerivedDailySummary *briefing.DerivedDailySummaryModule Daily summary facts for the forecast date.
.Modules.DerivedDaypartSummaries *map[string]briefing.DerivedDaypartSummaryModule Raw daypart summary map, when direct keyed access is needed.
.Modules.Dayparts []generatedtext.TomorrowDaypartContext Ordered daypart summaries for deterministic template rendering.
.Modules.TomorrowPlanning *briefing.TomorrowPlanningModule Planning facts for the next local civil day.

Prefer .Modules.Dayparts over ranging through .Modules.DerivedDaypartSummaries; it follows configured daypart order and falls back to sorted keys for any unmatched entries.

Daily Context

The Daily template receives the same five top-level values as Tomorrow, using DailyReportContext, Daily, and DailyTemplateModules.

Daily report metadata includes .Report.Title, .Report.ForecastDate, .Report.ForecastDateLabel, .Report.ForecastDayName, .Report.GeneratedAt, .Report.GeneratedAtLabel, .Report.ValidPeriod, and .Report.Timezone.

Daily generated text uses .GeneratedText.Summary, .GeneratedText.ForecastDiscussion, .GeneratedText.PrecipitationTiming, and .GeneratedText.Confidence. Forecast discussion is a slice of paragraphs and should be rendered with range.

Daily uses the shared alert_digest, daypart_forecast, and precipitation_timing partials.

Daily uses template ID daily, generated-text schema ID daily, and prompt source internal/reporttemplate/prompts/daily.generated_text.md.

Daily modules include the Hourly module fields plus:

Variable Type Description
.Modules.DerivedDailySummary *briefing.DerivedDailySummaryModule Daily summary facts for the forecast date.
.Modules.DerivedDaypartSummaries *map[string]briefing.DerivedDaypartSummaryModule Raw daypart summary map, when direct keyed access is needed.
.Modules.Dayparts []generatedtext.DailyDaypartContext Ordered daypart summaries for deterministic template rendering.
.Modules.DailyPlanning *briefing.DailyPlanningModule Planning facts for the selected local civil day.

Prefer .Modules.Dayparts over ranging through .Modules.DerivedDaypartSummaries; it follows configured daypart order and falls back to sorted keys for any unmatched entries.

Today Context

The Today template receives the same five top-level values as Tomorrow, using TodayReportContext, Today, and TodayTemplateModules.

Today report metadata includes .Report.Title, .Report.ForecastDate, .Report.ForecastDateLabel, .Report.ForecastDayName, .Report.GeneratedAt, .Report.GeneratedAtLabel, .Report.ValidPeriod, and .Report.Timezone.

Today generated text uses .GeneratedText.Summary, .GeneratedText.ForecastDiscussion, .GeneratedText.PrecipitationTiming, and .GeneratedText.Confidence. Forecast discussion is a slice of paragraphs and should be rendered with range.

Today uses the today_daypart_forecast partial so elapsed or missing dayparts can be omitted while Daily and Tomorrow keep their fallback row. It also uses the shared alert_digest and precipitation_timing partials.

Today uses template ID today, generated-text schema ID today, and prompt source internal/reporttemplate/prompts/today.generated_text.md.

Today modules include the Hourly module fields plus:

Variable Type Description
.Modules.DerivedDailySummary *briefing.DerivedDailySummaryModule Daily summary facts for the forecast date.
.Modules.DerivedDaypartSummaries *map[string]briefing.DerivedDaypartSummaryModule Raw daypart summary map, when direct keyed access is needed.
.Modules.Dayparts []generatedtext.TodayDaypartContext Ordered daypart summaries for deterministic template rendering.
.Modules.TodayPlanning *briefing.TodayPlanningModule Planning facts for the current local civil day.

Prefer .Modules.Dayparts over ranging through .Modules.DerivedDaypartSummaries; it follows configured daypart order and falls back to sorted keys for any unmatched entries.

Modules

.Modules exposes typed outputs from the same module pipeline used for the prompt data package. Module fields are pointers because missing-data policy may omit a stanza.

Templates render from rich module values, not from the curated YAML data package. Some fields documented below are deterministic wording helpers for Markdown templates and are intentionally omitted from data packages passed to Scriptorium. The data package is a prompt input, while the render context is the template surface.

Variable Type Description
.Modules.Metadata *briefing.MetadataModule Report metadata module output, when present.
.Modules.CurrentConditions *briefing.CurrentConditionsModule Current conditions from /conditions/current.
.Modules.HourlyForecast *briefing.HourlyForecastModule Hourly forecast periods overlapping the report valid period.
.Modules.PrecipTiming *briefing.PrecipTimingModule Derived precipitation timing facts and threshold windows.
.Modules.AlertDigest *briefing.AlertDigestModule Active alert status and relevant alert overlaps.
.Modules.SPCConvectiveOutlooks *briefing.SPCConvectiveOutlooksModule SPC outlooks that overlap the report valid period.
.Modules.AreaForecastDiscussion *briefing.AreaForecastDiscussionModule AFD key messages and configured discussion sections.
.Modules.SPCConvectiveDiscussion *briefing.SPCConvectiveDiscussionModule SPC discussions retained for qualifying overlapping categorical risk days.
.Modules.WeatherStory *briefing.WeatherStoryModule Latest NWS weather story, when available.

Current Conditions

Common fields:

Variable Type Description
.Modules.CurrentConditions.ConditionText string Current condition text.
.Modules.CurrentConditions.ConditionTextLower string Lower-case current condition text for inline sentences.
.Modules.CurrentConditions.TemperatureF *int Rounded current temperature.
.Modules.CurrentConditions.ApparentTemperatureF *int Rounded apparent temperature.
.Modules.CurrentConditions.RelativeHumidityPercent *int Rounded relative humidity.
.Modules.CurrentConditions.WindDirection string 16-point compass wind direction.
.Modules.CurrentConditions.WindDirectionText string Lower-case full wind direction text, such as northwest.
.Modules.CurrentConditions.WindSpeedMph *int Rounded wind speed.

Example:

{{ with .Modules.CurrentConditions }}
{{ .ConditionText }}{{ with .TemperatureF }}; {{ . }} F{{ end }}{{ with .WindDirection }}; wind {{ . }}{{ end }}{{ with .WindSpeedMph }} {{ . }} mph{{ end }}
{{ else }}
No current conditions available.
{{ end }}

Hourly Forecast

Common period fields:

Variable Type Description
.Modules.HourlyForecast.Periods []briefing.HourlyForecastPeriod Ordered periods for the hourly report valid period.
.Modules.HourlyForecast.Periods[].HourLabel string Friendly hour label such as 4:00 PM.
.Modules.HourlyForecast.Periods[].PeriodBegins string Friendly local period start label.
.Modules.HourlyForecast.Periods[].PeriodEnds string Friendly local period end label.
.Modules.HourlyForecast.Periods[].Name string Source period name.
.Modules.HourlyForecast.Periods[].TextDescription string Hourly forecast text.
.Modules.HourlyForecast.Periods[].TextDescriptionLower string Lower-case hourly forecast text for inline sentences.
.Modules.HourlyForecast.Periods[].TemperatureF *float64 Forecast temperature.
.Modules.HourlyForecast.Periods[].ProbabilityOfPrecipitationPercent *float64 Forecast precipitation probability.
.Modules.HourlyForecast.Periods[].MentionPrecipitation bool True when precipitation probability meets the hourly mention threshold.
.Modules.HourlyForecast.Periods[].WindDirection string 16-point compass wind direction.
.Modules.HourlyForecast.Periods[].WindSpeedMph *float64 Wind speed.
.Modules.HourlyForecast.Periods[].WindGustMph *float64 Wind gust.

Example:

{{ with .Modules.HourlyForecast }}{{ range .Periods }}
- **{{ .HourLabel }}:**{{ with .TemperatureF }} {{ . }}°F{{ end }} and {{ .TextDescriptionLower }}.{{ if .MentionPrecipitation }}{{ with .ProbabilityOfPrecipitationPercent }} Probability of precipitation is {{ . }}%.{{ end }}{{ end }}
{{ else }}
- No hourly forecast rows available.
{{ end }}{{ end }}

Precipitation Timing

Common fields:

Variable Type Description
.Modules.PrecipTiming.MaxPopPercent *int Highest hourly precipitation probability in the valid period.
.Modules.PrecipTiming.MaxPopTime string Friendly local time for the highest hourly precipitation probability.
.Modules.PrecipTiming.ProbabilityThreshold float64 Threshold used to define precipitation windows.
.Modules.PrecipTiming.PrecipitationWindows []briefing.PrecipitationWindowModule One or more threshold precipitation windows.
.Modules.PrecipTiming.PrecipitationWindows[].PeriodBegins string Friendly local window start.
.Modules.PrecipTiming.PrecipitationWindows[].PeriodBeginsHourLabel string Friendly window start hour, such as 4:00 PM.
.Modules.PrecipTiming.PrecipitationWindows[].PeriodEnds string Friendly local window end; omitted for open windows.
.Modules.PrecipTiming.PrecipitationWindows[].PeriodEndsHourLabel string Friendly window end hour; omitted for open windows.
.Modules.PrecipTiming.PrecipitationWindows[].MaxPopPercent *int Highest precipitation probability inside the window.
.Modules.PrecipTiming.PrecipitationWindows[].MaxPopTime string Friendly local time for the window maximum.
.Modules.PrecipTiming.PrecipitationWindows[].MaxPopHourLabel string Friendly hour label for the window maximum.
.Modules.PrecipTiming.PrecipitationWindows[].PrecipitationType string Conservatively inferred precipitation type, such as showers and thunderstorms.
.Modules.PrecipTiming.PrecipitationWindows[].ExpectationPhrase string Probability-based sentence used by precipitation timing templates.
.Modules.PrecipTiming.ThunderMentioned bool Whether thunder is mentioned in the forecast text.

Daypart Summaries

Daily, Today, and Tomorrow templates should use .Modules.Dayparts for ordered daypart rendering. Each item has Key and Summary; Summary is a rich briefing.DerivedDaypartSummaryModule.

The shared daypart partials render from these same .Modules.Dayparts values. Edit daypart_forecast.md.tmpl for common Daily/Tomorrow wording, and edit today_daypart_forecast.md.tmpl for Today-specific omission behavior.

Common rich daypart fields:

Variable Type Description
.Modules.Dayparts[].Summary.DisplayName string Human-readable daypart label.
.Modules.Dayparts[].Summary.PeriodBegins string Friendly local daypart start.
.Modules.Dayparts[].Summary.PeriodEnds string Friendly local daypart end.
.Modules.Dayparts[].Summary.TempRangeF string Rounded temperature range or single temperature.
.Modules.Dayparts[].Summary.TemperaturePhraseF string Temperature phrase used for steady template wording.
.Modules.Dayparts[].Summary.TemperatureTrend string Trend category such as rising, falling, peaking, or steady.
.Modules.Dayparts[].Summary.TemperatureStartPhraseF string Starting temperature phrase for rising/falling wording.
.Modules.Dayparts[].Summary.TemperatureEndPhraseF string Ending temperature phrase for rising/falling wording.
.Modules.Dayparts[].Summary.TemperaturePeakPhraseF string Peak temperature phrase for peaking wording.
.Modules.Dayparts[].Summary.TemperatureSteadyPhraseF string Steady temperature phrase.
.Modules.Dayparts[].Summary.MaxPopPercent *int Highest precipitation probability in the daypart.
.Modules.Dayparts[].Summary.MaxPopTime string Friendly local time for the highest precipitation probability.
.Modules.Dayparts[].Summary.MaxPopTimeLabel string Clock-style label for deterministic precipitation timing text.
.Modules.Dayparts[].Summary.MentionPrecipitation bool True when precipitation probability should be mentioned by the template.
.Modules.Dayparts[].Summary.DominantCondition string Dominant condition text.
.Modules.Dayparts[].Summary.DominantConditionLower string Lower-case condition text for inline sentences.
.Modules.Dayparts[].Summary.DominantConditionDisplay string Display-case condition text for bullet starts.
.Modules.Dayparts[].Summary.NotableConditions []string Notable condition labels retained for the daypart.

Template-only daypart helpers such as TemperaturePhraseF, DominantConditionLower, DominantConditionDisplay, and MaxPopTimeLabel remain available here even though they are not serialized into data-package YAML.

Alert Digest

Variable Type Description
.Modules.AlertDigest.Checked bool Whether alert data was checked successfully.
.Modules.AlertDigest.ActiveCount int Active alert count from the source.
.Modules.AlertDigest.RelevantCount int Alert count overlapping the report period.
.Modules.AlertDigest.Missing bool True when alert data is unavailable.
.Modules.AlertDigest.Relevant []briefing.AlertSummary Relevant alert summaries.
.Modules.AlertDigest.Relevant[].Event string Alert event name.
.Modules.AlertDigest.Relevant[].Headline string Alert headline.
.Modules.AlertDigest.Relevant[].Severity string Alert severity.
.Modules.AlertDigest.Relevant[].PeriodBegins string Friendly local alert applicability start.
.Modules.AlertDigest.Relevant[].PeriodEnds string Friendly local alert applicability end.
.Modules.AlertDigest.Relevant[].Instruction string Alert instruction text, when provided.
.Modules.AlertDigest.Relevant[].Description string Alert description text, when provided.

SPC Outlooks And Discussion

Variable Type Description
.Modules.SPCConvectiveOutlooks.Checked bool Whether SPC outlook data was checked successfully.
.Modules.SPCConvectiveOutlooks.AsOf string Friendly source as-of time.
.Modules.SPCConvectiveOutlooks.IssuedAt string Friendly source issue time.
.Modules.SPCConvectiveOutlooks.Outlooks []briefing.SPCConvectiveOutlookRecord Overlapping outlook records.
.Modules.SPCConvectiveOutlooks.Outlooks[].Day int SPC day number.
.Modules.SPCConvectiveOutlooks.Outlooks[].OutlookType string Outlook type, such as categorical.
.Modules.SPCConvectiveOutlooks.Outlooks[].Label string Short outlook label.
.Modules.SPCConvectiveOutlooks.Outlooks[].LabelText string Human-readable outlook label.
.Modules.SPCConvectiveOutlooks.Outlooks[].PeriodBegins string Friendly outlook period start.
.Modules.SPCConvectiveOutlooks.Outlooks[].PeriodEnds string Friendly outlook period end.
.Modules.SPCConvectiveOutlooks.Outlooks[].ImageURL string Source image URL.
.Modules.SPCConvectiveOutlooks.RiskDigest []briefing.SPCConvectiveOutlookDigest Curated categorical outlooks for the shared Alerts and Risk Products section.
.Modules.SPCConvectiveOutlooks.RiskDigest[].LabelText string Human-readable outlook label.
.Modules.SPCConvectiveOutlooks.RiskDigest[].RiskLabel string Sentence-style risk label for report rendering.
.Modules.SPCConvectiveOutlooks.RiskDigest[].PeriodBegins string Friendly outlook period start.
.Modules.SPCConvectiveOutlooks.RiskDigest[].PeriodEnds string Friendly outlook period end.
.Modules.SPCConvectiveDiscussion.IncludedBecause string Criterion used to include discussions.
.Modules.SPCConvectiveDiscussion.Discussions []briefing.SPCConvectiveDiscussionRecord Retained discussion records.
.Modules.SPCConvectiveDiscussion.Discussions[].Headline string Discussion headline.
.Modules.SPCConvectiveDiscussion.Discussions[].Summary string Discussion summary.
.Modules.SPCConvectiveDiscussion.Discussions[].Discussion string Full discussion text.

Area Forecast Discussion

Variable Type Description
.Modules.AreaForecastDiscussion.Product string Source product identifier.
.Modules.AreaForecastDiscussion.KeyMessages []string AFD key messages.
.Modules.AreaForecastDiscussion.ShortTerm string AFD short-term section text.
.Modules.AreaForecastDiscussion.LongTerm string AFD long-term section text.

Weather Story

Variable Type Description
.Modules.WeatherStory.Available bool True when a story is available.
.Modules.WeatherStory.OfficeID string Source office ID.
.Modules.WeatherStory.PeriodBegins string Friendly story period start.
.Modules.WeatherStory.PeriodEnds string Friendly story period end.
.Modules.WeatherStory.UpdatedAt *time.Time Canonical update timestamp.
.Modules.WeatherStory.Title string Story title.
.Modules.WeatherStory.Description string Story description.
.Modules.WeatherStory.AltText string Story image alt text.
.Modules.WeatherStory.Priority bool Source priority flag.
.Modules.WeatherStory.Order int Source order.
.Modules.WeatherStory.DownloadURL string Source download URL.

Collected And Derived Facts

The template also receives the full facts.CollectedFacts and facts.DerivedFacts structs:

  • .Collected contains normalized source data and provenance from upstream Weather API fetches.
  • .Derived contains shared slices and calculations used across modules, such as valid-period hourly periods, precipitation timing, alert overlaps, and SPC filtering inputs.

These values are intentionally lower-level than .Modules. Use them when a template needs a specific field that is not exposed by a module, but keep calculation-heavy changes in Go.

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 exercise the Daily, Today, Tomorrow, and Hourly templates through internal/generatedtext/render_context_test.go and internal/reporttemplate/reporttemplate_test.go.