diff --git a/docs/integrations/scriptorium.md b/docs/integrations/scriptorium.md new file mode 100644 index 0000000..e4f7416 --- /dev/null +++ b/docs/integrations/scriptorium.md @@ -0,0 +1,114 @@ +# weatherreporter Subprocess Integration + +## Purpose + +This document defines the supported subprocess contract for weatherreporter invoking Scriptorium through the public CLI. + +This is a CLI contract, not an internal Go package integration. + +## Supported Commands + +weatherreporter should invoke: + +- `scriptorium run` +- `scriptorium render` + +Use `run` for generation. + +Use `render` for preflight/debug output without LLM execution. + +## Recommended Invocation Shapes + +Run: + +```bash +scriptorium run \ + --prompt \ + --input data_package= \ + --out +``` + +Render: + +```bash +scriptorium render \ + --prompt \ + --input data_package= \ + --format json +``` + +weatherreporter may add: + +- `--config ` +- `--profile ` +- repeatable `--input name=path` +- repeatable `--var name=value` +- runtime overrides when explicitly needed (`--model`, `--llm-base-url`, `--timeout`, etc.) + +## Config And Directory Behavior + +weatherreporter can rely on resolved app config or pass explicit paths. + +- default config search order: + 1. `/usr/local/etc/scriptorium/config.yml` + 2. `/etc/scriptorium/config.yml` +- explicit `--config` requires file existence and valid syntax +- CLI flags override config values + +## Profile Selection + +Profile selection follows runner behavior: + +1. explicit `--profile` +2. prompt `default_profile` +3. error if neither is available + +weatherreporter should treat prompt/profile IDs as deployment configuration, not hardcoded logic. + +## Input And Variable Contract + +- Inputs use repeated `--input name=path`. +- Input names must match prompt definition input names. +- Variables use repeated `--var name=value` for small metadata values. +- Prefer file inputs for large content. + +## Environment Contract + +- Pass through required API-key environment variables referenced by `api_key_env`. +- Never pass raw API keys via CLI arguments. +- Keep subprocess environment scoped to required variables. + +## Output And Error Handling + +`run`: + +- stdout: artifact body unless `--out` is used +- `--out`: writes artifact to file +- stderr: success summary and errors + +`render`: + +- stdout: prepared-run output unless `--out` is used +- stderr: errors + +weatherreporter should capture stdout and stderr separately. + +## Exit Status Contract + +- `0`: success +- `1`: parse/config/load/render/generation/IO/runtime error +- `2`: run completed but validation failed + +A `run` exit code `2` can still produce output (stdout or `--out`). + +## Security Notes + +- Treat generated artifacts and stderr logs as potentially sensitive. +- Avoid logging full rendered prompts by default in production contexts. +- Use controlled output paths and access controls for persisted artifacts. + +## Canonical References + +- CLI behavior: [CLI reference](https://gitea.maximumdirect.net/eric/scriptorium/docs/cli.md) +- Config behavior: [Configuration reference](https://gitea.maximumdirect.net/eric/scriptorium/docs/config.md) +- Operations and failure handling: [Operations guide](https://gitea.maximumdirect.net/eric/scriptorium/docs/operations.md), [Troubleshooting](https://gitea.maximumdirect.net/eric/scriptorium/docs/troubleshooting.md) diff --git a/docs/integrations/weatherapi.md b/docs/integrations/weatherapi.md new file mode 100644 index 0000000..07f6f5b --- /dev/null +++ b/docs/integrations/weatherapi.md @@ -0,0 +1,354 @@ +# weatherapi External API + +This document describes the public HTTP API exposed by `weatherapi` for external consumers. + +## Base URL + +The service is typically served at your deployment host, for example: + +- `https://weather.api.rakestrawhome.com` + +All paths below are relative to the service root. + +## Common Conventions + +### Response envelope + +All endpoints return a top-level envelope: + +- `data`: endpoint payload or `null` when no current/latest resource is available. + +JSON example: + +```json +{ + "data": {"...": "..."} +} +``` + +### Output format + +Supported via `format` query parameter (case-insensitive): + +- `json` (default) +- `xml` +- `text` + +### Units + +Supported via `units` query parameter (case-insensitive): + +- `metric` (default) +- `us` + +Endpoints that include unit-based numeric fields return either metric or US field variants depending on this value. + +### Precision + +Supported where documented via `precision` query parameter: + +- integer range: `0` to `2` +- controls decimal rounding of numeric output fields + +### Timezone (`tz` / `TZ`) + +Supported where documented: + +- accepted values include: + - IANA timezone names (example: `America/Chicago`) + - common US abbreviations (example: `CDT`, `EST`) + - UTC offsets in `±H`, `±HH`, or `±HH:MM` (example: `-5`, `+09:30`) + - aliases including `Chicago` and `Stl` +- `tz` and `TZ` are treated equivalently +- if both are provided, they must match exactly or the request fails + +Timezone affects datetime rendering and day-slice filtering for `/today` and `/tomorrow` forecast routes. + +### Query validation + +- Unknown query parameters are rejected with `400 Bad Request`. +- Invalid parameter values are rejected with `400 Bad Request`. + +Error response body follows the service error envelope; exact fields may vary by error type. + +## Endpoints + +## `GET /observations` + +Returns the latest weather observation. + +Query parameters: + +- `units`: `metric` | `us` +- `format`: `json` | `xml` | `text` +- `precision`: `0..2` + +Response `data` fields: + +- `stationId` (string, optional) +- `stationName` (string, optional) +- `timestamp` (RFC3339 datetime, required) +- `conditionCode` (integer WMO code, required) +- `isDay` (boolean, optional) +- `textDescription` (string, optional) +- Metric mode fields: + - `temperatureC`, `dewpointC`, `windSpeedKmh`, `windGustKmh`, `barometricPressurePa`, `visibilityMeters`, `relativeHumidityPercent`, `apparentTemperatureC` (number, optional) + - `windDirectionDegrees` (number, optional) +- US mode fields: + - `temperatureF`, `dewpointF`, `windSpeedMph`, `windGustMph`, `barometricPressureInHg`, `visibilityMiles`, `relativeHumidityPercent`, `apparentTemperatureF` (number, optional) + - `windDirectionDegrees` (number, optional) +- `presentWeather` (array, optional) + +## `GET /alerts/active` + +Returns the latest active alert run. + +Query parameters: + +- `units`: `metric` | `us` (accepted; does not materially alter alert payload) +- `format`: `json` | `xml` | `text` + +Response `data` fields: + +- Weather alert run object from canonical model (includes run metadata and active alerts list). + +## `GET /conditions/current` + +Returns current conditions synthesized from latest observation/forecast data. + +Query parameters: + +- `units`: `metric` | `us` +- `format`: `json` | `xml` | `text` +- `precision`: `0..2` + +Response `data` fields: + +- Common: + - `conditionText` (string, optional) + - `isDay` (boolean, optional) + - `relativeHumidityPercent` (number, optional) + - `windDirectionDegrees` (number, optional) +- Metric mode: + - `temperatureC`, `apparentTemperatureC`, `dewpointC`, `windSpeedKmh` (number, optional) +- US mode: + - `temperatureF`, `apparentTemperatureF`, `dewpointF`, `windSpeedMph` (number, optional) + +## Forecast endpoints + +- `GET /forecast/hourly` +- `GET /forecast/hourly/today` +- `GET /forecast/hourly/tomorrow` +- `GET /forecast/narrative` +- `GET /forecast/narrative/today` +- `GET /forecast/narrative/tomorrow` + +Query parameters: + +- `units`: `metric` | `us` +- `format`: `json` | `xml` | `text` +- `precision`: `0..2` +- `tz` or `TZ`: timezone selector + +Day-slice routes: + +- `/today` returns periods with `period.startTime` in the current calendar day for the resolved timezone. +- `/tomorrow` returns periods with `period.startTime` in the next calendar day for the resolved timezone. + +Response `data` fields: + +- Run-level: + - `locationId` (string, optional) + - `locationName` (string, optional) + - `issuedAt` (RFC3339 datetime, required) + - `updatedAt` (RFC3339 datetime, optional) + - `product` (string, required; e.g. `hourly`, `narrative`) + - `latitude`, `longitude` (number, optional) + - Metric mode: `elevationMeters` (number, optional) + - US mode: `elevationFeet` (number, optional) + - `periods` (array, required) +- Period fields: + - `startTime`, `endTime` (RFC3339 datetime, required) + - `name` (string, optional) + - `isDay` (boolean, optional) + - `conditionCode` (integer WMO code, optional) + - `textDescription` (string, optional) + - Metric mode (optional): + - `temperatureC`, `temperatureCMin`, `temperatureCMax`, `dewpointC`, `windSpeedKmh`, `windGustKmh`, `barometricPressurePa`, `visibilityMeters`, `apparentTemperatureC`, `cloudCoverPercent`, `probabilityOfPrecipitationPercent`, `precipitationAmountMm`, `snowfallDepthMM`, `uvIndex`, `relativeHumidityPercent`, `windDirectionDegrees` + - US mode (optional): + - `temperatureF`, `temperatureFMin`, `temperatureFMax`, `dewpointF`, `windSpeedMph`, `windGustMph`, `barometricPressureInHg`, `visibilityMiles`, `apparentTemperatureF`, `cloudCoverPercent`, `probabilityOfPrecipitationPercent`, `precipitationAmountIn`, `snowfallDepthIn`, `uvIndex`, `relativeHumidityPercent`, `windDirectionDegrees` + +Notes: + +- Narrative periods may omit `conditionCode`. +- Text format uses forecast-specific templates (`hourly` and `narrative`). + +## Discussion endpoints + +- `GET /discussion` +- `GET /discussion/key-messages` +- `GET /discussion/short-term` +- `GET /discussion/long-term` + +Query parameters: + +- `units`: `metric` | `us` (accepted; does not materially alter discussion payload) +- `format`: `json` | `xml` | `text` +- `tz` or `TZ`: timezone selector + +Response `data` fields: + +- `/discussion`: + - `officeId` (string, optional) + - `officeName` (string, optional) + - `product` (string, required) + - `issuedAt` (RFC3339 datetime, required) + - `updatedAt` (RFC3339 datetime, optional) + - `keyMessages` (array of string) + - `shortTerm` (object, optional) + - `longTerm` (object, optional) +- `/discussion/key-messages`: + - `officeId`, `officeName`, `product`, `issuedAt`, `updatedAt` + - `keyMessages` (array of string) +- `/discussion/short-term`: + - `officeId`, `officeName`, `product`, `issuedAt`, `updatedAt` + - `shortTerm` (object, optional) +- `/discussion/long-term`: + - `officeId`, `officeName`, `product`, `issuedAt`, `updatedAt` + - `longTerm` (object, optional) + +Discussion section object fields: + +- `title` (string, optional) +- `narrative` (string, optional) +- `issuedAt` (RFC3339 datetime, optional) + +## Examples + +### Observation (JSON, metric) + +```http +GET /observations?format=json&units=metric&precision=1 +``` + +```json +{ + "data": { + "stationId": "KSTL", + "timestamp": "2026-05-29T14:00:00Z", + "conditionCode": 3, + "isDay": true, + "textDescription": "Partly cloudy", + "temperatureC": 24.4, + "windSpeedKmh": 17.2, + "relativeHumidityPercent": 56.0 + } +} +``` + +### Alerts (JSON) + +```http +GET /alerts/active?format=json +``` + +```json +{ + "data": { + "asOf": "2026-05-29T14:00:00Z", + "alerts": [] + } +} +``` + +### Current conditions (JSON, US) + +```http +GET /conditions/current?format=json&units=us&precision=1 +``` + +```json +{ + "data": { + "conditionText": "Partly cloudy", + "isDay": true, + "temperatureF": 75.9, + "apparentTemperatureF": 76.1, + "windSpeedMph": 10.7, + "relativeHumidityPercent": 56.0 + } +} +``` + +### Forecast narrative (JSON, optional `conditionCode`) + +```http +GET /forecast/narrative?format=json&units=metric&precision=1&tz=America/Chicago +``` + +```json +{ + "data": { + "locationId": "nws-lsx-grid-90-74", + "issuedAt": "2026-05-29T10:30:00-05:00", + "product": "narrative", + "periods": [ + { + "startTime": "2026-05-29T13:00:00-05:00", + "endTime": "2026-05-29T19:00:00-05:00", + "name": "Today", + "isDay": true, + "textDescription": "Partly sunny, with a high near 81.", + "temperatureC": 27.2, + "windSpeedKmh": 18.0, + "probabilityOfPrecipitationPercent": 10.0 + } + ] + } +} +``` + +### Forecast hourly today (text) + +```http +GET /forecast/hourly/today?format=text&units=us&precision=1&tz=CDT +``` + +```text + +``` + +### Discussion key messages (JSON) + +```http +GET /discussion/key-messages?format=json&tz=Chicago +``` + +```json +{ + "data": { + "officeId": "LSX", + "product": "discussion", + "issuedAt": "2026-05-29T09:25:00-05:00", + "keyMessages": [ + "Scattered showers possible this evening.", + "Warmer temperatures this weekend." + ] + } +} +``` + +### Invalid timezone error example + +```http +GET /forecast/narrative?tz=not-a-timezone +``` + +```json +{ + "error": { + "code": "invalid_parameter", + "message": "tz must be a valid timezone" + } +} +``` diff --git a/docs/roadmap/initial.md b/docs/roadmap/initial.md index 1b84a43..e0e80c6 100644 --- a/docs/roadmap/initial.md +++ b/docs/roadmap/initial.md @@ -115,6 +115,11 @@ Implement configuration loading and a stable command shape before integrating ex Fetch normalized weather data from the internal weather API and represent it as a stable forecast bundle inside the application. +### Key References + +- `docs/integrations/weatherapi.md` describes the weatherapi public API +- The local API endpoint is available at `https://weather.api.rakestrawhome.com/` and will return live data + ### Packages Introduced or Expanded - `internal/adapters/weatherapi` @@ -126,11 +131,11 @@ Fetch normalized weather data from the internal weather API and represent it as 1. Define the internal `forecast.Bundle` type. 2. Define source substructures for: - Hourly forecast data. - - Daily forecast data. + - Daily forecast data (NOTE: not yet implemented upstream in weatherapi, so this can remain a stub in the initial implementation). - NWS narrative forecast periods. - NWS alerts. - NWS forecast discussion. - - NWS weather story. + - NWS weather story (NOTE: not yet implemented upstream in weatherapi, so this can remain a stub in the initial implementation). 3. Implement the weather API client. 4. Add context-aware HTTP calls and timeouts. 5. Add actionable errors for failed API calls and decode failures. @@ -174,7 +179,7 @@ Implement deterministic forecast processing needed by the Daily Report. 4. Compute daypart summaries: - Temperature range. - Apparent-temperature range, if available. - - Max precipitation probability. + - Max precipitation probability and associated hour. - Peak wind speed. - Peak wind gust. - Dominant or notable conditions. @@ -357,6 +362,9 @@ Convert a briefing package into the structured variable payload expected by `scr Invoke `scriptorium` as a subprocess and produce the first rendered Markdown report. +### Key References + - `docs/integrations/scriptorium.md` describes the CLI contract for running `scriptorium` as a subprocess. + ### Packages Introduced or Expanded - `internal/adapters/scriptorium`