feat: detect last_changed/last_updated duration math and suggest for: field (#1157) - #1264
Conversation
… field (homeassistant-ai#1157) Adds _RE_DURATION_MATH to best_practice_checker.py to detect template conditions and triggers using now() - X.last_changed/last_updated arithmetic. These patterns should use the native `for:` field on state triggers instead (event-driven, no template re-evaluation overhead). Fires in both condition templates (_check_template_string) and template trigger value_templates (_check_triggers). Includes 6 new tests covering conditions, triggers, the positive clean case, skill ref presence, and no-generic-double-flag.
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request introduces a new best practice check to help users migrate from template-based duration arithmetic to the native Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here. Footnotes
|
There was a problem hiding this comment.
Code Review
This pull request introduces a new best practice check to the best_practice_checker.py tool, specifically targeting inefficient duration and recency calculations in Jinja templates (e.g., now() - last_changed). It suggests using Home Assistant's native for: field instead, which is more efficient and event-driven. Accompanying unit tests verify the detection logic across conditions and triggers. Feedback from the review highlights the need to refine the regex to ensure consistency and prevent false positives, as well as expanding the trigger check to cover other platforms like numeric_state that also support value_template.
…ternations
The second alternation previously matched bare Jinja variables named
`last_changed` (e.g. `{{ last_changed < now() }}`). Require at least one
dotted qualifier on both patterns so only entity attribute access is flagged.
Add two new tests:
- test_trigger_warning_uses_trigger_types_anchor: verifies trigger-path warning
links to #trigger-types (not #native-conditions)
- test_no_false_positive_bare_last_changed_variable: verifies bare Jinja
variable `last_changed < now()` does not trigger the detector
…template numeric_state triggers can carry a value_template field; duration/recency math inside that field was previously not flagged. Add a dedicated check block for platform: numeric_state so the detector covers both template and numeric_state trigger platforms. Add test_numeric_state_trigger_value_template_duration_math to verify.
|
RfR? I'd do some review, if you're done (for the moment). |
…or: field + scrub eval_template anti-patterns (#1383) * chore: bump skills-vendor to cf2b714 (HA 2026.5 best-practices) Brings in: - 'Purpose-Specific Triggers (2026.2+)' section in automation-patterns.md (door/window/motion/temperature triggers backed by standard state/numeric_state) - HA 2024+ plural-keyword form (triggers:/actions:/conditions:) across YAML examples - 2026.4+ template helpers documented (entity_name, state_attr_translated) - New yaml-only-integrations.md reference - Continue-on-Error, Repeat Actions, Disabling Automations sections Refs #1157. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(automations): teach native `for:` field in ha_config_set_automation Two changes to the ha_config_set_automation docstring: 1. Add a 'for:' bullet to the PREFER NATIVE SOLUTIONS list, pointing at the native for: field on state/numeric_state triggers and conditions as the replacement for {{ now() - X.last_changed > timedelta(...) }} duration math. Notes that HA 2026.5 expanded for: to purpose-specific triggers (motion, occupancy, doors, windows). 2. Modernize the Motion Light example. The previous example taught the stale turn_on + delay + turn_off pattern with mode: restart. Replace with a two-trigger + choose pattern using motion-on / motion-off (with for: 5 minutes) and native trigger-id conditions — no templates, no action-delay, mode: single suffices because for: handles re-trigger semantics. Refs #1157. Complements the best-practice detector in #1264. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(eval_template): remove automation-logic template examples ha_eval_template's docstring was teaching the exact anti-patterns the best-practice checker now flags. The 'Automation Conditions' use-case block showed `{{ is_state(...) and now().hour >= 7 }}` as the example of how to do conditions, and 'Test complex automation condition' wrote out the same shape combined with a `| float > 20` numeric comparison. Both teach agents that template logic is how you build automation conditions; the project actively steers the opposite direction. Replace with: - A 'When NOT to use this for automation/script logic' callout listing the native alternatives (numeric_state, state, time, sun, for:) and pointing at ha_get_skill_guide for the full list. - Reframe remaining examples so they're shown as legitimate template positions (notification bodies, dynamic data.* values, debugging existing templates) rather than as logic-building examples. Refs #1157. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * ci(renovate): enable git-submodules manager for skills-vendor The skills bundle (`src/ha_mcp/resources/skills-vendor`) is a git submodule. Submodules are pinned by design, and the workflows checkout with `submodules: true` — meaning each release ships exactly the SHA pinned at build time. Without auto-update infra, the pinned SHA drifts silently behind upstream until someone manually bumps it; that 'silently' is the failure mode that led to this PR (helper-selection.md served at runtime was missing the `filter`, `random`, `generic_thermostat`, `generic_hygrostat`, and `switch_as_x` helpers — all real types the `ha_config_set_helper` tool advertises). Enable Renovate's `git-submodules` manager so the submodule pointer gets opened as a reviewable PR whenever upstream main advances. The existing global Tuesday-3pm-UTC schedule applies. `.gitmodules` needs `branch = main` for Renovate to know which upstream ref to track — without it, Renovate defaults to `master`, which doesn't exist on `homeassistant-ai/skills`. The next time `homeassistant-ai/skills` lands a commit on `main`, Renovate will open a bump PR; merging it ships the new skill content in the next `publish-dev`/release cycle. Refs #1157. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs: address review — drop unverified version claim, fix Motion Light logic hole Three fixes from the contrib + Gemini review on this branch: 1. Drop the parenthetical claim that 'HA 2026.5 expanded for: to purpose-specific triggers'. The claim conflates two distinct things: for: on state/numeric_state has existed for years; the purpose- specific triggers (introduced 2025.12 / labelled 2026.2+ in the vendored skill) are a UI editor abstraction over the same YAML and are still a Labs preview behind an opt-in flag. The bullet's main point — use native for: instead of last_changed/last_updated math — stands on its own. 2. Motion Light example: top-level 'condition: sun, after: sunset' gated both the motion_on and motion_off branches of the choose. If the sun rose during the 5-minute for: window, motion_off fired but the top-level condition was false, leaving the light on. Move the sun condition into the motion_on branch only (matches Gemini's suggestion). Rephrase the example header to describe the actual change ('for: on the off-transition replaces action-delay') instead of overclaiming 'no template' (the previous example was also template-free). 3. ha_eval_template docstring: the Conditional Logic block showed '{% if is_state('sun.sun', 'above_horizon') %}' as a Jinja2 syntax example — but the new 'When NOT to use' callout explicitly tells agents not to write 'is_state('sun.sun', ...)' in condition positions. Swap the example subject to alarm_control_panel state (no native equivalent for the notification-string use case it illustrates) and tighten the section heading to 'Conditional Logic (for display strings — not for condition: positions)'. Also add a 'choose action over templated service: / action: strings' bullet to the callout — the lead-in mentioned action service names but no bullet covered them. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: kingpanther13 <kingpanther13@users.noreply.github.com> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
@SealKan please mark as ready for review if you're done working on this so we can do a formal review on it |
|
@SealKan can you give an update on this and your other PR please? I'm just trying to keep the pipeline moving forward. |
|
Apologies for the delay. The two gemini items were addressed in prior commits (c6a46e2 tightens the regex to require a dotted qualifier on both alternations to prevent false positives, 824d120 extends the detector to numeric_state value_template). Just pushed a ruff format fix so CI should go green. Marking ready for review now. |
|
@Patch76 following up on the Area 3 row in your May 22 status map: the Ruff Lint failure is resolved — pushed a Per your net, that should leave only the Area 4 decision before #1157 can close — happy to defer to whatever you and the maintainers land on there. The scripts |
Patch76
left a comment
There was a problem hiding this comment.
Thanks for this — the detection is well-targeted, and the test suite is genuinely thorough: condition + trigger contexts, the for:-already-present negative case, generic-fallback suppression, and the bare-variable false-positive guard. The regex comment matches the pattern, the warning text is accurate, and both skill-doc anchors (#native-conditions, #trigger-types) resolve.
One item before merge:
The reversed comparison form is matched and documented, but never positively tested. _RE_DURATION_MATH has two alternations:
now() - X.last_changed/last_updated # forward — well covered
X.last_changed/last_updated < now() # reversed — no positive test
Every positive test uses the forward form; the reversed form's only appearance is the bare variable in test_no_false_positive_bare_last_changed_variable (asserted not flagged). So the reversed alternation with a dotted qualifier — the case it exists to catch — ships without a regression guard, and a later refactor could drop it silently. Could you add one positive test per context, e.g.:
"{{ states.binary_sensor.motion.last_changed < now() }}" # condition → expect warning
"{{ states.sensor.temp.last_updated < now() - timedelta(minutes=5) }}" # trigger value_template → expect warningOne optional, non-blocking note: the duration assertions match on substring (any warning containing the fragments), so asserting exactly one such warning fires would also catch accidental double-flagging.
The reversed-form tests are the only blocker here; the rest is solid.
…istant-ai#1157) Cover the `X.last_changed/last_updated < now()` alternation of _RE_DURATION_MATH in both condition and trigger value_template contexts. Each test asserts exactly one warning fires, which also guards against the two alternations double-flagging the same template. Addresses review feedback on PR homeassistant-ai#1264.
|
Good catch @Patch76 - you're right, the reversed form had no positive coverage. Added one test per context (condition + trigger value_template) for the dotted-qualifier |
Patch76
left a comment
There was a problem hiding this comment.
Thanks for this — the detector is clean and the test coverage is genuinely thorough (both attributes, both regex alternations, the numeric_state path, the bare-last_changed false-positive guard, and double-flag suppression are all covered). The condition→#native-conditions / trigger→#trigger-types anchor split is correct and explicitly tested. None of the following are blockers.
1. PR description is out of date — the reversed form is caught.
The "Future improvements" note says states.sensor.x.last_changed < now() - timedelta(...) isn't matched by the current regex. It actually is: the second alternation (?:\w+\.)+last_(?:changed|updated)\s*<\s*now\(\) matches X.last_changed < now() and doesn't care what follows now(), so the offset form matches too. Your own test_trigger_reversed_comparison_last_updated_math and test_condition_reversed_comparison_last_changed_math confirm this. Worth deleting that bullet so the description doesn't contradict the tests.
2. numeric_state path has no anchor assertion.
test_numeric_state_trigger_value_template_duration_math asserts on the message text ("last_changed/last_updated", "for:") but not on the #trigger-types anchor, so a copy-paste slip to #native-conditions in the numeric_state block (best_practice_checker.py ~L549) wouldn't be caught — unlike the template-trigger path, which has test_trigger_warning_uses_trigger_types_anchor. A one-line addition mirroring that test (run with skill_prefix=SKILL_PREFIX, assert automation-patterns.md#trigger-types) closes the gap.
3. Nit — regex comment wording.
best_practice_checker.py:81 says "at least one dotted qualifier". (?:\w+\.)+ is one-or-more, so trigger.last_changed (one dot) and states.sensor.x.last_changed (three) both match. "one or more dotted qualifiers" reads more precisely. Trivial.
For the record: I checked the new regex for ReDoS. It's technically O(n²) on a pathological all-dots input (a property it shares with the other dotted-path regexes in this file), but at realistic template depths it stays well under a millisecond, so there's nothing to do here.
Patch76
left a comment
There was a problem hiding this comment.
The reversed-comparison regression tests I asked for are now in place — test_condition_reversed_comparison_last_changed_math and test_trigger_reversed_comparison_last_updated_math, both asserting exactly one warning fires, which also closes the double-flag concern. That was the only blocker, so I am approving.
The three items in my companion comment (the stale "Future improvements" bullet, the missing #trigger-types anchor assertion on the numeric_state test, and the comment-wording nit) are all non-blocking — nice to fold in while you are here, but none gate merge. Thanks for the thorough tests.
🧪 Your changes are now in the dev channel!Your PR has been merged to master and is available for testing in the dev channel. Test your changes before the next stable release (biweekly Wednesday): Quick start# Run dev version
uvx ha-mcp-dev
# Check version
uvx ha-mcp-dev --versionDocker: docker pull ghcr.io/homeassistant-ai/ha-mcp:dev
docker run --rm -i \
-e HOMEASSISTANT_URL=http://your-ha:8123 \
-e HOMEASSISTANT_TOKEN=your_token \
ghcr.io/homeassistant-ai/ha-mcp:devFound an issue? Please open a new bug report and mention this PR for context. |
…1483) * fix: refine last_changed/last_updated duration-math detector (#1157) Follow-up to #1264. A post-merge review surfaced three issues in the `now() - X.last_changed/last_updated` duration-math best-practice detector. The checker is advisory (it emits suggestions to the agent), so all changes affect the quality of advice, never runtime behaviour. - Contradictory advice: a recency template that also has a numeric compare (`(now() - X.last_changed).total_seconds() | int > 300`) matched both the numeric-comparison and duration detectors, emitting two conflicting native suggestions (`numeric_state` AND `for:`). Gate the numeric_state suggestion on `not duration_match` in both the condition and template-trigger paths. - False positive: the bare `X.last_changed < now()` is always true and carries no duration, so `for:` cannot express it. Require the subtraction on the reversed alternation. This corrects a test added in #1264 that asserted the bare form should fire; it now uses the real recency form, with a dedicated negative test locking in the corrected behaviour. - Missed forms: broaden the regex to also catch `>=`/`<=` comparators, the `now()`-on-the-left shape, `now().timestamp() - X.last_changed.timestamp()`, and `as_timestamp(now()) - as_timestamp(X.last_changed)`. The as_timestamp form closes a silent gap where a numeric_state-trigger value_template produced zero warnings. Trailing word boundaries on every alternation keep look-alike attributes (`last_changed_at`) from being mistaken for the real state property. 114 unit tests pass (was 101). ruff format/check and mypy clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix: detect `last_changed + delta` and as_timestamp filter recency forms Address Gemini review on #1483 — two more common recency idioms were missed by `_RE_DURATION_MATH`: - `X.last_changed + <delta> (<|<=|>|>=) now()` (delta added to the attribute; the mirror of the existing now()-on-the-left form) - `as_timestamp(now()) - X.last_changed | as_timestamp` (filter spelling) Tightened the first alternation vs. the bot suggestion to a lazy `[^<>{}]+?` so it cannot span template-block boundaries, and it leaves equality (`+ 1 == now()`) and no-comparison future-time computes unflagged. Added 3 tests (117 total). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: kingpanther13 <kingpanther13@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…➔ 7.7.0) (#994)
This PR contains the following updates:
| Package | Update | Change |
|---|---|---|
| [ghcr.io/homeassistant-ai/ha-mcp](https://github.com/homeassistant-ai/ha-mcp) | minor | `7.5.0` → `7.7.0` |
---
### Release Notes
<details>
<summary>homeassistant-ai/ha-mcp (ghcr.io/homeassistant-ai/ha-mcp)</summary>
### [`v7.7.0`](https://github.com/homeassistant-ai/ha-mcp/blob/HEAD/CHANGELOG.md#v770-2026-06-10)
[Compare Source](https://github.com/homeassistant-ai/ha-mcp/compare/v7.6.0...v7.7.0)
##### Added
- User-configurable custom filesystem directories for the file tools (closes [#​1567](https://github.com/homeassistant-ai/ha-mcp/issues/1567))
([#​1568](https://github.com/homeassistant-ai/ha-mcp/pull/1568))
- Expose all user-tunable env vars in the settings UI (add-on parity)
([#​1554](https://github.com/homeassistant-ai/ha-mcp/pull/1554))
- Warn when default MCP\_SECRET\_PATH is bound non-loopback
([#​1472](https://github.com/homeassistant-ai/ha-mcp/pull/1472))
- **search**: Consolidate ha\_search\_entities + ha\_deep\_search into ha\_search
([#​1529](https://github.com/homeassistant-ai/ha-mcp/pull/1529))
- **addon**: Install the MCP Server add-on from the ha\_mcp\_tools integration
([#​1528](https://github.com/homeassistant-ai/ha-mcp/pull/1528))
- Add opt-in dashboard screenshot mode
([#​1510](https://github.com/homeassistant-ai/ha-mcp/pull/1510))
- Add Linux support for install & docs
([#​1096](https://github.com/homeassistant-ai/ha-mcp/pull/1096))
- Surface the web settings page for non-add-on installs ([#​1458](https://github.com/homeassistant-ai/ha-mcp/issues/1458))
([#​1511](https://github.com/homeassistant-ai/ha-mcp/pull/1511))
- Convert Pydantic arg-validation errors to actionable ToolErrors
([#​1491](https://github.com/homeassistant-ai/ha-mcp/pull/1491))
- Per-key toggles for automation/script/scene in packages/\*.yaml
([#​1476](https://github.com/homeassistant-ai/ha-mcp/pull/1476))
- Direct skills retrieval for write tools + improved best practice checker warnings with embedded skills responses ([#​1182](https://github.com/homeassistant-ai/ha-mcp/issues/1182))
([#​1448](https://github.com/homeassistant-ai/ha-mcp/pull/1448))
- Detect last\_changed/last\_updated duration math and suggest for: field ([#​1157](https://github.com/homeassistant-ai/ha-mcp/issues/1157))
([#​1264](https://github.com/homeassistant-ai/ha-mcp/pull/1264))
- Advanced settings panel + nested beta master toggle ([#​1164](https://github.com/homeassistant-ai/ha-mcp/issues/1164))
([#​1431](https://github.com/homeassistant-ai/ha-mcp/pull/1431))
- Allow automation/script/scene yaml\_path in packages/\*.yaml only
([#​1452](https://github.com/homeassistant-ai/ha-mcp/pull/1452))
- Restrict ha\_mcp\_tools services to ha-mcp callers (caller token + ha\_call\_service refusal)
([#​1459](https://github.com/homeassistant-ai/ha-mcp/pull/1459))
##### Changed
- **security**: Soften vulnerability-response SLA to best-effort
([`a24e7da`](https://github.com/homeassistant-ai/ha-mcp/commit/a24e7da4787aad570ac2998a5732de06229fa160))
- Update contributors list \[contributors-updated]
([`7cc187f`](https://github.com/homeassistant-ai/ha-mcp/commit/7cc187f4de2f6eb58cafaa4fb21f8016cb180a61))
- Telemetry wording — follow HA analytics setting, not opt-in-only
([#​1481](https://github.com/homeassistant-ai/ha-mcp/pull/1481))
- **security**: Note that security-advisory disposition is API-blind (UI-only)
([#​1561](https://github.com/homeassistant-ai/ha-mcp/pull/1561))
- **tools**: Sharpen ha\_eval\_template usage routing for compute-from-state queries
([#​1550](https://github.com/homeassistant-ai/ha-mcp/pull/1550))
- Differentiate ha-mcp from Home Assistant's built-in MCP Server
([#​1542](https://github.com/homeassistant-ai/ha-mcp/pull/1542))
- Update advanced mode notes
([#​1533](https://github.com/homeassistant-ai/ha-mcp/pull/1533))
- **[#​1157](https://github.com/homeassistant-ai/ha-mcp/issues/1157)**: Scripts native-for: guidance + fix numeric\_state-condition for: overclaim
([#​1480](https://github.com/homeassistant-ai/ha-mcp/pull/1480))
- Clarify add-on vs uvx; add Codex + HTTP-native client setup
([#​1478](https://github.com/homeassistant-ai/ha-mcp/pull/1478))
- **security**: Explicit threat model for trusted clients, LAN, sandbox, and OAuth tokens
([#​1463](https://github.com/homeassistant-ai/ha-mcp/pull/1463))
- Clarify telemetry is a planned future feature, not implemented
([#​1469](https://github.com/homeassistant-ai/ha-mcp/pull/1469))
##### Fixed
- **tools**: Bring HA API field names to 2026.6 — stale docstrings, automation plural canonicalization, fan speed (closes [#​1540](https://github.com/homeassistant-ai/ha-mcp/issues/1540))
([#​1566](https://github.com/homeassistant-ai/ha-mcp/pull/1566))
- **energy**: Accept "water" energy source in ha\_manage\_energy\_prefs
([#​1553](https://github.com/homeassistant-ai/ha-mcp/pull/1553))
- **tools**: Use action: not service: in automation docstring examples
([#​1539](https://github.com/homeassistant-ai/ha-mcp/pull/1539))
- **security**: Narrow GHSA-mc92-ww4q-6fg4 to the masker and log redaction
([#​1512](https://github.com/homeassistant-ai/ha-mcp/pull/1512))
- **addon**: Restrict settings UI root routes to HA ingress
([#​1508](https://github.com/homeassistant-ai/ha-mcp/pull/1508))
- Add name attributes to generated settings-UI form controls (a11y)
([#​1497](https://github.com/homeassistant-ai/ha-mcp/pull/1497))
- Add-on-aware code-mode locked note + suppress settings-UI favicon 404
([#​1494](https://github.com/homeassistant-ai/ha-mcp/pull/1494))
- Surface the real reason a WebSocket connection failed
([#​1495](https://github.com/homeassistant-ai/ha-mcp/pull/1495))
- Remove str from ha\_bulk\_control.operations schema + fix wrong-reason test
([#​1492](https://github.com/homeassistant-ai/ha-mcp/pull/1492))
- Remove str from bool/int param schemas across all tools
([#​1490](https://github.com/homeassistant-ai/ha-mcp/pull/1490))
- **addon**: Expose non-beta tool options on the stable add-on
([#​1488](https://github.com/homeassistant-ai/ha-mcp/pull/1488))
- **addon**: Enable ingress so the stable add-on shows the Open Web UI / Settings UI
([#​1486](https://github.com/homeassistant-ai/ha-mcp/pull/1486))
- Refine last\_changed/last\_updated duration-math detector ([#​1157](https://github.com/homeassistant-ai/ha-mcp/issues/1157))
([#​1483](https://github.com/homeassistant-ai/ha-mcp/pull/1483))
- Remove str from config param schema on service and entity tools
([#​1487](https://github.com/homeassistant-ai/ha-mcp/pull/1487))
- Surface flow-helper config to agents reading UI-created templates
([#​1474](https://github.com/homeassistant-ai/ha-mcp/pull/1474))
- Remove str from config param schema on set tools
([#​1485](https://github.com/homeassistant-ai/ha-mcp/pull/1485))
- Route malformed ha\_mcp\_tools version to a distinct reinstall error
([#​1484](https://github.com/homeassistant-ai/ha-mcp/pull/1484))
- Persist DCR client registrations and HMAC secret across restarts ([#​1261](https://github.com/homeassistant-ai/ha-mcp/issues/1261))
([#​1265](https://github.com/homeassistant-ai/ha-mcp/pull/1265))
- Stop dev builds from publishing the :latest Docker tag
([#​1477](https://github.com/homeassistant-ai/ha-mcp/pull/1477))
- Subscribe to HACS dispatch signal instead of 10x1s blind poll
([#​1455](https://github.com/homeassistant-ai/ha-mcp/pull/1455))
- Reject python\_transform while loops
([#​1462](https://github.com/homeassistant-ai/ha-mcp/pull/1462))
##### Performance Improvements
- Fast-fail HACS not-found lookups + batch-verify deep-search E2E fixtures ([#​1515](https://github.com/homeassistant-ai/ha-mcp/issues/1515))
([#​1552](https://github.com/homeassistant-ai/ha-mcp/pull/1552))
##### Refactoring
- Add display title to ha\_get\_skill\_guide tool
([#​1543](https://github.com/homeassistant-ai/ha-mcp/pull/1543))
- Fold ha\_check\_config into ha\_get\_system\_health include="config\_check"
([#​1516](https://github.com/homeassistant-ai/ha-mcp/pull/1516))
- **c901**: Smart\_search.py below C901 threshold
([#​1507](https://github.com/homeassistant-ai/ha-mcp/pull/1507))
- **hacs**: Consolidate HACS tools into ha\_get\_hacs + ha\_manage\_hacs ([#​1045](https://github.com/homeassistant-ai/ha-mcp/issues/1045))
([#​1502](https://github.com/homeassistant-ai/ha-mcp/pull/1502))
- **c901**: Tools\_config\_helpers.py below C901 threshold
([#​1498](https://github.com/homeassistant-ai/ha-mcp/pull/1498))
- **complexity**: Reduce C901 in tools\_addons.py via class-based pattern
([#​1432](https://github.com/homeassistant-ai/ha-mcp/pull/1432))
***
<details>
<summary>Internal Changes</summary>
##### Changed
- Trim AGENTS.md below 40k + improve subdirectory CLAUDE.md files
([#​1499](https://github.com/homeassistant-ai/ha-mcp/pull/1499))
##### Chores
- **addon**: Publish dev addon version 7.6.0.dev415 \[skip ci]
([`2c0148b`](https://github.com/homeassistant-ai/ha-mcp/commit/2c0148ba512a02b5299edbb4086c38410777a295))
- **deps**: Update ghcr.io/home-assistant/home-assistant docker tag to v2026.6.1
([#​1571](https://github.com/homeassistant-ai/ha-mcp/pull/1571))
- **deps**: Update ghcr.io/astral-sh/uv docker tag to v0.11.19
([#​1570](https://github.com/homeassistant-ai/ha-mcp/pull/1570))
- **addon**: Publish dev addon version 7.6.0.dev414 \[skip ci]
([`0bf9e39`](https://github.com/homeassistant-ai/ha-mcp/commit/0bf9e39947e8bf87d18bae23877d6b0d955dd35f))
- Sync tool docs after merge \[skip ci]
([`8f5e037`](https://github.com/homeassistant-ai/ha-mcp/commit/8f5e037b89296fd483888d158d8f72f4b1b7dfa8))
- **addon**: Publish dev addon version 7.6.0.dev413 \[skip ci]
([`6729327`](https://github.com/homeassistant-ai/ha-mcp/commit/6729327de8c0747f5cc7bb639859f95bbe1f0cfc))
- Sync tool docs after merge \[skip ci]
([`4341e95`](https://github.com/homeassistant-ai/ha-mcp/commit/4341e9574b3270c67bc016676f854f585fec816f))
- **addon**: Publish dev addon version 7.6.0.dev412 \[skip ci]
([`148f506`](https://github.com/homeassistant-ai/ha-mcp/commit/148f506a98c8f89292616a3a05dd0c9156516439))
- **addon**: Publish dev addon version 7.6.0.dev411 \[skip ci]
([`287fe55`](https://github.com/homeassistant-ai/ha-mcp/commit/287fe5503917e551f2dcb363cd28250237ed880c))
- Sync tool docs after merge \[skip ci]
([`b642b8e`](https://github.com/homeassistant-ai/ha-mcp/commit/b642b8eba67d8015d8fe5a1c1f88c9dd72ffc45f))
- **addon**: Publish dev addon version 7.6.0.dev410 \[skip ci]
([`29e34dd`](https://github.com/homeassistant-ai/ha-mcp/commit/29e34dd6eb517399de3c0a6a886e45ecf4749923))
- **addon**: Publish dev addon version 7.6.0.dev409 \[skip ci]
([`dec16a1`](https://github.com/homeassistant-ai/ha-mcp/commit/dec16a12d2ac3341908b130e9ea79f950d02466b))
- Sync tool docs after merge \[skip ci]
([`dd72535`](https://github.com/homeassistant-ai/ha-mcp/commit/dd725357f5d48a00959aaa7eceb4bad67a7ba202))
- **addon**: Publish dev addon version 7.6.0.dev408 \[skip ci]
([`c3c89f1`](https://github.com/homeassistant-ai/ha-mcp/commit/c3c89f1a758b6086b59ff21f9044597da103fa25))
- **addon**: Publish dev addon version 7.6.0.dev407 \[skip ci]
([`94195ee`](https://github.com/homeassistant-ai/ha-mcp/commit/94195ee4c8dbd0d8eec13d7c3d7ee392e5b7240f))
- **addon**: Publish dev addon version 7.6.0.dev406 \[skip ci]
([`f439424`](https://github.com/homeassistant-ai/ha-mcp/commit/f4394240dd1170f9d978e3c4a5011bab12f17f54))
- Sync tool docs after merge \[skip ci]
([`7464277`](https://github.com/homeassistant-ai/ha-mcp/commit/746427745d3debccea57c844278d1ba834d7ebfb))
- **addon**: Publish dev addon version 7.6.0.dev405 \[skip ci]
([`146eb07`](https://github.com/homeassistant-ai/ha-mcp/commit/146eb073a6f260ed0b0653cdb71346e9d29deae7))
- **addon**: Publish dev addon version 7.6.0.dev404 \[skip ci]
([`6a707bb`](https://github.com/homeassistant-ai/ha-mcp/commit/6a707bba576b987f8c3395adca3d59f7dd8a1050))
- Sync tool docs after merge \[skip ci]
([`85f3935`](https://github.com/homeassistant-ai/ha-mcp/commit/85f3935f80d9677f791b3098b201ec9c27e643be))
- **addon**: Publish dev addon version 7.6.0.dev403 \[skip ci]
([`be1fa1d`](https://github.com/homeassistant-ai/ha-mcp/commit/be1fa1dd2693170cbe3c037e7a88cf02f1847dcf))
- Sync tool docs after merge \[skip ci]
([`d9adbd2`](https://github.com/homeassistant-ai/ha-mcp/commit/d9adbd2c27750c9bc8faa55470d24564c48b3dbf))
- **addon**: Publish dev addon version 7.6.0.dev402 \[skip ci]
([`41ad7ca`](https://github.com/homeassistant-ai/ha-mcp/commit/41ad7caf1e0d982dd9e7bda3420ba3ca577cf765))
- **addon**: Publish dev addon version 7.6.0.dev401 \[skip ci]
([`8205034`](https://github.com/homeassistant-ai/ha-mcp/commit/820503485386f13dc66a0da3d304739e1f03dafd))
- **deps**: Update ghcr.io/astral-sh/uv docker tag to v0.11.18
([#​1523](https://github.com/homeassistant-ai/ha-mcp/pull/1523))
- **addon**: Publish dev addon version 7.6.0.dev400 \[skip ci]
([`532cdc4`](https://github.com/homeassistant-ai/ha-mcp/commit/532cdc440a8db053c524579f3e6b48b099c13c66))
- Sync tool docs after merge \[skip ci]
([`e2c08ff`](https://github.com/homeassistant-ai/ha-mcp/commit/e2c08ff797ffabf7b39bfc4b22b498b1c02ce1fa))
- **addon**: Publish dev addon version 7.6.0.dev399 \[skip ci]
([`9501348`](https://github.com/homeassistant-ai/ha-mcp/commit/95013488ea99761535ea9532285839bcd0ec8e3b))
- Sync tool docs after merge \[skip ci]
([`e70a050`](https://github.com/homeassistant-ai/ha-mcp/commit/e70a050efcb6edeb65d51dabd5307a192a22e66c))
- **addon**: Publish dev addon version 7.6.0.dev398 \[skip ci]
([`0b61424`](https://github.com/homeassistant-ai/ha-mcp/commit/0b61424ed823453dec27bb173d049f901eddc2d3))
- Sync tool docs after merge \[skip ci]
([`6df7987`](https://github.com/homeassistant-ai/ha-mcp/commit/6df79877669686a9fee3ec04979dff3960bc5e3f))
- **addon**: Publish dev addon version 7.6.0.dev397 \[skip ci]
([`c34915f`](https://github.com/homeassistant-ai/ha-mcp/commit/c34915f40cd82f83f0eb4af5c3a5655843608770))
- Sync tool docs after merge \[skip ci]
([`6f88e7e`](https://github.com/homeassistant-ai/ha-mcp/commit/6f88e7e0c8dcb7fee27792e0f87f6acd8aa892c4))
- **addon**: Publish dev addon version 7.6.0.dev396 \[skip ci]
([`1490e19`](https://github.com/homeassistant-ai/ha-mcp/commit/1490e190382454b17fc14cd362b17612a6af253f))
- Sync tool docs after merge \[skip ci]
([`ac2c7d0`](https://github.com/homeassistant-ai/ha-mcp/commit/ac2c7d038a90fb44466afa8f047378d7e8daed94))
- **addon**: Publish dev addon version 7.6.0.dev395 \[skip ci]
([`11e5ee8`](https://github.com/homeassistant-ai/ha-mcp/commit/11e5ee8f07f63f63b8cdf017397263c7602e80f6))
- **addon**: Publish dev addon version 7.6.0.dev394 \[skip ci]
([`5fc3e0f`](https://github.com/homeassistant-ai/ha-mcp/commit/5fc3e0f572bfd1bb367e65b3f4d78b96cb78fa91))
- Flag untrusted third-party content in HACS and add-on tool responses
([#​1509](https://github.com/homeassistant-ai/ha-mcp/pull/1509))
- **addon**: Publish dev addon version 7.6.0.dev393 \[skip ci]
([`9a37c28`](https://github.com/homeassistant-ai/ha-mcp/commit/9a37c28cfa0d1f3f652fe441ce2fe1d72a7360ab))
- **addon**: Publish dev addon version 7.6.0.dev392 \[skip ci]
([`4f737ac`](https://github.com/homeassistant-ai/ha-mcp/commit/4f737ac7c116e9afa046ab45b1230e2cdb5ae959))
- **addon**: Publish dev addon version 7.6.0.dev391 \[skip ci]
([`fd5d3f2`](https://github.com/homeassistant-ai/ha-mcp/commit/fd5d3f2d4ce87baa4cfcc85a173bb0cc9d132a35))
- **addon**: Publish dev addon version 7.6.0.dev390 \[skip ci]
([`28dedf4`](https://github.com/homeassistant-ai/ha-mcp/commit/28dedf43f3cd094b1c40fb50e535166cc8c33388))
- **addon**: Publish dev addon version 7.6.0.dev389 \[skip ci]
([`9443446`](https://github.com/homeassistant-ai/ha-mcp/commit/9443446fdd607a75d8db5fdad009130b188267d6))
- Sync tool docs after merge \[skip ci]
([`94fcbeb`](https://github.com/homeassistant-ai/ha-mcp/commit/94fcbeb14bd9cfa3bef274182f95e4562a379971))
- **addon**: Publish dev addon version 7.6.0.dev388 \[skip ci]
([`ccc1816`](https://github.com/homeassistant-ai/ha-mcp/commit/ccc18162eec520950c58cc8eabb2aac04ac57ab3))
- Drop dead entity\_cache attr + ruff-format fuzzy\_search.py
([#​1503](https://github.com/homeassistant-ai/ha-mcp/pull/1503))
- **addon**: Publish dev addon version 7.6.0.dev387 \[skip ci]
([`057c108`](https://github.com/homeassistant-ai/ha-mcp/commit/057c108b2958959bfee34225899b47b5c989a119))
- **addon**: Publish dev addon version 7.6.0.dev386 \[skip ci]
([`66f4ac6`](https://github.com/homeassistant-ai/ha-mcp/commit/66f4ac6a37d85412b895962afef1b03707400e56))
- **addon**: Publish dev addon version 7.6.0.dev385 \[skip ci]
([`f331f11`](https://github.com/homeassistant-ai/ha-mcp/commit/f331f1150f525a18bf5bd2e27007b46a07a3492c))
- **addon**: Publish dev addon version 7.6.0.dev384 \[skip ci]
([`17c319e`](https://github.com/homeassistant-ai/ha-mcp/commit/17c319e68ba4b4d4e6acd84deb57c588aafcb48b))
- Sync tool docs after merge \[skip ci]
([`f36cbb7`](https://github.com/homeassistant-ai/ha-mcp/commit/f36cbb7e620839b16808b37b61dbc7602557b409))
- **addon**: Publish dev addon version 7.6.0.dev383 \[skip ci]
([`782ba3b`](https://github.com/homeassistant-ai/ha-mcp/commit/782ba3b2bbcfe50564c5524d6a2c018a4c9c9ba6))
- **addon**: Publish dev addon version 7.6.0.dev382 \[skip ci]
([`b647ab6`](https://github.com/homeassistant-ai/ha-mcp/commit/b647ab6eea76a030c7e3c46f72d732ff339398fe))
- **addon**: Publish dev addon version 7.6.0.dev381 \[skip ci]
([`e999c24`](https://github.com/homeassistant-ai/ha-mcp/commit/e999c242553a60561ca06dbefe3177c627bb9e2d))
- Sync tool docs after merge \[skip ci]
([`50d76b0`](https://github.com/homeassistant-ai/ha-mcp/commit/50d76b04a0691c565fafaabc76fd4bd3cf321953))
- **addon**: Publish dev addon version 7.6.0.dev380 \[skip ci]
([`ebdc69b`](https://github.com/homeassistant-ai/ha-mcp/commit/ebdc69bde929fd3342234149956af0710b9f260a))
- Sync tool docs after merge \[skip ci]
([`1f03967`](https://github.com/homeassistant-ai/ha-mcp/commit/1f03967160156cbffdfc9fc7deb5ed9a2b25f2ba))
- **addon**: Publish dev addon version 7.6.0.dev379 \[skip ci]
([`7cabb2e`](https://github.com/homeassistant-ai/ha-mcp/commit/7cabb2ec342561dbc74251f7697e3c4df0a8fcb3))
- **addon**: Publish dev addon version 7.6.0.dev378 \[skip ci]
([`7b631c7`](https://github.com/homeassistant-ai/ha-mcp/commit/7b631c75e0e4163ee13906b90ddad7a1b744e402))
- **addon**: Publish dev addon version 7.6.0.dev377 \[skip ci]
([`ea7b614`](https://github.com/homeassistant-ai/ha-mcp/commit/ea7b614615606a8fc05a0a18cb9cafa2f0a42c0d))
- **addon**: Publish dev addon version 7.6.0.dev376 \[skip ci]
([`fd33ecd`](https://github.com/homeassistant-ai/ha-mcp/commit/fd33ecd4d260f5fc2ab4f229c90b1a4514c5ccde))
- Sync tool docs after merge \[skip ci]
([`ba8fae3`](https://github.com/homeassistant-ai/ha-mcp/commit/ba8fae3cc4f451dc65022756a86cce5275f6e35f))
- **addon**: Publish dev addon version 7.6.0.dev375 \[skip ci]
([`afcd0d8`](https://github.com/homeassistant-ai/ha-mcp/commit/afcd0d8e061e1cba65fd119727fc64ed77f1818d))
- Sync tool docs after merge \[skip ci]
([`f9b55ad`](https://github.com/homeassistant-ai/ha-mcp/commit/f9b55ad59c6f03d6a98c3d3f6dd52ba9ff7c8a7a))
- **addon**: Publish dev addon version 7.6.0.dev374 \[skip ci]
([`eecdf8b`](https://github.com/homeassistant-ai/ha-mcp/commit/eecdf8b058ba932ba94cfb292ebf2331a54d2def))
- Sync tool docs after merge \[skip ci]
([`ef16a8a`](https://github.com/homeassistant-ai/ha-mcp/commit/ef16a8a197c76e51a49ae6ac69eecb15d202a194))
- **addon**: Publish dev addon version 7.6.0.dev373 \[skip ci]
([`9a93703`](https://github.com/homeassistant-ai/ha-mcp/commit/9a9370362fe5573ac71cd6e90353877faccce8a6))
- **addon**: Publish dev addon version 7.6.0.dev372 \[skip ci]
([`7352ce8`](https://github.com/homeassistant-ai/ha-mcp/commit/7352ce88ef59feef74c29ab47f6991cc2ac132a8))
- **addon**: Publish dev addon version 7.6.0.dev371 \[skip ci]
([`d7601f5`](https://github.com/homeassistant-ai/ha-mcp/commit/d7601f5796308e1c42a01dbce9861460027a93c4))
- Sync tool docs after merge \[skip ci]
([`d0a4482`](https://github.com/homeassistant-ai/ha-mcp/commit/d0a448276306a08f8a52c4645f1b9c5aeaafd68e))
- **addon**: Publish dev addon version 7.6.0.dev370 \[skip ci]
([`f83c32c`](https://github.com/homeassistant-ai/ha-mcp/commit/f83c32c747ddaeccffb040bc28d3e08d7507ded4))
- **addon**: Publish dev addon version 7.6.0.dev369 \[skip ci]
([`ea16661`](https://github.com/homeassistant-ai/ha-mcp/commit/ea16661f1d144feada93aee119b625f968f990cb))
- **addon**: Publish dev addon version 7.6.0.dev368 \[skip ci]
([`af49ea5`](https://github.com/homeassistant-ai/ha-mcp/commit/af49ea5aff5c9f54914943cc2f8a67ebeea2fdee))
- **addon**: Publish dev addon version 7.6.0.dev367 \[skip ci]
([`7dd5f4c`](https://github.com/homeassistant-ai/ha-mcp/commit/7dd5f4cd0237ef4d80a454efe4dfc0801f18fdbd))
- **addon**: Publish dev addon version 7.6.0.dev366 \[skip ci]
([`6273b7e`](https://github.com/homeassistant-ai/ha-mcp/commit/6273b7ec8695706948eefe8e617cac39363940ce))
- Sync tool docs after merge \[skip ci]
([`4e3fd5f`](https://github.com/homeassistant-ai/ha-mcp/commit/4e3fd5f331ce5fefa8e0e5560da411de17f2a8db))
- **addon**: Publish dev addon version 7.6.0.dev365 \[skip ci]
([`f3bf17b`](https://github.com/homeassistant-ai/ha-mcp/commit/f3bf17be132ebc67005c33a3c8fde85025d56809))
- Sync tool docs after merge \[skip ci]
([`5307b60`](https://github.com/homeassistant-ai/ha-mcp/commit/5307b608879154fccf67bc1894f61e97f26719c6))
- **addon**: Publish dev addon version 7.6.0.dev364 \[skip ci]
([`76ec1ae`](https://github.com/homeassistant-ai/ha-mcp/commit/76ec1aefab8e904abf620bf1c1130e5f5d0c4bd9))
- Sync tool docs after merge \[skip ci]
([`be864b5`](https://github.com/homeassistant-ai/ha-mcp/commit/be864b5d685f167334487d4fe83324afbb4999ca))
- **addon**: Publish dev addon version 7.6.0.dev363 \[skip ci]
([`da10c75`](https://github.com/homeassistant-ai/ha-mcp/commit/da10c75a248dcc19442e4db6f34f325683cb0a71))
- **addon**: Publish dev addon version 7.6.0.dev362 \[skip ci]
([`69f4527`](https://github.com/homeassistant-ai/ha-mcp/commit/69f45279707d18c724bd702ced46111b26cd000c))
- **addon**: Publish version 7.6.0 \[skip ci]
([`086d75d`](https://github.com/homeassistant-ai/ha-mcp/commit/086d75d72dd7d1c735413d96ef2fd38ae57b90ca))
##### Continuous Integration
- Vendor Puppet add-on as a pinned submodule + retry transient add-on builds
([#​1565](https://github.com/homeassistant-ai/ha-mcp/pull/1565))
- Make sync-tool-docs push resilient to concurrent master advances
([#​1564](https://github.com/homeassistant-ai/ha-mcp/pull/1564))
- Fix stale token-cap comment and harden triage budget tests ([#​1514](https://github.com/homeassistant-ai/ha-mcp/issues/1514))
([#​1560](https://github.com/homeassistant-ai/ha-mcp/pull/1560))
- **deps**: Bump the github-actions group with 2 updates
([#​1556](https://github.com/homeassistant-ai/ha-mcp/pull/1556))
- Budget triage prompt dynamically under the GitHub Models cap ([#​1514](https://github.com/homeassistant-ai/ha-mcp/issues/1514))
([#​1522](https://github.com/homeassistant-ai/ha-mcp/pull/1522))
- Reduce Docker Hub pulls in performance-tests workflow
([#​1549](https://github.com/homeassistant-ai/ha-mcp/pull/1549))
- Add JavaScript to the CodeQL code-quality gate
([#​1548](https://github.com/homeassistant-ai/ha-mcp/pull/1548))
- Add CodeQL code-quality CI gate and clear all code-quality findings
([#​1526](https://github.com/homeassistant-ai/ha-mcp/pull/1526))
- Drop tool list from evaluate prompt + tighten caps to fit 8K token limit
([`6f47c92`](https://github.com/homeassistant-ai/ha-mcp/commit/6f47c92507ef0d854153632107c0c702812f0c3c))
- Remove broken maintainer check (GITHUB\_TOKEN lacks read:org)
([`010ec58`](https://github.com/homeassistant-ai/ha-mcp/commit/010ec58d1f3b6d46b20aa83c3caee373dd826694))
- Switch evaluate step to gpt-4o-mini (16K token free tier vs 8K on gpt-4.1)
([#​1496](https://github.com/homeassistant-ai/ha-mcp/pull/1496))
- Issue bot v2 — GitHub Models triage, needs-info auto-close, duplicate detection
([#​1442](https://github.com/homeassistant-ai/ha-mcp/pull/1442))
##### Refactoring
- Extract settings-UI JavaScript and CSS to separate files
([#​1505](https://github.com/homeassistant-ai/ha-mcp/pull/1505))
- Collapse settings-UI route registration into one table
([#​1504](https://github.com/homeassistant-ai/ha-mcp/pull/1504))
##### Testing
- **oauth**: Add HTTP smoke tests for OAuth metadata-discovery endpoints
([#​1562](https://github.com/homeassistant-ai/ha-mcp/pull/1562))
- **uat**: Relabel c01 as a mode-discrimination probe (taxonomy consistency)
([#​1563](https://github.com/homeassistant-ai/ha-mcp/pull/1563))
- **uat**: Rework c01 routing probe to ha\_search registry-listing mode after [#​1529](https://github.com/homeassistant-ai/ha-mcp/issues/1529)
([#​1559](https://github.com/homeassistant-ai/ha-mcp/pull/1559))
- **uat**: Add response\_contains\_any check and always log agent responses
([#​1537](https://github.com/homeassistant-ai/ha-mcp/pull/1537))
- **uat**: Treat request timeout as per-story failure, not suite abort
([#​1536](https://github.com/homeassistant-ai/ha-mcp/pull/1536))
- **uat**: Harden BAT story runner against agent crashes
([#​1535](https://github.com/homeassistant-ai/ha-mcp/pull/1535))
- **uat**: Log model and quantization in BAT story results
([#​1525](https://github.com/homeassistant-ai/ha-mcp/pull/1525))
- Capture reasoning tokens and detect inert --no-think in BAT openai agent
([#​1524](https://github.com/homeassistant-ai/ha-mcp/pull/1524))
</details>
### [`v7.6.0`](https://github.com/homeassistant-ai/ha-mcp/blob/HEAD/CHANGELOG.md#v760-2026-05-27)
[Compare Source](https://github.com/homeassistant-ai/ha-mcp/compare/v7.5.0...v7.6.0)
##### Added
- Make HTTP bind host configurable via MCP\_HOST (closes [#​1434](https://github.com/homeassistant-ai/ha-mcp/issues/1434))
([#​1436](https://github.com/homeassistant-ai/ha-mcp/pull/1436))
- Tool Security Policies — per-tool approval gating ([#​966](https://github.com/homeassistant-ai/ha-mcp/issues/966))
([#​1421](https://github.com/homeassistant-ai/ha-mcp/pull/1421))
- Rename ha\_delete\_helpers\_integrations → ha\_remove\_helpers\_integrations + raise on missing target
([#​1424](https://github.com/homeassistant-ai/ha-mcp/pull/1424))
- Auto-backup edited entities before write/destructive tool calls (closes [#​1288](https://github.com/homeassistant-ai/ha-mcp/issues/1288))
([#​1403](https://github.com/homeassistant-ai/ha-mcp/pull/1403))
- Persistent settings UI for stdio mode
([#​1381](https://github.com/homeassistant-ai/ha-mcp/pull/1381))
- Add fields= projection to ha\_search\_entities, ha\_get\_overview, ha\_get\_state, ha\_get\_history, ha\_config\_list\_areas, ha\_list\_services ([#​1199](https://github.com/homeassistant-ai/ha-mcp/issues/1199))
([#​1225](https://github.com/homeassistant-ai/ha-mcp/pull/1225))
- Route entity-registration wait through WS events (closes [#​1152](https://github.com/homeassistant-ai/ha-mcp/issues/1152))
([#​1382](https://github.com/homeassistant-ai/ha-mcp/pull/1382))
- Add config subentry support
([#​1393](https://github.com/homeassistant-ai/ha-mcp/pull/1393))
- Add Assist pipeline management tool
([#​1392](https://github.com/homeassistant-ai/ha-mcp/pull/1392))
- Add knx to ha\_config\_set\_yaml allowlist
([#​1374](https://github.com/homeassistant-ai/ha-mcp/pull/1374))
- Extend automation\_id parity to set/remove automation responses
([#​1343](https://github.com/homeassistant-ai/ha-mcp/pull/1343))
- **haos-e2e**: Add parallel inaddon test tier (ha-mcp runs inside HAOS addon)
([#​1361](https://github.com/homeassistant-ai/ha-mcp/pull/1361))
- Expose integration diagnostics via ha\_get\_integration and ha\_get\_system\_health (closes [#​1148](https://github.com/homeassistant-ai/ha-mcp/issues/1148))
([#​1328](https://github.com/homeassistant-ai/ha-mcp/pull/1328))
- Return canonical script\_id from ha\_config\_get\_script ([#​1334](https://github.com/homeassistant-ai/ha-mcp/issues/1334))
([#​1352](https://github.com/homeassistant-ai/ha-mcp/pull/1352))
- Add automation\_id parity key to ha\_config\_get\_automation
([#​1329](https://github.com/homeassistant-ai/ha-mcp/pull/1329))
- Reject empty/whitespace identifiers on registry-metadata writes (closes [#​1294](https://github.com/homeassistant-ai/ha-mcp/issues/1294))
([#​1312](https://github.com/homeassistant-ai/ha-mcp/pull/1312))
- Add HA brand assets for custom integration
([#​1317](https://github.com/homeassistant-ai/ha-mcp/pull/1317))
- Unify ha\_config\_set\_helper response shape (closes [#​1293](https://github.com/homeassistant-ai/ha-mcp/issues/1293))
([#​1303](https://github.com/homeassistant-ai/ha-mcp/pull/1303))
- Mirror create-side validation guards onto update path (closes [#​1292](https://github.com/homeassistant-ai/ha-mcp/issues/1292))
([#​1304](https://github.com/homeassistant-ai/ha-mcp/pull/1304))
- Add array\_patch mode to ha\_manage\_addon for atomic GET-modify-POST
([#​1063](https://github.com/homeassistant-ai/ha-mcp/pull/1063))
##### Changed
- **agents**: Drop ha\_backup\_create + ha\_backup\_restore from accepted exceptions
([#​1445](https://github.com/homeassistant-ai/ha-mcp/pull/1445))
- Update contributors list \[contributors-updated]
([`c7665a6`](https://github.com/homeassistant-ai/ha-mcp/commit/c7665a6f5a08737d8fcbebbbe6afdc88ec5c4901))
- **overview**: Enumerate dismissed\_repair\_count in fields= description + static drift test
([#​1411](https://github.com/homeassistant-ai/ha-mcp/pull/1411))
- Credit [@​tomwilkie](https://github.com/tomwilkie) and six other contributors in README
([#​1400](https://github.com/homeassistant-ai/ha-mcp/pull/1400))
- **[#​1157](https://github.com/homeassistant-ai/ha-mcp/issues/1157)**: Bump skills-vendor + auto-update via Renovate + native for: field + scrub eval\_template anti-patterns
([#​1383](https://github.com/homeassistant-ai/ha-mcp/pull/1383))
- Extend Boy Scout weasel-phrase list with common variants; clarify semantic match
([#​1373](https://github.com/homeassistant-ai/ha-mcp/pull/1373))
- Merge Boy Scout Rule + Handling Discovered Improvements; tighten deferral gate
([#​1359](https://github.com/homeassistant-ai/ha-mcp/pull/1359))
- Categorize Issue Labels table and document 6 reverse-drift labels
([#​1335](https://github.com/homeassistant-ai/ha-mcp/pull/1335))
- Strip stale L-refs from test\_identifier\_validation\_family docstrings
([#​1324](https://github.com/homeassistant-ai/ha-mcp/pull/1324))
- Align label refs with live label set and fix triaged-removal trigger
([#​1316](https://github.com/homeassistant-ai/ha-mcp/pull/1316))
- Surface tool-discovery / categorized search
([#​1123](https://github.com/homeassistant-ai/ha-mcp/pull/1123))
- Fix two stale ha\_get\_skill\_guide references missed in [#​1289](https://github.com/homeassistant-ai/ha-mcp/issues/1289)
([#​1305](https://github.com/homeassistant-ai/ha-mcp/pull/1305))
- Clarify setup wizard placeholders need braces removed ([#​1284](https://github.com/homeassistant-ai/ha-mcp/issues/1284))
([#​1286](https://github.com/homeassistant-ai/ha-mcp/pull/1286))
##### Fixed
- Remove counter from ha\_reload\_core targets ([#​1453](https://github.com/homeassistant-ai/ha-mcp/issues/1453))
([#​1456](https://github.com/homeassistant-ai/ha-mcp/pull/1456))
- **backup**: Post-timeout match correctness + state-gate (closes [#​1433](https://github.com/homeassistant-ai/ha-mcp/issues/1433))
([#​1435](https://github.com/homeassistant-ai/ha-mcp/pull/1435))
- Sync addon settings UI with Supervisor options end-to-end
([#​1420](https://github.com/homeassistant-ai/ha-mcp/pull/1420))
- **calendar**: Switch ha\_config\_remove\_calendar\_event to WebSocket (closes [#​1413](https://github.com/homeassistant-ai/ha-mcp/issues/1413), [#​1416](https://github.com/homeassistant-ai/ha-mcp/issues/1416))
([#​1418](https://github.com/homeassistant-ai/ha-mcp/pull/1418))
- Error-shape consistency for non-entity not-found (closes [#​1297](https://github.com/homeassistant-ai/ha-mcp/issues/1297))
([#​1397](https://github.com/homeassistant-ai/ha-mcp/pull/1397))
- Guard against silent automation overwrite on id mismatch ([#​1404](https://github.com/homeassistant-ai/ha-mcp/issues/1404))
([#​1405](https://github.com/homeassistant-ai/ha-mcp/pull/1405))
- Cache YAML instance to prevent CPU spikes in bulk edits ([#​1370](https://github.com/homeassistant-ai/ha-mcp/issues/1370))
([#​1371](https://github.com/homeassistant-ai/ha-mcp/pull/1371))
- **client**: Route get\_error\_log via hassio proxy on external-HAOS clients
([#​1360](https://github.com/homeassistant-ai/ha-mcp/pull/1360))
- Classify dashboard 404s ("unknown config specified") as RESOURCE\_NOT\_FOUND
([#​1345](https://github.com/homeassistant-ai/ha-mcp/pull/1345))
- Detect HA addon installs as http transport, not stdio ([#​1322](https://github.com/homeassistant-ai/ha-mcp/issues/1322))
([#​1327](https://github.com/homeassistant-ai/ha-mcp/pull/1327))
- Actionable 403 suggestion when addon has unmapped container ports ([#​1319](https://github.com/homeassistant-ai/ha-mcp/issues/1319))
([#​1325](https://github.com/homeassistant-ai/ha-mcp/pull/1325))
- Filter dismissed repairs in overview and system\_health ([#​1307](https://github.com/homeassistant-ai/ha-mcp/issues/1307))
([#​1309](https://github.com/homeassistant-ai/ha-mcp/pull/1309))
- Exit on HA container death + daily reset before CI check
([#​1295](https://github.com/homeassistant-ai/ha-mcp/pull/1295))
- Align ha\_config\_set\_dashboard with sibling re-fetch-after-save pattern ([#​1291](https://github.com/homeassistant-ai/ha-mcp/issues/1291))
([#​1301](https://github.com/homeassistant-ai/ha-mcp/pull/1301))
- Allow str.replace in python\_transform; hint at search mode on IndexError
([#​1287](https://github.com/homeassistant-ai/ha-mcp/pull/1287))
- **array\_patch**: Tighten validation and surface silent failures
([#​1285](https://github.com/homeassistant-ai/ha-mcp/pull/1285))
- HA Core proxy fallback for ha\_get\_logs(source=system\_service) on non-addon installs
([#​1283](https://github.com/homeassistant-ai/ha-mcp/pull/1283))
##### Performance Improvements
- Tighten \_poll\_for\_automation\_entity first-poll cadence
([#​1384](https://github.com/homeassistant-ai/ha-mcp/pull/1384))
- Parallelize ha\_get\_system\_health optional sections via asyncio.gather
([#​1336](https://github.com/homeassistant-ai/ha-mcp/pull/1336))
##### Refactoring
- **service**: Compact ha\_call\_service result default ([#​1446](https://github.com/homeassistant-ai/ha-mcp/issues/1446))
([#​1447](https://github.com/homeassistant-ai/ha-mcp/pull/1447))
- Rename ha\_update\_device → ha\_set\_device
([#​1444](https://github.com/homeassistant-ai/ha-mcp/pull/1444))
- Remove duplicate flat area/floor list tools (consolidation followup to [#​1016](https://github.com/homeassistant-ai/ha-mcp/issues/1016))
([#​1429](https://github.com/homeassistant-ai/ha-mcp/pull/1429))
- **complexity**: Migrate tools\_utility.py to class-based pattern
([#​1423](https://github.com/homeassistant-ai/ha-mcp/pull/1423))
- **complexity**: Reduce C901 violations in tools/ — batch 4
([#​1408](https://github.com/homeassistant-ai/ha-mcp/pull/1408))
- Route \_poll\_for\_automation\_entity through WS event waiter (closes [#​1395](https://github.com/homeassistant-ai/ha-mcp/issues/1395))
([#​1406](https://github.com/homeassistant-ai/ha-mcp/pull/1406))
- **yaml**: Use threading.local subclass for cached instance
([#​1396](https://github.com/homeassistant-ai/ha-mcp/pull/1396))
- Align dashboards 404 shape with sibling config tools
([#​1386](https://github.com/homeassistant-ai/ha-mcp/pull/1386))
- Complete singular warning → warnings list migration repo-wide (closes [#​1332](https://github.com/homeassistant-ai/ha-mcp/issues/1332))
([#​1341](https://github.com/homeassistant-ai/ha-mcp/pull/1341))
- Complete warnings-list migration for lifecycle-write tools
([#​1340](https://github.com/homeassistant-ai/ha-mcp/pull/1340))
- Drop redundant identifier echo key from ha\_config\_get\_automation
([#​1354](https://github.com/homeassistant-ai/ha-mcp/pull/1354))
- Drop logger.error in config-tool except blocks ([#​1302](https://github.com/homeassistant-ai/ha-mcp/issues/1302))
([#​1353](https://github.com/homeassistant-ai/ha-mcp/pull/1353))
- Extend validate\_identifier\_not\_empty to automations/scripts/dashboards CRUD (closes [#​1313](https://github.com/homeassistant-ai/ha-mcp/issues/1313))
([#​1321](https://github.com/homeassistant-ai/ha-mcp/pull/1321))
- Migrate tools\_config\_scenes inline empty-id guards to shared helper
([#​1320](https://github.com/homeassistant-ai/ha-mcp/pull/1320))
- Remove ha\_get\_helper\_schema (closes [#​1186](https://github.com/homeassistant-ai/ha-mcp/issues/1186))
([#​1315](https://github.com/homeassistant-ai/ha-mcp/pull/1315))
- Consolidate skill tools; fix stable submodule packaging
([#​1289](https://github.com/homeassistant-ai/ha-mcp/pull/1289))
- Align tools\_config\_automations.py error-handling with sibling pattern ([#​1290](https://github.com/homeassistant-ai/ha-mcp/issues/1290))
([#​1298](https://github.com/homeassistant-ai/ha-mcp/pull/1298))
***
<details>
<summary>Internal Changes</summary>
##### Fixed
- **ci**: Install libguestfs in HAOS publish workflow
([#​1358](https://github.com/homeassistant-ai/ha-mcp/pull/1358))
##### Build System
- **deps**: Bump esbuild from 0.24.2 to 0.25.0 in /tests/js
([#​1427](https://github.com/homeassistant-ai/ha-mcp/pull/1427))
- **deps**: Bump devalue from 5.6.4 to 5.8.1 in /site
([#​1282](https://github.com/homeassistant-ai/ha-mcp/pull/1282))
- **deps**: Bump astro from 6.1.6 to 6.1.10 in /site
([#​1274](https://github.com/homeassistant-ai/ha-mcp/pull/1274))
##### Chores
- **addon**: Publish dev addon version 7.5.0.dev360 \[skip ci]
([`ad7aed1`](https://github.com/homeassistant-ai/ha-mcp/commit/ad7aed13d6843967e2a259ae46fec2bbc6abc896))
- Sync tool docs after merge \[skip ci]
([`9c4984f`](https://github.com/homeassistant-ai/ha-mcp/commit/9c4984fc44d30c15a96372fbc1b401fbd679dc8f))
- **deps**: Update ghcr.io/home-assistant/home-assistant docker tag to v2026.5.4
([#​1450](https://github.com/homeassistant-ai/ha-mcp/pull/1450))
- **addon**: Publish dev addon version 7.5.0.dev359 \[skip ci]
([`b82d4ee`](https://github.com/homeassistant-ai/ha-mcp/commit/b82d4eea85792b620368d4859e99c143f9fbfadf))
- **deps**: Update ghcr.io/astral-sh/uv docker tag to v0.11.16
([#​1449](https://github.com/homeassistant-ai/ha-mcp/pull/1449))
- **addon**: Publish dev addon version 7.5.0.dev358 \[skip ci]
([`53fba6d`](https://github.com/homeassistant-ai/ha-mcp/commit/53fba6da76ce8c78a0de035883233a36762601bc))
- Sync tool docs after merge \[skip ci]
([`dc7750d`](https://github.com/homeassistant-ai/ha-mcp/commit/dc7750de16b60f70e40e6e5c8908d9e84e544683))
- **addon**: Publish dev addon version 7.5.0.dev357 \[skip ci]
([`fd150c9`](https://github.com/homeassistant-ai/ha-mcp/commit/fd150c9b9c4bdb9026e67eae340226c36b270d94))
- **addon**: Publish dev addon version 7.5.0.dev356 \[skip ci]
([`5fa1463`](https://github.com/homeassistant-ai/ha-mcp/commit/5fa14630229ba0d6b97d9328768e247bf9c20af4))
- **addon**: Publish dev addon version 7.5.0.dev355 \[skip ci]
([`174ac5d`](https://github.com/homeassistant-ai/ha-mcp/commit/174ac5dca7667702cd664420c50e0101366e6c3a))
- **addon**: Publish dev addon version 7.5.0.dev354 \[skip ci]
([`4f93989`](https://github.com/homeassistant-ai/ha-mcp/commit/4f939892dea2d1951541b1a557c51e957f6751c0))
- **addon**: Publish dev addon version 7.5.0.dev353 \[skip ci]
([`53f282f`](https://github.com/homeassistant-ai/ha-mcp/commit/53f282f19ee736637106f5baececa3939393778e))
- **addon**: Publish dev addon version 7.5.0.dev352 \[skip ci]
([`4911d46`](https://github.com/homeassistant-ai/ha-mcp/commit/4911d4682c4a865a93a8e821bc86bd26cef0ed5a))
- Sync tool docs after merge \[skip ci]
([`8a79837`](https://github.com/homeassistant-ai/ha-mcp/commit/8a798373a7b2f1adb94b93e65d626ab582c7bd5d))
- **addon**: Publish dev addon version 7.5.0.dev351 \[skip ci]
([`13afa9d`](https://github.com/homeassistant-ai/ha-mcp/commit/13afa9df026dd27332277140c34f7d41d0229efd))
- **addon**: Publish dev addon version 7.5.0.dev350 \[skip ci]
([`e93d680`](https://github.com/homeassistant-ai/ha-mcp/commit/e93d6806025c6d7fd2ef94c509a607c4ac85c8e0))
- **addon**: Publish dev addon version 7.5.0.dev349 \[skip ci]
([`1631ad1`](https://github.com/homeassistant-ai/ha-mcp/commit/1631ad10bdada4487d7b54049e92df6ddb29439a))
- **addon**: Publish dev addon version 7.5.0.dev348 \[skip ci]
([`18a8aef`](https://github.com/homeassistant-ai/ha-mcp/commit/18a8aef50675c1a881b279666e0af1b093679850))
- Sync tool docs after merge \[skip ci]
([`9e0493d`](https://github.com/homeassistant-ai/ha-mcp/commit/9e0493d248e23a8042841e90847662926395a448))
- **addon**: Publish dev addon version 7.5.0.dev347 \[skip ci]
([`e2067e4`](https://github.com/homeassistant-ai/ha-mcp/commit/e2067e446b127097e61d07516ae0e742ae2de6c8))
- Sync tool docs after merge \[skip ci]
([`7bdb3d4`](https://github.com/homeassistant-ai/ha-mcp/commit/7bdb3d402b60900a1012b8269e52b7cbeb400f84))
- **addon**: Publish dev addon version 7.5.0.dev346 \[skip ci]
([`c2d4dd7`](https://github.com/homeassistant-ai/ha-mcp/commit/c2d4dd7091653a618326f665fd34b5458d26c8f6))
- Sync tool docs after merge \[skip ci]
([`393b354`](https://github.com/homeassistant-ai/ha-mcp/commit/393b354e8a8e1280029eee9521971c693526970a))
- **addon**: Publish dev addon version 7.5.0.dev345 \[skip ci]
([`42ede8b`](https://github.com/homeassistant-ai/ha-mcp/commit/42ede8b0e6066faf3ed6f6920629a8d94d77f69a))
- **addon**: Publish dev addon version 7.5.0.dev344 \[skip ci]
([`e6cc7a1`](https://github.com/homeassistant-ai/ha-mcp/commit/e6cc7a1b8ed252f1aaa2b8c964e56c97a27b94c2))
- Sync tool docs after merge \[skip ci]
([`fb35f30`](https://github.com/homeassistant-ai/ha-mcp/commit/fb35f305cbf7de6807c29bd3ada9da2f028ff730))
- **addon**: Publish dev addon version 7.5.0.dev343 \[skip ci]
([`401b7b4`](https://github.com/homeassistant-ai/ha-mcp/commit/401b7b4d707dbb3c56a3afecad9e9d22ecbc7d1e))
- **addon**: Publish dev addon version 7.5.0.dev342 \[skip ci]
([`0679371`](https://github.com/homeassistant-ai/ha-mcp/commit/06793710b04a985ed0d66861266b9b79494e4111))
- Sync tool docs after merge \[skip ci]
([`f6796ec`](https://github.com/homeassistant-ai/ha-mcp/commit/f6796ec19b4596455ff54b58746bd3e075d5d280))
- **addon**: Publish dev addon version 7.5.0.dev341 \[skip ci]
([`3654478`](https://github.com/homeassistant-ai/ha-mcp/commit/3654478f80428d15671e49162acecea19d67f672))
- **addon**: Publish dev addon version 7.5.0.dev340 \[skip ci]
([`64f00b6`](https://github.com/homeassistant-ai/ha-mcp/commit/64f00b658846cad0e0714f37d221fb65327015cf))
- **addon**: Publish dev addon version 7.5.0.dev339 \[skip ci]
([`d6e8873`](https://github.com/homeassistant-ai/ha-mcp/commit/d6e88731556464deb768524dc24c90fd0a622a96))
- Sync tool docs after merge \[skip ci]
([`7525e93`](https://github.com/homeassistant-ai/ha-mcp/commit/7525e930a872871fed78f9b1461aea8e78eb5ad7))
- **addon**: Publish dev addon version 7.5.0.dev338 \[skip ci]
([`288ca4a`](https://github.com/homeassistant-ai/ha-mcp/commit/288ca4abd00b2b366cbaf671c1ace3398cc8f2fd))
- **addon**: Publish dev addon version 7.5.0.dev337 \[skip ci]
([`f539ae5`](https://github.com/homeassistant-ai/ha-mcp/commit/f539ae5aa881853d831e6952ff3af8bc85eb8b2a))
- **addon**: Publish dev addon version 7.5.0.dev336 \[skip ci]
([`5568a86`](https://github.com/homeassistant-ai/ha-mcp/commit/5568a861002cfb909e29368bd4e93ef0bd2e4c03))
- **addon**: Publish dev addon version 7.5.0.dev335 \[skip ci]
([`e069405`](https://github.com/homeassistant-ai/ha-mcp/commit/e0694054bd8627f6464379c34c1e3eec5b080a44))
- **addon**: Publish dev addon version 7.5.0.dev334 \[skip ci]
([`f7be6ea`](https://github.com/homeassistant-ai/ha-mcp/commit/f7be6ead486a32840a935a1e5ec78a34f8003c0d))
- **addon**: Publish dev addon version 7.5.0.dev333 \[skip ci]
([`cb480ea`](https://github.com/homeassistant-ai/ha-mcp/commit/cb480eae4d855345c19a6465351e0bdef2bdf5c3))
- Sync tool docs after merge \[skip ci]
([`9a5bc3c`](https://github.com/homeassistant-ai/ha-mcp/commit/9a5bc3c61372159bb936d7b929166924343dc76f))
- **addon**: Publish dev addon version 7.5.0.dev332 \[skip ci]
([`e0e59ee`](https://github.com/homeassistant-ai/ha-mcp/commit/e0e59ee08072bb4aac51e90928fab2d68f6156ce))
- Sync tool docs after merge \[skip ci]
([`499ebf0`](https://github.com/homeassistant-ai/ha-mcp/commit/499ebf0c9d4c4ec3784dd72782fe301cd9c19d60))
- **addon**: Publish dev addon version 7.5.0.dev331 \[skip ci]
([`3e0ce92`](https://github.com/homeassistant-ai/ha-mcp/commit/3e0ce92e11777a8fd9c86153e4c248007b8edae9))
- **addon**: Publish dev addon version 7.5.0.dev330 \[skip ci]
([`e48d056`](https://github.com/homeassistant-ai/ha-mcp/commit/e48d056ab356e11f8b2952b6c675307d1e76a895))
- **deps**: Update ghcr.io/astral-sh/uv docker tag to v0.11.15
([#​1376](https://github.com/homeassistant-ai/ha-mcp/pull/1376))
- **deps**: Update ghcr.io/home-assistant/home-assistant docker tag to v2026.5.3
([#​1377](https://github.com/homeassistant-ai/ha-mcp/pull/1377))
- **addon**: Publish dev addon version 7.5.0.dev329 \[skip ci]
([`c523c50`](https://github.com/homeassistant-ai/ha-mcp/commit/c523c502c5c6f282905620d3db489e9c69ec2472))
- Sync tool docs after merge \[skip ci]
([`5b7a8aa`](https://github.com/homeassistant-ai/ha-mcp/commit/5b7a8aa0794359a90d7b89a9cc61d73d8cf038d2))
- **addon**: Publish dev addon version 7.5.0.dev328 \[skip ci]
([`6c42fba`](https://github.com/homeassistant-ai/ha-mcp/commit/6c42fba92d4786d7498f738c53dfe50c899d0890))
- **addon**: Publish dev addon version 7.5.0.dev327 \[skip ci]
([`aecd025`](https://github.com/homeassistant-ai/ha-mcp/commit/aecd025eeea3d1edcd9466db3720cb17de71b90a))
- **addon**: Publish dev addon version 7.5.0.dev326 \[skip ci]
([`399c17c`](https://github.com/homeassistant-ai/ha-mcp/commit/399c17c36602a7767491df6e317186cb6291f3e4))
- **addon**: Publish dev addon version 7.5.0.dev325 \[skip ci]
([`b580b45`](https://github.com/homeassistant-ai/ha-mcp/commit/b580b452e9007deb33acc49098238988aa768603))
- Sync tool docs after merge \[skip ci]
([`8567c3a`](https://github.com/homeassistant-ai/ha-mcp/commit/8567c3a6e66e7bebbbad8e96b94058f8456deb14))
- **addon**: Publish dev addon version 7.5.0.dev324 \[skip ci]
([`a65579d`](https://github.com/homeassistant-ai/ha-mcp/commit/a65579d0b6e4a8bb7f8c1ed97fd432cd770c47a4))
- **addon**: Publish dev addon version 7.5.0.dev323 \[skip ci]
([`c7667ba`](https://github.com/homeassistant-ai/ha-mcp/commit/c7667ba66538f1ba8a06b7616fb15896bf021744))
- **addon**: Publish dev addon version 7.5.0.dev322 \[skip ci]
([`44d15a8`](https://github.com/homeassistant-ai/ha-mcp/commit/44d15a89cbacc2c38ab39868b380414507a6708b))
- **addon**: Publish dev addon version 7.5.0.dev321 \[skip ci]
([`8739f6c`](https://github.com/homeassistant-ai/ha-mcp/commit/8739f6c09121c88a596470df293ac8e7e0f1050a))
- **addon**: Publish dev addon version 7.5.0.dev320 \[skip ci]
([`02b6e47`](https://github.com/homeassistant-ai/ha-mcp/commit/02b6e47f8eb6c778f709d7adca115638c2fe98a2))
- Sync tool docs after merge \[skip ci]
([`ab68c9a`](https://github.com/homeassistant-ai/ha-mcp/commit/ab68c9a9aa94ac6861af7b59997ec679f1849503))
- **addon**: Publish dev addon version 7.5.0.dev319 \[skip ci]
([`4472904`](https://github.com/homeassistant-ai/ha-mcp/commit/44729040c11af0bd97189080c1ec59995fc563b4))
- **addon**: Publish dev addon version 7.5.0.dev318 \[skip ci]
([`e030dbc`](https://github.com/homeassistant-ai/ha-mcp/commit/e030dbcc99e002751834274b1d53da161ab27759))
- **addon**: Publish dev addon version 7.5.0.dev317 \[skip ci]
([`d87855c`](https://github.com/homeassistant-ai/ha-mcp/commit/d87855cf07cef9d9d7babf0bbec74d228149327d))
- Sync tool docs after merge \[skip ci]
([`a72a4e8`](https://github.com/homeassistant-ai/ha-mcp/commit/a72a4e8c0de99a8516f3820545642c37a31c17e5))
- **addon**: Publish dev addon version 7.5.0.dev316 \[skip ci]
([`bd9397f`](https://github.com/homeassistant-ai/ha-mcp/commit/bd9397f3a088a24a14af66a97afcf1c97904ef61))
- **addon**: Publish dev addon version 7.5.0.dev315 \[skip ci]
([`264bfc2`](https://github.com/homeassistant-ai/ha-mcp/commit/264bfc2fcb5ef6fe3ee6f9e073b69e0469eeafdd))
- **addon**: Publish dev addon version 7.5.0.dev314 \[skip ci]
([`df62881`](https://github.com/homeassistant-ai/ha-mcp/commit/df6288194cdde8b625132f19b0dd3edb2142a2b3))
- **addon**: Publish dev addon version 7.5.0.dev313 \[skip ci]
([`f6c47ca`](https://github.com/homeassistant-ai/ha-mcp/commit/f6c47caa21b0d82799b2be9330f97aa5494aa3c8))
- **addon**: Publish dev addon version 7.5.0.dev312 \[skip ci]
([`2bb7a74`](https://github.com/homeassistant-ai/ha-mcp/commit/2bb7a74f06e0652a729a735b08fc7cdc20a034f6))
- Sync tool docs after merge \[skip ci]
([`137e279`](https://github.com/homeassistant-ai/ha-mcp/commit/137e27943b1b704fe1d3e3a5b525b4d82bce33eb))
- **addon**: Publish dev addon version 7.5.0.dev311 \[skip ci]
([`28324ea`](https://github.com/homeassistant-ai/ha-mcp/commit/28324ea4a92fbf61f5ee40c561286c466af2309a))
- Sync tool docs after merge \[skip ci]
([`9a753d4`](https://github.com/homeassistant-ai/ha-mcp/commit/9a753d49abb4ccd84e874451dbcc563260f9e19d))
- **addon**: Publish dev addon version 7.5.0.dev310 \[skip ci]
([`f893b2e`](https://github.com/homeassistant-ai/ha-mcp/commit/f893b2ebf91967d0e2548f9205a15bfe0e7d86c2))
- **addon**: Publish dev addon version 7.5.0.dev309 \[skip ci]
([`8cbdb7b`](https://github.com/homeassistant-ai/ha-mcp/commit/8cbdb7bf318707fed1a0b3e8cb9922e6c170521e))
- **addon**: Publish dev addon version 7.5.0.dev308 \[skip ci]
([`2d18016`](https://github.com/homeassistant-ai/ha-mcp/commit/2d18016de8eb26a18cfb471e7b5f755f1309bd36))
- **addon**: Publish dev addon version 7.5.0.dev307 \[skip ci]
([`3fc3b28`](https://github.com/homeassistant-ai/ha-mcp/commit/3fc3b28881f237df02da8b65467fba9a7d693009))
- Sync tool docs after merge \[skip ci]
([`9e6cff8`](https://github.com/homeassistant-ai/ha-mcp/commit/9e6cff8f641bcd8122e94fc8be9c30aa18456e80))
- **addon**: Publish dev addon version 7.5.0.dev306 \[skip ci]
([`8bdd0fc`](https://github.com/homeassistant-ai/ha-mcp/commit/8bdd0fca9c107f45e4c3719e7616984b68876a9e))
- **addon**: Publish dev addon version 7.5.0.dev305 \[skip ci]
([`83535b9`](https://github.com/homeassistant-ai/ha-mcp/commit/83535b99e190fb56b7ce227334331ebf2affb3e1))
- **addon**: Publish dev addon version 7.5.0.dev304 \[skip ci]
([`1435b3a`](https://github.com/homeassistant-ai/ha-mcp/commit/1435b3a24d73503e189b83f8ea5aaeea20d9ebf3))
- **addon**: Publish dev addon version 7.5.0.dev303 \[skip ci]
([`e2da659`](https://github.com/homeassistant-ai/ha-mcp/commit/e2da6591d6ad2def0b48a9be750cb8a41f40524d))
- Sync tool docs after merge \[skip ci]
([`23789fa`](https://github.com/homeassistant-ai/ha-mcp/commit/23789fa978591b7d3966894082a2683ca6a6ae3b))
- **addon**: Publish dev addon version 7.5.0.dev302 \[skip ci]
([`6c8e574`](https://github.com/homeassistant-ai/ha-mcp/commit/6c8e574e7e3d8d78b3a2e48f6a70531d7a95eed8))
- Sync tool docs after merge \[skip ci]
([`d2329cb`](https://github.com/homeassistant-ai/ha-mcp/commit/d2329cbff39891d209317528fd7b42759c3414a8))
- **addon**: Publish dev addon version 7.5.0.dev301 \[skip ci]
([`bb538f7`](https://github.com/homeassistant-ai/ha-mcp/commit/bb538f70d2fc57072f09cfc6202e9d3dc1a2d257))
- Sync tool docs after merge \[skip ci]
([`f70f0e1`](https://github.com/homeassistant-ai/ha-mcp/commit/f70f0e14222b29a8923e706f113d1fafb4a5c23e))
- **addon**: Publish version 7.5.0 \[skip ci]
([`9c5eb37`](https://github.com/homeassistant-ai/ha-mcp/commit/9c5eb37779236ef19366a2a59a667d3916458e5a))
##### Continuous Integration
- **deps**: Bump actions/upload-artifact in the github-actions group
([#​1437](https://github.com/homeassistant-ai/ha-mcp/pull/1437))
- Share qcow2 cache + GHCR fallback between HAOS lanes
([#​1407](https://github.com/homeassistant-ai/ha-mcp/pull/1407))
- Add ruff format --check on changed Python files
([#​1387](https://github.com/homeassistant-ai/ha-mcp/pull/1387))
- Exempt assigned issues from stale bot
([#​1368](https://github.com/homeassistant-ai/ha-mcp/pull/1368))
- **deps**: Bump the github-actions group with 3 updates
([#​1362](https://github.com/homeassistant-ai/ha-mcp/pull/1362))
##### Refactoring
- Consolidate lovelace/dashboards/list through shared helper
([#​1344](https://github.com/homeassistant-ai/ha-mcp/pull/1344))
##### Testing
- **haos-e2e**: Bake + install webhook-proxy addon and exercise its runtime
([#​1443](https://github.com/homeassistant-ai/ha-mcp/pull/1443))
- **config-subentry**: Mark forecast\_solar e2e as known flaky + relative-import sweep
([#​1430](https://github.com/homeassistant-ai/ha-mcp/pull/1430))
- **haos-e2e**: Trim cache-save race, compress GHCR qcow2, eval boot snapshot
([#​1428](https://github.com/homeassistant-ai/ha-mcp/pull/1428))
- JSDOM behaviour harness + auto-discovery parse coverage for every rendered <script>
([#​1425](https://github.com/homeassistant-ai/ha-mcp/pull/1425))
- **hacs**: Retry TestMcpToolsInstallation on flake
([#​1426](https://github.com/homeassistant-ai/ha-mcp/pull/1426))
- **e2e**: Drop redundant lifecycle roundtrips, keep only Matter Server ([#​1414](https://github.com/homeassistant-ai/ha-mcp/issues/1414))
([#​1419](https://github.com/homeassistant-ai/ha-mcp/pull/1419))
- **e2e**: Assert backend dispatch matches workflow env on every lane
([#​1409](https://github.com/homeassistant-ai/ha-mcp/pull/1409))
- Escape ideographic space and format file ([#​1237](https://github.com/homeassistant-ai/ha-mcp/issues/1237))
([#​1410](https://github.com/homeassistant-ai/ha-mcp/pull/1410))
- **e2e**: Measure \_POLL\_CADENCE p50/p99 to validate or retune (closes [#​1389](https://github.com/homeassistant-ai/ha-mcp/issues/1389))
([#​1398](https://github.com/homeassistant-ai/ha-mcp/pull/1398))
- **e2e**: Wait for addon state=started in haos proxy header test
([#​1402](https://github.com/homeassistant-ai/ha-mcp/pull/1402))
- Pin remaining \_classify\_by\_message branches
([#​1385](https://github.com/homeassistant-ai/ha-mcp/pull/1385))
- **haos-e2e**: Slim addon set + real-addon ha\_manage\_addon coverage (closes [#​1350](https://github.com/homeassistant-ai/ha-mcp/issues/1350))
([#​1379](https://github.com/homeassistant-ai/ha-mcp/pull/1379))
- **haos-e2e**: Close out [#​1349](https://github.com/homeassistant-ai/ha-mcp/issues/1349) — lifecycle, integrations, supervisor\_mock migration, no more skips
([#​1375](https://github.com/homeassistant-ai/ha-mcp/pull/1375))
- **e2e**: Consolidate readiness gates onto /api/core/state (refs [#​366](https://github.com/homeassistant-ai/ha-mcp/issues/366))
([#​1372](https://github.com/homeassistant-ai/ha-mcp/pull/1372))
- **e2e**: Tighten 5 readiness-gate budgets with 2-63x headroom (refs [#​366](https://github.com/homeassistant-ai/ha-mcp/issues/366))
([#​1369](https://github.com/homeassistant-ai/ha-mcp/pull/1369))
- Scaffold HAOS E2E tier image-build pipeline (refs [#​1281](https://github.com/homeassistant-ai/ha-mcp/issues/1281))
([#​1326](https://github.com/homeassistant-ai/ha-mcp/pull/1326))
- **e2e**: Instrument HA\_MCP\_TOOLS\_WAIT readiness gate (refs [#​366](https://github.com/homeassistant-ai/ha-mcp/issues/366))
([#​1346](https://github.com/homeassistant-ai/ha-mcp/pull/1346))
- **e2e**: Centralize wait\_for\_entity\_registration helper (refs [#​366](https://github.com/homeassistant-ai/ha-mcp/issues/366))
([#​1308](https://github.com/homeassistant-ai/ha-mcp/pull/1308))
- **e2e**: Unify dict-error message extraction across e2e tests (refs [#​366](https://github.com/homeassistant-ai/ha-mcp/issues/366))
([#​1311](https://github.com/homeassistant-ai/ha-mcp/pull/1311))
- **e2e**: Surface readiness-gate elapsed times in CI logs (refs [#​366](https://github.com/homeassistant-ai/ha-mcp/issues/366))
([#​1310](https://github.com/homeassistant-ai/ha-mcp/pull/1310))
</details>
</details>
---
### Configuration
📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).
🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.
♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.
🔕 **Ignore**: Close this PR and you won't be reminded about these updates again.
---
- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box
---
This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4xMDEuMSIsInVwZGF0ZWRJblZlciI6IjQzLjEwMS4xIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJyZW5vdmF0ZS9jb250YWluZXIiLCJ0eXBlL21pbm9yIl19-->
Reviewed-on: https://git.erwanleboucher.dev/eleboucher/homelab/pulls/994
…➔ 7.7.0) (#243) This PR contains the following updates: | Package | Update | Change | |---|---|---| | [ghcr.io/homeassistant-ai/ha-mcp](https://github.com/homeassistant-ai/ha-mcp) | minor | `7.6.0` → `7.7.0` | --- ### Release Notes <details> <summary>homeassistant-ai/ha-mcp (ghcr.io/homeassistant-ai/ha-mcp)</summary> ### [`v7.7.0`](https://github.com/homeassistant-ai/ha-mcp/blob/HEAD/CHANGELOG.md#v770-2026-06-10) [Compare Source](homeassistant-ai/ha-mcp@v7.6.0...v7.7.0) ##### Added - User-configurable custom filesystem directories for the file tools (closes [#​1567](homeassistant-ai/ha-mcp#1567)) ([#​1568](homeassistant-ai/ha-mcp#1568)) - Expose all user-tunable env vars in the settings UI (add-on parity) ([#​1554](homeassistant-ai/ha-mcp#1554)) - Warn when default MCP\_SECRET\_PATH is bound non-loopback ([#​1472](homeassistant-ai/ha-mcp#1472)) - **search**: Consolidate ha\_search\_entities + ha\_deep\_search into ha\_search ([#​1529](homeassistant-ai/ha-mcp#1529)) - **addon**: Install the MCP Server add-on from the ha\_mcp\_tools integration ([#​1528](homeassistant-ai/ha-mcp#1528)) - Add opt-in dashboard screenshot mode ([#​1510](homeassistant-ai/ha-mcp#1510)) - Add Linux support for install & docs ([#​1096](homeassistant-ai/ha-mcp#1096)) - Surface the web settings page for non-add-on installs ([#​1458](homeassistant-ai/ha-mcp#1458)) ([#​1511](homeassistant-ai/ha-mcp#1511)) - Convert Pydantic arg-validation errors to actionable ToolErrors ([#​1491](homeassistant-ai/ha-mcp#1491)) - Per-key toggles for automation/script/scene in packages/\*.yaml ([#​1476](homeassistant-ai/ha-mcp#1476)) - Direct skills retrieval for write tools + improved best practice checker warnings with embedded skills responses ([#​1182](homeassistant-ai/ha-mcp#1182)) ([#​1448](homeassistant-ai/ha-mcp#1448)) - Detect last\_changed/last\_updated duration math and suggest for: field ([#​1157](homeassistant-ai/ha-mcp#1157)) ([#​1264](homeassistant-ai/ha-mcp#1264)) - Advanced settings panel + nested beta master toggle ([#​1164](homeassistant-ai/ha-mcp#1164)) ([#​1431](homeassistant-ai/ha-mcp#1431)) - Allow automation/script/scene yaml\_path in packages/\*.yaml only ([#​1452](homeassistant-ai/ha-mcp#1452)) - Restrict ha\_mcp\_tools services to ha-mcp callers (caller token + ha\_call\_service refusal) ([#​1459](homeassistant-ai/ha-mcp#1459)) ##### Changed - **security**: Soften vulnerability-response SLA to best-effort ([`a24e7da`](homeassistant-ai/ha-mcp@a24e7da)) - Update contributors list \[contributors-updated] ([`7cc187f`](homeassistant-ai/ha-mcp@7cc187f)) - Telemetry wording — follow HA analytics setting, not opt-in-only ([#​1481](homeassistant-ai/ha-mcp#1481)) - **security**: Note that security-advisory disposition is API-blind (UI-only) ([#​1561](homeassistant-ai/ha-mcp#1561)) - **tools**: Sharpen ha\_eval\_template usage routing for compute-from-state queries ([#​1550](homeassistant-ai/ha-mcp#1550)) - Differentiate ha-mcp from Home Assistant's built-in MCP Server ([#​1542](homeassistant-ai/ha-mcp#1542)) - Update advanced mode notes ([#​1533](homeassistant-ai/ha-mcp#1533)) - **[#​1157](homeassistant-ai/ha-mcp#1157: Scripts native-for: guidance + fix numeric\_state-condition for: overclaim ([#​1480](homeassistant-ai/ha-mcp#1480)) - Clarify add-on vs uvx; add Codex + HTTP-native client setup ([#​1478](homeassistant-ai/ha-mcp#1478)) - **security**: Explicit threat model for trusted clients, LAN, sandbox, and OAuth tokens ([#​1463](homeassistant-ai/ha-mcp#1463)) - Clarify telemetry is a planned future feature, not implemented ([#​1469](homeassistant-ai/ha-mcp#1469)) ##### Fixed - **tools**: Bring HA API field names to 2026.6 — stale docstrings, automation plural canonicalization, fan speed (closes [#​1540](homeassistant-ai/ha-mcp#1540)) ([#​1566](homeassistant-ai/ha-mcp#1566)) - **energy**: Accept "water" energy source in ha\_manage\_energy\_prefs ([#​1553](homeassistant-ai/ha-mcp#1553)) - **tools**: Use action: not service: in automation docstring examples ([#​1539](homeassistant-ai/ha-mcp#1539)) - **security**: Narrow GHSA-mc92-ww4q-6fg4 to the masker and log redaction ([#​1512](homeassistant-ai/ha-mcp#1512)) - **addon**: Restrict settings UI root routes to HA ingress ([#​1508](homeassistant-ai/ha-mcp#1508)) - Add name attributes to generated settings-UI form controls (a11y) ([#​1497](homeassistant-ai/ha-mcp#1497)) - Add-on-aware code-mode locked note + suppress settings-UI favicon 404 ([#​1494](homeassistant-ai/ha-mcp#1494)) - Surface the real reason a WebSocket connection failed ([#​1495](homeassistant-ai/ha-mcp#1495)) - Remove str from ha\_bulk\_control.operations schema + fix wrong-reason test ([#​1492](homeassistant-ai/ha-mcp#1492)) - Remove str from bool/int param schemas across all tools ([#​1490](homeassistant-ai/ha-mcp#1490)) - **addon**: Expose non-beta tool options on the stable add-on ([#​1488](homeassistant-ai/ha-mcp#1488)) - **addon**: Enable ingress so the stable add-on shows the Open Web UI / Settings UI ([#​1486](homeassistant-ai/ha-mcp#1486)) - Refine last\_changed/last\_updated duration-math detector ([#​1157](homeassistant-ai/ha-mcp#1157)) ([#​1483](homeassistant-ai/ha-mcp#1483)) - Remove str from config param schema on service and entity tools ([#​1487](homeassistant-ai/ha-mcp#1487)) - Surface flow-helper config to agents reading UI-created templates ([#​1474](homeassistant-ai/ha-mcp#1474)) - Remove str from config param schema on set tools ([#​1485](homeassistant-ai/ha-mcp#1485)) - Route malformed ha\_mcp\_tools version to a distinct reinstall error ([#​1484](homeassistant-ai/ha-mcp#1484)) - Persist DCR client registrations and HMAC secret across restarts ([#​1261](homeassistant-ai/ha-mcp#1261)) ([#​1265](homeassistant-ai/ha-mcp#1265)) - Stop dev builds from publishing the :latest Docker tag ([#​1477](homeassistant-ai/ha-mcp#1477)) - Subscribe to HACS dispatch signal instead of 10x1s blind poll ([#​1455](homeassistant-ai/ha-mcp#1455)) - Reject python\_transform while loops ([#​1462](homeassistant-ai/ha-mcp#1462)) ##### Performance Improvements - Fast-fail HACS not-found lookups + batch-verify deep-search E2E fixtures ([#​1515](homeassistant-ai/ha-mcp#1515)) ([#​1552](homeassistant-ai/ha-mcp#1552)) ##### Refactoring - Add display title to ha\_get\_skill\_guide tool ([#​1543](homeassistant-ai/ha-mcp#1543)) - Fold ha\_check\_config into ha\_get\_system\_health include="config\_check" ([#​1516](homeassistant-ai/ha-mcp#1516)) - **c901**: Smart\_search.py below C901 threshold ([#​1507](homeassistant-ai/ha-mcp#1507)) - **hacs**: Consolidate HACS tools into ha\_get\_hacs + ha\_manage\_hacs ([#​1045](homeassistant-ai/ha-mcp#1045)) ([#​1502](homeassistant-ai/ha-mcp#1502)) - **c901**: Tools\_config\_helpers.py below C901 threshold ([#​1498](homeassistant-ai/ha-mcp#1498)) - **complexity**: Reduce C901 in tools\_addons.py via class-based pattern ([#​1432](homeassistant-ai/ha-mcp#1432)) *** <details> <summary>Internal Changes</summary> ##### Changed - Trim AGENTS.md below 40k + improve subdirectory CLAUDE.md files ([#​1499](homeassistant-ai/ha-mcp#1499)) ##### Chores - **addon**: Publish dev addon version 7.6.0.dev415 \[skip ci] ([`2c0148b`](homeassistant-ai/ha-mcp@2c0148b)) - **deps**: Update ghcr.io/home-assistant/home-assistant docker tag to v2026.6.1 ([#​1571](homeassistant-ai/ha-mcp#1571)) - **deps**: Update ghcr.io/astral-sh/uv docker tag to v0.11.19 ([#​1570](homeassistant-ai/ha-mcp#1570)) - **addon**: Publish dev addon version 7.6.0.dev414 \[skip ci] ([`0bf9e39`](homeassistant-ai/ha-mcp@0bf9e39)) - Sync tool docs after merge \[skip ci] ([`8f5e037`](homeassistant-ai/ha-mcp@8f5e037)) - **addon**: Publish dev addon version 7.6.0.dev413 \[skip ci] ([`6729327`](homeassistant-ai/ha-mcp@6729327)) - Sync tool docs after merge \[skip ci] ([`4341e95`](homeassistant-ai/ha-mcp@4341e95)) - **addon**: Publish dev addon version 7.6.0.dev412 \[skip ci] ([`148f506`](homeassistant-ai/ha-mcp@148f506)) - **addon**: Publish dev addon version 7.6.0.dev411 \[skip ci] ([`287fe55`](homeassistant-ai/ha-mcp@287fe55)) - Sync tool docs after merge \[skip ci] ([`b642b8e`](homeassistant-ai/ha-mcp@b642b8e)) - **addon**: Publish dev addon version 7.6.0.dev410 \[skip ci] ([`29e34dd`](homeassistant-ai/ha-mcp@29e34dd)) - **addon**: Publish dev addon version 7.6.0.dev409 \[skip ci] ([`dec16a1`](homeassistant-ai/ha-mcp@dec16a1)) - Sync tool docs after merge \[skip ci] ([`dd72535`](homeassistant-ai/ha-mcp@dd72535)) - **addon**: Publish dev addon version 7.6.0.dev408 \[skip ci] ([`c3c89f1`](homeassistant-ai/ha-mcp@c3c89f1)) - **addon**: Publish dev addon version 7.6.0.dev407 \[skip ci] ([`94195ee`](homeassistant-ai/ha-mcp@94195ee)) - **addon**: Publish dev addon version 7.6.0.dev406 \[skip ci] ([`f439424`](homeassistant-ai/ha-mcp@f439424)) - Sync tool docs after merge \[skip ci] ([`7464277`](homeassistant-ai/ha-mcp@7464277)) - **addon**: Publish dev addon version 7.6.0.dev405 \[skip ci] ([`146eb07`](homeassistant-ai/ha-mcp@146eb07)) - **addon**: Publish dev addon version 7.6.0.dev404 \[skip ci] ([`6a707bb`](homeassistant-ai/ha-mcp@6a707bb)) - Sync tool docs after merge \[skip ci] ([`85f3935`](homeassistant-ai/ha-mcp@85f3935)) - **addon**: Publish dev addon version 7.6.0.dev403 \[skip ci] ([`be1fa1d`](homeassistant-ai/ha-mcp@be1fa1d)) - Sync tool docs after merge \[skip ci] ([`d9adbd2`](homeassistant-ai/ha-mcp@d9adbd2)) - **addon**: Publish dev addon version 7.6.0.dev402 \[skip ci] ([`41ad7ca`](homeassistant-ai/ha-mcp@41ad7ca)) - **addon**: Publish dev addon version 7.6.0.dev401 \[skip ci] ([`8205034`](homeassistant-ai/ha-mcp@8205034)) - **deps**: Update ghcr.io/astral-sh/uv docker tag to v0.11.18 ([#​1523](homeassistant-ai/ha-mcp#1523)) - **addon**: Publish dev addon version 7.6.0.dev400 \[skip ci] ([`532cdc4`](homeassistant-ai/ha-mcp@532cdc4)) - Sync tool docs after merge \[skip ci] ([`e2c08ff`](homeassistant-ai/ha-mcp@e2c08ff)) - **addon**: Publish dev addon version 7.6.0.dev399 \[skip ci] ([`9501348`](homeassistant-ai/ha-mcp@9501348)) - Sync tool docs after merge \[skip ci] ([`e70a050`](homeassistant-ai/ha-mcp@e70a050)) - **addon**: Publish dev addon version 7.6.0.dev398 \[skip ci] ([`0b61424`](homeassistant-ai/ha-mcp@0b61424)) - Sync tool docs after merge \[skip ci] ([`6df7987`](homeassistant-ai/ha-mcp@6df7987)) - **addon**: Publish dev addon version 7.6.0.dev397 \[skip ci] ([`c34915f`](homeassistant-ai/ha-mcp@c34915f)) - Sync tool docs after merge \[skip ci] ([`6f88e7e`](homeassistant-ai/ha-mcp@6f88e7e)) - **addon**: Publish dev addon version 7.6.0.dev396 \[skip ci] ([`1490e19`](homeassistant-ai/ha-mcp@1490e19)) - Sync tool docs after merge \[skip ci] ([`ac2c7d0`](homeassistant-ai/ha-mcp@ac2c7d0)) - **addon**: Publish dev addon version 7.6.0.dev395 \[skip ci] ([`11e5ee8`](homeassistant-ai/ha-mcp@11e5ee8)) - **addon**: Publish dev addon version 7.6.0.dev394 \[skip ci] ([`5fc3e0f`](homeassistant-ai/ha-mcp@5fc3e0f)) - Flag untrusted third-party content in HACS and add-on tool responses ([#​1509](homeassistant-ai/ha-mcp#1509)) - **addon**: Publish dev addon version 7.6.0.dev393 \[skip ci] ([`9a37c28`](homeassistant-ai/ha-mcp@9a37c28)) - **addon**: Publish dev addon version 7.6.0.dev392 \[skip ci] ([`4f737ac`](homeassistant-ai/ha-mcp@4f737ac)) - **addon**: Publish dev addon version 7.6.0.dev391 \[skip ci] ([`fd5d3f2`](homeassistant-ai/ha-mcp@fd5d3f2)) - **addon**: Publish dev addon version 7.6.0.dev390 \[skip ci] ([`28dedf4`](homeassistant-ai/ha-mcp@28dedf4)) - **addon**: Publish dev addon version 7.6.0.dev389 \[skip ci] ([`9443446`](homeassistant-ai/ha-mcp@9443446)) - Sync tool docs after merge \[skip ci] ([`94fcbeb`](homeassistant-ai/ha-mcp@94fcbeb)) - **addon**: Publish dev addon version 7.6.0.dev388 \[skip ci] ([`ccc1816`](homeassistant-ai/ha-mcp@ccc1816)) - Drop dead entity\_cache attr + ruff-format fuzzy\_search.py ([#​1503](homeassistant-ai/ha-mcp#1503)) - **addon**: Publish dev addon version 7.6.0.dev387 \[skip ci] ([`057c108`](homeassistant-ai/ha-mcp@057c108)) - **addon**: Publish dev addon version 7.6.0.dev386 \[skip ci] ([`66f4ac6`](homeassistant-ai/ha-mcp@66f4ac6)) - **addon**: Publish dev addon version 7.6.0.dev385 \[skip ci] ([`f331f11`](homeassistant-ai/ha-mcp@f331f11)) - **addon**: Publish dev addon version 7.6.0.dev384 \[skip ci] ([`17c319e`](homeassistant-ai/ha-mcp@17c319e)) - Sync tool docs after merge \[skip ci] ([`f36cbb7`](homeassistant-ai/ha-mcp@f36cbb7)) - **addon**: Publish dev addon version 7.6.0.dev383 \[skip ci] ([`782ba3b`](homeassistant-ai/ha-mcp@782ba3b)) - **addon**: Publish dev addon version 7.6.0.dev382 \[skip ci] ([`b647ab6`](homeassistant-ai/ha-mcp@b647ab6)) - **addon**: Publish dev addon version 7.6.0.dev381 \[skip ci] ([`e999c24`](homeassistant-ai/ha-mcp@e999c24)) - Sync tool docs after merge \[skip ci] ([`50d76b0`](homeassistant-ai/ha-mcp@50d76b0)) - **addon**: Publish dev addon version 7.6.0.dev380 \[skip ci] ([`ebdc69b`](homeassistant-ai/ha-mcp@ebdc69b)) - Sync tool docs after merge \[skip ci] ([`1f03967`](homeassistant-ai/ha-mcp@1f03967)) - **addon**: Publish dev addon version 7.6.0.dev379 \[skip ci] ([`7cabb2e`](homeassistant-ai/ha-mcp@7cabb2e)) - **addon**: Publish dev addon version 7.6.0.dev378 \[skip ci] ([`7b631c7`](homeassistant-ai/ha-mcp@7b631c7)) - **addon**: Publish dev addon version 7.6.0.dev377 \[skip ci] ([`ea7b614`](homeassistant-ai/ha-mcp@ea7b614)) - **addon**: Publish dev addon version 7.6.0.dev376 \[skip ci] ([`fd33ecd`](homeassistant-ai/ha-mcp@fd33ecd)) - Sync tool docs after merge \[skip ci] ([`ba8fae3`](homeassistant-ai/ha-mcp@ba8fae3)) - **addon**: Publish dev addon version 7.6.0.dev375 \[skip ci] ([`afcd0d8`](homeassistant-ai/ha-mcp@afcd0d8)) - Sync tool docs after merge \[skip ci] ([`f9b55ad`](homeassistant-ai/ha-mcp@f9b55ad)) - **addon**: Publish dev addon version 7.6.0.dev374 \[skip ci] ([`eecdf8b`](homeassistant-ai/ha-mcp@eecdf8b)) - Sync tool docs after merge \[skip ci] ([`ef16a8a`](homeassistant-ai/ha-mcp@ef16a8a)) - **addon**: Publish dev addon version 7.6.0.dev373 \[skip ci] ([`9a93703`](homeassistant-ai/ha-mcp@9a93703)) - **addon**: Publish dev addon version 7.6.0.dev372 \[skip ci] ([`7352ce8`](homeassistant-ai/ha-mcp@7352ce8)) - **addon**: Publish dev addon version 7.6.0.dev371 \[skip ci] ([`d7601f5`](homeassistant-ai/ha-mcp@d7601f5)) - Sync tool docs after merge \[skip ci] ([`d0a4482`](homeassistant-ai/ha-mcp@d0a4482)) - **addon**: Publish dev addon version 7.6.0.dev370 \[skip ci] ([`f83c32c`](homeassistant-ai/ha-mcp@f83c32c)) - **addon**: Publish dev addon version 7.6.0.dev369 \[skip ci] ([`ea16661`](homeassistant-ai/ha-mcp@ea16661)) - **addon**: Publish dev addon version 7.6.0.dev368 \[skip ci] ([`af49ea5`](homeassistant-ai/ha-mcp@af49ea5)) - **addon**: Publish dev addon version 7.6.0.dev367 \[skip ci] ([`7dd5f4c`](homeassistant-ai/ha-mcp@7dd5f4c)) - **addon**: Publish dev addon version 7.6.0.dev366 \[skip ci] ([`6273b7e`](homeassistant-ai/ha-mcp@6273b7e)) - Sync tool docs after merge \[skip ci] ([`4e3fd5f`](homeassistant-ai/ha-mcp@4e3fd5f)) - **addon**: Publish dev addon version 7.6.0.dev365 \[skip ci] ([`f3bf17b`](homeassistant-ai/ha-mcp@f3bf17b)) - Sync tool docs after merge \[skip ci] ([`5307b60`](homeassistant-ai/ha-mcp@5307b60)) - **addon**: Publish dev addon version 7.6.0.dev364 \[skip ci] ([`76ec1ae`](homeassistant-ai/ha-mcp@76ec1ae)) - Sync tool docs after merge \[skip ci] ([`be864b5`](homeassistant-ai/ha-mcp@be864b5)) - **addon**: Publish dev addon version 7.6.0.dev363 \[skip ci] ([`da10c75`](homeassistant-ai/ha-mcp@da10c75)) - **addon**: Publish dev addon version 7.6.0.dev362 \[skip ci] ([`69f4527`](homeassistant-ai/ha-mcp@69f4527)) - **addon**: Publish version 7.6.0 \[skip ci] ([`086d75d`](homeassistant-ai/ha-mcp@086d75d)) ##### Continuous Integration - Vendor Puppet add-on as a pinned submodule + retry transient add-on builds ([#​1565](homeassistant-ai/ha-mcp#1565)) - Make sync-tool-docs push resilient to concurrent master advances ([#​1564](homeassistant-ai/ha-mcp#1564)) - Fix stale token-cap comment and harden triage budget tests ([#​1514](homeassistant-ai/ha-mcp#1514)) ([#​1560](homeassistant-ai/ha-mcp#1560)) - **deps**: Bump the github-actions group with 2 updates ([#​1556](homeassistant-ai/ha-mcp#1556)) - Budget triage prompt dynamically under the GitHub Models cap ([#​1514](homeassistant-ai/ha-mcp#1514)) ([#​1522](homeassistant-ai/ha-mcp#1522)) - Reduce Docker Hub pulls in performance-tests workflow ([#​1549](homeassistant-ai/ha-mcp#1549)) - Add JavaScript to the CodeQL code-quality gate ([#​1548](homeassistant-ai/ha-mcp#1548)) - Add CodeQL code-quality CI gate and clear all code-quality findings ([#​1526](homeassistant-ai/ha-mcp#1526)) - Drop tool list from evaluate prompt + tighten caps to fit 8K token limit ([`6f47c92`](homeassistant-ai/ha-mcp@6f47c92)) - Remove broken maintainer check (GITHUB\_TOKEN lacks read:org) ([`010ec58`](homeassistant-ai/ha-mcp@010ec58)) - Switch evaluate step to gpt-4o-mini (16K token free tier vs 8K on gpt-4.1) ([#​1496](homeassistant-ai/ha-mcp#1496)) - Issue bot v2 — GitHub Models triage, needs-info auto-close, duplicate detection ([#​1442](homeassistant-ai/ha-mcp#1442)) ##### Refactoring - Extract settings-UI JavaScript and CSS to separate files ([#​1505](homeassistant-ai/ha-mcp#1505)) - Collapse settings-UI route registration into one table ([#​1504](homeassistant-ai/ha-mcp#1504)) ##### Testing - **oauth**: Add HTTP smoke tests for OAuth metadata-discovery endpoints ([#​1562](homeassistant-ai/ha-mcp#1562)) - **uat**: Relabel c01 as a mode-discrimination probe (taxonomy consistency) ([#​1563](homeassistant-ai/ha-mcp#1563)) - **uat**: Rework c01 routing probe to ha\_search registry-listing mode after [#​1529](homeassistant-ai/ha-mcp#1529) ([#​1559](homeassistant-ai/ha-mcp#1559)) - **uat**: Add response\_contains\_any check and always log agent responses ([#​1537](homeassistant-ai/ha-mcp#1537)) - **uat**: Treat request timeout as per-story failure, not suite abort ([#​1536](homeassistant-ai/ha-mcp#1536)) - **uat**: Harden BAT story runner against agent crashes ([#​1535](homeassistant-ai/ha-mcp#1535)) - **uat**: Log model and quantization in BAT story results ([#​1525](homeassistant-ai/ha-mcp#1525)) - Capture reasoning tokens and detect inert --no-think in BAT openai agent ([#​1524](homeassistant-ai/ha-mcp#1524)) </details> </details> --- ### Configuration 📅 **Schedule**: (in timezone America/New_York) - Branch creation - At any time (no schedule defined) - Automerge - At any time (no schedule defined) 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about these updates again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR has been generated by [Mend Renovate](https://github.com/renovatebot/renovate). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yMTQuNiIsInVwZGF0ZWRJblZlciI6IjQzLjIxNC42IiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJyZW5vdmF0ZS9jb250YWluZXIiLCJ0eXBlL21pbm9yIl19--> Reviewed-on: https://git.greyrock.io/greyrock-labs/home-ops/pulls/243
What does this PR do?
Closes #1157 (partial — covers the best-practice detector for
now() - X.last_changed/last_updatedpatterns).HA 2026.5 introduced the native
for:field onstatetriggers and conditions for duration-based checks. This PR adds a detector inbest_practice_checker.pythat catches automations still using the old template approach (now() - X.last_changed/last_updated) and suggests the nativefor:alternative.Changes:
best_practice_checker.py: New_RE_DURATION_MATHregex (two alternations:now() - X.last_changedandX.last_changed < now(); both require a dotted qualifier so bare Jinja variables namedlast_changedare not falsely flagged). Warning fires in both_check_template_string(conditions) and_check_triggers(template triggervalue_template). Warning text includes a concreteplatform: state, for: {minutes: N}example and links toautomation-patterns.md#native-conditions/automation-patterns.md#trigger-types.test_best_practice_checker.py: 8 new tests covering conditionlast_changed, conditionlast_updated, trigger template, clean positive case (for:field — no warning), skill-ref presence, no generic double-flag, trigger warning uses#trigger-typesanchor, and no false positive on barelast_changedJinja variable.Out of scope (per issue scope guidance):
ha_config_set_automation/ha_config_set_script— separate PR once the skill content is updated upstreamautomation-patterns.md) — separate PR tohomeassistant-ai/skillsType of change
Testing
uv run pytest)uv run ruff check)98 unit tests pass (was 90; 8 new). Ruff and mypy clean.
Future improvements
states.sensor.x.last_changed < now() - timedelta(...)is not caught by the current regex (the<alternation only coversX.last_changed < now()with nothing following). This is a rare HA pattern; it could be added as a third alternation if it shows up in practice.numeric_statetrigger also supports afor:field for similar duration checks; a separate detector could be added later.Checklist