plugins/claude-code-homeassistant-hermit/skills/ha-morning-brief/SKILL.md
Morning house brief — live status, overnight anomalies, energy snapshot, pending proposals, and today's priorities. Runs as a daily routine or on demand.
npx skillsauth add gtapps/claude-code-hermit ha-morning-briefInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
A house-focused morning brief that combines live HA state with hermit session context. Designed to run as the morning-brief routine at start of day.
When both claude-code-hermit and claude-code-homeassistant-hermit are installed and morning-brief is enabled, this skill subsumes /claude-code-hermit:brief --morning — operators should disable the core morning routine to avoid duplicate notifications. For hermits without HA, /claude-code-hermit:brief --morning remains the standalone path.
Time & context — Call GetDateTime for current time. Read .claude-code-hermit/OPERATOR.md for priorities and language preferences.
Fetch overnight history: Run ${CLAUDE_PLUGIN_ROOT}/bin/ha-agent-lab ha fetch-history --window-days 1. On non-zero exit, log a single line to SHELL.md ## Monitoring (history fetch failed: <stderr first line>) and skip the Overnight: section entirely — no fallback wording in the brief. On success, read .claude-code-hermit/raw/snapshot-ha-history-1d-latest.json.
Live house snapshot — Call GetLiveContext. Extract and organize:
Overnight highlights (only when 1d history artifact is present): read .claude-code-hermit/raw/snapshot-ha-normalized-latest.json for silence_summary.silent_event_sensors, then surface 1–3 highlights for the Overnight: section using only honest signals:
entity_aggregates[*].hour_histogram[0:7] for the highest sum across all entities. If any non-trivial activity (sum > 0), emit one line — e.g., "light.kitchen — 12 state changes between 00:00 and 06:00".silence_summary.silent_event_sensors, emit sensors still silent — e.g., "binary_sensor.motion_corridor — no events for 14 days".climate.* entity, read state_durations from the history artifact. If state_durations["heat"] or state_durations["cool"] ≥ 1800 seconds (30 min), emit one line — e.g., "climate.heat_pump — heated ~Xh overnight" where X is derived directly from state_durations. Never substitute event count for active hours.Energy snapshot — From the live context, pull current power draw and any energy sensors. Compare with known baselines from memory if available. Flag anything unusual (e.g., high overnight consumption).
Context freshness — Check .claude-code-hermit/raw/snapshot-ha-context-latest.json modification time. If older than 24h, note it as stale.
Overnight activity — Read .claude-code-hermit/sessions/SHELL.md. Scan both the Monitoring section and the Findings section (last 20 lines combined). In newborn-phase hermits (< 3 days old), pattern observations land in Findings as Noticed: <pattern> entries — include those. Surface any alerts or notable patterns found overnight.
Cost-spike check — Read .claude-code-hermit/state/reflection-state.json if it exists. Look for any cost_spike entry with a timestamp within the last 24 hours. If found, include a "Cost alert" bullet in the brief with the flagged amount.
8a. Pending updates: Run ${CLAUDE_PLUGIN_ROOT}/bin/ha-agent-lab ha updates --digest and capture stdout. Branch on its content (the command always exits 0 — never branch on exit code):
(skipped: — log a single line to SHELL.md ## Monitoring (updates fetch failed: <detail after "skipped:">) and omit the Updates: section entirely.(no updates pending) — omit the Updates: section entirely.Updates: section, translating tier labels into the operator's language. For each [tier] Title: installed → latest line (skip the + N more … collapse line and the [hacs] aggregate line), Glob .claude-code-hermit/proposals/PROP-*.md for a [ha-update] proposal whose title carries the same tier and target version (e.g. [ha-update] HA Core → 2026.7.1) and append (PROP-NNN); if none matches yet, render the line without an id. Step 9 reuses this glob result when this branch ran it.Glob .claude-code-hermit/proposals/PROP-*.md (reuse step 8a's glob result if its Otherwise branch already ran it; otherwise run the Glob here) — read status from each, list any pending proposals. Exclude a pending proposal whose title starts with [ha-update] only when the Updates: section is present (it surfaces there instead); when step 8a omitted the Updates: section (skipped fetch or no updates pending), keep [ha-update] proposals in this list so they are not lost.claude-code-hermit/sessions/NEXT-TASK.md exists (queued task).claude-code-hermit/cost-summary.md if it exists — include yesterday's cost9a. Micro-proposals lifecycle — age the queue in one call: .claude-code-hermit/bin/hermit-run proposal micro .claude-code-hermit brief-cycle. This runs core's writer through the project-resident bin/hermit-run, which resolves core's plugin root (a static ../claude-code-hermit/… path can't — HA's ${CLAUDE_PLUGIN_ROOT} is <cache>/<marketplace>/claude-code-homeassistant-hermit/<version>/ and the version segment isn't knowable from skill text). It performs the whole follow_up_count 0/1/2+ lifecycle atomically (re-nudges count-1 entries, expires count-2+ entries, records each expiry) and prints one JSON line {"new":[…],"renudged":[…],"expired":[…]}. Never hand-edit state/micro-proposals.json. Render from that verdict:
new entry: include in Awaiting decision: output (see Output Format).renudged entry: include in Awaiting decision: with softer framing: "Still waiting on MP-YYYYMMDD-N: [question] (ignore again to drop it)".expired entries were dropped this cycle — do not surface them.new and renudged are both empty: skip this step entirely.Compose brief — Write a concise morning brief in the operator's language (from OPERATOR.md preferences). Use the format below.
Write to compiled/ — Write the composed brief to .claude-code-hermit/compiled/brief-morning-<YYYY-MM-DD>.md with frontmatter:
title: "Morning Brief — <YYYY-MM-DD>"
type: brief
created: <ISO8601>
session: <session_id from runtime.json, or null if absent>
tags: [morning-brief, ha]
Then append the following line to .claude-code-hermit/sessions/SHELL.md under a ### Artifacts produced this session subsection in ## Monitoring (create the subsection if absent):
- [[compiled/brief-morning-<YYYY-MM-DD>]]
This citation is lifted into ## Artifacts when /claude-code-hermit:session-close archives the session.
Good morning! Home - [date]
Current state:
- [presence, lights, climate, covers - concise bullets]
Overnight:
- [top-active entity, stuck sensors, HVAC duration — omit section when history unavailable]
Energy:
- [current draw, notable consumption]
Alerts:
- [devices offline, unusual states, or "All clear"]
Updates:
- [tier] Title: installed → latest (PROP-NNN if a matching proposal exists)
- [N HACS updates pending]
- [Omit section entirely when none pending or the fetch was skipped.]
Pending:
- [proposals, queued tasks, or "Nothing pending"]
Awaiting decision:
- [`new` entry: "MP-YYYYMMDD-N (tier N): [question] — Reply `MP-YYYYMMDD-N yes` or `MP-YYYYMMDD-N no`"]
- [`renudged` entry: "Still waiting on MP-YYYYMMDD-N: [question] (ignore again to drop it)"]
- [Omit section entirely when the step-9a verdict's `new` and `renudged` are both empty.]
Cost:
- [yesterday's cost if available; cost-spike alert if flagged by reflect]
Today's priorities:
- [from OPERATOR.md Current Priority, filtered to actionable items]
Adapt the greeting and section headers to the operator's configured language. Keep the entire brief under 25 lines — strip lower-priority lines (e.g., Cost when no spike) if the Overnight section pushes over the cap. Awaiting decision: lines are final and non-droppable — strip from Energy, Cost, Today's priorities, and Updates (in that order) before touching MP lines.
config.always_on is true in .claude-code-hermit/config.json: deliver the composed brief via the Operator Notification protocol in CLAUDE.md (core resolves the channel and falls back to push / SHELL.md logging when no channel is reachable). The terminal is unmonitored in always-on mode — never gate delivery on session_state. For the push-fallback branch, condense to a single line (per § Operator Notification push format): lead with any overnight anomaly or open Awaiting decision: count, then energy/cost if flagged. Example: House OK overnight, 2 awaiting decision, 14kWh — open CC to view.tools
Composes and delivers the daily fitness brief — a forward-looking morning read (readiness + today's plan) or a backward-looking evening read (today's training, or an earned-rest note, + tomorrow's setup) — in the operator's configured voice. Invoke with /claude-code-fitness-hermit:fitness-brief --morning|--evening|--slot <name>. Becomes the plugin's two daily beats — the morning Strava connectivity check and the evening activity sync, RPE binding, and Run deep-dive.
development
Renew the hermit's long-lived Claude login token over the channel, before it expires. Relays a one-time sign-in link to the operator, takes the code back, installs the new token, and restarts. Activates on messages like 'relogin', 'renew my login', 'reauth', 'the login is expiring', or when doctor's credential-expiry check flags setup-token.
development
Synthesizes the past 7 days of archived briefs into a weekly digest — top stories, emerging vs faded themes, category activity, and per-source performance built from archive frontmatter. Delivers to the operator's configured channel and archives a weekly note. Designed as a weekly routine. Invoke with /feed-hermit:weekly-digest.
development
Manage developing story arcs tracked across briefs — add, resolve, and list active arcs in compiled/story-arcs-*.md. Arc Watch keywords drive the feed-brief arc-tagging enrichment. Invoke with /feed-hermit:story-arcs add|resolve|list.