# Review

> Use when analyzing, reviewing, auditing, or checking Home Assistant automations, scripts, or helpers for errors, best-practice violations, and conflicts. Do not invoke `ha-nova:read` separately — this skill handles discovery and reading internally.

- **Type:** Skill
- **Install:** `agentstack add skill-markusleben-ha-nova-review`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [markusleben](https://agentstack.voostack.com/s/markusleben)
- **Installs:** 0
- **Category:** [AI & ML](https://agentstack.voostack.com/c/ai-and-ml)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [markusleben](https://github.com/markusleben)
- **Source:** https://github.com/markusleben/ha-nova/tree/main/skills/review
- **Website:** https://github.com/markusleben/ha-nova

## Install

```sh
agentstack add skill-markusleben-ha-nova-review
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## 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`, or `DELETE` config 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 path
- `relay core --method  --path  --body-file ` — canonical REST path
- `relay ... --jq-file ` — canonical complex filter path
- `relay ... --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:
1. If the user asks for a bulk audit by `prefix`, `domain`, `area`, or `label`, build a shortlist first using `skills/ha-nova/bulk-patterns.md`.
   - use `config/entity_registry/list_for_display` for direct `prefix` / `domain` resolution
   - escalate to `config/entity_registry/list` and `config/area_registry/list` only when richer area/label evidence is required
   - for room/area phrasing, resolve the area and use `search/related` with `item_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.entity` is only a fallback seed for automation/script derivation when the target-family arrays are absent
   - use direct registry `area_id` only 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 like `COLLISION_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
2. 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/entity_registry/list_for_display"}`.
   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(["input_boolean","input_number","input_text","input_select","input_datetime","input_button","counter","timer","schedule"] | index($domain))`.
3. 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 `title` within the supported helper domains
   - linked `entity_id` by matching entity-registry `config_entry_id`
   Build the canonical metadata item:
   - `entry_id`
   - `domain`
   - `title`
   - `state`
   - `linked_entities[]`
4. If multiple matches remain outside an intentional bulk-selector flow: present top candidates (max 5) and ask one clarifying question. Never guess.
5. For automation/script targets, resolve `unique_id` (config key) — the entity_id slug and config key differ for UI-created items (see `relay-api.md` → ID Types):
   Create `` with the final `config/entity_registry/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.unique_id`, 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 `"entity_id":"script."`.
   Skip this step for config-entry helpers — `entry_id` is already the canonical identity.
6. 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 `config_filter_file` 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.
7. 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 entity_id is unknown: run Target Resolution search (above) to find entity_id. 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.md` for 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 R` and 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:
1. Check local reference doc
2. If not found, check the official HA docs above
3. 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.md` before evaluating findings.
- `skills/review/SKILL.md` is the stable review entrypoint; `skills/review/checks.md` is 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/related` on 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, script `fields`, 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](https://github.com/markusleben)
- **Source:** [markusleben/ha-nova](https://github.com/markusleben/ha-nova)
- **License:** MIT
- **Homepage:** https://github.com/markusleben/ha-nova

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** yes
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-markusleben-ha-nova-review
- Seller: https://agentstack.voostack.com/s/markusleben
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
