Install
$ agentstack add skill-markusleben-ha-nova-review ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ● Network access Used
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
HA NOVA Review
Scope
Read-only quality review for automations, scripts, and helpers:
- Config quality checks (safety, reliability, performance, style)
- Collision scan (other automations targeting same entities)
- Conflict analysis (real conflicts vs safe patterns)
- Explorative questions for complex automation/script behavior
- Suggestion synthesis that separates open questions from confident recommendations
- Quick-Fix: if an acute state problem is detected, offer a single corrective service call
- Bulk review: aggregate the same checks across a deterministic multi-target workset
Read-only analysis. Exception: after explicit user confirmation, one Quick-Fix service call may be executed to correct an acute state problem detected during review.
- No
POST,PUT,PATCH, orDELETEconfig writes through the relay. - If the user wants to change an automation or script, hand off to
ha-nova:write. - If the user wants to change a helper, hand off to
ha-nova:helper. - The Quick-Fix service call in Step 4 is the only write exception in this skill.
- Bulk review is stricter: no Quick-Fix, no service calls, no write exception.
Bootstrap
Relay CLI: ha-nova relay
- Preflight:
ha-nova relay health(once per session, skip if already verified) relay ws --data-file— canonical WebSocket pathrelay core --method --path --body-file— canonical REST pathrelay ... --jq-file— canonical complex filter pathrelay ... --out— canonical large-output path
Target Resolution
If user provides an exact automation/script entity_id (e.g., automation.main_lights), skip search and go directly to config read.
For helpers, resolve the family first:
- storage-based family: entity_id domain is one of
input_boolean,input_number,input_text,input_select,input_datetime,input_button,counter,timer,schedule - supported config-entry family: domain is one of
utility_meter,derivative,integration,min_max,threshold,tod,statistics,group,history_stats - config-entry helper review remains minimal, but target resolution must still normalize to a real
entry_id
If the target config is not already in the thread context, resolve it yourself:
- If the user asks for a bulk audit by
prefix,domain,area, orlabel, build a shortlist first usingskills/ha-nova/bulk-patterns.md.
- use
config/entity_registry/list_for_displayfor directprefix/domainresolution - escalate to
config/entity_registry/listandconfig/area_registry/listonly when richer area/label evidence is required - for room/area phrasing, resolve the area and use
search/relatedwithitem_type:"area"before any registry-first fallback - treat area-related results as a keyed object (
automation,script,entity,device, ...), not as a flat array - use the canonical area projection by target family:
- automation review ->
.data.automation - script review ->
.data.script - helper-in-area is not a first-class bulk selector contract
.data.entityis only a fallback seed for automation/script derivation when the target-family arrays are absent- use direct registry
area_idonly as supplemental evidence when it is actually populated - dedupe the shortlist on canonical
entity_id, then sort deterministically and persist the matched shortlist - derive the current review set before any per-item reads:
- exact single target -> current review set = that one target
- more than one resolved target -> current review set = the resolved targets in deterministic order, trimmed to the first 5 only when more than 5 targets match
- carry the exact matched count plus current review-set size into Bulk Mode Gate
- do not resolve unique_ids, read configs, read states, or run collision scans for matched-but-non-audited remainder targets outside the current review set
- a narrow collision explanation may inspect one extra target outside the matched remainder when needed to classify a cluster; keep that read explicit, read-only, outside the audited-item count, and clearly marked as related/collision evidence in the transcript
- prefer explicit command/file naming such as
related-config; if the marker must live in command transcript output, emit a line likeCOLLISION_EVIDENCE= - never build a full matched-set config cache or evidence snapshot; if caching helps, cache only the current review set
- once the shortlist or workset is saved, keep that file immutable; use dedicated filenames for later registry, config, and collision outputs
- if the user intentionally requested a bulk selector, do not ask a clarifying question just because multiple matches remain
- Search by name using entity registry (compact fields:
ei=entity_id,en=name/alias):
Skip this step when step 1 already produced a resolved current review set. Create ` with {"type":"config/entityregistry/listfordisplay"}. Then run: `text ha-nova relay ws --data-file --jq-file ` Write with: `jq .data.entities[] | select(.ei | startswith("automation.")) | "\(.ei) | \(.en // "unnamed")" ` Filter the resulting text with the client's native search/filter tool, not shell-specific pipelines. For scripts: select(.ei | startswith("script.")). For helpers: (.ei | split(".")[0]) as $domain | select(["inputboolean","inputnumber","inputtext","inputselect","inputdatetime","input_button","counter","timer","schedule"] | index($domain))`.
- If the helper might be from the config-entry family, also read:
``text ha-nova relay ws --data-file --out ha-nova relay ws --data-file --out `` with:
{"type":"config_entries/get"}{"type":"config/entity_registry/list"}
Resolve the target by one of:
- exact
entry_id - config-entry
titlewithin the supported helper domains - linked
entity_idby matching entity-registryconfig_entry_id
Build the canonical metadata item:
entry_iddomaintitlestatelinked_entities[]
- If multiple matches remain outside an intentional bulk-selector flow: present top candidates (max 5) and ask one clarifying question. Never guess.
- For automation/script targets, resolve
unique_id(config key) — the entity_id slug and config key differ for UI-created items (seerelay-api.md→ ID Types):
Create ` with the final config/entityregistry/get request in one write step, then run: `text ha-nova relay ws --data-file --out ha-nova relay jq -r --file '.data.unique_id' ` The jq filter quoting above is a POSIX example. On Windows/PowerShell pass the same filter with native argument quoting. Use that saved-result + -r form for the scalar. Do not create a separate jq file for .data.uniqueid, do not strip quotes with shell substitutions afterward, and do not write placeholder payload templates that are rewritten later with perl -0pi, sed -i, or similar commands. For scripts: use "entityid":"script.". Skip this step for config-entry helpers — entryid` is already the canonical identity.
- Read the target:
``text # Automation: ha-nova relay core --method GET --path /api/config/automation/config/ --jq-file --out # Script: ha-nova relay core --method GET --path /api/config/script/config/ --jq-file --out # Helper (storage-based family, WS list + filter): ha-nova relay ws --data-file --jq-file --out ` Preferred: copy skills/ha-nova/config-body-filter.jq to and use that copied file directly. If you must recreate it, write with: `jq if .ok then .data.body else error("relay error: \(.error.message // "unknown")") end ` When writing this jq file, paste that jq program body exactly as shown. Do not add extra shell-escape backslashes around the jq interpolation or run a probe variant first. POSIX shell example only: `sh cat "$config_filter_file" if .ok then .data.body else error("relay error: \(.error.message // "unknown")") end EOF ` On Windows/PowerShell, use the native file-writing equivalent or copy the canonical file while preserving the exact jq file body. The jq file body must contain exactly that one jq expression and nothing else. Do not add extra single quotes inside the error string. If you print the file for confirmation, do not compare it against a shell-escaped string, do not store the jq program in a shell variable, and do not wrap it in an if [ "$line" != ... ] guard. If the printed contents differ, overwrite the same configfilterfile with the exact canonical line before the first config read; do not create probe variants or alternate filenames, and do not patch the file afterward with in-place rewrite commands. Write with: `jq if .ok then [.data[] | select(.name | test("";"i"))] else error("relay error: \(.error.message // "unknown")") end ` For config-entry helpers, persist the canonical metadata item from step 3 to instead of attempting {type}/list`. Then read the file with the native file-reading tool for complete, untruncated access.
- After reading the config for an automation or script, extract the primary controlled entity from the config actions (the first significant entity_id being controlled, e.g.,
light.main_light,climate.main_zone— NOT the automation/script entity itself). Read its current state (for Quick-Fix detection at end of review):
``text ha-nova relay core --method GET --path /api/states/ --jq-file --out ` Write with: `jq if .ok then .data.body else empty end `` Skip this step when the current review set contains more than one target. If no controlled entity found in actions, or state read fails: continue review — Quick-Fix will be skipped. For standalone config-entry helper review, skip this step entirely. There is no config body with actions to analyze for a primary controlled entity.
If config is already in the thread context (e.g., user pasted YAML):
- If entity_id is known for an automation or script: skip Target Resolution entirely, go straight to Config Quality Review (Step 1). But still read the primary controlled entity's state (step 7 above) for Quick-Fix detection when the current review set contains exactly one target — this step is independent of Target Resolution.
- If the target already in context is a config-entry helper metadata item: skip Target Resolution entirely and go straight to the config-entry helper review lane in Step 1. Do not attempt primary-controlled-entity state reads or Quick-Fix detection from that path.
- If entityid is unknown: run Target Resolution search (above) to find entityid. If not found, proceed with Config Quality Review only. Note in output: "Collision scan skipped — no entity_id available."
Do NOT invoke ha-nova:entity-discovery or ha-nova:read as separate skills — handle everything within this review flow.
Bulk Mode Gate
After target resolution:
- resolved targets
== 1: stay in normal single-target review mode - resolved targets
> 1: enter aggregate multi-target review mode automatically
Multi-target rules:
- multi-target review starts only after the current review set is trimmed
- Quick-Fix is single-target only; skip Step 4 and its prerequisite state-read step whenever the current review set contains more than one target
Bulk mode rules:
- use
skills/ha-nova/bulk-patterns.mdfor selector semantics, stable ordering, and workset limits - audit only the current workset (max 5 targets)
- stop after that one workset; do not start a second batch in the same standalone request
- resolve
unique_id, config, state, and related-item evidence per target inside the current workset only; no prefetch for the remaining matched targets - run the same Step 1 / Step 2 / Step 3 checks per item
- dedupe official-doc verification by pattern across the workset; do not refetch the same doc page per item
- cap related-config deep reads across the whole workset, not per item
- aggregate findings by repeated pattern, but preserve affected item lists
- skip Steps 4-6 entirely; bulk mode does not offer Quick-Fix, exploratory questions, or single-target suggestion synthesis
- persist collision candidate sets to files when needed; do not embed JSON arrays in shell variables for later command generation
- when multiple Relay probes are needed inside one temp directory, keep shared temp files serial or use dedicated payload filenames per probe
- write each Relay payload file as the final JSON body for that request; do not create placeholder templates and patch them later
- if more targets remain after the current workset, report
matched N / audited M / remaining Rand wait for an explicit follow-up request before continuing
Flow
Pre-Analysis Reference
Before analyzing, consult these sources:
Local reference (always):
docs/reference/ha-template-reference.md— valid Jinja2 functions, constants, filters
Official HA docs (fetch selectively based on config content — do NOT fetch all for every review):
- Trigger issues → https://www.home-assistant.io/docs/automation/trigger/
- Mode issues → https://www.home-assistant.io/docs/automation/modes/
- Action/script issues → https://www.home-assistant.io/docs/scripts/
- Template issues → https://www.home-assistant.io/docs/configuration/templating/
- Schema questions → https://www.home-assistant.io/docs/automation/yaml/
Only fetch pages relevant to the triggers, actions, and templates found in the config. Cross-check against documented gotchas and constraints — this catches issues beyond the hardcoded checks below.
Verify-before-flag rule: Before reporting ANY issue:
- Check local reference doc
- If not found, check the official HA docs above
- Only flag as error if confirmed invalid after both checks
Do NOT flag valid HA builtins or documented behavior as errors.
Step 1: Config Quality Review
Analyze config against the review catalog plus any additional issues found in the official docs. Report only violations found.
Traverse all variables: mappings in the config, not just the top-level block. Include root variables: on the automation/script plus local variables: actions inside choose, if / then / else, default, repeat, and nested sequence blocks.
Rule Catalog
- Load
skills/review/checks.mdbefore evaluating findings. skills/review/SKILL.mdis the stable review entrypoint;skills/review/checks.mdis the full rule catalog.
Check Taxonomy (internal only):
- Format:
{CATEGORY}-{NN}(example:H-09) - Category letter = family
- Severity is separate from the code
- Codes are internal only; NEVER show them in any user-facing message (reports, chat replies, follow-up questions) — describe findings in plain language instead
Apply these families by domain:
- Automation: S-01..S-03, R-01..R-22, P-01..P-05, M-01..M-03
- Script: automation families plus F-01..F-08
- Helper (storage-based family): H-01..H-10
- Helper (config-entry family): minimal config-entry review
- do not apply H-01..H-10
- confirm config-entry metadata is present
- inspect linked entities when available
- in Step 2, derive collision candidates from
linked_entities[], not from config actions - run
search/relatedon up to 3 linked entities - say explicitly that config-entry helper review does not use the storage-helper H rules
- If an automation or script references helpers in actions or direct thresholds, also apply H-01..H-10 to those helpers
- R-17 is an intra-config branch comparison only. Never emit it from collision scan or cross-automation conflict analysis.
- R-18 applies only to sibling-variable references within one
variables:mapping. Never emit it for cross-action or cross-scope references, scriptfields, HA builtins, or{% set %}locals inside the same template. - For R-18 outp
…
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: markusleben
- Source: markusleben/ha-nova
- License: MIT
- Homepage: https://github.com/markusleben/ha-nova
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.