@kody/morning-briefing
Composable daily briefing from calendar, weather, and optional inbox or home signals.
README.md
127 lines · 5.7 KB · Markdown@kody/morning-briefing
Composable daily briefing from calendar, weather, and optional inbox, health, or home signals. Delivered by email or a short notify-self message. No Discord.
Intent
Give any signed-in account one reliable morning update they can compose
themselves. Calendar and weather are the default sources. Inbox, health (air
quality), and home are optional and degrade to a skipped or warning section when
auth or data is missing. Success is a structured report plus a dryRun preview
that never sends mail until you choose an output channel and turn dry-run off.
This package is the generic official briefing. It does not post to Discord, and it does not ship Kent-specific Kit, YouTube, GitHub, Tesla, or apartment wiring.
What it does
- Build today's briefing from the sources you have connected
- Preview the email or notify payload with
dryRun: true - Read a stored report for a date without rebuilding every source
- Schedule a disabled-by-default 07:00 UTC job after you save config
Compose sources
Pass sources to choose what runs. Default is calendar and weather.
| Source | Default | What it reads | Auth |
|---|---|---|---|
calendar | yes | Today's events via @kody/google/calendar | Google OAuth (account, default personal → integration google) |
weather | yes | Daily forecast + current conditions via Open-Meteo | None. Pass location (city or place name) |
inbox | no | Unread Gmail via @kody/google/gmail | Google OAuth with Gmail read scopes (gmail.readonly) |
health | no | US AQI / PM2.5 via Open-Meteo Air Quality | None. Uses location (or health.location) |
home | no | Caller-supplied snapshot items | None in this package. Pass home.items, or skip until you have a home connector |
Sources run independently. A missing integration becomes a warning or skipped section; the rest of the briefing still builds.
Prerequisites / setup
Calendar (Google OAuth). Connect the saved google integration:
https://kody.codes/connect/oauth?provider=googlePass calendar.accounts using @kody/google aliases (personal, business,
…). Every Calendar call needs an explicit account. Widen Calendar scopes from
the connect UI when a mailbox has more than the primary calendar.
Weather and health (zero auth). Public Open-Meteo geocoding, forecast, and
air-quality APIs. Attribute Open-Meteo (CC BY 4.0)
when you reuse the data. Set location on the run or persist it in package
config for the scheduled job.
Inbox (Google OAuth with Gmail read). Gmail read scopes are restricted —
this package still exports the inbox source; do not hide it. Create a Google
Cloud OAuth Web application client, register redirect
https://kody.codes/connect/oauth, enable the Gmail API and Calendar API,
publish the app to Production (Testing refresh tokens expire after seven
days), then connect:
https://kody.codes/connect/oauth?provider=google&authorizeUrl=https%3A%2F%2Faccounts.google.com%2Fo%2Foauth2%2Fv2%2Fauth&tokenUrl=https%3A%2F%2Foauth2.googleapis.com%2Ftoken&flow=confidential&scopes=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fcalendar.readonly%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fgmail.readonly&allowedHosts=www.googleapis.com%2Cgmail.googleapis.com&extraAuthorizeParams=%7B%22access_type%22%3A%22offline%22%2C%22prompt%22%3A%22consent%22%7DUse the personal (or other) @kody/google account alias that matches that
connection. A 403 / insufficient-scope error names gmail.readonly and this
URL. See coding_guide_get({ guide: "provider_google" }).
Home. This official package does not call a personal home MCP or Discord.
Pass home.items from your own home package, or omit home from sources.
This composer does not need an API-key secret. There is no
/account/secrets/new step for calendar, weather, health, or email output.
Hosts
www.googleapis.com— Calendargmail.googleapis.com— inbox (BYO only)geocoding-api.open-meteo.com,api.open-meteo.com,air-quality-api.open-meteo.com— weather and health (public)
Scopes
- Calendar:
https://www.googleapis.com/auth/calendar.readonly(orcalendar.events.readonly) - Inbox:
https://www.googleapis.com/auth/gmail.readonly(restricted; BYO client)
If Google returns 403 / insufficient-scope, the package throws (or records a warning section) naming the missing scope and the next connect URL. It does not fail silently.
Agents: see AGENTS.md for import paths, smoke checks, and
delivery dry-runs.
Output: email or notify
output is email (default) or notify. Both use kody.emailSend to your
own account address.
email— full markdown briefingnotify— short subject + callout-only body
dryRun: true builds and stores the report, returns preview.subject /
preview.text, and does not send. The scheduled wrapper uses the same
implementation; keep the job disabled until a dry-run looks right.
Persist config for the job
The no-argument job daily-morning-briefing loads JSON from package storage
table config key briefing (same fields as the run input, minus dryRun).
Save it once, invoke ./run-morning-briefing with no params to prove the
scheduler contract, then enable the job.
Done when
- Weather-only
build-reportreturns sections without OAuth - Delivery dry-run returns
previewand does not send mail - Optional Google sources warn or skip when auth is missing instead of aborting the whole briefing
daily-morning-briefingstays disabled until config is saved and a dry-run looks right
Jobs
daily-morning-briefing runs ./run-morning-briefing daily at 07:00 UTC. It is
enabled: false. Enabling it is an operator choice after you save config
and confirm a dry-run.