Skip to content

fix: survive read-only filesystems at startup - #1138

Merged
kingpanther13 merged 3 commits into
masterfrom
fix/readonly-home-1125
May 6, 2026
Merged

fix: survive read-only filesystems at startup#1138
kingpanther13 merged 3 commits into
masterfrom
fix/readonly-home-1125

Conversation

@kingpanther13

@kingpanther13 kingpanther13 commented May 5, 2026

Copy link
Copy Markdown
Member

What does this PR do?

Fixes #1125ghcr.io/homeassistant-ai/ha-mcp:latest crashes at startup
under hardened Docker setups (read_only: true, user: 1000:1000,
tmpfs: /tmp):

OSError: [Errno 30] Read-only file system: '/.ha-mcp'
  in _get_config_path() → home_dir.mkdir(parents=True, exist_ok=True)

Two contributing factors:

  1. The Dockerfile didn't set ENV HOME, so under USER mcpuser Docker
    left HOME=/ (moby/moby#2968).
    Path.home() resolved to /, ha-mcp tried to mkdir /.ha-mcp, and
    read_only: true made that fatal. Even on writable filesystems this
    silently polluted the container's filesystem root with a /.ha-mcp/
    directory.
  2. _get_config_path() (added in feat: web-based settings UI for per-tool enable/disable/pin #960) unconditionally mkdirs the
    home dir on every server start, with no fallback.

Coordinated changes

Shared resolver (src/ha_mcp/utils/data_paths.py, new):
single source of truth for "where does ha-mcp write its persistent files".

# Source Used for
1 HA_MCP_CONFIG_DIR env var Hardened Docker bind-mount override
2 /data (when SUPERVISOR_TOKEN set) Home Assistant add-on persistent dir
3 ~/.ha-mcp Standard install
4 <tempdir>/ha-mcp Last-resort fallback (server still runs, no persistence)

The resolved dir is memoized at module level so the fallback warning
emits once at startup instead of on every save/load HTTP request.

settings_ui:

  • _get_config_path becomes a thin get_data_dir() / "tool_config.json" wrapper.
  • load_tool_config replaces the path.exists() + read_text() two-step with a single try: read_text() except OSError:. Path.exists() only swallows ENOENT/ENOTDIR/EBADF/ELOOP, so EACCES (e.g. HA_MCP_CONFIG_DIR pointing at an existing 0700 dir owned by another UID) would re-introduce the same class of crash. Confirmed empirically: errno=13 propagates from pathlib.Path.exists().
  • save_tool_config now returns bool, and the _save_tools HTTP route returns 500 when the write fails. The JS already handles !resp.ok with "Save failed!" — it was never given the chance.

utils/usage_logger: switch the default log path from Path.home() / ".ha-mcp" / "logs" to get_data_dir() / "logs". Logs now follow the same precedence as the tool config — HA_MCP_CONFIG_DIR works for them too, and add-on mode lands in /data/logs/ (the supervisor's persistent location, was previously ephemeral ~/.ha-mcp/logs/).

Dockerfile:

  • ENV HOME=/home/mcpuser so Path.home() resolves correctly under the default user.
  • chmod 0755 /home/mcpuser because the base image's /etc/login.defs sets HOME_MODE=0700; that's fine when the container runs as mcpuser, but un-traversable when users override --user UID:GID (the issue reporter does so) — anything that stats a path under HOME then raises PermissionError. Mode 0755 keeps write access restricted to mcpuser.

Tests

File Class What it pins
test_data_paths.py (new) TestPriorityOrder HA_MCP_CONFIG_DIR > /data > ~/.ha-mcp
TestFallbacks Issue #1125 regression; HA_MCP_CONFIG_DIR mkdir-fail chains to tmpdir
TestMemoization Single warning per startup; resolver re-runs when cache cleared
test_settings_ui.py TestConfigPath Wrapper sanity; load_tool_config doesn't crash on EACCES (same-class regression guard)
TestSaveToolConfig (new) bool return contract
TestSaveToolsValidation 500 surfaced when save fails
test_usage_logger.py TestUsageLoggerDefaults Honors HA_MCP_CONFIG_DIR

Full unit suite: 1684 passed, 1 skipped (numpy not installed, unrelated). ruff check clean. mypy src/ clean.

Local Docker verification

Built locally and confirmed three real scenarios:

Scenario Before After
Reporter's compose: --read-only --user 1000:1000 --tmpfs /tmp crash runs (config falls back to /tmp/ha-mcp/)
Default user (no overrides) "works" but creates /.ha-mcp 🚨 works (creates ~/.ha-mcp)
HA_MCP_CONFIG_DIR=/data/ha-mcp with bind-mount + read-only n/a runs, settings + logs persist to bind-mount

In all "after" cases the FastMCP banner displays and uvicorn binds http://0.0.0.0:8086. The original stack trace from #1125 no longer reproduces.

Release note

Users who ran :latest between #960 (2026-05-02) and this fix and had a writable / (default Docker, no read_only: true) will have had their settings UI tool config silently written to /.ha-mcp/tool_config.json at the filesystem root, because Docker leaves HOME=/ under USER mcpuser without an explicit ENV HOME (moby/moby#2968). After this fix the resolver writes to ~/.ha-mcp (or HA_MCP_CONFIG_DIR / /data when applicable) and no code path reads from /.ha-mcp/ — any per-tool enable/disable/pin choices made on broken :latest need to be recreated in the settings UI after upgrading. (Users who hit the actual #1125 crash had nothing persisted, so nothing to migrate.)

Type of change

  • 🐛 Bug fix
  • ✨ New feature
  • 📚 Documentation
  • 🔧 Maintenance/refactor
  • 🧪 Tests only
  • 💥 Breaking change

Testing

  • I have tested these changes with a LLM agent
  • All automated tests pass (uv run pytest) — 1684 passed, 1 skipped
  • Code follows style guidelines (uv run ruff check) — and mypy src/ clean

Checklist

  • I have updated documentation if needed — HA_MCP_CONFIG_DIR is documented in the resolver's docstring; happy to surface it in README.md or the setup wizard if you'd like.

🤖 Generated with Claude Code

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, 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 addresses startup crashes occurring in hardened Docker environments where the filesystem is read-only or the home directory is not writable. By improving how the application locates its configuration file and adjusting Docker container defaults, the service is now more robust and flexible for various deployment configurations.

Highlights

  • Configuration Path Resilience: Updated _get_config_path to handle read-only filesystems by falling back to a temporary directory and introducing an HA_MCP_CONFIG_DIR environment variable for explicit overrides.
  • Docker Environment Improvements: Explicitly set HOME in the Dockerfile to prevent path resolution issues and updated home directory permissions to 0755 to support non-root user UID/GID overrides.
  • Testing: Added three new unit tests to verify configuration path precedence, fallback behavior on read-only filesystems, and regression protection for startup crashes.
Using Gemini Code Assist

The 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 /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

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 .gemini/ folder in the base of the repository. Detailed instructions can be found here.

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

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request improves the robustness of the MCP server when running in restricted environments, such as read-only Docker containers. Key changes include setting the HOME environment variable explicitly in the Dockerfile, adjusting home directory permissions to 0755, and implementing a fallback mechanism to a temporary directory for the tool configuration when the home directory is unwritable. Additionally, a new HA_MCP_CONFIG_DIR environment variable allows for explicit configuration path overrides. The feedback suggests refining the fallback logic to improve debuggability by including specific operation context in log messages and ensuring the operation context is initialized before fallible actions.

Comment thread src/ha_mcp/settings_ui.py Outdated
@kingpanther13
kingpanther13 force-pushed the fix/readonly-home-1125 branch from 73bc5f0 to 5024a43 Compare May 5, 2026 19:32

@kingpanther13 kingpanther13 left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review pass complete (force-pushed 5024a43)

Ran the PR review toolkit (code-reviewer, pr-test-analyzer, comment-analyzer, silent-failure-hunter) plus addressed Gemini's inline suggestion. Findings I confirmed empirically and fixed:

Finding Source Status
load_tool_config() path.exists() propagates PermissionError (EACCES not in pathlib._IGNORED_ERRNOS) — same class as the original #1125 bug silent-failure-hunter Fixed: replaced exists()+read_text() two-step with single try: read_text() except OSError:
HA_MCP_CONFIG_DIR set-but-unwritable returned a broken path; every save then OSError'd in save_tool_config code-reviewer + pr-test-analyzer + silent-failure-hunter Fixed: HA_MCP_CONFIG_DIR mkdir failure now chains into the tmpdir fallback (consistent with home-dir branch)
Warning emitted on every _get_config_path() call (called from each settings UI HTTP request) → log spam silent-failure-hunter Fixed: result memoized in module-level _CONFIG_PATH_CACHE; warning emits once at startup
Double warning when home AND tmpdir both fail; second one misleadingly says "Falling back to ..." Gemini + silent-failure-hunter Fixed: single warning per resolution, message branches on fallback mkdir success
~50% of original diff was unrelated ruff format reflows on untouched code code-reviewer Reverted: restored settings_ui.py from origin/master and re-applied only the targeted fix; diff is now focused (87 added / 11 removed in settings_ui.py, vs. 152/38 before)
Dockerfile chmod comment framing about useradd default 0700 was image-specific; comment-analyzer also flagged "Path.home() raises PermissionError" being technically inaccurate (traversal raises, not Path.home() itself) code-reviewer + comment-analyzer Reworded: comment now references /etc/login.defs HOME_MODE and "stats a path under HOME" rather than Path.home()

Confirmed but deliberately deferred (out of PR scope)

  • usage_logger.py:120-127 already uses try/except OSError but its logger.exception on save failures will now write to a same-class fallback path (i.e. /home/mcpuser/.ha-mcp/logs/) that's unwritable for --user UID:GID users; should adopt the same memoized-resolution + tempdir-fallback pattern in a follow-up.
  • save_tool_config returns None on OSError and the HTTP handler reports success: True to the browser — this is a UX bug (user thinks save worked), but predates this PR and has its own scope.
  • Test edge case (both home AND tmpdir unwritable) — defensive-only, low priority; left as a possible follow-up.

Tests

5 unit tests in TestConfigPath (all in tests/src/unit/test_settings_ui.py):

  • test_ha_mcp_config_dir_overrides_supervisor_token — env var precedence
  • test_falls_back_to_tmpdir_when_home_unwritable — issue #1125 regression
  • test_ha_mcp_config_dir_unwritable_chains_to_tmpdir — new fallback chaining
  • test_load_tool_config_does_not_crash_on_unreadable_config_dir — same-class follow-up regression
  • test_warning_emitted_only_once_via_module_cache — log-spam guard

Full unit suite: 1679 passed, 1 skipped (numpy unrelated). ruff check src/ tests/ homeassistant-addon/ homeassistant-addon-webhook-proxy/ scripts/ clean. mypy src/ clean.

Re-verified the three Docker scenarios (reporter's compose, default user, HA_MCP_CONFIG_DIR bind-mount) — all start cleanly under :fix-1125 build.

Comment thread tests/src/unit/test_settings_ui.py Fixed
@kingpanther13
kingpanther13 force-pushed the fix/readonly-home-1125 branch from 5024a43 to 8f8efc0 Compare May 5, 2026 20:06
@kingpanther13 kingpanther13 changed the title fix: tolerate read-only filesystem when locating tool config (#1125) fix: survive read-only filesystems at startup (#1125) May 5, 2026

@kingpanther13 kingpanther13 left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Follow-ups addressed (force-pushed 8f8efc0)

Pulled in the items I'd previously marked deferred:

Concern Source Fix
usage_logger.py had the same root cause but wasn't patched (would silently fall back to Path.home()/... and ignore HA_MCP_CONFIG_DIR) code-reviewer issue #1 Extracted shared resolver to new utils/data_paths.py; both settings_ui and usage_logger now go through get_data_dir(). Add-on mode now lands logs in /data/logs/ (the supervisor's persistent dir) instead of ephemeral ~/.ha-mcp/logs/.
save_tool_config swallowed OSError and _save_tools returned {success: true} while the user's change was lost silent-failure-hunter issue #4 save_tool_config now returns bool; _save_tools returns 500 with a structured error body when it fails. The JS at saveConfig() already shows "Save failed!" on !resp.ok — it just wasn't being given the chance.
Mixed import and from … import in test fixture github-code-quality bot Replaced import ha_mcp.settings_ui as su + manual reset with monkeypatch.setattr("ha_mcp.utils.data_paths._DATA_DIR_CACHE", None) — also gives proper between-test isolation via monkeypatch's auto-restore. Thread resolved.
PR title was vague user feedback Renamed: fix: tolerate read-only filesystem when locating tool configfix: survive read-only filesystems at startup.

New tests (9 total across new + existing files):

  • test_data_paths.py: priority order, both fallback branches, memoization (single-warning guard), uncached resolver re-runs.
  • test_settings_ui.py: save_tool_config bool contract (success + OSError → False); _save_tools returns 500 when save fails.
  • test_usage_logger.py: default path uses shared resolver; HA_MCP_CONFIG_DIR redirects logs.

Full unit suite: 1684 passed, 1 skipped. ruff check src/ tests/ ... clean. mypy src/ clean. Re-verified the three Docker scenarios under the new build.

Comment thread src/ha_mcp/settings_ui.py Fixed
@kingpanther13 kingpanther13 changed the title fix: survive read-only filesystems at startup (#1125) fix: fix read-only filesystems /:latest at startup ( fixes #1125) May 5, 2026
`:latest` crashed at startup under hardened Docker setups (`read_only: true`,
`user: 1000:1000`) because `_get_config_path()` did an unconditional
`mkdir(parents=True, exist_ok=True)` on `Path.home() / ".ha-mcp"`. Two
contributing factors:

1. The Dockerfile didn't set `ENV HOME`, so under `USER mcpuser` Docker
   left `HOME=/`. `Path.home()` resolved to `/`, ha-mcp tried to mkdir
   `/.ha-mcp`, and `read_only: true` made that fatal (issue #1125).
2. Even on writable filesystems this silently polluted the container's
   filesystem root with a `/.ha-mcp/` directory.

Coordinated changes:

**Shared resolver** (`utils/data_paths.py`, new): single source of truth
for "where does ha-mcp write its persistent files". Priority:
1. `HA_MCP_CONFIG_DIR` env var — explicit override for hardened Docker
   setups bind-mounting a writable volume.
2. `/data` — Home Assistant add-on supervisor data dir.
3. `~/.ha-mcp` — standard.
4. `<tempdir>/ha-mcp` — last-resort fallback.

The result is memoized so the fallback warning emits once at startup
instead of on every save/load HTTP request. Replaces the previous
inconsistent ad-hoc resolution in two places (`settings_ui` and
`usage_logger`).

**`settings_ui`**: `_get_config_path` becomes a thin
`get_data_dir() / "tool_config.json"` wrapper. `load_tool_config`
replaces the `path.exists()` + `read_text()` two-step with a single
`try: read_text() except OSError:` — `Path.exists()` only swallows
ENOENT/ENOTDIR/EBADF/ELOOP, so EACCES (e.g. `HA_MCP_CONFIG_DIR` pointing
at an existing 0700 dir owned by another UID) would re-introduce the
same class of crash. `save_tool_config` returns `bool` so the
`_save_tools` HTTP route can return 500 when the write fails — the JS
already handles `!resp.ok` with "Save failed!", but it was never given
the chance.

**`usage_logger`**: switch the default log path from
`Path.home() / ".ha-mcp" / "logs"` to `get_data_dir() / "logs"`. Logs
now follow the same precedence as the settings-UI tool config — honors
`HA_MCP_CONFIG_DIR` so users with a bind-mount don't lose their logs,
lands in `/data/logs/` in add-on mode (the supervisor's persistent
location, was previously going to ephemeral `~/.ha-mcp/logs`).

**Dockerfile**: set `ENV HOME=/home/mcpuser` so `Path.home()` resolves
correctly under the default user. `chmod 0755 /home/mcpuser` because
the base image's `/etc/login.defs` sets `HOME_MODE=0700`; that's fine
when the container runs as mcpuser, but un-traversable when users
override `--user UID:GID` (the issue reporter does so) — anything that
stats a path under HOME then raises PermissionError. Mode 0755 keeps
write access restricted to mcpuser.

Tests: 9 new in `test_data_paths.py` and `test_settings_ui.py` covering
priority order, both fallback chains, memoization, the `load_tool_config`
EACCES regression guard, the `save_tool_config` bool contract, and the
500-on-save-failure HTTP path. Plus a `usage_logger` test verifying it
uses the shared resolver.

Verified locally with three Docker scenarios: bondskin's hardened compose
(`--read-only --user 1000:1000 --tmpfs /tmp`), default user, and
`HA_MCP_CONFIG_DIR=/data/ha-mcp` bind-mount. Server starts cleanly in all
three; original stack trace from #1125 no longer reproduces.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@kingpanther13
kingpanther13 force-pushed the fix/readonly-home-1125 branch from 8f8efc0 to 3a53371 Compare May 5, 2026 20:17
Internal review pass on the read-only-fs fix surfaced ten items;
addressing them all in one follow-up commit.

Production code:

- data_paths.py: rewrite the priority docstring to reflect actual
  behavior — an explicit HA_MCP_CONFIG_DIR override that fails to
  mkdir short-circuits the home-dir step instead of silently writing
  to ~/.ha-mcp (respects user intent).
- data_paths.py + settings_ui.py: drop the duplicate _is_addon helpers;
  both now import is_running_in_addon from _version. Single source of
  truth, no drift risk.
- settings_ui.py: load_tool_config's OSError branch now passes
  exc_info=True so operators see the errno (EROFS vs EACCES vs ENOSPC)
  in logs instead of a bare "Cannot read tool config at /path".
- usage_logger.py: replace the silent _enabled = False on mkdir failure
  with a logger.warning naming the path and the OSError. Operators no
  longer have to guess why mcp_usage.jsonl is empty.
- Dockerfile: rephrase the chmod 0755 comment to describe the
  observable behavior (HOME-relative paths must be stat-able under
  --user UID:GID) rather than pinning to the base image's
  HOME_MODE=0700 default.

Tests:

- test_data_paths.py: add coverage for the last-resort branch where
  env-mkdir, home-mkdir, and tmpdir-mkdir all fail — resolver must
  return a Path, not raise, so callers can degrade gracefully.
- test_settings_ui.py: add a POSIX-only end-to-end EACCES regression
  using a real chmod 0o000 dir. The mocked-read_text test still pins
  the going-forward contract; the real-chmod test catches a future
  refactor that reintroduces an upstream Path.exists() check.
- test_usage_logger.py: replace the str(path).endswith("/logs/...")
  assertion with a Path-equality comparison so the test passes on
  Windows (Path stringifies with backslashes there).
- test_docker_build.py: add two integration tests that assert
  $HOME=/home/mcpuser and stat -c '%a' /home/mcpuser is 755.
  Catches a future PR that accidentally drops the ENV HOME line or
  the chmod (both are the actual fix for #1125 and have no
  unit-level coverage otherwise).

Verified: `uv run pytest tests/src/unit/test_data_paths.py
tests/src/unit/test_settings_ui.py tests/src/unit/test_usage_logger.py`
→ 46 passed, 1 skipped (POSIX-only test on Windows).
`uv run ruff check src/ tests/` clean.
`uv run mypy src/` clean (the SIGHUP and TextIO.reconfigure errors
are Windows-only and pre-date this PR).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@kingpanther13
kingpanther13 marked this pull request as ready for review May 5, 2026 20:58
@kingpanther13
kingpanther13 requested review from a team and Patch76 May 5, 2026 20:58
@kingpanther13
kingpanther13 enabled auto-merge (squash) May 5, 2026 20:58
@kingpanther13

Copy link
Copy Markdown
Member Author

Implementation Summary

Choices Made:

  • Extracted a shared resolver to a new utils/data_paths.py rather than duplicating fallback logic in settings_ui and usage_logger. Both modules now route through get_data_dir(), so HA_MCP_CONFIG_DIR and add-on /data mode work identically for tool config and logs.
  • 4-tier precedence: HA_MCP_CONFIG_DIR env → /data (when SUPERVISOR_TOKEN is set) → ~/.ha-mcp<tempdir>/ha-mcp last-resort. The server keeps running even when nothing is writable; only persistence is lost.
  • Memoized result in a module-level _DATA_DIR_CACHE so the fallback warning emits once at startup instead of on every settings-UI HTTP request.
  • Replaced path.exists() + read_text() in load_tool_config with a single try: read_text() except OSError:. Path.exists() only swallows ENOENT/ENOTDIR/EBADF/ELOOP; EACCES propagates and would re-introduce the same class of crash as Updating to :latest (dev) is failing #1125.
  • save_tool_config now returns bool; _save_tools returns 500 with a structured error body on failure. The JS at saveConfig() already had a !resp.ok → "Save failed!" branch — it just wasn't being given the chance.
  • Dockerfile: explicit ENV HOME=/home/mcpuser (otherwise Docker leaves HOME=/ under non-root users — Set $HOME in container moby/moby#2968) and chmod 0755 /home/mcpuser so users overriding --user UID:GID can still stat paths under HOME without PermissionError. Mode 0755 keeps writes restricted to mcpuser.

Problems Encountered:

  • Initial fix introduced a same-class regression: load_tool_config()'s path.exists() would still propagate PermissionError on an unreadable config dir. Caught by silent-failure-hunter and pinned with test_load_tool_config_does_not_crash_on_unreadable_config_dir.
  • HA_MCP_CONFIG_DIR set-but-unwritable returned a broken path; every save then OSError'd. Chained the env-var branch into the same tmpdir fallback as the home-dir branch (test_ha_mcp_config_dir_unwritable_chains_to_tmpdir).
  • usage_logger.py had the same root cause but wasn't part of the original fix — it would silently fall back to Path.home()/.ha-mcp/logs/ and ignore HA_MCP_CONFIG_DIR. Initially deferred, then pulled in once the shared resolver existed.
  • Original diff accidentally bundled ~50% unrelated ruff format reflows on untouched code. Reverted settings_ui.py to origin/master and re-applied only the targeted fix; settings_ui diff dropped from 152/38 to 87/11.
  • Comment rot: Dockerfile comment cited useradd defaults (image-specific) and said Path.home() raises PermissionError (technically the traversal raises, not Path.home() itself). Reworded to reference /etc/login.defs HOME_MODE and "stats a path under HOME". Caught by comment-analyzer.
  • A test fixture mixed import ha_mcp.settings_ui as su + manual cache reset. Replaced with monkeypatch.setattr("ha_mcp.utils.data_paths._DATA_DIR_CACHE", None) so test isolation comes from monkeypatch's auto-restore rather than ad-hoc teardown.

Verification:

  • Full unit suite: 1684 passed, 1 skipped (numpy unrelated). ruff check clean. mypy src/ clean. All PR Validation Pipeline checks green.
  • Local Docker: reporter's --read-only --user 1000:1000 --tmpfs /tmp compose, default-user, and HA_MCP_CONFIG_DIR bind-mount scenarios all start cleanly under :fix-1125. Original Updating to :latest (dev) is failing #1125 stack trace no longer reproduces.

@Patch76 Patch76 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-review of HEAD d66c651a. The fix closes #1125. ENV HOME, the EACCES handling in load_tool_config, and the shared data_paths.get_data_dir() resolver are all correct. Test coverage — including the real chmod 0o000 regression guard at tests/src/unit/test_settings_ui.py:198 — is solid.

Three sticking points before squash:

  • One residual same-class bug: the addon-mode branch at data_paths.py:70-71 returns Path("/data") without verifying writability and silently overrides an explicit HA_MCP_CONFIG_DIR if its mkdir failed.
  • One env-var edge case: HA_MCP_CONFIG_DIR=" " (whitespace) is truthy, mkdirs a three-space-named directory under cwd. Path(" ").absolute() empirically resolves cwd-relative.
  • The PR title — auto-merge is queued, so the squash subject inherits fix: fix read-only filesystems /:latest at startup ( fixes #1125) verbatim into master history the moment the next approval lands. git log upstream/master --grep="^fix: fix " returns nothing else; this would be the first double-verb fix subject, alongside the /:latest typo and the leading space inside the parens. Worth editing before approving.

For existing :latest users who hit the original bug, data was previously written to /.ha-mcp/ (filesystem root, from HOME=/); after this fix no code path reads from there. Worth a one-line release note.

Findings inline.

Comment thread src/ha_mcp/utils/data_paths.py Outdated
Comment thread src/ha_mcp/utils/data_paths.py
Comment thread src/ha_mcp/utils/data_paths.py
Comment thread src/ha_mcp/utils/data_paths.py
Comment thread tests/src/unit/test_data_paths.py
Five inline review findings from Patch76's re-review of HEAD d66c651:

data_paths.py
- Addon-mode branch now writability-checks /data before returning, and
  honors an explicit HA_MCP_CONFIG_DIR override even when it failed
  mkdir (was silently discarded). Closes the residual same-class
  #1125 bug for read-only /data, and the silent-override-discard for
  env-fail + SUPERVISOR_TOKEN-set.
- Strip HA_MCP_CONFIG_DIR before truthiness test. "   " (e.g. trailing
  space in a .env file) is otherwise truthy and Path("   ") resolves
  cwd-relative, mkdir-ing a literal whitespace-named directory.
- Docstring now flags the lru_cache concurrent-first-access caveat:
  the warning typically emits once but may emit twice under racing
  threads (idempotent mkdir, cosmetic only).
- Last-resort branch upgraded from logger.warning to logger.error.
  Persistence is silently disabled; supervisor log viewer surfaces
  errors more prominently than warnings.

test_data_paths.py
- New test_whitespace_only_ha_mcp_config_dir_is_ignored.
- New test_ha_mcp_config_dir_unwritable_in_addon_mode_chains_to_tmpdir
  pinning the silent-override-discard regression.
- New test_falls_back_when_addon_data_dir_unwritable pinning the
  residual same-class bug.
- Updated test_addon_path_when_supervisor_token_set to stub
  Path.mkdir for /data (dev/CI machines don't have it).
- test_returns_unwritable_tmpdir_when_everything_fails now asserts
  the persistence-disabled record is logged at ERROR.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@kingpanther13 kingpanther13 changed the title fix: fix read-only filesystems /:latest at startup ( fixes #1125) fix: survive read-only filesystems at startup May 6, 2026

@kingpanther13 kingpanther13 left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Patch76's review addressed in befcd9a

All five inline findings + the title.

Finding Fix
Addon branch returns Path("/data") without writability check; silently discards HA_MCP_CONFIG_DIR override on env-var mkdir failure mkdir-then-check; on success returns /data only when preferred is None (failed override falls through to tmpdir); on failure sets preferred = /data and continues into the home/tmpdir chain
HA_MCP_CONFIG_DIR=" " is truthy → mkdir's a literal whitespace-named dir under cwd os.environ.get("HA_MCP_CONFIG_DIR", "").strip()
Docstring "warning emits once" overclaims under concurrent first-access Weakened: now flags lru_cache doesn't serialize the wrapped call when empty; idempotent mkdir, cosmetic-only double warning
Last-resort branch logged at WARNING when persistence is silently disabled Upgraded to logger.error
No test for env-fail + SUPERVISOR_TOKEN-set interaction Added test_ha_mcp_config_dir_unwritable_in_addon_mode_chains_to_tmpdir (silent-override-discard regression) and test_falls_back_when_addon_data_dir_unwritable (residual same-class bug)
PR title double-verb / /:latest typo / stray space Renamed to fix: survive read-only filesystems at startup

Existing test_addon_path_when_supervisor_token_set updated to stub Path.mkdir for /data (the new writability check would otherwise hit the real path on dev/CI machines). test_returns_unwritable_tmpdir_when_everything_fails now asserts levelno == logging.ERROR.

For existing :latest users who hit the original bug, data was previously written to /.ha-mcp/ (filesystem root, from HOME=/); after this fix no code path reads from there. Worth a one-line release note.

Good call — that's a stranded-data note worth surfacing, and we already have the conventional-commit body to drive a release note. I'll add it to the PR description rather than the commit (the description is what the addon CHANGELOG sync uses).

@kingpanther13
kingpanther13 requested a review from Patch76 May 6, 2026 10:55

@Patch76 Patch76 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Round 2: all 5 inline findings verified fixed in befcd9a. CI green (17 pass / 2 skipping for hotfix-origin and dependabot). Per-thread verifications posted as replies above; threads already resolved.

Two unrelated observations for before-approval:

High — auto_merge.commit_title is cached at enable-time and ships at squash time:

.title:                    "fix: survive read-only filesystems at startup"           (clean)
.auto_merge.commit_title:  "fix: fix read-only filesystems /:latest at startup ( fixes #1125) (#1138)"  (cached)

The PR title rename did not refresh the auto-merge cache. GitHub Community Discussion #16271 reproduces that the cached value is what lands on master at squash time, not the live .title. Either disable + re-enable auto-merge to refresh, or use gh pr merge 1138 --squash --subject "..." for manual merge. Otherwise the squash commit on master will carry fix: fix, /:latest, and the leading space inside the parens.

Low — cosmetic double-warning on the env-fail + addon-set + /data-unwritable trace (src/ha_mcp/utils/data_paths.py:82-87): user sees both HA_MCP_CONFIG_DIR=... could not be prepared and /data is not writable in add-on mode warnings, even though the env-fail short-circuit already determined the outcome (the override would have won). Cosmetic only — no functional issue, and a guard would complicate the flow disproportionately.

@Patch76
Patch76 disabled auto-merge May 6, 2026 12:15

@Patch76 Patch76 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verified befcd9a against the Round-2 review above — all 5 inline fixes land cleanly, CI green on required checks. Auto-merge disabled to prevent the cached typo squash-subject from shipping; merge timing and subject are yours to control.

@kingpanther13
kingpanther13 merged commit 8a4a30a into master May 6, 2026
19 checks passed
@kingpanther13
kingpanther13 deleted the fix/readonly-home-1125 branch May 6, 2026 12:20
@github-actions

github-actions Bot commented May 6, 2026

Copy link
Copy Markdown
Contributor

🧪 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):
📖 Dev Channel Documentation

Quick start

# Run dev version
uvx ha-mcp-dev

# Check version
uvx ha-mcp-dev --version

Docker:

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:dev

Found an issue? Please open a new bug report and mention this PR for context.

Patch76 added a commit to Patch76/ha-mcp that referenced this pull request May 7, 2026
Merge brings in homeassistant-ai#1126, homeassistant-ai#1135, homeassistant-ai#1136, homeassistant-ai#1138 and the dev-addon publish
chain since the branch's previous head `147ad5f`. Conflict in
`tests/src/unit/test_settings_ui.py` resolved by keeping both adjacent
additions: master's `test_returns_500_when_save_fails` (read-only-fs
500-surfacing test from homeassistant-ai#1138) inside `TestSaveToolsValidation`, plus
this PR's new `TestRestartAddon` class right after.

KP13 round-1 review asks (CHANGES_REQUESTED 2026-05-06 20:38 UTC) all
addressed:

1. **Narrow connection-drop catch** — the `except` tuple in
   `_restart_addon` (in `settings_ui.py`) is now
   `(httpx.ReadError, httpx.RemoteProtocolError)`. `httpx.ConnectError`
   is no longer treated as a successful restart; it falls through to
   the `httpx.HTTPError` handler returning 502 + `CONNECTION_FAILED`.
   Inline comment documents the deliberate exclusion (DNS /
   TCP-refused / supervisor-socket-misconfigured all mean Supervisor
   was unreachable, not that a restart was initiated).

2. **Parametrize connection-drop test** + separate `ConnectError` →
   502 case. `test_treats_connection_drop_as_success` now parametrizes
   over `(httpx.ReadError, httpx.RemoteProtocolError)`. New
   `test_connect_error_returns_502` locks the contract that a
   connection-failure-before-handshake surfaces as 502.

3. **Boy-Scout: pin remaining `_restart_addon` branches.** Two new
   tests: `test_generic_http_error_returns_502` (uses
   `httpx.PoolTimeout` to exercise the `httpx.HTTPError` fall-through)
   and `test_supervisor_4xx_returns_502` (Supervisor returns 401 →
   handler maps to 502).

4. **Symbol-based test docstrings** — class-docstring + method
   docstrings now reference "the `if not token:` guard", "the catch
   on `(ReadError, RemoteProtocolError)`", "the `httpx.HTTPError`
   handler", "the `status_code >= 400` branch" instead of line numbers
   that shift with every kwarg-split / refactor.

5. **Top-level `import httpx`** in `tests/src/unit/test_settings_ui.py`
   replaces the inline `__import__("httpx").ReadError(...)` workaround.

6. **Trim "post-G1 state"** from the `verify_ssl = True` fixture
   comment. Kept the substantive part ("must resolve to a real bool,
   not a MagicMock, because httpx accepts only bool/SSLContext for
   `verify=`") that pays off in 6 months.

7. **Move homeassistant-ai#960 cross-reference** out of the `TestRestartAddon` class
   docstring. Closed-PR review history rots fast in source; the PR
   body is the right place for it.

Local: 1762 unit tests pass, ruff lint + format clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
eleboucher pushed a commit to eleboucher/homelab that referenced this pull request May 13, 2026
…→ 7.5.0) (#455)

This PR contains the following updates:

| Package | Update | Change |
|---|---|---|
| [ghcr.io/homeassistant-ai/ha-mcp](https://github.com/homeassistant-ai/ha-mcp) | minor | `7.4.0` → `7.5.0` |

---

> ⚠️ **Warning**
>
> Some dependencies could not be looked up. Check the [Dependency Dashboard](issues/3) for more information.

---

### Release Notes

<details>
<summary>homeassistant-ai/ha-mcp (ghcr.io/homeassistant-ai/ha-mcp)</summary>

### [`v7.5.0`](https://github.com/homeassistant-ai/ha-mcp/blob/HEAD/CHANGELOG.md#v750-2026-05-13)

[Compare Source](homeassistant-ai/ha-mcp@v7.4.0...v7.5.0)

##### Added

- Add ENABLE\_LITE\_DOCSTRINGS beta toggle
  ([#&#8203;1259](homeassistant-ai/ha-mcp#1259))
- Add ha\_call\_event tool for publishing events on the HA event bus ([#&#8203;996](homeassistant-ai/ha-mcp#996))
  ([#&#8203;1239](homeassistant-ai/ha-mcp#1239))
- Pinpoint backslash-escape mistake in python\_sandbox errors
  ([#&#8203;1204](homeassistant-ai/ha-mcp#1204))
- Reject empty-trigger automations targeting scene.create
  ([#&#8203;1187](homeassistant-ai/ha-mcp#1187))
- Add scene config tools — ha\_config\_get/set/remove\_scene
  ([#&#8203;1168](homeassistant-ai/ha-mcp#1168))
- **addon**: Optional OAuth 2.1 mode for webhook proxy (beta)
  ([#&#8203;1184](homeassistant-ai/ha-mcp#1184))
- Surface helper schema inline in ha\_config\_set\_helper validation errors ([#&#8203;1149](homeassistant-ai/ha-mcp#1149))
  ([#&#8203;1179](homeassistant-ai/ha-mcp#1179))
- Emit progress via FastMCP Context in long-running tools
  ([#&#8203;1124](homeassistant-ai/ha-mcp#1124))
- Broaden python\_transform AST allowlist + improve error UX
  ([#&#8203;1163](homeassistant-ai/ha-mcp#1163))
- Add ha\_manage\_custom\_tool — sandboxed code execution escape hatch
  ([#&#8203;854](homeassistant-ai/ha-mcp#854))
- Always-on skills; rename list/read resource tools with ha\_ prefix
  ([#&#8203;1136](homeassistant-ai/ha-mcp#1136))
- Expose device\_class + options on ha\_set\_entity / ha\_get\_entity (Show As)
  ([#&#8203;1135](homeassistant-ai/ha-mcp#1135))
- **site**: Inline wizard data into setup.astro, migrate setup nuggets, drop content collections
  ([#&#8203;1120](homeassistant-ai/ha-mcp#1120))
- Add "Advanced debug logging" toggle for kill-signal diagnostics
  ([#&#8203;1117](homeassistant-ai/ha-mcp#1117))
- **yaml**: Scoped lovelace.dashboards.\<url\_path> support (issue [#&#8203;1034](homeassistant-ai/ha-mcp#1034))
  ([#&#8203;1103](homeassistant-ai/ha-mcp#1103))
- Add HA\_VERIFY\_SSL toggle to disable TLS verification
  ([#&#8203;1104](homeassistant-ai/ha-mcp#1104))
- Per-top-level-key config\_hash for ha\_manage\_energy\_prefs ([#&#8203;1049](homeassistant-ai/ha-mcp#1049))
  ([#&#8203;1098](homeassistant-ai/ha-mcp#1098))
- **site**: Add gemini-cli setup notes + compose hardening to wizard ([#&#8203;1027](homeassistant-ai/ha-mcp#1027))
  ([#&#8203;1087](homeassistant-ai/ha-mcp#1087))
- Add convenience modes to ha\_manage\_energy\_prefs ([#&#8203;1050](homeassistant-ai/ha-mcp#1050))
  ([#&#8203;1073](homeassistant-ai/ha-mcp#1073))
- Surface integration log levels in ha\_get\_logs/integration/addon ([#&#8203;956](homeassistant-ai/ha-mcp#956))
  ([#&#8203;1003](homeassistant-ai/ha-mcp#1003))
- Expose allowlist\_external\_dirs in ha\_get\_overview full system\_info
  ([#&#8203;1053](homeassistant-ai/ha-mcp#1053))
- **dashboards**: Unify identifier handling in ha\_config\_\*\_dashboard tools ([#&#8203;981](homeassistant-ai/ha-mcp#981))
  ([#&#8203;1075](homeassistant-ai/ha-mcp#1075))
- Include addon container logs in bug reports
  ([#&#8203;934](homeassistant-ai/ha-mcp#934))
- Add WebSocket response-shaping controls to ha\_manage\_addon
  ([#&#8203;1009](homeassistant-ai/ha-mcp#1009))
- Web-based settings UI for per-tool enable/disable/pin
  ([#&#8203;960](homeassistant-ai/ha-mcp#960))
- **site**: Add OpenCode support to setup wizard
  ([#&#8203;1080](homeassistant-ai/ha-mcp#1080))

##### Changed

- Clarify standard-mode HTTP deployment guidance
  ([#&#8203;1185](homeassistant-ai/ha-mcp#1185))
- Add Cloudflared add-on hostname alternative for tunnel service
  ([#&#8203;1183](homeassistant-ai/ha-mcp#1183))
- Align tool naming convention between AGENTS.md and styleguide ([#&#8203;943](homeassistant-ai/ha-mcp#943))
  ([#&#8203;1174](homeassistant-ai/ha-mcp#1174))
- **addon**: Note tool-list ([#&#8203;985](homeassistant-ai/ha-mcp#985 divergence; fix [#&#8203;1139](https://github.com/homeassistant-ai/ha-mcp/issues/1139)/[#&#8203;1162](https://github.com/homeassistant-ai/ha-mcp/issues/1162) test conflict
  ([#&#8203;1172](homeassistant-ai/ha-mcp#1172))
- Add brew install option for mcp-proxy on macOS
  ([#&#8203;1171](homeassistant-ai/ha-mcp#1171))
- Update contributors list \[contributors-updated]
  ([`aba01a1`](homeassistant-ai/ha-mcp@aba01a1))
- Warn against enable\_tool\_search on Claude Sonnet/Opus ([#&#8203;1088](homeassistant-ai/ha-mcp#1088))
  ([#&#8203;1140](homeassistant-ai/ha-mcp#1140))
- Address [#&#8203;1094](homeassistant-ai/ha-mcp#1094) review nits on OpenCode mirror comments
  ([#&#8203;1105](homeassistant-ai/ha-mcp#1105))

##### Fixed

- **integrations**: Surface ConfigEntry.options via OptionsFlow probe
  ([#&#8203;1245](homeassistant-ai/ha-mcp#1245))
- **backup**: Discover local agent at call time instead of hardcoding hassio.local
  ([#&#8203;1244](homeassistant-ai/ha-mcp#1244))
- Triage all 10 ha\_search\_entities behaviors from [#&#8203;1170](homeassistant-ai/ha-mcp#1170)
  ([#&#8203;1195](homeassistant-ai/ha-mcp#1195))
- Replace cron with systemd for demo server (prevents process leak)
  ([#&#8203;1110](homeassistant-ai/ha-mcp#1110))
- Improve ha\_manage\_addon discoverability (BM25 keywords + slug examples)
  ([#&#8203;1200](homeassistant-ai/ha-mcp#1200))
- Route Supervisor 401s to structured tool errors + add E2E coverage ([#&#8203;1129](homeassistant-ai/ha-mcp#1129))
  ([#&#8203;1192](homeassistant-ai/ha-mcp#1192))
- Harden \_validate\_category\_id gate to cover dict-promoted category
  ([#&#8203;1190](homeassistant-ai/ha-mcp#1190))
- Broaden template anti-pattern detection + skill discoverability ([#&#8203;1011](homeassistant-ai/ha-mcp#1011))
  ([#&#8203;1181](homeassistant-ai/ha-mcp#1181))
- Return newest automation traces, add offset+order pagination ([#&#8203;1177](homeassistant-ai/ha-mcp#1177))
  ([#&#8203;1178](homeassistant-ai/ha-mcp#1178))
- **security**: Write YAML backups outside www/ (GHSA-g39v-cvjh-8fpf)
  ([#&#8203;1180](homeassistant-ai/ha-mcp#1180))
- **search**: Apply domain\_filter when area\_filter is set ([#&#8203;1162](homeassistant-ai/ha-mcp#1162))
  ([#&#8203;1165](homeassistant-ai/ha-mcp#1165))
- **resources**: Reject HA-config YAML in dashboard resource content
  ([#&#8203;1160](homeassistant-ai/ha-mcp#1160))
- Close 19 bugs in ha\_config\_set\_helper (issue [#&#8203;1150](homeassistant-ai/ha-mcp#1150))
  ([#&#8203;1151](homeassistant-ai/ha-mcp#1151))
- Route addon log fetches directly to supervisor on addon installs
  ([#&#8203;1126](homeassistant-ai/ha-mcp#1126))
- Survive read-only filesystems at startup
  ([#&#8203;1138](homeassistant-ai/ha-mcp#1138))
- **helpers**: Clarify name-required-on-create for ha\_config\_set\_helper
  ([#&#8203;1143](homeassistant-ai/ha-mcp#1143))
- Resolve disabled entities via entity\_registry in helper deletion
  ([#&#8203;1119](homeassistant-ai/ha-mcp#1119))
- Allow unary operators in python\_transform sandbox
  ([#&#8203;1118](homeassistant-ai/ha-mcp#1118))
- **site**: Add github-copilot-agents wizard branch + delete unreferenced data/clients.ts
  ([#&#8203;1108](homeassistant-ai/ha-mcp#1108))
- **addons**: Route addon API calls through HA Core ingress proxy
  ([#&#8203;1069](homeassistant-ai/ha-mcp#1069))
- **webhook-proxy**: Surface webhook registration failures instead of silently loading
  ([#&#8203;1101](homeassistant-ai/ha-mcp#1101))
- **site**: Resolve client display-order collisions and anchor OpenCode shape
  ([#&#8203;1094](homeassistant-ai/ha-mcp#1094))

##### Performance Improvements

- Dedupe lovelace/dashboards/list in ha\_config\_set\_dashboard ([#&#8203;1085](homeassistant-ai/ha-mcp#1085))
  ([#&#8203;1191](homeassistant-ai/ha-mcp#1191))

##### Refactoring

- Drop obsolete ha\_mcp\_tools defensive ruamel.yaml imports ([post-#&#8203;1268](https://github.com/post-/ha-mcp/issues/1268))
  ([#&#8203;1269](homeassistant-ai/ha-mcp#1269))
- Extract shared Supervisor httpx client helper ([#&#8203;1130](homeassistant-ai/ha-mcp#1130))
  ([#&#8203;1203](homeassistant-ai/ha-mcp#1203))
- Surface client identity, AI model, config toggles, and prompt context in ha\_report\_issue
  ([#&#8203;1189](homeassistant-ai/ha-mcp#1189))
- Harden Context injection with safe-emit + branch coverage
  ([#&#8203;1173](homeassistant-ai/ha-mcp#1173))
- Consolidate area/floor set+remove tools (revisit of [#&#8203;813](homeassistant-ai/ha-mcp#813))
  ([#&#8203;1139](homeassistant-ai/ha-mcp#1139))
- Pass verify\_ssl to remaining direct-Supervisor httpx callers
  ([#&#8203;1128](homeassistant-ai/ha-mcp#1128))
- Validate only new entries on convenience-mode writes ([#&#8203;1086](homeassistant-ai/ha-mcp#1086))
  ([#&#8203;1100](homeassistant-ai/ha-mcp#1100))

***

<details>
<summary>Internal Changes</summary>

##### Fixed

- **ci**: Align pr.yml E2E with --dist loadscope ([#&#8203;1206](homeassistant-ai/ha-mcp#1206))
  ([#&#8203;1247](homeassistant-ai/ha-mcp#1247))
- **ci**: Switch Renovate to a GitHub App token to allow workflow-file pushes
  ([#&#8203;1229](homeassistant-ai/ha-mcp#1229))
- **ci**: Break gemini-triage retrigger loop and bump turn budget
  ([#&#8203;1131](homeassistant-ai/ha-mcp#1131))
- **ci**: Harden gemini-triage so failures stop spamming user issues
  ([#&#8203;1122](homeassistant-ai/ha-mcp#1122))
- **ci**: Unbreak hotfix-release semantic-release run
  ([#&#8203;1091](homeassistant-ai/ha-mcp#1091))

##### Chores

- **addon**: Publish dev addon version 7.4.1.dev299 \[skip ci]
  ([`397aa6d`](homeassistant-ai/ha-mcp@397aa6d))
- **addon**: Publish dev addon version 7.4.1.dev298 \[skip ci]
  ([`942b7e0`](homeassistant-ai/ha-mcp@942b7e0))
- Sync tool docs after merge \[skip ci]
  ([`6823c47`](homeassistant-ai/ha-mcp@6823c47))
- **addon**: Publish dev addon version 7.4.1.dev297 \[skip ci]
  ([`6eac062`](homeassistant-ai/ha-mcp@6eac062))
- **addon**: Publish dev addon version 7.4.1.dev296 \[skip ci]
  ([`b2afe93`](homeassistant-ai/ha-mcp@b2afe93))
- **addon**: Publish dev addon version 7.4.1.dev295 \[skip ci]
  ([`4f4c4f3`](homeassistant-ai/ha-mcp@4f4c4f3))
- **deps**: Update ghcr.io/home-assistant/home-assistant docker tag to v2026.5.1
  ([#&#8203;1236](homeassistant-ai/ha-mcp#1236))
- **addon**: Publish dev addon version 7.4.1.dev294 \[skip ci]
  ([`fd24991`](homeassistant-ai/ha-mcp@fd24991))
- **deps**: Update ghcr.io/astral-sh/uv docker tag to v0.11.13
  ([#&#8203;1233](homeassistant-ai/ha-mcp#1233))
- **addon**: Publish dev addon version 7.4.1.dev293 \[skip ci]
  ([`fcc6496`](homeassistant-ai/ha-mcp@fcc6496))
- **addon**: Publish dev addon version 7.4.1.dev292 \[skip ci]
  ([`2961650`](homeassistant-ai/ha-mcp@2961650))
- **addon**: Publish dev addon version 7.4.1.dev291 \[skip ci]
  ([`5703112`](homeassistant-ai/ha-mcp@5703112))
- **addon**: Publish dev addon version 7.4.1.dev290 \[skip ci]
  ([`19b2f65`](homeassistant-ai/ha-mcp@19b2f65))
- **addon**: Publish dev addon version 7.4.1.dev289 \[skip ci]
  ([`e5a1365`](homeassistant-ai/ha-mcp@e5a1365))
- Sync tool docs after merge \[skip ci]
  ([`d2ff93b`](homeassistant-ai/ha-mcp@d2ff93b))
- **addon**: Publish dev addon version 7.4.1.dev288 \[skip ci]
  ([`0f62400`](homeassistant-ai/ha-mcp@0f62400))
- Sync tool docs after merge \[skip ci]
  ([`c7e2066`](homeassistant-ai/ha-mcp@c7e2066))
- **addon**: Publish dev addon version 7.4.1.dev287 \[skip ci]
  ([`c1133d4`](homeassistant-ai/ha-mcp@c1133d4))
- **addon**: Publish dev addon version 7.4.1.dev286 \[skip ci]
  ([`1ae790e`](homeassistant-ai/ha-mcp@1ae790e))
- **addon**: Publish dev addon version 7.4.1.dev285 \[skip ci]
  ([`2387d0c`](homeassistant-ai/ha-mcp@2387d0c))
- **addon**: Publish dev addon version 7.4.1.dev284 \[skip ci]
  ([`dd3a4a5`](homeassistant-ai/ha-mcp@dd3a4a5))
- **addon**: Publish dev addon version 7.4.1.dev283 \[skip ci]
  ([`78af8eb`](homeassistant-ai/ha-mcp@78af8eb))
- Sync tool docs after merge \[skip ci]
  ([`093fd74`](homeassistant-ai/ha-mcp@093fd74))
- **addon**: Publish dev addon version 7.4.1.dev282 \[skip ci]
  ([`2141e15`](homeassistant-ai/ha-mcp@2141e15))
- Sync tool docs after merge \[skip ci]
  ([`7810c95`](homeassistant-ai/ha-mcp@7810c95))
- **addon**: Publish dev addon version 7.4.1.dev281 \[skip ci]
  ([`7d79ec2`](homeassistant-ai/ha-mcp@7d79ec2))
- Sync tool docs after merge \[skip ci]
  ([`a73dc81`](homeassistant-ai/ha-mcp@a73dc81))
- **addon**: Publish dev addon version 7.4.1.dev280 \[skip ci]
  ([`c858ce3`](homeassistant-ai/ha-mcp@c858ce3))
- Sync tool docs after merge \[skip ci]
  ([`a587be0`](homeassistant-ai/ha-mcp@a587be0))
- **addon**: Publish dev addon version 7.4.1.dev279 \[skip ci]
  ([`b78ddb2`](homeassistant-ai/ha-mcp@b78ddb2))
- Sync tool docs after merge \[skip ci]
  ([`1210725`](homeassistant-ai/ha-mcp@1210725))
- **addon**: Publish dev addon version 7.4.1.dev278 \[skip ci]
  ([`a282c17`](homeassistant-ai/ha-mcp@a282c17))
- **addon**: Publish dev addon version 7.4.1.dev277 \[skip ci]
  ([`1081768`](homeassistant-ai/ha-mcp@1081768))
- Sync tool docs after merge \[skip ci]
  ([`e03f5d2`](homeassistant-ai/ha-mcp@e03f5d2))
- **addon**: Publish dev addon version 7.4.1.dev276 \[skip ci]
  ([`c4ef680`](homeassistant-ai/ha-mcp@c4ef680))
- **addon**: Publish dev addon version 7.4.1.dev275 \[skip ci]
  ([`780422d`](homeassistant-ai/ha-mcp@780422d))
- Sync tool docs after merge \[skip ci]
  ([`8a2bd1a`](homeassistant-ai/ha-mcp@8a2bd1a))
- **addon**: Publish dev addon version 7.4.1.dev274 \[skip ci]
  ([`f0f09de`](homeassistant-ai/ha-mcp@f0f09de))
- **addon**: Publish dev addon version 7.4.1.dev273 \[skip ci]
  ([`cb49f68`](homeassistant-ai/ha-mcp@cb49f68))
- **addon**: Publish dev addon version 7.4.1.dev272 \[skip ci]
  ([`5097186`](homeassistant-ai/ha-mcp@5097186))
- **addon**: Publish dev addon version 7.4.1.dev271 \[skip ci]
  ([`4714342`](homeassistant-ai/ha-mcp@4714342))
- **addon**: Publish dev addon version 7.4.1.dev270 \[skip ci]
  ([`217982a`](homeassistant-ai/ha-mcp@217982a))
- **addon**: Publish dev addon version 7.4.1.dev269 \[skip ci]
  ([`a65dd5f`](homeassistant-ai/ha-mcp@a65dd5f))
- Sync tool docs after merge \[skip ci]
  ([`0e6b54f`](homeassistant-ai/ha-mcp@0e6b54f))
- **addon**: Publish dev addon version 7.4.1.dev268 \[skip ci]
  ([`60ba1f2`](homeassistant-ai/ha-mcp@60ba1f2))
- **addon**: Publish dev addon version 7.4.1.dev267 \[skip ci]
  ([`13412aa`](homeassistant-ai/ha-mcp@13412aa))
- Sync tool docs after merge \[skip ci]
  ([`2702a0f`](homeassistant-ai/ha-mcp@2702a0f))
- **addon**: Publish dev addon version 7.4.1.dev266 \[skip ci]
  ([`77abe0b`](homeassistant-ai/ha-mcp@77abe0b))
- **addon**: Publish dev addon version 7.4.1.dev265 \[skip ci]
  ([`08b69db`](homeassistant-ai/ha-mcp@08b69db))
- Sync tool docs after merge \[skip ci]
  ([`c1f24b5`](homeassistant-ai/ha-mcp@c1f24b5))
- **addon**: Publish dev addon version 7.4.1.dev264 \[skip ci]
  ([`f2583f6`](homeassistant-ai/ha-mcp@f2583f6))
- Sync tool docs after merge \[skip ci]
  ([`c2ed2d3`](homeassistant-ai/ha-mcp@c2ed2d3))
- **addon**: Publish dev addon version 7.4.1.dev263 \[skip ci]
  ([`9d43e54`](homeassistant-ai/ha-mcp@9d43e54))
- **addon**: Publish dev addon version 7.4.1.dev262 \[skip ci]
  ([`a7355c8`](homeassistant-ai/ha-mcp@a7355c8))
- Sync tool docs after merge \[skip ci]
  ([`085bd8a`](homeassistant-ai/ha-mcp@085bd8a))
- Convert agents to skills
  ([#&#8203;1084](homeassistant-ai/ha-mcp#1084))
- **addon**: Publish dev addon version 7.4.1.dev261 \[skip ci]
  ([`0d1af36`](homeassistant-ai/ha-mcp@0d1af36))
- **addon**: Publish dev addon version 7.4.1.dev260 \[skip ci]
  ([`29397dc`](homeassistant-ai/ha-mcp@29397dc))
- **addon**: Publish dev addon version 7.4.1.dev259 \[skip ci]
  ([`4bbc74b`](homeassistant-ai/ha-mcp@4bbc74b))
- Sync tool docs after merge \[skip ci]
  ([`0f6d41e`](homeassistant-ai/ha-mcp@0f6d41e))
- **addon**: Publish dev addon version 7.4.1.dev258 \[skip ci]
  ([`6751d08`](homeassistant-ai/ha-mcp@6751d08))
- **addon**: Publish dev addon version 7.4.1.dev257 \[skip ci]
  ([`2213c89`](homeassistant-ai/ha-mcp@2213c89))
- **addon**: Publish dev addon version 7.4.1.dev256 \[skip ci]
  ([`18a366e`](homeassistant-ai/ha-mcp@18a366e))
- **addon**: Publish dev addon version 7.4.1.dev255 \[skip ci]
  ([`0e9b18d`](homeassistant-ai/ha-mcp@0e9b18d))
- **addon**: Publish dev addon version 7.4.1.dev254 \[skip ci]
  ([`39fc65b`](homeassistant-ai/ha-mcp@39fc65b))
- Sync tool docs after merge \[skip ci]
  ([`9fa0aea`](homeassistant-ai/ha-mcp@9fa0aea))
- **addon**: Publish dev addon version 7.4.1.dev253 \[skip ci]
  ([`0dcc59e`](homeassistant-ai/ha-mcp@0dcc59e))
- Sync tool docs after merge \[skip ci]
  ([`ec7413f`](homeassistant-ai/ha-mcp@ec7413f))
- **addon**: Publish dev addon version 7.4.1.dev252 \[skip ci]
  ([`345640c`](homeassistant-ai/ha-mcp@345640c))
- **addon**: Publish dev addon version 7.4.1.dev251 \[skip ci]
  ([`bab9d49`](homeassistant-ai/ha-mcp@bab9d49))
- Sync tool docs after merge \[skip ci]
  ([`726f0a5`](homeassistant-ai/ha-mcp@726f0a5))
- **addon**: Publish dev addon version 7.4.1.dev250 \[skip ci]
  ([`ded04ea`](homeassistant-ai/ha-mcp@ded04ea))
- **addon**: Publish dev addon version 7.4.1.dev249 \[skip ci]
  ([`37d5628`](homeassistant-ai/ha-mcp@37d5628))
- **addon**: Publish dev addon version 7.4.1.dev248 \[skip ci]
  ([`530786a`](homeassistant-ai/ha-mcp@530786a))
- Sync tool docs after merge \[skip ci]
  ([`36719c3`](homeassistant-ai/ha-mcp@36719c3))
- **addon**: Publish dev addon version 7.4.1.dev247 \[skip ci]
  ([`4dc47b5`](homeassistant-ai/ha-mcp@4dc47b5))
- **addon**: Publish dev addon version 7.4.1.dev246 \[skip ci]
  ([`6ffbd6a`](homeassistant-ai/ha-mcp@6ffbd6a))
- Sync tool docs after merge \[skip ci]
  ([`add66e3`](homeassistant-ai/ha-mcp@add66e3))
- **addon**: Publish dev addon version 7.4.1.dev245 \[skip ci]
  ([`d0114af`](homeassistant-ai/ha-mcp@d0114af))
- Sync tool docs after merge \[skip ci]
  ([`0ca41af`](homeassistant-ai/ha-mcp@0ca41af))
- **addon**: Publish dev addon version 7.4.1.dev244 \[skip ci]
  ([`d052dd0`](homeassistant-ai/ha-mcp@d052dd0))
- **addon**: Publish dev addon version 7.4.0.dev243 \[skip ci]
  ([`827bc65`](homeassistant-ai/ha-mcp@827bc65))
- Bump package version to 7.4.1 to match released addon
  ([`4f65497`](homeassistant-ai/ha-mcp@4f65497))
- **addon**: Publish dev addon version 7.4.0.dev242 \[skip ci]
  ([`8ba80ae`](homeassistant-ai/ha-mcp@8ba80ae))
- **addon**: Publish hotfix version 7.4.1
  ([`bda75e6`](homeassistant-ai/ha-mcp@bda75e6))
- **addon**: Publish dev addon version 7.4.0.dev241 \[skip ci]
  ([`2126428`](homeassistant-ai/ha-mcp@2126428))

##### Continuous Integration

- **deps**: Bump renovatebot/github-action in the github-actions group
  ([#&#8203;1218](homeassistant-ai/ha-mcp#1218))
- **deps**: Bump renovatebot/github-action in the github-actions group
  ([#&#8203;1111](homeassistant-ai/ha-mcp#1111))

##### Refactoring

- Extract \_fetch\_dashboards\_list helper ([#&#8203;1193](homeassistant-ai/ha-mcp#1193))
  ([#&#8203;1207](homeassistant-ai/ha-mcp#1207))

##### Testing

- **e2e**: Module-scope bulk\_automations + bulk\_scripts fixtures (refs [#&#8203;366](homeassistant-ai/ha-mcp#366))
  ([#&#8203;1275](homeassistant-ai/ha-mcp#1275))
- **e2e**: Lower INPUT\_BOOLEAN\_WAIT from 30s to 10s (refs [#&#8203;366](homeassistant-ai/ha-mcp#366))
  ([#&#8203;1273](homeassistant-ai/ha-mcp#1273))
- **e2e**: Generalize readiness-gate diagnostics helper (closes [#&#8203;1267](homeassistant-ai/ha-mcp#1267))
  ([#&#8203;1271](homeassistant-ai/ha-mcp#1271))
- **e2e**: Narrow except clauses in e2e polling helpers (closes [#&#8203;1266](homeassistant-ai/ha-mcp#1266))
  ([#&#8203;1270](homeassistant-ai/ha-mcp#1270))
- **e2e**: Drop ha\_mcp\_tools retry-path + pre-install manifest requirements
  ([#&#8203;1268](homeassistant-ai/ha-mcp#1268))
- **e2e**: Instrument and retry ha\_mcp\_tools readiness wait
  ([#&#8203;1262](homeassistant-ai/ha-mcp#1262))
- Use time.monotonic() in UAT runner and test\_env\_manager
  ([#&#8203;1254](homeassistant-ai/ha-mcp#1254))
- **e2e**: Detect partial/corrupt hacs\_frontend dir in fast-path guard
  ([#&#8203;1253](homeassistant-ai/ha-mcp#1253))
- **e2e**: Remove unused wait/assert helpers ([post-#&#8203;1249](https://github.com/post-/ha-mcp/issues/1249) audit)
  ([#&#8203;1256](homeassistant-ai/ha-mcp#1256))
- **e2e**: Clear stale .hacs\_frontend.lock from prior crashed runs
  ([#&#8203;1252](homeassistant-ai/ha-mcp#1252))
- **e2e**: Use time.monotonic() in workflow polling loops
  ([#&#8203;1258](homeassistant-ai/ha-mcp#1258))
- **e2e**: Use time.monotonic() for duration polling ([#&#8203;1234](homeassistant-ai/ha-mcp#1234))
  ([#&#8203;1249](homeassistant-ai/ha-mcp#1249))
- **e2e**: Close ARM ha\_mcp\_tools readiness race under loadscope
  ([#&#8203;1208](homeassistant-ai/ha-mcp#1208))
- **hacs**: Tighten is\_hacs\_unavailable to not match legitimate "Repository not found"
  ([#&#8203;1246](homeassistant-ai/ha-mcp#1246))
- **seed**: Unblock 3 silent-skip pagination/state tests via baked recorder DB
  ([#&#8203;1240](homeassistant-ai/ha-mcp#1240))
- **seed**: Register a writable local\_calendar to unblock event-creation test
  ([#&#8203;1243](homeassistant-ai/ha-mcp#1243))
- **addon**: Fix base64 padding-bit flake in token tamper tests ([#&#8203;1238](homeassistant-ai/ha-mcp#1238))
  ([#&#8203;1241](homeassistant-ai/ha-mcp#1241))
- **seed**: Add a writable scene for test\_call\_service\_scene\_turn\_on
  ([#&#8203;1231](homeassistant-ai/ha-mcp#1231))
- **seed**: Assign demo device to living\_room area for filter test
  ([#&#8203;1230](homeassistant-ai/ha-mcp#1230))
- **e2e**: Drop nonexistent sun service from session readiness wait
  ([#&#8203;1227](homeassistant-ai/ha-mcp#1227))
- **e2e**: Self-contain dashboard register/remove to fix ARM xdist race ([#&#8203;1196](homeassistant-ai/ha-mcp#1196))
  ([#&#8203;1201](homeassistant-ai/ha-mcp#1201))
- Fix EN dash in docstring causing RUF002 lint failure
  ([`eac5916`](homeassistant-ai/ha-mcp@eac5916))
- Address Gemini review feedback on host detection and port allocation
  ([`960305e`](homeassistant-ai/ha-mcp@960305e))
- Fix three categories of E2E test flakiness
  ([`39417ff`](homeassistant-ai/ha-mcp@39417ff))
- **e2e**: Pin config\_hash stability for dashboards
  ([#&#8203;1132](homeassistant-ai/ha-mcp#1132))

</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/455
doonga added a commit to greyrock-labs/home-ops that referenced this pull request May 13, 2026
….0 ) (#26)

This PR contains the following updates:

| Package | Update | Change |
|---|---|---|
| [ghcr.io/homeassistant-ai/ha-mcp](https://github.com/homeassistant-ai/ha-mcp) | minor | `7.4.0` → `7.5.0` |

---

### Release Notes

<details>
<summary>homeassistant-ai/ha-mcp (ghcr.io/homeassistant-ai/ha-mcp)</summary>

### [`v7.5.0`](https://github.com/homeassistant-ai/ha-mcp/blob/HEAD/CHANGELOG.md#v750-2026-05-13)

[Compare Source](homeassistant-ai/ha-mcp@v7.4.0...v7.5.0)

##### Added

- Add ENABLE\_LITE\_DOCSTRINGS beta toggle
  ([#&#8203;1259](homeassistant-ai/ha-mcp#1259))
- Add ha\_call\_event tool for publishing events on the HA event bus ([#&#8203;996](homeassistant-ai/ha-mcp#996))
  ([#&#8203;1239](homeassistant-ai/ha-mcp#1239))
- Pinpoint backslash-escape mistake in python\_sandbox errors
  ([#&#8203;1204](homeassistant-ai/ha-mcp#1204))
- Reject empty-trigger automations targeting scene.create
  ([#&#8203;1187](homeassistant-ai/ha-mcp#1187))
- Add scene config tools — ha\_config\_get/set/remove\_scene
  ([#&#8203;1168](homeassistant-ai/ha-mcp#1168))
- **addon**: Optional OAuth 2.1 mode for webhook proxy (beta)
  ([#&#8203;1184](homeassistant-ai/ha-mcp#1184))
- Surface helper schema inline in ha\_config\_set\_helper validation errors ([#&#8203;1149](homeassistant-ai/ha-mcp#1149))
  ([#&#8203;1179](homeassistant-ai/ha-mcp#1179))
- Emit progress via FastMCP Context in long-running tools
  ([#&#8203;1124](homeassistant-ai/ha-mcp#1124))
- Broaden python\_transform AST allowlist + improve error UX
  ([#&#8203;1163](homeassistant-ai/ha-mcp#1163))
- Add ha\_manage\_custom\_tool — sandboxed code execution escape hatch
  ([#&#8203;854](homeassistant-ai/ha-mcp#854))
- Always-on skills; rename list/read resource tools with ha\_ prefix
  ([#&#8203;1136](homeassistant-ai/ha-mcp#1136))
- Expose device\_class + options on ha\_set\_entity / ha\_get\_entity (Show As)
  ([#&#8203;1135](homeassistant-ai/ha-mcp#1135))
- **site**: Inline wizard data into setup.astro, migrate setup nuggets, drop content collections
  ([#&#8203;1120](homeassistant-ai/ha-mcp#1120))
- Add "Advanced debug logging" toggle for kill-signal diagnostics
  ([#&#8203;1117](homeassistant-ai/ha-mcp#1117))
- **yaml**: Scoped lovelace.dashboards.\<url\_path> support (issue [#&#8203;1034](homeassistant-ai/ha-mcp#1034))
  ([#&#8203;1103](homeassistant-ai/ha-mcp#1103))
- Add HA\_VERIFY\_SSL toggle to disable TLS verification
  ([#&#8203;1104](homeassistant-ai/ha-mcp#1104))
- Per-top-level-key config\_hash for ha\_manage\_energy\_prefs ([#&#8203;1049](homeassistant-ai/ha-mcp#1049))
  ([#&#8203;1098](homeassistant-ai/ha-mcp#1098))
- **site**: Add gemini-cli setup notes + compose hardening to wizard ([#&#8203;1027](homeassistant-ai/ha-mcp#1027))
  ([#&#8203;1087](homeassistant-ai/ha-mcp#1087))
- Add convenience modes to ha\_manage\_energy\_prefs ([#&#8203;1050](homeassistant-ai/ha-mcp#1050))
  ([#&#8203;1073](homeassistant-ai/ha-mcp#1073))
- Surface integration log levels in ha\_get\_logs/integration/addon ([#&#8203;956](homeassistant-ai/ha-mcp#956))
  ([#&#8203;1003](homeassistant-ai/ha-mcp#1003))
- Expose allowlist\_external\_dirs in ha\_get\_overview full system\_info
  ([#&#8203;1053](homeassistant-ai/ha-mcp#1053))
- **dashboards**: Unify identifier handling in ha\_config\_\*\_dashboard tools ([#&#8203;981](homeassistant-ai/ha-mcp#981))
  ([#&#8203;1075](homeassistant-ai/ha-mcp#1075))
- Include addon container logs in bug reports
  ([#&#8203;934](homeassistant-ai/ha-mcp#934))
- Add WebSocket response-shaping controls to ha\_manage\_addon
  ([#&#8203;1009](homeassistant-ai/ha-mcp#1009))
- Web-based settings UI for per-tool enable/disable/pin
  ([#&#8203;960](homeassistant-ai/ha-mcp#960))
- **site**: Add OpenCode support to setup wizard
  ([#&#8203;1080](homeassistant-ai/ha-mcp#1080))

##### Changed

- Clarify standard-mode HTTP deployment guidance
  ([#&#8203;1185](homeassistant-ai/ha-mcp#1185))
- Add Cloudflared add-on hostname alternative for tunnel service
  ([#&#8203;1183](homeassistant-ai/ha-mcp#1183))
- Align tool naming convention between AGENTS.md and styleguide ([#&#8203;943](homeassistant-ai/ha-mcp#943))
  ([#&#8203;1174](homeassistant-ai/ha-mcp#1174))
- **addon**: Note tool-list ([#&#8203;985](homeassistant-ai/ha-mcp#985 divergence; fix [#&#8203;1139](https://github.com/homeassistant-ai/ha-mcp/issues/1139)/[#&#8203;1162](https://github.com/homeassistant-ai/ha-mcp/issues/1162) test conflict
  ([#&#8203;1172](homeassistant-ai/ha-mcp#1172))
- Add brew install option for mcp-proxy on macOS
  ([#&#8203;1171](homeassistant-ai/ha-mcp#1171))
- Update contributors list \[contributors-updated]
  ([`aba01a1`](homeassistant-ai/ha-mcp@aba01a1))
- Warn against enable\_tool\_search on Claude Sonnet/Opus ([#&#8203;1088](homeassistant-ai/ha-mcp#1088))
  ([#&#8203;1140](homeassistant-ai/ha-mcp#1140))
- Address [#&#8203;1094](homeassistant-ai/ha-mcp#1094) review nits on OpenCode mirror comments
  ([#&#8203;1105](homeassistant-ai/ha-mcp#1105))

##### Fixed

- **integrations**: Surface ConfigEntry.options via OptionsFlow probe
  ([#&#8203;1245](homeassistant-ai/ha-mcp#1245))
- **backup**: Discover local agent at call time instead of hardcoding hassio.local
  ([#&#8203;1244](homeassistant-ai/ha-mcp#1244))
- Triage all 10 ha\_search\_entities behaviors from [#&#8203;1170](homeassistant-ai/ha-mcp#1170)
  ([#&#8203;1195](homeassistant-ai/ha-mcp#1195))
- Replace cron with systemd for demo server (prevents process leak)
  ([#&#8203;1110](homeassistant-ai/ha-mcp#1110))
- Improve ha\_manage\_addon discoverability (BM25 keywords + slug examples)
  ([#&#8203;1200](homeassistant-ai/ha-mcp#1200))
- Route Supervisor 401s to structured tool errors + add E2E coverage ([#&#8203;1129](homeassistant-ai/ha-mcp#1129))
  ([#&#8203;1192](homeassistant-ai/ha-mcp#1192))
- Harden \_validate\_category\_id gate to cover dict-promoted category
  ([#&#8203;1190](homeassistant-ai/ha-mcp#1190))
- Broaden template anti-pattern detection + skill discoverability ([#&#8203;1011](homeassistant-ai/ha-mcp#1011))
  ([#&#8203;1181](homeassistant-ai/ha-mcp#1181))
- Return newest automation traces, add offset+order pagination ([#&#8203;1177](homeassistant-ai/ha-mcp#1177))
  ([#&#8203;1178](homeassistant-ai/ha-mcp#1178))
- **security**: Write YAML backups outside www/ (GHSA-g39v-cvjh-8fpf)
  ([#&#8203;1180](homeassistant-ai/ha-mcp#1180))
- **search**: Apply domain\_filter when area\_filter is set ([#&#8203;1162](homeassistant-ai/ha-mcp#1162))
  ([#&#8203;1165](homeassistant-ai/ha-mcp#1165))
- **resources**: Reject HA-config YAML in dashboard resource content
  ([#&#8203;1160](homeassistant-ai/ha-mcp#1160))
- Close 19 bugs in ha\_config\_set\_helper (issue [#&#8203;1150](homeassistant-ai/ha-mcp#1150))
  ([#&#8203;1151](homeassistant-ai/ha-mcp#1151))
- Route addon log fetches directly to supervisor on addon installs
  ([#&#8203;1126](homeassistant-ai/ha-mcp#1126))
- Survive read-only filesystems at startup
  ([#&#8203;1138](homeassistant-ai/ha-mcp#1138))
- **helpers**: Clarify name-required-on-create for ha\_config\_set\_helper
  ([#&#8203;1143](homeassistant-ai/ha-mcp#1143))
- Resolve disabled entities via entity\_registry in helper deletion
  ([#&#8203;1119](homeassistant-ai/ha-mcp#1119))
- Allow unary operators in python\_transform sandbox
  ([#&#8203;1118](homeassistant-ai/ha-mcp#1118))
- **site**: Add github-copilot-agents wizard branch + delete unreferenced data/clients.ts
  ([#&#8203;1108](homeassistant-ai/ha-mcp#1108))
- **addons**: Route addon API calls through HA Core ingress proxy
  ([#&#8203;1069](homeassistant-ai/ha-mcp#1069))
- **webhook-proxy**: Surface webhook registration failures instead of silently loading
  ([#&#8203;1101](homeassistant-ai/ha-mcp#1101))
- **site**: Resolve client display-order collisions and anchor OpenCode shape
  ([#&#8203;1094](homeassistant-ai/ha-mcp#1094))

##### Performance Improvements

- Dedupe lovelace/dashboards/list in ha\_config\_set\_dashboard ([#&#8203;1085](homeassistant-ai/ha-mcp#1085))
  ([#&#8203;1191](homeassistant-ai/ha-mcp#1191))

##### Refactoring

- Drop obsolete ha\_mcp\_tools defensive ruamel.yaml imports ([post-#&#8203;1268](https://github.com/post-/ha-mcp/issues/1268))
  ([#&#8203;1269](homeassistant-ai/ha-mcp#1269))
- Extract shared Supervisor httpx client helper ([#&#8203;1130](homeassistant-ai/ha-mcp#1130))
  ([#&#8203;1203](homeassistant-ai/ha-mcp#1203))
- Surface client identity, AI model, config toggles, and prompt context in ha\_report\_issue
  ([#&#8203;1189](homeassistant-ai/ha-mcp#1189))
- Harden Context injection with safe-emit + branch coverage
  ([#&#8203;1173](homeassistant-ai/ha-mcp#1173))
- Consolidate area/floor set+remove tools (revisit of [#&#8203;813](homeassistant-ai/ha-mcp#813))
  ([#&#8203;1139](homeassistant-ai/ha-mcp#1139))
- Pass verify\_ssl to remaining direct-Supervisor httpx callers
  ([#&#8203;1128](homeassistant-ai/ha-mcp#1128))
- Validate only new entries on convenience-mode writes ([#&#8203;1086](homeassistant-ai/ha-mcp#1086))
  ([#&#8203;1100](homeassistant-ai/ha-mcp#1100))

***

<details>
<summary>Internal Changes</summary>

##### Fixed

- **ci**: Align pr.yml E2E with --dist loadscope ([#&#8203;1206](homeassistant-ai/ha-mcp#1206))
  ([#&#8203;1247](homeassistant-ai/ha-mcp#1247))
- **ci**: Switch Renovate to a GitHub App token to allow workflow-file pushes
  ([#&#8203;1229](homeassistant-ai/ha-mcp#1229))
- **ci**: Break gemini-triage retrigger loop and bump turn budget
  ([#&#8203;1131](homeassistant-ai/ha-mcp#1131))
- **ci**: Harden gemini-triage so failures stop spamming user issues
  ([#&#8203;1122](homeassistant-ai/ha-mcp#1122))
- **ci**: Unbreak hotfix-release semantic-release run
  ([#&#8203;1091](homeassistant-ai/ha-mcp#1091))

##### Chores

- **addon**: Publish dev addon version 7.4.1.dev299 \[skip ci]
  ([`397aa6d`](homeassistant-ai/ha-mcp@397aa6d))
- **addon**: Publish dev addon version 7.4.1.dev298 \[skip ci]
  ([`942b7e0`](homeassistant-ai/ha-mcp@942b7e0))
- Sync tool docs after merge \[skip ci]
  ([`6823c47`](homeassistant-ai/ha-mcp@6823c47))
- **addon**: Publish dev addon version 7.4.1.dev297 \[skip ci]
  ([`6eac062`](homeassistant-ai/ha-mcp@6eac062))
- **addon**: Publish dev addon version 7.4.1.dev296 \[skip ci]
  ([`b2afe93`](homeassistant-ai/ha-mcp@b2afe93))
- **addon**: Publish dev addon version 7.4.1.dev295 \[skip ci]
  ([`4f4c4f3`](homeassistant-ai/ha-mcp@4f4c4f3))
- **deps**: Update ghcr.io/home-assistant/home-assistant docker tag to v2026.5.1
  ([#&#8203;1236](homeassistant-ai/ha-mcp#1236))
- **addon**: Publish dev addon version 7.4.1.dev294 \[skip ci]
  ([`fd24991`](homeassistant-ai/ha-mcp@fd24991))
- **deps**: Update ghcr.io/astral-sh/uv docker tag to v0.11.13
  ([#&#8203;1233](homeassistant-ai/ha-mcp#1233))
- **addon**: Publish dev addon version 7.4.1.dev293 \[skip ci]
  ([`fcc6496`](homeassistant-ai/ha-mcp@fcc6496))
- **addon**: Publish dev addon version 7.4.1.dev292 \[skip ci]
  ([`2961650`](homeassistant-ai/ha-mcp@2961650))
- **addon**: Publish dev addon version 7.4.1.dev291 \[skip ci]
  ([`5703112`](homeassistant-ai/ha-mcp@5703112))
- **addon**: Publish dev addon version 7.4.1.dev290 \[skip ci]
  ([`19b2f65`](homeassistant-ai/ha-mcp@19b2f65))
- **addon**: Publish dev addon version 7.4.1.dev289 \[skip ci]
  ([`e5a1365`](homeassistant-ai/ha-mcp@e5a1365))
- Sync tool docs after merge \[skip ci]
  ([`d2ff93b`](homeassistant-ai/ha-mcp@d2ff93b))
- **addon**: Publish dev addon version 7.4.1.dev288 \[skip ci]
  ([`0f62400`](homeassistant-ai/ha-mcp@0f62400))
- Sync tool docs after merge \[skip ci]
  ([`c7e2066`](homeassistant-ai/ha-mcp@c7e2066))
- **addon**: Publish dev addon version 7.4.1.dev287 \[skip ci]
  ([`c1133d4`](homeassistant-ai/ha-mcp@c1133d4))
- **addon**: Publish dev addon version 7.4.1.dev286 \[skip ci]
  ([`1ae790e`](homeassistant-ai/ha-mcp@1ae790e))
- **addon**: Publish dev addon version 7.4.1.dev285 \[skip ci]
  ([`2387d0c`](homeassistant-ai/ha-mcp@2387d0c))
- **addon**: Publish dev addon version 7.4.1.dev284 \[skip ci]
  ([`dd3a4a5`](homeassistant-ai/ha-mcp@dd3a4a5))
- **addon**: Publish dev addon version 7.4.1.dev283 \[skip ci]
  ([`78af8eb`](homeassistant-ai/ha-mcp@78af8eb))
- Sync tool docs after merge \[skip ci]
  ([`093fd74`](homeassistant-ai/ha-mcp@093fd74))
- **addon**: Publish dev addon version 7.4.1.dev282 \[skip ci]
  ([`2141e15`](homeassistant-ai/ha-mcp@2141e15))
- Sync tool docs after merge \[skip ci]
  ([`7810c95`](homeassistant-ai/ha-mcp@7810c95))
- **addon**: Publish dev addon version 7.4.1.dev281 \[skip ci]
  ([`7d79ec2`](homeassistant-ai/ha-mcp@7d79ec2))
- Sync tool docs after merge \[skip ci]
  ([`a73dc81`](homeassistant-ai/ha-mcp@a73dc81))
- **addon**: Publish dev addon version 7.4.1.dev280 \[skip ci]
  ([`c858ce3`](homeassistant-ai/ha-mcp@c858ce3))
- Sync tool docs after merge \[skip ci]
  ([`a587be0`](homeassistant-ai/ha-mcp@a587be0))
- **addon**: Publish dev addon version 7.4.1.dev279 \[skip ci]
  ([`b78ddb2`](homeassistant-ai/ha-mcp@b78ddb2))
- Sync tool docs after merge \[skip ci]
  ([`1210725`](homeassistant-ai/ha-mcp@1210725))
- **addon**: Publish dev addon version 7.4.1.dev278 \[skip ci]
  ([`a282c17`](homeassistant-ai/ha-mcp@a282c17))
- **addon**: Publish dev addon version 7.4.1.dev277 \[skip ci]
  ([`1081768`](homeassistant-ai/ha-mcp@1081768))
- Sync tool docs after merge \[skip ci]
  ([`e03f5d2`](homeassistant-ai/ha-mcp@e03f5d2))
- **addon**: Publish dev addon version 7.4.1.dev276 \[skip ci]
  ([`c4ef680`](homeassistant-ai/ha-mcp@c4ef680))
- **addon**: Publish dev addon version 7.4.1.dev275 \[skip ci]
  ([`780422d`](homeassistant-ai/ha-mcp@780422d))
- Sync tool docs after merge \[skip ci]
  ([`8a2bd1a`](homeassistant-ai/ha-mcp@8a2bd1a))
- **addon**: Publish dev addon version 7.4.1.dev274 \[skip ci]
  ([`f0f09de`](homeassistant-ai/ha-mcp@f0f09de))
- **addon**: Publish dev addon version 7.4.1.dev273 \[skip ci]
  ([`cb49f68`](homeassistant-ai/ha-mcp@cb49f68))
- **addon**: Publish dev addon version 7.4.1.dev272 \[skip ci]
  ([`5097186`](homeassistant-ai/ha-mcp@5097186))
- **addon**: Publish dev addon version 7.4.1.dev271 \[skip ci]
  ([`4714342`](homeassistant-ai/ha-mcp@4714342))
- **addon**: Publish dev addon version 7.4.1.dev270 \[skip ci]
  ([`217982a`](homeassistant-ai/ha-mcp@217982a))
- **addon**: Publish dev addon version 7.4.1.dev269 \[skip ci]
  ([`a65dd5f`](homeassistant-ai/ha-mcp@a65dd5f))
- Sync tool docs after merge \[skip ci]
  ([`0e6b54f`](homeassistant-ai/ha-mcp@0e6b54f))
- **addon**: Publish dev addon version 7.4.1.dev268 \[skip ci]
  ([`60ba1f2`](homeassistant-ai/ha-mcp@60ba1f2))
- **addon**: Publish dev addon version 7.4.1.dev267 \[skip ci]
  ([`13412aa`](homeassistant-ai/ha-mcp@13412aa))
- Sync tool docs after merge \[skip ci]
  ([`2702a0f`](homeassistant-ai/ha-mcp@2702a0f))
- **addon**: Publish dev addon version 7.4.1.dev266 \[skip ci]
  ([`77abe0b`](homeassistant-ai/ha-mcp@77abe0b))
- **addon**: Publish dev addon version 7.4.1.dev265 \[skip ci]
  ([`08b69db`](homeassistant-ai/ha-mcp@08b69db))
- Sync tool docs after merge \[skip ci]
  ([`c1f24b5`](homeassistant-ai/ha-mcp@c1f24b5))
- **addon**: Publish dev addon version 7.4.1.dev264 \[skip ci]
  ([`f2583f6`](homeassistant-ai/ha-mcp@f2583f6))
- Sync tool docs after merge \[skip ci]
  ([`c2ed2d3`](homeassistant-ai/ha-mcp@c2ed2d3))
- **addon**: Publish dev addon version 7.4.1.dev263 \[skip ci]
  ([`9d43e54`](homeassistant-ai/ha-mcp@9d43e54))
- **addon**: Publish dev addon version 7.4.1.dev262 \[skip ci]
  ([`a7355c8`](homeassistant-ai/ha-mcp@a7355c8))
- Sync tool docs after merge \[skip ci]
  ([`085bd8a`](homeassistant-ai/ha-mcp@085bd8a))
- Convert agents to skills
  ([#&#8203;1084](homeassistant-ai/ha-mcp#1084))
- **addon**: Publish dev addon version 7.4.1.dev261 \[skip ci]
  ([`0d1af36`](homeassistant-ai/ha-mcp@0d1af36))
- **addon**: Publish dev addon version 7.4.1.dev260 \[skip ci]
  ([`29397dc`](homeassistant-ai/ha-mcp@29397dc))
- **addon**: Publish dev addon version 7.4.1.dev259 \[skip ci]
  ([`4bbc74b`](homeassistant-ai/ha-mcp@4bbc74b))
- Sync tool docs after merge \[skip ci]
  ([`0f6d41e`](homeassistant-ai/ha-mcp@0f6d41e))
- **addon**: Publish dev addon version 7.4.1.dev258 \[skip ci]
  ([`6751d08`](homeassistant-ai/ha-mcp@6751d08))
- **addon**: Publish dev addon version 7.4.1.dev257 \[skip ci]
  ([`2213c89`](homeassistant-ai/ha-mcp@2213c89))
- **addon**: Publish dev addon version 7.4.1.dev256 \[skip ci]
  ([`18a366e`](homeassistant-ai/ha-mcp@18a366e))
- **addon**: Publish dev addon version 7.4.1.dev255 \[skip ci]
  ([`0e9b18d`](homeassistant-ai/ha-mcp@0e9b18d))
- **addon**: Publish dev addon version 7.4.1.dev254 \[skip ci]
  ([`39fc65b`](homeassistant-ai/ha-mcp@39fc65b))
- Sync tool docs after merge \[skip ci]
  ([`9fa0aea`](homeassistant-ai/ha-mcp@9fa0aea))
- **addon**: Publish dev addon version 7.4.1.dev253 \[skip ci]
  ([`0dcc59e`](homeassistant-ai/ha-mcp@0dcc59e))
- Sync tool docs after merge \[skip ci]
  ([`ec7413f`](homeassistant-ai/ha-mcp@ec7413f))
- **addon**: Publish dev addon version 7.4.1.dev252 \[skip ci]
  ([`345640c`](homeassistant-ai/ha-mcp@345640c))
- **addon**: Publish dev addon version 7.4.1.dev251 \[skip ci]
  ([`bab9d49`](homeassistant-ai/ha-mcp@bab9d49))
- Sync tool docs after merge \[skip ci]
  ([`726f0a5`](homeassistant-ai/ha-mcp@726f0a5))
- **addon**: Publish dev addon version 7.4.1.dev250 \[skip ci]
  ([`ded04ea`](homeassistant-ai/ha-mcp@ded04ea))
- **addon**: Publish dev addon version 7.4.1.dev249 \[skip ci]
  ([`37d5628`](homeassistant-ai/ha-mcp@37d5628))
- **addon**: Publish dev addon version 7.4.1.dev248 \[skip ci]
  ([`530786a`](homeassistant-ai/ha-mcp@530786a))
- Sync tool docs after merge \[skip ci]
  ([`36719c3`](homeassistant-ai/ha-mcp@36719c3))
- **addon**: Publish dev addon version 7.4.1.dev247 \[skip ci]
  ([`4dc47b5`](homeassistant-ai/ha-mcp@4dc47b5))
- **addon**: Publish dev addon version 7.4.1.dev246 \[skip ci]
  ([`6ffbd6a`](homeassistant-ai/ha-mcp@6ffbd6a))
- Sync tool docs after merge \[skip ci]
  ([`add66e3`](homeassistant-ai/ha-mcp@add66e3))
- **addon**: Publish dev addon version 7.4.1.dev245 \[skip ci]
  ([`d0114af`](homeassistant-ai/ha-mcp@d0114af))
- Sync tool docs after merge \[skip ci]
  ([`0ca41af`](homeassistant-ai/ha-mcp@0ca41af))
- **addon**: Publish dev addon version 7.4.1.dev244 \[skip ci]
  ([`d052dd0`](homeassistant-ai/ha-mcp@d052dd0))
- **addon**: Publish dev addon version 7.4.0.dev243 \[skip ci]
  ([`827bc65`](homeassistant-ai/ha-mcp@827bc65))
- Bump package version to 7.4.1 to match released addon
  ([`4f65497`](homeassistant-ai/ha-mcp@4f65497))
- **addon**: Publish dev addon version 7.4.0.dev242 \[skip ci]
  ([`8ba80ae`](homeassistant-ai/ha-mcp@8ba80ae))
- **addon**: Publish hotfix version 7.4.1
  ([`bda75e6`](homeassistant-ai/ha-mcp@bda75e6))
- **addon**: Publish dev addon version 7.4.0.dev241 \[skip ci]
  ([`2126428`](homeassistant-ai/ha-mcp@2126428))

##### Continuous Integration

- **deps**: Bump renovatebot/github-action in the github-actions group
  ([#&#8203;1218](homeassistant-ai/ha-mcp#1218))
- **deps**: Bump renovatebot/github-action in the github-actions group
  ([#&#8203;1111](homeassistant-ai/ha-mcp#1111))

##### Refactoring

- Extract \_fetch\_dashboards\_list helper ([#&#8203;1193](homeassistant-ai/ha-mcp#1193))
  ([#&#8203;1207](homeassistant-ai/ha-mcp#1207))

##### Testing

- **e2e**: Module-scope bulk\_automations + bulk\_scripts fixtures (refs [#&#8203;366](homeassistant-ai/ha-mcp#366))
  ([#&#8203;1275](homeassistant-ai/ha-mcp#1275))
- **e2e**: Lower INPUT\_BOOLEAN\_WAIT from 30s to 10s (refs [#&#8203;366](homeassistant-ai/ha-mcp#366))
  ([#&#8203;1273](homeassistant-ai/ha-mcp#1273))
- **e2e**: Generalize readiness-gate diagnostics helper (closes [#&#8203;1267](homeassistant-ai/ha-mcp#1267))
  ([#&#8203;1271](homeassistant-ai/ha-mcp#1271))
- **e2e**: Narrow except clauses in e2e polling helpers (closes [#&#8203;1266](homeassistant-ai/ha-mcp#1266))
  ([#&#8203;1270](homeassistant-ai/ha-mcp#1270))
- **e2e**: Drop ha\_mcp\_tools retry-path + pre-install manifest requirements
  ([#&#8203;1268](homeassistant-ai/ha-mcp#1268))
- **e2e**: Instrument and retry ha\_mcp\_tools readiness wait
  ([#&#8203;1262](homeassistant-ai/ha-mcp#1262))
- Use time.monotonic() in UAT runner and test\_env\_manager
  ([#&#8203;1254](homeassistant-ai/ha-mcp#1254))
- **e2e**: Detect partial/corrupt hacs\_frontend dir in fast-path guard
  ([#&#8203;1253](homeassistant-ai/ha-mcp#1253))
- **e2e**: Remove unused wait/assert helpers ([post-#&#8203;1249](https://github.com/post-/ha-mcp/issues/1249) audit)
  ([#&#8203;1256](homeassistant-ai/ha-mcp#1256))
- **e2e**: Clear stale .hacs\_frontend.lock from prior crashed runs
  ([#&#8203;1252](homeassistant-ai/ha-mcp#1252))
- **e2e**: Use time.monotonic() in workflow polling loops
  ([#&#8203;1258](homeassistant-ai/ha-mcp#1258))
- **e2e**: Use time.monotonic() for duration polling ([#&#8203;1234](homeassistant-ai/ha-mcp#1234))
  ([#&#8203;1249](homeassistant-ai/ha-mcp#1249))
- **e2e**: Close ARM ha\_mcp\_tools readiness race under loadscope
  ([#&#8203;1208](homeassistant-ai/ha-mcp#1208))
- **hacs**: Tighten is\_hacs\_unavailable to not match legitimate "Repository not found"
  ([#&#8203;1246](homeassistant-ai/ha-mcp#1246))
- **seed**: Unblock 3 silent-skip pagination/state tests via baked recorder DB
  ([#&#8203;1240](homeassistant-ai/ha-mcp#1240))
- **seed**: Register a writable local\_calendar to unblock event-creation test
  ([#&#8203;1243](homeassistant-ai/ha-mcp#1243))
- **addon**: Fix base64 padding-bit flake in token tamper tests ([#&#8203;1238](homeassistant-ai/ha-mcp#1238))
  ([#&#8203;1241](homeassistant-ai/ha-mcp#1241))
- **seed**: Add a writable scene for test\_call\_service\_scene\_turn\_on
  ([#&#8203;1231](homeassistant-ai/ha-mcp#1231))
- **seed**: Assign demo device to living\_room area for filter test
  ([#&#8203;1230](homeassistant-ai/ha-mcp#1230))
- **e2e**: Drop nonexistent sun service from session readiness wait
  ([#&#8203;1227](homeassistant-ai/ha-mcp#1227))
- **e2e**: Self-contain dashboard register/remove to fix ARM xdist race ([#&#8203;1196](homeassistant-ai/ha-mcp#1196))
  ([#&#8203;1201](homeassistant-ai/ha-mcp#1201))
- Fix EN dash in docstring causing RUF002 lint failure
  ([`eac5916`](homeassistant-ai/ha-mcp@eac5916))
- Address Gemini review feedback on host detection and port allocation
  ([`960305e`](homeassistant-ai/ha-mcp@960305e))
- Fix three categories of E2E test flakiness
  ([`39417ff`](homeassistant-ai/ha-mcp@39417ff))
- **e2e**: Pin config\_hash stability for dashboards
  ([#&#8203;1132](homeassistant-ai/ha-mcp#1132))

</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:eyJjcmVhdGVkSW5WZXIiOiI0My4xNjAuNyIsInVwZGF0ZWRJblZlciI6IjQzLjE2MC43IiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJyZW5vdmF0ZS9jb250YWluZXIiLCJ0eXBlL21pbm9yIl19-->

Co-authored-by: todd <tpunderson@greyrock.io>
Reviewed-on: https://git.greyrock.io/greyrock-labs/home-ops/pulls/26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Updating to :latest (dev) is failing

2 participants