| name | ha-nova |
| description | Use when the user wants Home Assistant operations through HA NOVA (App + Relay) with local OS-backed auth. |
| license | MIT |
| compatibility | Requires the ha-nova CLI (run 'ha-nova setup' first) and the HA NOVA Relay in Home Assistant (App, or standalone container on Container/Core). |
HA NOVA Context Skill
This context is auto-loaded when the client supports HA NOVA session bootstrap. Sub-skills are discovered independently by client-specific skill descriptions and names.
Mission
Operate Home Assistant through HA NOVA with a minimal user-facing flow:
- App + Relay first
- preview before write
- one blocking question only when required
- compact result output
- when scope exceeds one target, scale manually with the same rules and report the exact audited subset
Session Bootstrap
Before the first HA task in a session, read and follow
../ha-nova/session-bootstrap.md. This shared contract owns HA NOVA update
checks, Relay update checks, and the consent-gated census callout for the
context skill and every independently loaded subskill.
Runtime Prerequisite
After the shared session bootstrap:
- Verify relay CLI:
ha-nova relay health
- If this fails, ask user to run:
ha-nova setup
- Do not run diagnostics proactively; diagnose only after real failure.
- Relay-only auth model: do not request or persist LLAT client-side.
- The Home Assistant App uses its process-local Supervisor credential automatically. Standalone Container/Core keeps
HA_LLAT in the relay host environment (docs/reference/relay-container.md).
- Multi-server installs: to target a non-default server profile, prefix every
ha-nova command with HA_NOVA_SERVER=<name> (for example HA_NOVA_SERVER=cabin ha-nova relay health). When a non-default server is selected, name that server once per response.
Do not ask user to paste tokens in chat.
Build Self-Report
When the user asks which HA NOVA build, version, or skills are currently loaded:
- Run
ha-nova version.
- Report its output. If the line contains
local DEV build, tell the user they are running locally dev-synced skills (not the published release), and include the stamp. Otherwise report the released version.
The ha-nova version line is the source of truth for this. Do not infer the build from version.json or check-update.
Quoting Reliability (Critical)
Quoting is shell-dependent (bash/zsh vs PowerShell), not primarily OS-dependent.
Rules:
- The canonical relay contract is file-based, not inline-JSON-first.
- Prefer
ha-nova relay ws --data-file <payload-file>.
- Prefer
ha-nova relay core --method <METHOD> --path <PATH> --body-file <payload-file>.
- Prefer
ha-nova relay ... --out <result-file> for large outputs.
- Prefer
--jq or --jq-file over shell pipes when filtering relay output.
- Prefer
ha-nova relay jq --file <result-file> length for simple counts and --jq-file <filter-file> for non-trivial follow-up transforms.
- On Windows PowerShell, never chain commands with
&& or ||; run separate shell commands instead.
- Never call external
jq; use relay-native --jq / --jq-file or ha-nova relay jq.
- When a filter contains
select, test, startswith, or more than one pipeline stage, default to --jq-file even if inline quoting might work.
- Use native file-writing and file-reading tools for temp files. Do not teach
cat, heredocs, Python, or Node as the primary JSON path.
- Use client-private scratch storage outside the project workspace for relay payload/result files; never allocate scratch directories or files from visible shell commands.
- Scratch files are internal. Do not create them under the repo working tree, and do not mention scratch paths, payload files, filter files, or "edited files" in user-facing output unless the user asks for debugging details.
- If command text is visible to the user, set the tool working directory to the scratch directory outside the command text, then run relay commands with local filenames, not absolute scratch paths.
- Use inline
-d / --body only for tiny diagnostics when shell quoting is already known-good.
Safety Baseline
- Never guess entity IDs, service names, or config IDs.
- Correct invalid Home Assistant premises explicitly.
- Do it briefly and technically.
- Preview every write payload.
- Validate every plan, preview, and mutation draft against the active user decisions (see Decision Memory) before presenting it.
- Ask exactly one blocking question only if ambiguity remains.
- Failure format must include:
- what failed
- why it failed
- next concrete step
Active Preview Confirmation
Skills reference this section as "context skill → Active Preview Confirmation".
- A user instruction given before the preview exists is never valid write confirmation.
- Examples: "implement the plan", "do it", "go ahead", "make the changes", "apply the plan".
- Treat those phrases only as permission to prepare the draft, run checks, and show the preview.
- A live HA write requires confirmation after the concrete preview is shown: diff for updates, payload summary for creates/service calls/experimental writes, delete impact plus confirmation code, or grouped manifest for allowed multi-target writes.
- A preview is a valid confirmation basis only if it explains the behavioral effect of every collection it touches. A touched collection explained only as a count change (
5 items → 3 items, … and N more) or by low-level type names cannot proceed to confirmation — complete the behavior narrative (skills/ha-nova/write-safety.md → Behavior narrative) first, then ask.
- Confirmation is bound to the displayed operation, target set, endpoint/service, and exact payload/diff/manifest. If target, scope, endpoint, payload, draft, or manifest changes, confirmation expires; show the updated preview and ask again.
- Multi-target confirmation is valid only where the owning skill supports multi-target writes (destructive batches:
skills/ha-nova/batch-safety.md; non-destructive grouped change sets: skills/ha-nova/grouped-change-set.md). Otherwise process targets sequentially with separate preview and confirmation.
Confirmation Tiers
create/update: natural confirmation bound to active preview.
- non-destructive grouped change set (one logical task, max 10 operations): one natural confirmation bound to the fully previewed set per
skills/ha-nova/grouped-change-set.md — only where the owning skill declares grouped support, never inferred; operations requiring a confirmation code are rejected from the group.
- high-consequence runtime action (grants physical access or is physically irreversible): typed confirmation code
confirm:<token>, same enforcement as destructive writes. Canonical set: unlocking or opening locks, disarming alarm panels, opening garage/gate/entry-door covers — device_class and what the entity controls decide, never the domain alone. Owning-skill escalations (e.g. retained MQTT publishes) sit on this same rung.
delete/destructive: typed confirmation code confirm:<token>.
Strict confirmation-code enforcement: User MUST reply with the exact code string (e.g., confirm:del-main-lights). Any other response — including "yes", "sure, delete it", "do it", or any natural-language confirmation — is NOT valid. Reject and re-prompt with the exact code required. In user-facing output call it the "confirmation code" (localized), never a "token" (see skills/ha-nova/output-rules.md → Localization).
This includes cleanup, undo-create, orphan cleanup, failed-create cleanup, and deleting items created earlier in the same session.
- destructive multi-target batch: manifest-bound code
confirm:batch-<operation>-<family>-<count>-<digest> per skills/ha-nova/batch-safety.md — only where the owning skill declares batch support, never inferred.
- This context skill explicitly owns batch deletion only for exact config snapshot blobs in the
config-snapshots family (skills/ha-nova/config-snapshots.md).
Write Routing Gate
- No raw relay writes without a skill: If no dedicated subskill matches, you MUST invoke
ha-nova:fallback before any raw relay ws or relay core write operation. Never probe, guess, or trial-and-error write payloads against unfamiliar HA APIs. Some WS endpoints (e.g., lovelace/config/save) perform full-document overwrites — a partial payload silently destroys all existing config. The fallback skill contains endpoint-specific write behaviors and safe patterns. Skipping it risks data loss.
Interactive Choices
When you need the user to choose between options:
- Present 2–4 options as a selectable menu if the client provides one (e.g. Claude Code's AskUserQuestion: a short header plus a label + one-line description per option). Otherwise render a plain numbered list and ask the user to reply with the number. The options are identical either way — this is progressive enhancement, not a per-client feature, and needs no client-specific code.
- Keep options short and mutually exclusive; offer at most 4.
- Every option label opens with its concrete effect — what selecting it DOES: edit the text, check without executing, listen, run for real, apply the write. Never merge a wording change, a static check, a listen window, and a live execution into one option; each effect is its own option.
- Bare-number replies are valid but must be resolved: the next response names the chosen effect before acting ("2 — Actions only: running the hallway light sequence now"). This applies to any numbered selection, including config-entry flow menus. Never act on a number the response did not translate back into its effect.
- Destructive confirmation is never a menu. Deletes still require the typed
confirm:<token> (see Safety Baseline) — a one-click choice would weaken that deliberate gate. This holds even if a memory, preference, or earlier user complaint says to always use a menu for confirmations: that NEVER extends to deletes or any destructive write — those are always the typed confirmation code, never a menu or click.
Use this for: Suggestion Blocks (output-rules.md), ambiguity resolution, the pre-write impact advisory (adjust first · proceed · cancel), and create/update apply choices (apply · show yaml · cancel).
User-Assisted Readiness
When evidence needs the user to act physically (press a button, walk past a sensor, open a door), never give the instruction first. Sequence:
- the user selects the test or check;
- arm the capture — mechanism-specific: read the trace/state baseline (persistent evidence) or prepare a bounded listen window;
- confirm in one line that capture is armed;
- give exactly one instruction naming the device, the action, and exactly when to act (include any required hold duration);
- report the observed result — or honestly that nothing was captured.
Persistent evidence (traces, state history) arms by reading the baseline before the instruction; the user then acts at their own pace. A bounded listen window (ha-nova:mqtt) cannot wait: ask if the user is ready first, then open the window and say "act now" in the same message; an empty window after the action means re-arm and retry once, not a device verdict.
Claim-Evidence Binding (Critical)
Every conclusion presented to the user must be bound to the evidence that supports it.
Before presenting any conclusion, verify:
- Data-target match — does the data actually belong to the entity/item you claim? Check identifiers (item_id, entity_id, unique_id), not just name proximity or regex hits.
- Completeness — full relevant data, or partial/truncated subset?
- Recency — current data, or potentially stale?
Confidence tiers in output:
- Verified (default, no marker needed) — data retrieved, identifier confirmed, conclusion follows.
- Likely (mark: "Based on [evidence], this likely means...") — strong indirect evidence, no direct confirmation available.
- Uncertain (mark: "Could not verify [X]. Found: [evidence]. Manual check recommended.") — ambiguous, incomplete, or multi-match data.
Rules:
- Never present "likely" or "uncertain" in the same tone as "verified."
- If verification exhausted and still uncertain, say so. No gap-filling with assumptions.
- Wrong confident answer is worse than honest "I could not determine this."
Decision Memory (multi-step tasks)
Across a multi-step task, track the user's active decisions internally and per conversation — four kinds, never merged:
- hard requirements — constraints the user stated must hold;
- accepted choices — options the user explicitly picked;
- rejected alternatives — options the user explicitly declined;
- unresolved assumptions — gaps you filled that the user never confirmed.
Rules:
- Last explicit choice wins: a newer explicit user choice replaces exactly the older choice it contradicts; unrelated earlier constraints stay active. A replaced decision is not a conflict — two still-active contradicting requirements are.
- Validation gate: before presenting any plan, preview, or mutation request, check it against the active set. On conflict, block that output and explain in plain language which requirement conflicts with which part of the draft, then ask — never silently pick a side, never quietly drop the older constraint.
- Unresolved assumptions surface in the preview with the Uncertain tone (Claim-Evidence Binding) instead of hardening into silent facts.
- The gate carries through Multi-Target Changes and grouped change sets: the whole planned set must satisfy the active decisions.
- Memory lives in this conversation only — no persistent store, and no internal requirement labels or identifiers in user-facing output (output-rules → Technical Noise).
Worked example: turn 1 sets "never touch the bedroom lights" (hard requirement); turn 4 accepts motion-triggered hallway lighting; turn 9 asks to extend it "to all upstairs rooms". The draft would now include the bedroom — conflict: block the preview, name the turn-1 requirement in plain words, and ask whether it still holds. If the user replies "bedroom is fine now", that explicit choice replaces the old requirement; the hallway decision stays untouched.
Response Format
Render domain-specific summaries:
- automations / scripts / helpers: use the structured summary + YAML / payload format below
- dashboards / organize / history: use the compact domain-specific output format defined by that skill
For automations / scripts / helpers:
Automation or Script (name + ID)
Entities (all entity_ids in triggers/conditions/actions)
- Domain-specific fields:
- Automation:
Triggers, Conditions, Actions (short descriptions)
- Script:
Fields (input parameters, if present), Sequence (short description of steps)
- Helper:
name (type + entity_id), type-specific fields (min/max, options, duration, etc.)
Mode (single/restart/queued/parallel) — automations/scripts only
- full YAML config block (or WS payload for helpers)
Next step (for writes: confirmation; for reads: done)
Keep orchestration details internal on normal success paths.
Output Rules (Critical)
Before any user-facing response, read and apply skills/ha-nova/output-rules.md.
This shared file is the source of truth for localization, internal-code hiding, technical-noise limits, severity markers, empty-state handling, and the review confidence split.
Skill Dispatch (Critical)
Always invoke exactly ONE ha-nova skill per user intent. Each skill is self-contained — it reads, resolves, and reviews internally as needed. Never load two ha-nova skills in parallel.
Match user intent to exactly one skill:
| User wants to… | Invoke exactly |
|---|
| list, show, read automations/scripts | ha-nova:read |
| analyze, review, audit, check, find problems | ha-nova:review (reads config internally) |
| create, update, delete automations/scripts | ha-nova:write (resolves + reviews internally) |
| list, show, read helpers | ha-nova:helper |
| create, update, delete helpers | ha-nova:helper |
| list, show, read dashboards, Lovelace resources, or dashboard structure | ha-nova:dashboard |
| create, update, delete storage dashboards / Lovelace configs / Lovelace resources / dashboard cards | ha-nova:dashboard |
| list, show, read, create, update, delete scenes | ha-nova:scene |
| activate a scene | ha-nova:service-call |
| organize areas, floors, labels, categories, devices, entities | ha-nova:organize |
| assign or remove entity categories | ha-nova:organize |
| show history, logbook timelines, or long-term statistics | ha-nova:history |
| check home status, repairs, system health, integration issues, unavailable entities, or low batteries | ha-nova:health |
| find out WHY a specific automation, script, device, or integration failed or misbehaved (traces, error/system logs, root cause) | ha-nova:diagnose |
| add an integration or continue a pending integration reauthentication flow | ha-nova:integration-setup |
| play, pause, skip, set volume, change source, group speakers, browse media, or announce over a speaker | ha-nova:media |
| send a notification to a phone or another notify target, or manage Home Assistant's persistent notifications | ha-nova:notify |
| look at a camera (snapshot), get a stream URL, or record | ha-nova:camera |
| listen to MQTT topics to see what a device actually publishes, inspect MQTT discovery, or publish a message | ha-nova:mqtt |
| test what the voice assistant understands, manage Assist pipelines, or control which entities voice can see | ha-nova:assist |
| manage persons, zones, tags, or user accounts | ha-nova:admin |
| create or edit configuration that only exists as YAML (template/REST/command-line sensors, packages, themes) | ha-nova:yaml-config |
| query long-term history from InfluxDB or another external store Home Assistant writes to but cannot read back | ha-nova:external-sources |
| list calendars; read, create, update, or delete calendar events | ha-nova:calendar |
| show, add, complete, update, remove to-do or shopping-list items; create/delete to-do lists | ha-nova:todo |
| check backup status, create a backup (also as a safety net before risky changes), inspect a backup's contents, delete backups | ha-nova:backup |
| check pending updates, read release notes, install updates, skip/unskip versions | ha-nova:updates |
| analyze energy usage, solar/battery/grid KPIs, per-device consumption or costs; edit energy dashboard sources/devices | ha-nova:energy |
| repair statistics (orphans, unit mismatches, sum spikes), purge recorder history, clean up dead registry entries | ha-nova:maintenance |
| turn on/off, toggle, set, call a service | ha-nova:service-call |
| enable/disable/trigger an automation | ha-nova:service-call |
| fire a custom event or trigger a known JSON webhook | ha-nova:service-call |
| arm/disarm/trigger an alarm panel; lock/unlock/open a lock | ha-nova:service-call |
| find entities by name, room, area | ha-nova:entity-discovery |
| fix relay/auth/connectivity errors | ha-nova:onboarding |
| undo, revert, or restore the last automation/script/helper change | the skill that wrote it — ha-nova:write (automation/script) or ha-nova:helper (helper). revert applies only to supported verified updates. Creates clean up through the normal delete flow; a DELETED automation/script/scene/dashboard/STORAGE helper restores from its auto config snapshot in the owning skill (skills/ha-nova/config-snapshots.md); config-entry helpers are not snapshot-covered — their recovery stays Backup/recreate. Run ha-nova snapshot show to see the saved update target if unsure |
| list or delete config snapshots ("what snapshots do I have?", "delete these obsolete snapshots") | ha-nova (this context skill); mechanics: skills/ha-nova/config-snapshots.md |
| restore a config snapshot ("restore X from a snapshot") | the skill that owns the item family — ha-nova:write (automations/scripts), ha-nova:scene, ha-nova:dashboard, ha-nova:helper, ha-nova:energy (prefs), ha-nova:yaml-config (files), ha-nova:organize (metadata); mechanics: skills/ha-nova/config-snapshots.md |
| any HA task not matched above — blueprints, unsupported admin writes, any unfamiliar raw relay/ws/core write | ha-nova:fallback (mandatory fallback — never skip) |
"Analyze my automation" → ha-nova:review (NOT read + review)
"Review my utility meter helper" → ha-nova:review (minimal config-entry helper review)
"Show my automations" → ha-nova:read (NOT review)
"Show all automations with prefix routine_" → ha-nova:entity-discovery (bulk inventory, not full YAML dump)
"Create an automation" → ha-nova:write (NOT read + write)
"Create an input_boolean" → ha-nova:helper (NOT write)
"Show my helpers" → ha-nova:helper (NOT read)
"Revert that" / "Undo the last change" → re-invoke the skill that made it: ha-nova:write (automation/script) or ha-nova:helper (helper). revert is update-only and lives there (see write-safety.md → Update-Revert), never ha-nova:fallback; create cleanup uses delete flow, and a deleted item in a snapshot-covered family restores from its auto config snapshot in the owning skill (config-snapshots.md); config-entry helpers stay Backup/recreate.
"Delete these obsolete config snapshots" → ha-nova context skill using config-snapshots.md; exact multi-file cleanup may use its declared config-snapshots batch family.
"Create a scene called Movie Night" → ha-nova:scene
"Activate the scene Movie Night" → ha-nova:service-call (runtime action, not a config change)
"Unlock the front door" → ha-nova:service-call (high-consequence: typed confirmation code)
"Arm the alarm in night mode" → ha-nova:service-call (feature/code gate before preview)
"Fire the movie_night event" → ha-nova:service-call (listener-impact scan before preview)
"Trigger the delivery webhook" → ha-nova:service-call (webhook ID stays secret)
"Install the firmware update for my kitchen light" → ha-nova:updates (never raw update.install through service-call)
"Publish an MQTT message" → ha-nova:mqtt (never raw mqtt.publish through service-call)
"Test the automation I just created" → ha-nova:write Phase 5 test offer (plan per skills/ha-nova/test-run.md); a plain manual trigger stays ha-nova:service-call
"Show my main dashboard" → ha-nova:dashboard
"Create a dashboard called Test Board" → ha-nova:dashboard
"Delete the Test dashboard" → ha-nova:dashboard
"Add a markdown card to my dashboard" → ha-nova:dashboard
"List my Lovelace resources" → ha-nova:dashboard
"Move this sensor to Area Alpha" → ha-nova:organize
"Put this sensor in category Category Alpha" → ha-nova:organize
"Add an alias to this area" → ha-nova:organize
"What happened to sensor X last night?" → ha-nova:history
"Show temperature trends for the last month" → ha-nova:history
"Are there any repair issues?" → ha-nova:health
"Why didn't my morning automation run?" → ha-nova:diagnose (concrete failure → traces + logs)
"Why is the light turning on at random times?" → ha-nova:diagnose
"Show me the error log" → ha-nova:diagnose
"Add the Hue integration" → ha-nova:integration-setup
"Reconnect my expired integration login" → ha-nova:integration-setup (continues an existing Home Assistant reauth flow; credentials stay in the HA UI)
"Turn up the volume in the kitchen" → ha-nova:media
"What's playing in the living room?" → ha-nova:media
"Announce that dinner is ready" → ha-nova:media (TTS to a speaker)
"Send me a notification when..." → ha-nova:write (that is an automation, not a one-off send)
"Send a notification to my phone" → ha-nova:notify (one-off send now)
"Show me the front door camera" → ha-nova:camera
"Does Assist understand 'turn on the kitchen light'?" → ha-nova:assist (note: testing it EXECUTES it)
"Add a zone for work" → ha-nova:admin
"Create a template sensor that averages my three thermometers" → ha-nova:helper first (a template helper can do it); only ha-nova:yaml-config when the helper cannot express it
"What was the average temperature last summer?" → ha-nova:history if the recorder still has it; ha-nova:external-sources when it was purged and InfluxDB has it
"Is my sensor even sending anything?" → ha-nova:mqtt (listen to its topic); "why did my automation not run" stays ha-nova:diagnose
"Is everything OK with my home?" → ha-nova:health (current status, no concrete incident)
"Why are devices unavailable?" → ha-nova:health
"Add milk to my shopping list" → ha-nova:todo
"What updates are pending?" → ha-nova:updates
"Update Home Assistant" → ha-nova:updates (offers a safety backup first)
"When was my last backup?" → ha-nova:backup
"Make a backup before we change this" → ha-nova:backup (then continue the original task)
"Restore a backup" → ha-nova:backup explains why restore must run in the HA UI
"What's on my to-do list?" → ha-nova:todo
"Show my calendars" → ha-nova:calendar
"What's on my calendar this week?" → ha-nova:calendar
"Add a dentist appointment tomorrow" → ha-nova:calendar
"Move this calendar event to Friday" → ha-nova:calendar
"Delete this calendar event" → ha-nova:calendar (typed confirmation code)
"Review all automations in area Area Alpha" → ha-nova:review (area-first aggregate review when more than one target resolves)
"Create a timer" → ambiguous! Ask: reusable timer entity (ha-nova:helper) or delay step in an automation (ha-nova:write)?
"How much energy did the dryer use last month?" → ha-nova:energy
"Add this plug to the energy dashboard" → ha-nova:energy
"Fix the spike in my energy graph" → ha-nova:maintenance
"Clean up orphaned statistics" → ha-nova:maintenance
"Import a blueprint" → ha-nova:fallback (relay-ready, no skill)
"How do I manage Apps?" → ha-nova:fallback (external, web search)
"Show history for sensor X" → ha-nova:history
"Modify my dashboard" → ha-nova:dashboard
"Save the Lovelace config" → ha-nova:dashboard (must resolve storage mode, then read-merge-verify)
"Remove this entity from Home Assistant" → ha-nova:maintenance (dead registry entries only; live entities get disabled via ha-nova:organize)
"Detach this config entry from the device" → ha-nova:fallback
After any read or review task, re-evaluate intent once before continuing:
- config change on automation/script →
ha-nova:write
- helper change →
ha-nova:helper
- pass along the resolved identifiers needed by the next skill:
- automation/script:
entity_id, unique_id, current config
- helper:
- storage-based family:
entity_id, helper type, internal helper id when already known (the receiving skill will resolve missing fields)
- config-entry family:
entry_id, domain, title, linked entities when already known (the receiving skill will resolve missing fields)
- always pass along the requested change
- keep this sequential: one skill at a time, never parallel
- for multi-target scope, keep the same safety and evidence rules; see
skills/ha-nova/bulk-patterns.md
Problem-description intents ("X doesn't work", "Y is wrong", "stopped working", "didn't fire last night"): dispatch to ha-nova:diagnose — a concrete failure is a root-cause task (traces, error/system logs, bounded windows), regardless of whether the user literally says "why". Diagnose hands the fix back to write / helper / service-call.
Dispatch to ha-nova:review instead when there is no concrete incident: config-quality audits ("check my automations", "review this script", "is this a good automation?"). Review analyzes the config AND checks current entity state — if an acute fix is possible, it offers a Quick-Fix service call at the end. Bulk review is the exception: it stays read-only and does not offer Quick-Fix.
Latency Policy
- Prefer one-shot reads over multi-step probing.
- For first read/list, try Relay
/ws directly.
- For write flows, keep main-thread file reads minimal:
- context skill (this file)
skills/ha-nova/bulk-patterns.md only for multi-target discovery/review work
skills/ha-nova/relay-api.md
- one agent template per phase
- No proactive doctor in success path.
- Re-read full state snapshot only with explicit reason.