Skip to main content
Glama

Server Configuration

Describes the environment variables required to run the server.

NameRequiredDescriptionDefault
HA_URLYesHome Assistant URLhttp://homeassistant.local:8123
HA_TOKENYesLong-lived access token (required for standalone mode)
NEXUS_PORTNoHTTP server port7123
NEXUS_API_KEYNoPin to a specific API key (auto-generated if not set)
HA_CONFIG_PATHNoPath to HA config directory (for git tools)/config
SUPERVISOR_TOKENNoAuto-injected when running as Home Assistant add-on

Instructions

Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.

This server publishes no instructions, or was last inspected before Glama recorded them.

Capabilities

Features and capabilities supported by this server

Protocol revision2025-11-25

CapabilityDetails
tools
{
  "listChanged": true
}
logging
{}
prompts
{
  "listChanged": false
}
resources
{
  "subscribe": false,
  "listChanged": false
}
extensions
{
  "io.modelcontextprotocol/ui": {}
}
experimental
{}

Tools

Functions exposed to the LLM to take actions

NameDescription
entities_list_entitiesA

List entity states, optionally filtered by domain, with pagination and field selection.

Reads live states via ha.get_states() over HTTP; when fields requests area_id, device_id or labels, it also fetches the entity registry over WebSocket and joins it by entity ID. Filtering by domain and pagination (limit/offset) are applied client-side after the fetch.

Use when: browsing or searching current entity states across the whole installation or one domain. Not for: raw registry fields such as disabled/hidden status — use entities_list_entity_registry; a plain unfiltered state dump — use ws_get_states. Returns: list of dicts, one per entity, containing only the requested fields. Limits: limit/offset paginate the already-filtered list; no size cap beyond that.

entities_get_entityA

Get the full state and attributes of a single entity.

Calls ha.get_state(entity_id), a single HTTP GET to /api/states/<entity_id>; the response includes state, attributes, last_changed and last_updated as reported by Home Assistant.

Use when: inspecting one entity's current value and attributes before or after an action. Not for: many entities at once — use entities_list_entities or snapshot_get_snapshot. Returns: dict with entity_id, state, attributes, last_changed, last_updated, context.

entities_turn_onA

Turn on an entity, optionally with light-only color and brightness options.

Calls <domain>.turn_on for the entity's domain over HTTP. If any of brightness, color_temp, color_temp_kelvin or rgb_color is given for a non-light entity, the service is not called at all — HA's own turn_on for other domains (e.g. switch) rejects unknown fields, so this checks the domain first. A given color_temp (mireds) is converted to Kelvin (round(1_000_000 / mireds)) since HA's light.turn_on no longer accepts mireds.

Use when: turning on any entity, with or without light color/brightness. Not for: a dedicated light color/brightness change without an on/off intent — use services_set_light_color; an input_boolean-only helper — helpers_set_input_boolean is the domain-specific equivalent. Returns: the list of changed states from Home Assistant, or an error dict. Errors: {"error": "..."} when a light-only option is given for a non-light domain.

entities_turn_offA

Turn off an entity by calling its domain's turn_off action.

Calls <domain>.turn_off with {"entity_id": entity_id} over HTTP.

Use when: turning off any controllable entity regardless of domain. Not for: flipping state without knowing the target — use entities_toggle. Returns: the list of changed states from Home Assistant.

entities_toggleA

Toggle an entity between on and off by calling its domain's toggle action.

Calls <domain>.toggle with {"entity_id": entity_id} over HTTP; the resulting state depends on the entity's current state, so repeating this call flips it back and forth.

Use when: the desired end state is unknown or irrelevant, only "flip it". Not for: a deterministic on/off — use entities_turn_on/entities_turn_off. Returns: the list of changed states from Home Assistant.

entities_set_valueA

Set the numeric value of an input_number, number or climate entity.

Dispatches to input_number.set_value, number.set_value or climate.set_temperature depending on entity_id's domain; any other domain raises ValueError before any HTTP call is made.

Use when: writing a target number or temperature to one of these three domains. Not for: input_text, input_select, input_boolean or input_datetime — use helpers_set_input_text, helpers_set_input_select, helpers_set_input_boolean or helpers_set_input_datetime. Returns: the list of changed states from Home Assistant. Errors: raises ValueError for any domain other than input_number, number or climate.

entities_select_optionA

Select an option on an input_select or select entity.

Calls input_select.select_option for input_select.* entities, or select.select_option for every other domain (in practice select.*).

Use when: setting the current option of an input_select or select entity. Not for: an input_select-only call site — helpers_set_input_select does the same thing for that domain specifically. Returns: the list of changed states from Home Assistant.

entities_update_entity_nameA

Rename an entity in the entity registry, replacing its current display name.

Calls WS config/entity_registry/update with name=name; the previous name is not returned or preserved anywhere by this call.

Use when: correcting or customising an entity's display name. Not for: reassigning area, or enabling/disabling — use entities_assign_entity_to_area, entities_disable_entity, entities_enable_entity. Returns: the updated entity registry entry from Home Assistant.

entities_assign_entity_to_areaA

Assign an entity to an area, replacing its current area assignment.

Calls WS config/entity_registry/update with area_id=area_id; any previous area assignment is overwritten and not returned.

Use when: moving an entity to a different area in the registry. Not for: renaming it, or toggling exposure — use entities_update_entity_name or entities_set_entity_exposure. Returns: the updated entity registry entry from Home Assistant.

entities_disable_entityA

Disable an entity in the registry so Home Assistant stops creating its state.

Calls WS config/entity_registry/update with disabled_by="user".

Use when: retiring an entity without deleting its registry entry. Not for: re-enabling it — use entities_enable_entity. Returns: the updated entity registry entry from Home Assistant.

entities_enable_entityA

Re-enable a previously disabled entity in the registry.

Calls WS config/entity_registry/update with disabled_by=None.

Use when: restoring an entity disabled via entities_disable_entity. Not for: disabling it — use entities_disable_entity. Returns: the updated entity registry entry from Home Assistant.

entities_list_entity_registryA

Get the raw entity registry, including disabled and hidden entities.

Calls WS config/entity_registry/list and filters client-side by domain when given. Unlike entities_list_entities, this has no state values, only registry metadata (area_id, device_id, disabled_by, labels, ...).

Use when: auditing registry metadata, including disabled/hidden entities that carry no live state. Not for: current state values — use entities_list_entities. Returns: list of raw entity registry entry dicts from Home Assistant.

entities_bulk_controlA

Turn on, turn off or toggle many entities in one call, grouped by domain.

Groups entity_ids by domain and issues one <domain>.<action> service call per domain group (e.g. all light.* entities get a single light.turn_on), instead of one call per entity.

Use when: applying the same on/off/toggle action to many entities across domains at once. Not for: writing arbitrary states instead of calling a service — use entities_bulk_set_state; controlling every entity of one domain in a single area by area_id rather than an explicit entity_id list — use areas_control_area. Returns: dict mapping domain to the number of entities affected. Errors: raises ValueError when action is not one of turn_on, turn_off, toggle.

entities_bulk_set_stateA

Write states for many entities directly via the states API, one call per entity.

Calls ha.set_state(entity_id, state, attributes) per item in updates, which posts to /api/states/<entity_id>; this sets a virtual state that a real device driver overwrites on its next update, unlike a real service call.

Use when: seeding or overriding state for testing, template sensors, or entities with no backing device. Not for: actually controlling a device — use entities_bulk_control. Returns: list of per-update dicts ({entity_id, ok, error?, error_type?}); a missing entity_id/state or a failed write is reported per item, not raised. Errors: per-item {"ok": false, "error": "...", "error_type": "..."}; error_type is "validation" for a missing entity_id/state (no write attempted), "http" for an httpx.HTTPError from the write call (bad response or network failure talking to Home Assistant), or "unexpected" for any other exception. An "unexpected" error is still caught per item and does not abort the rest of the batch.

entities_set_entity_exposureA

Expose or hide one entity to one voice assistant.

Calls WS homeassistant/expose_entity with a single-element entity_ids/assistants list.

Use when: changing exposure for one entity and one assistant. Not for: many entities or assistants at once — use entities_bulk_set_entity_exposure. Returns: dict with entity_id, assistant, should_expose and the raw WS result. Errors: raises ValueError when assistant is not one of conversation, cloud.alexa, cloud.google_assistant.

entities_get_entity_exposureA

Get exposure flags for one entity across all voice assistants.

Home Assistant has no per-entity exposure query, so this fetches the full exposure map via WS homeassistant/expose_entity/list and filters it client-side; an entity absent from that map is reported as False for every assistant.

Use when: checking whether one entity is exposed, and to which assistants. Not for: the whole exposure map for one assistant — use entities_list_exposed_entities. Returns: dict with entity_id and exposure (assistant name -> bool for conversation, cloud.alexa, cloud.google_assistant).

entities_list_exposed_entitiesA

List every entity currently exposed to one voice assistant.

Home Assistant has no per-assistant exposure query, so this fetches the full exposure map via WS homeassistant/expose_entity/list and filters it client-side for the given assistant.

Use when: auditing what one assistant can currently see. Not for: exposure of one specific entity — use entities_get_entity_exposure. Returns: dict with assistant and exposed (list of entity IDs). Errors: raises ValueError when assistant is not one of conversation, cloud.alexa, cloud.google_assistant.

entities_bulk_set_entity_exposureA

Expose or hide many entities across one or more voice assistants in a single call.

Calls WS homeassistant/expose_entity once with the full entity_ids and assistants lists, which HA accepts natively, instead of one call per entity/assistant pair. Returns immediately with an empty result when entity_ids is empty.

Use when: changing exposure for many entities and/or several assistants at once. Not for: a single entity and assistant — use entities_set_entity_exposure. Returns: dict with count, assistants, should_expose and the raw WS result. Errors: raises ValueError when assistants contains an identifier outside conversation, cloud.alexa, cloud.google_assistant.

services_call_serviceA

Call any Home Assistant action by domain and service name over HTTP.

Posts to /api/services/<domain>/<service> with data as the JSON body; data holds both fields and targets (entity_id/area_id/ device_id). Effect depends entirely on the domain/service passed. domain/service must match [A-Za-z0-9_]+ (ADR-0006 D3) or the call is refused before any request is built. Refuses hassio.addon_stop/ app_stop/addon_stdin/app_stdin against nexus's own add-on (self_protection.is_own_addon); addon_restart/app_restart stay allowed. homeassistant.restart/stop, hassio.host_reboot/ host_shutdown/restore_full/restore_partial, update.install and group.remove additionally require confirm=True (ADR-0006 D2) — a human-in-the-loop checkpoint, not a security boundary; ignored for every other service.

Use when: no dedicated tool exists for the action needed. Not for: an action returning response data (e.g. weather.get_forecasts) — use ws_call_service, which refuses the same eight guarded services outright (ADR-0006 D5) instead of accepting confirm. Returns: the list of states changed during the call. Errors: {"error": "invalid_service_name"} for a malformed domain/service; {"error": "self_addon_hassio_service_blocked", "message": ...} for the blocked hassio.* cases; {"error": "confirmation_required", "message": ..., "action": ...} for a guarded service called without confirm=True.

services_list_servicesA

List all services Home Assistant currently has registered, optionally filtered by domain.

Calls ha.list_services() (HTTP GET /api/services) and filters the result client-side by domain when given.

Use when: discovering which services and fields a domain supports before calling services_call_service. Returns: list of dicts, one per domain, each with its available services and their fields.

services_fire_eventA

Fire an arbitrary Home Assistant event with an optional data payload.

Posts to /api/events/<event_type> with event_data as the JSON body; any automation or integration listening for event_type reacts to it, so the effect depends entirely on what is registered to listen.

Use when: triggering automations or integrations that listen for a specific event type. Returns: dict confirming the event was fired, as returned by Home Assistant.

services_render_templateA

Render a Jinja2 template string once through HA's template engine over HTTP.

Posts to /api/template with {"template": template} and returns the rendered text.

Use when: testing a template's output before saving it into an automation, script or template sensor. Not for: rendering through the WebSocket subscription transport — use ws_render_template. Returns: the rendered template as plain text.

services_reload_configA

Reload one domain's configuration from disk by calling its reload action.

Calls <domain>.reload (e.g. automation.reload, input_boolean.reload) over HTTP with no data.

Use when: applying YAML changes for automations, scripts, scenes or input helpers without restarting Home Assistant. Not for: reloading every helper domain in one call — use helpers_reload_helpers. Returns: the list of states changed by the reload.

services_press_buttonA

Press a button entity, running whatever action it is configured to perform.

Calls button.press with {"entity_id": entity_id} over HTTP.

Use when: running a button entity's configured action, such as a template button or a device's physical-button equivalent. Returns: the list of states changed by the press.

services_set_cover_positionA

Set a cover/blind/shutter to a specific open position.

Calls cover.set_cover_position with {"entity_id": entity_id, "position": position} over HTTP.

Use when: moving a cover to a specific percentage rather than fully open/closed. Returns: the list of states changed by the call.

services_set_cover_tiltA

Set a cover's slat/tilt position independently of its open/closed position.

Calls cover.set_cover_tilt_position with {"entity_id": entity_id, "tilt_position": tilt_position} over HTTP.

Use when: adjusting slat angle on a cover that supports tilt. Not for: the cover's overall open/closed position — use services_set_cover_position. Returns: the list of states changed by the call.

services_set_climate_modeA

Set a climate entity's heating/cooling mode.

Calls climate.set_hvac_mode with {"entity_id": entity_id, "hvac_mode": hvac_mode} over HTTP.

Use when: switching a thermostat between heat/cool/auto/off/fan_only/dry. Not for: the target temperature — use entities_set_value. Returns: the list of states changed by the call.

services_set_light_colorA

Set a light's color, color temperature and/or brightness in one call.

Calls light.turn_on with only the given fields set (rgb_color, color_temp_kelvin, brightness); a given color_temp (mireds) is converted to Kelvin (round(1_000_000 / mireds)) first, since HA's light.turn_on no longer accepts mireds.

Use when: adjusting a light's color/brightness, whether it is currently on or off — light.turn_on also turns it on. Not for: a plain on/off/toggle with no color change — use entities_turn_on, which supports the same brightness/color options for lights alongside generic on/off for any domain. Returns: the list of states changed by the call.

services_media_play_pauseA

Toggle a media player between playing and paused.

Calls media_player.media_play_pause with {"entity_id": entity_id} over HTTP; the resulting state depends on the player's current state.

Use when: a simple play/pause toggle is enough, without checking current state first. Returns: the list of states changed by the call.

services_media_seekA

Seek a media player to an absolute playback position.

Calls media_player.media_seek with {"entity_id": entity_id, "seek_position": position} over HTTP.

Use when: jumping to a specific point in the currently playing media. Returns: the list of states changed by the call.

services_set_volumeA

Set a media player's volume level.

Calls media_player.volume_set with {"entity_id": entity_id, "volume_level": volume} over HTTP.

Use when: setting an exact volume rather than stepping it up/down. Returns: the list of states changed by the call.

services_send_notificationA

Send a notification through a Home Assistant notify service.

Calls notify.<target> (or plain notify.notify when target is omitted) with message and optional title; target may include the domain (notify.xyz) or be a bare service name, but a dotted target must name the notify domain itself (ADR-0006 D6) — otherwise it would let any domain.service be reached under cover of a "notification". Each call dispatches a new notification to whatever device or channel that service delivers to, which can be outside the local network (e.g. a phone push).

Use when: pushing a message to a person or device through a configured notify service. Not for: an in-UI banner tracked by an ID — use services_notify_persistent_create. Returns: the list of states changed by the call (notify services typically change none). Errors: {"error": "invalid_notify_target", "message": ...} when a dotted target names a domain other than notify; {"error": "invalid_service_name"} when the part after notify. is not itself a bare [A-Za-z0-9_]+ service name (e.g. a second dot).

services_camera_snapshotA

Save a still snapshot from a camera entity to a file, overwriting any existing file at that path.

Calls camera.snapshot with {"entity_id": entity_id, "filename": filename} over HTTP. filename must be inside the HA config directory and allow-listed via allowlist_external_dirs, typically under /config/www/snapshots/... so it can be served by HA.

Use when: capturing a single still frame to a known path, e.g. for a dashboard image or Lovelace card. Not for: a video clip — use services_camera_record. Returns: dict with entity_id, filename and the raw service call result.

services_camera_recordA

Record a short clip from a camera entity to a file, overwriting any existing file at that path.

Calls camera.record with {"entity_id": entity_id, "filename": filename, "duration": duration} over HTTP.

Use when: capturing a short video clip rather than a single still frame. Not for: a single still frame — use services_camera_snapshot. Returns: dict with entity_id, filename, duration and the raw service call result. Limits: blocks for roughly duration seconds while HA records.

services_notify_persistent_createA

Create or replace a persistent notification banner in the Home Assistant UI.

Calls persistent_notification.create with message, optional title and notification_id. Giving the same notification_id again replaces that notification's content in place; omitting it creates a new, separately addressable notification each time.

Use when: showing a UI banner that a person can dismiss, as opposed to a push notification. Not for: a push notification to a device — use services_send_notification. Returns: dict with notification_id and the raw service call result.

services_notify_persistent_dismissA

Dismiss one persistent notification by its ID.

Calls persistent_notification.dismiss with {"notification_id": notification_id} over HTTP; dismissing an already-dismissed or unknown ID is a no-op from this tool's perspective.

Use when: clearing one specific UI banner. Not for: clearing every banner — use services_notify_persistent_dismiss_all. Returns: dict with notification_id and the raw service call result.

services_notify_persistent_dismiss_allA

Dismiss every persistent notification currently shown in the Home Assistant UI.

Calls persistent_notification.dismiss_all over HTTP with no data.

Use when: clearing all UI banners at once. Not for: clearing a single banner — use services_notify_persistent_dismiss. Returns: dict with the raw service call result.

automations_list_automationsA

List all automations with their current state.

Reads ha.get_states() and keeps entries whose entity_id starts with 'automation.'.

Returns: list[dict] {"entity_id", "state", "friendly_name", "last_triggered"} per automation.

automations_trigger_automationA

Run an automation's actions now, skipping its normal trigger.

Calls the automation.trigger service with entity_id; Home Assistant skips the automation's conditions by default (skip_condition=true), so this can fire actions the automation's own conditions would otherwise block.

Use when: testing or forcing an automation's actions on demand. Returns: list[dict], the raw automation.trigger service-call response from Home Assistant.

automations_enable_automationA

Enable a disabled automation.

Calls the automation.turn_on service with entity_id.

Not for: running the automation's actions immediately — use automations_trigger_automation. Returns: list[dict], the raw automation.turn_on service-call response.

automations_disable_automationA

Disable an automation so it stops reacting to its triggers.

Calls the automation.turn_off service with entity_id; the automation's stored config is untouched, only its runtime state changes.

Returns: list[dict], the raw automation.turn_off service-call response.

automations_reload_automationsA

Reload all automations from YAML.

Calls the automation.reload service, which re-reads automations.yaml/packages and re-applies enabled/disabled state; any automations created only via automations_set_automation_config since the last reload are included too, since that tool writes through the same config store.

Returns: list[dict], the raw automation.reload service-call response.

automations_list_scriptsA

List all scripts with their current state.

Reads ha.get_states() and keeps entries whose entity_id starts with 'script.'.

Returns: list[dict] {"entity_id", "state", "friendly_name", "last_triggered"} per script.

automations_run_scriptA

Start a script and return immediately without waiting for it to finish.

Calls the script.turn_on service with entity_id and, when given, variables as the script's fields; the call returns as soon as Home Assistant accepts it and does not return the script's response variables.

Not for: getting the script's result — this tool never returns it, regardless of the script's own response_variable. Returns: list[dict], the raw script.turn_on service-call response.

automations_reload_scriptsA

Reload all scripts from YAML.

Calls the script.reload service, which re-reads scripts.yaml/packages and re-registers script entities.

Returns: list[dict], the raw script.reload service-call response.

automations_list_scenesA

List all scenes.

Reads ha.get_states() and keeps entries whose entity_id starts with 'scene.'.

Returns: list[dict] {"entity_id", "friendly_name"} per scene.

automations_activate_sceneA

Activate a scene, applying its stored entity states.

Calls the scene.turn_on service with entity_id.

Returns: list[dict], the raw scene.turn_on service-call response.

automations_reload_scenesA

Reload scenes from YAML.

Calls the scene.reload service, which re-reads scenes.yaml and re-registers scene entities from it; scenes saved via automations_set_scene_config are included since that tool writes to the same config store.

Returns: list[dict], the raw scene.reload service-call response.

automations_get_scene_configA

Get a scene's stored config (member entities and their target states).

Requests /api/config/scene/config/<id> over HTTP and returns the parsed JSON, or None on a 404.

Not for: the scene's current runtime state — use automations_list_scenes or entities_get_entity for that. Returns: dict with id, name and entities (mapping entity_id to its target state dict), or None when no scene has that id.

automations_set_scene_configA

Create or overwrite a scene's stored config, then reload scenes.

Posts {id, name, entities} to /api/config/scene/config/<id>, replacing any existing config at that id, then calls the scene.reload service so the change takes effect immediately.

Not for: applying the scene's states right now — use automations_activate_scene. Returns: dict {"scene_id", "name", "entity_count", ...} merged with HA's save response. Errors: returns {"error": "entities must be a non-empty dict of {entity_id: state_dict}"} when entities is empty or not a dict. Limits: no confirm parameter; an existing scene at scene_id is replaced without a prompt.

automations_delete_sceneA

Delete a scene config, then reload scenes.

Without confirm=True returns a safety prompt and touches nothing; with confirm=True deletes /api/config/scene/config/<id> and calls the scene.reload service.

Returns: dict {"deleted": sid, ...} merged with HA's delete response, or {"status": "not_found", "scene_id": sid} when no scene has that id. Errors: returns {"error": "confirmation_required", "message": ..., "action": ...} when confirm is not True. Limits: requires confirm=True; deletion is immediate and permanent.

automations_get_automation_configA

Get the stored config of one automation (automations.yaml) as a dict.

Requests /api/config/automation/config/<id> over HTTP and returns the parsed JSON, or None on a 404 — including for automations defined in packages/YAML without an id, since those have no config-id route.

Not for: the automation's current runtime state — use automations_list_automations or entities_get_entity for that. Returns: dict with id, alias, trigger/triggers, condition/conditions, action/actions and mode, or None when no automation has that config id.

automations_set_automation_configA

Create or replace the automation whose config id is automation_id.

Posts config to /api/config/automation/config/<id>, replacing the whole stored config at that id (or creating a new automation if the id is unused), then calls the automation.reload service.

Not for: editing a single field without resending the rest of the config — this tool always replaces the whole stored config. Returns: dict {"status": "saved", "automation_id", "result"}. Errors: returns {"error": "config must be a dict"} when config isn't a dict, or {"error": "config must contain at least 'alias' or 'trigger'/'triggers'"} when both are missing. Limits: no confirm parameter; an existing automation at automation_id is replaced without a prompt.

automations_delete_automationA

Delete an automation by config id, then reload automations.

Without confirm=True returns a safety prompt; with confirm=True deletes /api/config/automation/config/<id> and calls the automation.reload service.

Returns: dict {"status": "deleted", "automation_id", "result"}. Errors: returns {"error": "confirmation_required", "message": ..., "action": ...} when confirm is not True, or {"error": "not found", "automation_id": aid} when no automation has that config id. Limits: requires confirm=True; deletion is immediate and permanent.

automations_get_script_configA

Get a script's stored YAML config as a dict.

Requests /api/config/script/config/<id> over HTTP and returns the parsed JSON, or None on a 404.

Not for: the script's current runtime state — use automations_list_scripts or entities_get_entity for that. Returns: dict with the script's alias, sequence, fields and mode, or None when no script has that id.

automations_set_script_configA

Create or overwrite a script's stored YAML config, then reload scripts.

Posts config to /api/config/script/config/<id>, replacing the whole stored config at that id (or creating a new script if the id is unused), then calls the script.reload service.

Not for: running the script — use automations_run_script. Returns: dict {"status": "saved", "script_id", "result"}. Errors: returns {"error": "config must be a dict"} when config isn't a dict, or {"error": "config must contain at least 'alias' or 'sequence'"} when both are missing. Limits: no confirm parameter; an existing script at script_id is replaced without a prompt.

automations_delete_scriptA

Delete a script by id, then reload scripts.

Without confirm=True returns a safety prompt; with confirm=True deletes /api/config/script/config/<id> and calls the script.reload service.

Returns: dict {"status": "deleted", "script_id", "result"}. Errors: returns {"error": "confirmation_required", "message": ..., "action": ...} when confirm is not True, or {"error": "not found", "script_id": sid} when no script has that id. Limits: requires confirm=True; deletion is immediate and permanent.

automations_list_automation_tracesA

List trace summaries (recent runs) for an automation.

Calls the trace/list WebSocket command for domain 'automation' and automation_id.

Returns: list[dict] of trace summaries (run_id, timestamps, script_execution outcome) — no step-by-step detail; use automations_get_automation_trace for one run's full detail. Limits: blocks for the WebSocket round trip.

automations_get_automation_traceA

Get a full automation trace (steps, timing, condition results) for a specific run.

Calls the trace/get WebSocket command for domain 'automation', automation_id and run_id.

Not for: finding which run_id to use — use automations_list_automation_traces or automations_get_last_automation_trace first. Returns: dict with the full step-by-step trace for that run. Limits: blocks for the WebSocket round trip.

automations_list_script_tracesA

List trace summaries (recent runs) for a script.

Calls the trace/list WebSocket command for domain 'script' and script_id.

Returns: list[dict] of trace summaries (run_id, timestamps, script_execution outcome) — no step-by-step detail; use automations_get_script_trace for one run's full detail. Limits: blocks for the WebSocket round trip.

automations_get_script_traceA

Get a full script trace (steps, timing, action results) for a specific run.

Calls the trace/get WebSocket command for domain 'script', script_id and run_id.

Not for: finding which run_id to use — use automations_list_script_traces or automations_get_last_script_trace first. Returns: dict with the full step-by-step trace for that run. Limits: blocks for the WebSocket round trip.

automations_get_last_automation_traceA

Fetch the most recent trace for an automation in one call.

Calls trace/list for automation_id, then picks a run_id (the most recent overall, or with failed_only=True the most recent whose script_execution isn't 'finished') and calls trace/get for it.

Use when: debugging "why didn't this fire?" without first listing traces and picking a run_id by hand. Returns: dict with the full step-by-step trace for the picked run. Errors: returns {"error": "no_traces"|"no_failed_traces", "automation_id": aid} when no matching run exists. Limits: blocks for two sequential WebSocket round trips.

automations_get_last_script_traceA

Fetch the most recent (or most recent failed) trace for a script.

Calls trace/list for script_id, then picks a run_id (the most recent overall, or with failed_only=True the most recent whose script_execution isn't 'finished') and calls trace/get for it.

Use when: debugging why a script didn't behave as expected without first listing traces and picking a run_id by hand. Returns: dict with the full step-by-step trace for the picked run. Errors: returns {"error": "no_traces"|"no_failed_traces", "script_id": sid} when no matching run exists. Limits: blocks for two sequential WebSocket round trips.

automations_validate_best_practicesA

Validate automation YAML against static Home Assistant authoring rules.

Parses yaml_content with plain yaml.safe_load (HA-only tags like !input/!secret are NOT resolved and make parsing fail with a YAML parse error, same as any other unknown tag) and runs fixed checks: a state trigger without 'for:', a missing 'mode:', multiple triggers without 'id:', a missing 'alias:'/'id:', the deprecated 'service:' action key, 'restart' mode, and a missing 'description:'.

Use when: linting automation YAML before saving it with automations_set_automation_config. Not for: checking that referenced entities/services actually exist — use automations_validate_automation_references; blueprint content with unresolved '!input'/'!secret' tags — extract them to plain YAML first. Returns: dict {valid_yaml, automations_checked, issues_total, warnings, infos, issues[], summary}; each issue is {automation, rule, severity, message} with severity 'warning' (should fix) or 'info' (good to know). Errors: returns {"valid_yaml": False, "error": "YAML parse error: ...", "issues": []} for invalid YAML.

automations_validate_automation_referencesA

Cross-check entity IDs and services used in automation YAML against the live registry.

Unlike automations_validate_best_practices (static), this calls ha.get_states() and ha.list_services() to verify that every literal entity_id value and every literal service:/action: string in yaml_content exists. It only looks at literal values — it does NOT resolve device_id, area_id, label_id, or any templated reference, not just the ones containing '{{ ... }}' (which are explicitly skipped and counted in template_refs_skipped).

Use when: checking that an automation's references are real before saving it with automations_set_automation_config. Not for: YAML syntax or authoring-rule checks — use automations_validate_best_practices. Returns: dict {valid_yaml, automations_checked, entities_checked, services_checked, missing_entities[], missing_services[], template_refs_skipped, entities_check, services_check, errors[], summary}. entities_check/services_check are 'ok' or 'unavailable'. Errors: returns {"valid_yaml": False, "error": "YAML parse error: ..."} for invalid YAML. When ha.get_states() or ha.list_services() raises, the matching entities_check/services_check is 'unavailable' and errors names which fetch failed; the corresponding missing_* list stays empty rather than reporting a false "nothing missing" or a false "everything is missing". Limits: fetches the full live state list and full service list on every call.

automations_list_groupsA

List all Home Assistant entity groups (group.* entities).

Reads ha.get_states() and keeps entries whose entity_id starts with 'group.', with their members, icon and current state.

Returns: list[dict] {"entity_id", "state", "friendly_name", "entity_ids", "icon", "all", "order"} per group.

automations_set_groupA

Create or update an old-style group.* entity at runtime.

Calls the group.set service with object_id=group_id and whichever of name/entities/icon/all/add_entities/remove_entities were given. The group is NOT written to groups.yaml and disappears on restart or automations_reload_groups-style YAML reload; for a persistent group use a Group helper or add it to groups.yaml with the files_write_config_file tools. Does not create light/switch/cover group helpers.

Not for: a group that survives a restart — define it in groups.yaml instead (files_write_config_file) or create a Group helper. Returns: dict {"status": "set", "group_id": "group.<id>"}. Errors: returns {"error": "entities cannot be combined with add_entities/remove_entities — pass a full member list via entities, or incremental changes via add_entities/remove_entities, not both"} when entities is given together with add_entities or remove_entities; group.set is not called in that case. Limits: entities replaces the whole member list and must not be combined with add_entities/remove_entities in the same call.

automations_remove_groupA

Remove a group created with automations_set_group.

Without confirm=True returns a safety prompt; with confirm=True calls the group.remove service with object_id. Groups defined in groups.yaml come back on the next restart or YAML reload — this only removes the runtime entity.

Returns: dict {"status": "removed", "group_id": "group.<id>"}. Errors: returns {"error": "confirmation_required", "message": ..., "action": ...} when confirm is not True. Limits: requires confirm=True; has no effect on a group defined in groups.yaml beyond the next reload/restart.

areas_list_areasA

List all Home Assistant areas (rooms).

Reads the area registry over WebSocket (config/area_registry/list) and returns every entry exactly as Home Assistant reports it, unfiltered.

Use when: you need area IDs and names before assigning entities, devices or labels to an area. Returns: list of area registry dicts (area_id, name, floor_id, icon, aliases, picture).

areas_create_areaA

Create a new Home Assistant area (room).

Calls WS config/area_registry/create with name; Home Assistant assigns a new area_id and there is no way to request a specific one, so calling this twice with the same name creates two distinct areas.

Use when: you need a new area to assign devices, entities or labels to. Not for: renaming or moving an existing area — no update tool exists for areas in this namespace. Returns: the created area registry dict (area_id, name, floor_id, icon, aliases, picture).

areas_delete_areaA

Delete a Home Assistant area by its area_id.

Calls WS config/area_registry/delete and returns Home Assistant's result unchanged; the area disappears from the registry immediately.

Use when: removing an area that is no longer used. Returns: the raw WS deletion result. Limits: irreversible — there is no restore tool for a deleted area.

areas_list_floorsA

List all floors defined in Home Assistant.

Reads the floor registry over WebSocket (config/floor_registry/list) and returns every entry exactly as Home Assistant reports it, unfiltered.

Use when: grouping areas by floor, e.g. before building a floor-scoped dashboard. Returns: list of floor registry dicts as reported by Home Assistant.

areas_list_devicesA

List all devices in Home Assistant's device registry, unfiltered.

Calls WS config/device_registry/list via ha_client and returns every registry entry exactly as Home Assistant reports it, with every field (unlike the slimmed projection other tools apply).

Use when: you need the complete raw device registry, including fields not exposed elsewhere. Not for: a smaller per-field view — use devices_list_devices, which projects each entry down to id/name/area_id/manufacturer/model/ entry_type plus config_entries/disabled_by; devices scoped to one area — use devices_list_devices_in_area; fuzzy name-based search — use search_search_devices. Returns: list of full device registry dicts as returned by config/device_registry/list.

areas_get_area_entitiesA

Get every entity registered in a given area, directly or via its device.

Reads the entity and device registries over WebSocket, then keeps entity-registry rows whose own area_id matches, or whose device_id belongs to a device assigned to the area.

Use when: you need the entity registry rows for one area, e.g. before bulk-editing labels or categories. Not for: current state values — use areas_get_area_states, or a combined view — use snapshot_get_area_snapshot. Returns: list of entity registry dicts (entity_id, device_id, area_id, labels, …) belonging to the area. Limits: an unknown area_id returns an empty list rather than an error.

areas_get_area_statesA

Get current states of every entity in a given area.

Calls areas_get_area_entities for the area, then filters the full state list (ha.get_states()) down to the entity_ids found in that call.

Use when: you need live state values scoped to one area, e.g. before deciding what to control. Not for: registry rows without state values — use areas_get_area_entities, or a combined view — use snapshot_get_area_snapshot. Returns: list of HA state objects (entity_id, state, attributes, last_changed, last_updated) for entities in the area.

areas_control_areaA

Turn on, off or toggle every entity of one domain in an area.

Calls service <domain>.<action> over HTTP with {"area_id": area_id} as the target, so Home Assistant dispatches it to every entity of that domain in the area. action must be one of turn_on/turn_off/toggle (ADR-0006 D6) — an unchecked value here could reach an arbitrary <domain>.<action> service under cover of "controlling an area".

Use when: controlling a whole area by domain, e.g. all lights in a room. Not for: controlling an explicit list of entity_ids across areas — use entities_bulk_control. Returns: list of state-change dicts as returned by the HA service call. Errors: raises ValueError when action is not one of turn_on, turn_off, toggle. Limits: an invalid domain (no such domain, or the domain has no matching service) fails with the underlying HTTP error from Home Assistant.

history_get_state_historyA

Get an entity's recorded state history over the last N hours.

Calls GET /api/history/period/<start> filtered to entity_id, where start is now - hours; returns whatever the recorder database has kept for that window.

Use when: seeing how one entity's state changed over time, e.g. a temperature trend. Not for: human-readable event descriptions — use history_get_logbook; this is raw, short-term state history, not the recorder's long-term pre-aggregated sum/mean/min/max values — use statistics_get_statistics for those, or statistics_list_statistic_ids to discover which entities have them. Returns: HA's raw history-period payload — a list of state-change records for the entity. Errors: raises httpx.HTTPStatusError if the HA API request fails. Limits: only as far back as the recorder integration has retained data for this entity.

history_get_logbookA

Get human-readable logbook entries from the last N hours.

Calls GET /api/logbook/<start>, optionally filtered by entity_id, where start is now - hours.

Use when: a narrative of what happened (state changes, triggered automations) is more useful than raw state-history records. Not for: raw per-state timestamps and values for one entity — use history_get_state_history. Returns: HA's raw logbook payload — a list of {when, name, message, entity_id, ...}-shaped entries. Errors: raises httpx.HTTPStatusError if the HA API request fails. Limits: only as far back as the recorder integration has retained logbook data.

history_get_error_logA

Fetch Home Assistant's error log as plain text.

Prefers the raw log file via GET /api/error_log. That view only exists when HA logs to a file — Supervisor installs ship with duplicate_log_file: false, so it 404s there, in which case the warning/error records held by the system_log integration are rendered into log-file-like text instead.

Use when: diagnosing recent warnings/errors across the whole instance. Not for: one entity's history or logbook — use history_get_state_history or history_get_logbook. Returns: plain-text log content, from either source. Errors: re-raises httpx.HTTPStatusError for any status other than 404 from /api/error_log.

history_get_system_infoA

Get Home Assistant's raw API liveness message.

Calls GET /api/, which returns only a fixed liveness message (e.g. {"message": "API running."}) — no version or system data despite the tool's name.

Use when: a plain proof that the HTTP API is answering is enough. Not for: version/location/units/components — use history_get_ha_config; for subsystem health — use system_get_system_health; for Core/OS details — use supervisor_get_core_info or supervisor_get_host_info; for a simple reachable/unreachable boolean — use system_ping_ha. Returns: {"message": "API running."} (HA's fixed liveness payload). Errors: raises httpx.HTTPStatusError if the HA API request fails.

history_get_ha_configA

Get Home Assistant's current configuration.

Calls GET /api/config for location, unit system, HA version and loaded components.

Use when: version, location, unit system or the loaded-components list is needed. Not for: the equivalent WebSocket command — use ws_get_config; for subsystem health checks — use system_get_system_health. Returns: HA's raw config payload (latitude, longitude, unit_system, version, components, and related fields). Errors: raises httpx.HTTPStatusError if the HA API request fails.

helpers_list_helpersA

List every helper entity across all helper domains, with its current state.

Reads all states via ha.get_states() over HTTP and keeps only entities whose domain is one of input_boolean, input_number, input_text, input_select, input_datetime, input_button, counter, timer, schedule.

Use when: browsing which helpers exist and their current values. Not for: helpers of one specific domain filtered generically — use entities_list_entities with domain set. Returns: list of dicts with entity_id, state, attributes for each matching helper entity.

helpers_set_input_booleanA

Set an input_boolean helper to true or false.

Calls input_boolean.turn_on when value is true, otherwise input_boolean.turn_off, over HTTP.

Use when: setting a known boolean helper to a specific value. Not for: any other domain's on/off state — use entities_turn_on/ entities_turn_off, which work generically across domains including input_boolean. Returns: the list of states changed by the call.

helpers_set_input_numberA

Set an input_number helper's numeric value.

Calls input_number.set_value with {"entity_id": entity_id, "value": value} over HTTP.

Use when: writing a specific number to an input_number helper. Not for: a number/climate entity too — entities_set_value covers input_number identically plus the number and climate domains. Returns: the list of states changed by the call.

helpers_set_input_textA

Set an input_text helper's text value.

Calls input_text.set_value with {"entity_id": entity_id, "value": value} over HTTP.

Use when: writing a specific string to an input_text helper. Returns: the list of states changed by the call.

helpers_set_input_selectA

Set an input_select helper to one of its configured options.

Calls input_select.select_option with {"entity_id": entity_id, "option": option} over HTTP.

Use when: setting a known input_select helper to a specific option. Not for: the generic select/input_select dispatch that also handles plain select entities — entities_select_option covers input_select identically plus the select domain. Returns: the list of states changed by the call.

helpers_set_input_datetimeA

Set an input_datetime helper's date, time or combined datetime value.

Calls input_datetime.set_datetime over HTTP with whichever of date, time, datetime are given; passing none of them still calls the service with only entity_id.

Use when: writing a specific date/time to an input_datetime helper. Returns: the list of states changed by the call.

helpers_increment_counterA

Increment a counter helper by its configured step.

Calls counter.increment with {"entity_id": entity_id} over HTTP; repeating this call keeps increasing the counter's value.

Use when: counting up an event occurrence. Not for: setting the counter back to zero — use helpers_reset_counter. Returns: the list of states changed by the call.

helpers_reset_counterA

Reset a counter helper's value back to 0.

Calls counter.reset with {"entity_id": entity_id} over HTTP; the counter is runtime UI state, not stored configuration.

Use when: clearing a counter back to its initial value. Not for: increasing it by one — use helpers_increment_counter. Returns: the list of states changed by the call.

helpers_start_timerA

Start a timer helper, optionally overriding its duration.

Calls timer.start over HTTP with entity_id and duration when given; calling this on an already-running timer restarts it with the new duration.

Use when: starting a countdown, e.g. for a reminder or process timeout. Not for: stopping it early — use helpers_cancel_timer. Returns: the list of states changed by the call.

helpers_cancel_timerA

Cancel a running timer helper.

Calls timer.cancel with {"entity_id": entity_id} over HTTP.

Use when: stopping a timer before it finishes. Not for: starting one — use helpers_start_timer. Returns: the list of states changed by the call.

helpers_reload_helpersA

Reload every helper domain's entities from configuration in one call.

Calls <domain>.reload over HTTP for each of input_boolean, input_number, input_text, input_select, input_datetime, counter, timer in turn; a domain whose reload call raises is skipped but its error is captured rather than silently dropped.

Use when: applying YAML changes across several helper domains without restarting Home Assistant. Not for: reloading one specific domain — use services_reload_config. Returns: {"reloaded": [...], "failed": {domain: message}} — combined list of states changed across every domain that reloaded successfully, plus a per-domain map of the error message for every domain whose reload call raised. Errors: a domain's failure never raises out of this call; instead its exception message is recorded under failed[<domain>] so the caller can tell which domain, if any, did not reload.

system_check_configA

Validate the current Home Assistant configuration without applying anything.

Calls POST /api/config/core/check_config, the same YAML validation HA runs internally before a restart; nothing is reloaded or restarted by this call.

Use when: verifying configuration.yaml and related files are valid before calling system_restart_ha. Not for: applying a change into the running instance — use system_reload_all for a no-downtime reload or system_restart_ha for a full restart. Returns: HA's check payload, typically {"result": "valid"|"invalid", "errors": ...}. Errors: raises httpx.HTTPStatusError if the HA API request itself fails (e.g. HA unreachable).

system_restart_haA

Restart Home Assistant after an explicit confirmation.

Calls the homeassistant.restart service, which causes roughly 30 seconds of downtime for the whole instance, including this add-on. Without confirm=True nothing is restarted; the call only returns a safety prompt describing how to confirm.

Use when: a config change requires a full restart, e.g. after system_check_config reports the config is valid. Not for: a no-downtime reload — use system_reload_all; stopping HA without restarting it — use system_stop_ha; restarting only Core under Supervisor — use supervisor_restart_core. Returns: the homeassistant.restart service-call result when confirmed, otherwise a confirmation prompt. Errors: returns {"error": "confirmation_required", "message": ..., "action": ...} when confirm is false. Limits: interrupts Home Assistant for about 30 seconds; requires confirm=True.

system_stop_haA

Stop Home Assistant after an explicit confirmation.

Calls the homeassistant.stop service. Unlike a restart, nothing brings the instance back automatically — a manual restart is required. Without confirm=True nothing is stopped; the call only returns a safety prompt.

Use when: HA needs to be taken fully offline, e.g. before host maintenance. Not for: a temporary interruption that comes back on its own — use system_restart_ha. Returns: the homeassistant.stop service-call result when confirmed, otherwise a confirmation prompt. Errors: returns {"error": "confirmation_required", "message": ..., "action": ...} when confirm is false. Limits: requires a manual restart to bring HA back online; requires confirm=True.

system_reload_allA

Reload core Home Assistant configuration without restarting the instance.

Calls the homeassistant.reload_all service, which HA fans out to every component that supports a config reload (automations, scripts, scenes, groups and more), re-reading their YAML from disk.

Use when: YAML for automations/scripts/scenes/groups changed and a fast, no-downtime reload is enough. Not for: changes that require a full restart, e.g. new integrations or structural configuration.yaml edits — use system_restart_ha; for one integration only — use system_reload_integration. Returns: {"status": "reload_all triggered"}; it does not wait for or report individual component reload results.

system_create_backupA

Create a Home Assistant backup using whichever backup service the instance registers.

On Supervisor installs backup.create does not exist, so this calls backup.create_automatic instead, which creates a backup using the automatic-backup settings configured in Settings -> System -> Backups; when a retention count is configured there, those same settings prune older automatic backups as a side effect of this call. On HA Core/Container installs, where backup.create exists, that one is called instead — no name, folder selection or password. Returns an error if neither service is registered.

Use when: HA already has the wanted automatic-backup settings configured and a quick backup with no extra parameters is enough. Not for: a named, partial, and/or password-protected backup on a Supervisor install, or a backup that never deletes older ones — use supervisor_create_backup. Returns: the called service's result, or an error dict when neither service is registered. Errors: {"error": "Neither backup.create nor backup.create_automatic is registered on this Home Assistant instance."}. Limits: on Supervisor installs, applies the instance's configured retention count, which can delete older backups.

system_list_integrationsA

List every Home Assistant config entry, whatever its state.

Calls the raw config_entries/get WebSocket command and returns it unfiltered: every field HA stores per entry, in any state (loaded, not_loaded, setup_error, disabled). On instances with many integrations this can be a large payload.

Use when: the raw config-entry objects, with every field, are needed. Not for: a compact, easier-to-scan listing — use system_get_all_integrations, which strips this down to entry_id/domain/title/state/source. Returns: list of raw config-entry dicts as returned by HA's WebSocket API. Errors: raises RuntimeError if the underlying WebSocket call fails (e.g. auth or WS-level error). Limits: no pagination or filtering; large HA instances get a large response.

system_reload_integrationA

Reload a single integration's config entry without restarting Home Assistant.

Calls the homeassistant.reload_config_entry service for the given entry_id, which unloads and re-sets-up that one integration only.

Use when: one integration needs to pick up new options or recover from a transient setup error. Not for: reloading every reloadable component at once — use system_reload_all. Returns: the homeassistant.reload_config_entry service-call result. Errors: raises httpx.HTTPStatusError if entry_id does not exist or the domain does not support config-entry reload.

system_ping_haA

Check whether the Home Assistant API is reachable over HTTP.

Calls GET /api/ through ha.ping(), which catches any connection error internally and reports plain reachability, not health or subsystem status.

Use when: confirming HA is up before other calls, quick liveness probing. Not for: the raw /api/ payload itself — use history_get_system_info; for HA version/location/config use history_get_ha_config; for subsystem health use system_get_system_health. Returns: {"reachable": bool, "url": <configured HA_URL>}.

system_get_all_integrationsA

List every config entry as a compact summary of its key fields.

Calls the same config_entries/get WebSocket command as system_list_integrations and projects each entry down to entry_id, domain, title, state and source; every state is included, so filter on state yourself.

Use when: scanning or filtering integrations by domain/state without the full raw payload. Not for: every field HA stores on the entry — use system_list_integrations. Returns: list of {entry_id, domain, title, state, source} dicts. Errors: raises RuntimeError if the underlying WebSocket call fails (e.g. auth or WS-level error).

system_get_system_healthA

Get Home Assistant's system-health report across its core subsystems.

Runs the system_health/info WebSocket subscription to completion and merges its initial/update/finish events into one dict, since HA exposes system health only as a WebSocket stream, not over HTTP.

Use when: checking recorder/websocket/cloud/network-style health checks and basic system info (version, dev mode, virtualenv) in one call. Not for: a plain liveness check — use system_ping_ha; for HA version/location/config use history_get_ha_config. Returns: dict keyed by integration domain, each with an info dict mapping check name to value (or {"error": ...} for a failed check). Errors: raises RuntimeError on WebSocket auth failure or a WS-level error from system_health/info. Limits: waits up to an internal 15-second timeout for the stream's finish event; on timeout it returns whatever partial data arrived instead of raising.

system_get_repairsA

List Home Assistant's active repair issues.

Calls the repairs/list_issues WebSocket command and projects each issue down to its id, domain, severity, breaks_in_ha_version, learn-more URL, translation key, and ignored/is_fixable flags.

Use when: surfacing deprecated config, broken integrations or required migrations that need attention. Not for: the full raw repair-issue payload with every field HA stores — this always returns the projected subset above. Returns: list of {issue_id, domain, severity, breaks_in_ha_version, learn_more_url, translation_key, ignored, is_fixable} dicts. Errors: raises RuntimeError if the underlying WebSocket call fails (e.g. auth or WS-level error).

system_get_updatesA

List Home Assistant's update.* entities, one per updatable component.

Reads all HA states and filters to entities in the update domain (core, add-ons, HACS repositories, custom components), extracts installed/latest version and release info from their attributes, and sorts pending updates first.

Use when: checking what has an update available across the whole instance in one call. Not for: live Supervisor add-on state beyond this snapshot — use supervisor_get_addon or supervisor_list_addons. Returns: list of {entity_id, name, installed_version, latest_version, update_available, release_url, release_notes, skipped_version, in_progress, auto_update}, sorted with available updates first.

dashboards_list_dashboardsA

List every registered Lovelace dashboard.

Calls lovelace/dashboards/list and returns the raw collection: each entry has id, url_path, title, mode (storage or yaml), and related flags.

Use when: discovering a dashboard's url_path before calling dashboards_get_dashboard_config or dashboards_screenshot. Returns: list of dashboard dicts, unfiltered. The default dashboard is not included — it has no url_path entry here.

dashboards_add_dashboard_resourceA

Register a custom JS or CSS resource that loads on every Lovelace dashboard page.

Sends url/resource_type to lovelace/resources/create, which stores a new resource entry with a server-generated id — repeating this call registers a second, distinct resource rather than updating one. The tool itself only stores the URL string; it never fetches url — the browser loads it later, from /local/, /hacsfiles/, or any external CDN the URL names.

Use when: registering a custom card, theme, or script so it becomes available on every dashboard. Not for: changing an existing resource's URL/type — use dashboards_update_dashboard_resource. Returns: {"status": "added", "url": ..., "resource_type": ..., "result": ...} on success. Errors: {"error": "resource_type must be 'module', 'js', or 'css'"} when resource_type is anything else.

dashboards_remove_dashboard_resourceA

Remove a registered Lovelace resource by its numeric id.

Requires confirm=True; without it, returns a confirmation prompt and makes no change. With confirm=True, calls lovelace/resources/delete, which drops the resource from every dashboard page that loaded it — any custom card/theme it provided stops rendering until the resource is re-added.

Use when: removing a resource that is no longer needed (e.g. after uninstalling a HACS frontend card). Returns: {"status": "removed", "resource_id": ..., "result": ...} on success. Errors: {"error": "confirmation_required", "message": ..., "action": ...} when confirm is false.

dashboards_update_dashboard_resourceA

Replace the URL and type of an existing Lovelace resource.

Sends resource_id, url and resource_type to lovelace/resources/update, replacing both fields of that resource entry — the previous URL/type are not recoverable afterwards. Like dashboards_add_dashboard_resource, this tool never fetches url itself.

Use when: repointing an existing resource entry at a new file or changing its declared type. Not for: registering a brand-new resource — use dashboards_add_dashboard_resource. Returns: {"status": "updated", "resource_id": ..., "url": ..., "resource_type": ..., "result": ...} on success. Errors: {"error": "resource_type must be 'module', 'js', or 'css'"} when resource_type is anything else.

dashboards_get_dashboard_configA

Get one Lovelace dashboard's config, or a read-only excerpt of one view.

Calls lovelace/config for url_path as a dashboard; if that raises config_not_found, re-fetches the default dashboard and returns the matching view instead, since url_path may instead be that view's own path.

Use when: reading a dashboard's views/sections before editing it, or inspecting one view without the surrounding dashboard. Not for: passing the view-path result back into dashboards_save_dashboard_config — that excerpt is not a full dashboard config and would delete every other view. Returns: the full dashboard dict (with views) for a dashboard url_path; {"view": ..., "source": "default_dashboard_view", "path": ...} for a view path in the default dashboard. Errors: raises RuntimeError when url_path matches neither a dashboard nor a view in the default dashboard.

dashboards_save_dashboard_configA

Replace the entire config of one storage-mode Lovelace dashboard.

Sends config as-is to lovelace/config/save, fully overwriting that dashboard's stored views/sections with no validation, backup, or undo — keep the previous config (e.g. from dashboards_get_dashboard_config) if you need to restore it.

Use when: writing back a dashboard object built or fetched in full. Not for: a single card or section change — use dashboards_add_card_to_section/dashboards_update_card_in_section/ dashboards_remove_card_from_section (sections views) or dashboards_add_card_to_view (masonry/panel views), which read-modify- write the config for you. Returns: {"status": "saved", "url_path": ...}.

dashboards_get_dashboard_resourcesA

List every registered Lovelace resource (custom cards, CSS).

Calls lovelace/resources and returns the raw collection: each entry has id, type (module/js/css), and url.

Use when: finding a resource's numeric id before calling dashboards_update_dashboard_resource or dashboards_remove_dashboard_resource. Returns: list of resource dicts, unfiltered.

dashboards_add_card_to_viewA

Append a card to one view's cards list and save the whole dashboard.

Reads the dashboard via dashboards_get_dashboard_config, appends card_config to views[view_index]["cards"] (creating that key if absent), and writes the whole dashboard back with dashboards_save_dashboard_config — every other view and card is round-tripped unchanged.

Use when: adding a card to a masonry/panel view. Not for: a type: sections view — there, cards in view.cards render only in edit mode; use dashboards_add_card_to_section instead. Returns: {"status": "saved", "url_path": ...} from the underlying save. Errors: raises ValueError when view_index is out of range for the dashboard's view count.

dashboards_add_view_to_dashboardA

Append a new view to a dashboard and save the whole dashboard.

Reads the dashboard via dashboards_get_dashboard_config, appends view_config to its views list, and writes the whole dashboard back with dashboards_save_dashboard_config — every existing view and card is round-tripped unchanged.

Use when: adding a whole new tab/view to a dashboard. Not for: adding a card to an existing view — use dashboards_add_card_to_view or dashboards_add_card_to_section. Returns: {"status": "saved", "url_path": ...} from the underlying save.

dashboards_get_view_sectionsA

List the sections of one type: sections view, with real indexes, headings and card counts.

Resolves the view via _load_view (dashboard config or default- dashboard view path), requires it to be a sections view, and reports each section's position, a fallback-derived heading (its heading card, or title), and card count.

Use when: reading current section indexes before calling dashboards_add_card_to_section / dashboards_update_card_in_section / dashboards_remove_card_from_section, or before re-sending expected_config_hash to one of them after their previous call changed it. Returns: {status, url_path, view_index, view_title, view_path, sections: [{section_index, heading, card_count}, ...], config_hash} — pass config_hash back as expected_config_hash to dashboards_add_card_to_section / _update_card_in_section / _remove_card_from_section / _add_section_to_view to detect a dashboard change before your write lands. Errors: raises ValueError when the view can't be resolved (bad index/path) or is not a type: sections view.

dashboards_add_card_to_sectionA

Insert a card into one section of a type: sections view, leaving every other view intact.

Resolves the view via _load_view, requires it to be a sections view, inserts card_config into that section's cards list at position (or the end), and saves the whole dashboard back. This is the only way to make a card visible on a sections view — dashboards_add_card_to_view writes to view.cards, which such a view renders only in edit mode. When expected_config_hash is given, it is checked against the dashboard's hash right after the read and before any change, so a stale caller never overwrites the wrong section.

Use when: adding a card to a specific section of a sections view. Pass expected_config_hash whenever section_index/position came from an earlier read that might now be stale. Not for: a masonry/panel view — use dashboards_add_card_to_view. Returns: {status: "added", url_path, view_index, view_title, section_index, card_index, cards_in_section, config_hash} — config_hash is re-read from HA after the save (not the locally built dict), ready to chain into the next call's expected_config_hash. Errors: raises ValueError when card_config has no type key, the view can't be resolved, isn't a sections view, or section_index is out of range. Returns {"error": "config_changed", "expected_config_hash", "current_config_hash", "action"} without saving when expected_config_hash doesn't match.

dashboards_update_card_in_sectionA

Change one existing card inside a section of a type: sections view.

Resolves the view and target card via _load_view/_require_card, then merges card_config's keys into the existing card (merge=True, the default) or replaces it outright (merge=False), and saves the whole dashboard back. The previous card is only recoverable via card_before in this call's own response — storage itself keeps no history. With expected_config_hash, the dashboard's hash is checked right after the read and before any change, so a stale caller can't edit the wrong card.

Use when: tweaking or replacing one card already placed in a section. Pass expected_config_hash when section_index/card_index came from a read that might now be stale. Not for: adding a new card — use dashboards_add_card_to_section; removing one — use dashboards_remove_card_from_section. Returns: {status: "updated", url_path, view_index, view_title, section_index, card_index, card_before, card_after, config_hash} — config_hash is re-read from HA after the save, for the next call's expected_config_hash. Errors: raises ValueError when card_config is empty, merge=False lacks a type key, or the view/section/card can't be resolved. Returns {"error": "config_changed", ...} without saving when expected_config_hash doesn't match.

dashboards_remove_card_from_sectionA

Delete one card from a section of a type: sections view.

Resolves the view and section via _load_view/_require_section, pops the card at card_index from that section's cards list, and saves the whole dashboard back. card_index is a position, not a stable id — repeating this call with the same section_index/ card_index after a first successful removal deletes whatever card has shifted into that position next, not a no-op, unless expected_config_hash is also passed and now points at the pre-removal hash, in which case the repeat is rejected with config_changed instead of deleting the wrong card.

Use when: removing a card that's no longer wanted on a sections view. Pass expected_config_hash whenever section_index/card_index came from an earlier read that might now be stale. Returns: {status: "removed", url_path, view_index, view_title, section_index, card_index, removed_card, cards_in_section, config_hash} — removed_card can be passed back to dashboards_add_card_to_section to restore it; config_hash is re-read from HA after the save, ready to chain into the next call's expected_config_hash. Errors: raises ValueError when the view/section/card can't be resolved (bad index/path). Returns {"error": "config_changed", "expected_config_hash", "current_config_hash", "action"} without saving when expected_config_hash doesn't match.

dashboards_add_section_to_viewA

Insert a new section into a type: sections view.

Resolves the view via _load_view, requires it to be a sections view, defaults section_config to {"type": "grid", "cards": []} when omitted, inserts it into that view's sections list at position (or the end), and saves the whole dashboard back. When expected_config_hash is given, it is checked against the dashboard's hash right after the read and before any change.

Use when: adding a whole new section (a card group with its own grid) to a sections view, before populating it with dashboards_add_card_to_section. Pass expected_config_hash whenever position came from an earlier read that might now be stale. Returns: {status: "added", url_path, view_index, view_title, section_index, sections_in_view, config_hash} — config_hash is re-read from HA after the save, ready to chain into the next call's expected_config_hash. Errors: raises ValueError when section_config["cards"] isn't a list, or the view can't be resolved/isn't a sections view. Returns {"error": "config_changed", "expected_config_hash", "current_config_hash", "action"} without saving when expected_config_hash doesn't match.

dashboards_screenshotA

Capture a PNG screenshot of one Lovelace dashboard view via the Puppet add-on engine.

Resolves url_path to a concrete frontend route (see the parameter description), rejects paths containing unsafe characters, then calls the Puppet engine (discovered via Supervisor or NEXUS_SCREENSHOT_ENGINE_URL) over HTTP with the resolved viewport/ zoom/wait parameters and returns its PNG response as base64. Deciding between a dashboard route and a default-dashboard view path costs one lovelace/dashboards/list call (skipped when url_path already starts with lovelace). Reaches only a local/LAN add-on, not the public internet.

Use when: visually verifying a dashboard or view after editing it. Returns: {url_path, engine, format: "png", width, height, image_base64, size_bytes} on success — url_path echoes the resolved route, not the raw argument, and image_base64 can be large, especially with full_page=True (fixed 4096px height). Errors: {"error": "dashboard_list_unavailable" | "invalid_path" | "engine_not_available" | "engine_unreachable" | "engine_http_<code>" | "empty_response", "detail": ..., ...} when the dashboard list can't be fetched, the path is unsafe, the Puppet engine isn't installed/ started, or the engine request itself fails. Limits: 60-second engine timeout; full_page=True only approximates full-scroll capture since the engine does not measure actual page height, so it can crop tall pages or leave blank space on short ones.

files_read_config_fileA

Read one config file's raw text from the HA config directory.

Resolves relative_path under HA_CONFIG_PATH via _safe_path (blocking paths outside the directory, disallowed extensions, and secrets.yaml/ .storage) and returns its content as a UTF-8 string; nothing is parsed or validated.

Use when: reading the current text of a YAML/JSON/txt file before editing it. Not for: checking whether that text is valid YAML — pass it to files_validate_yaml_content; discovering which files exist first — use files_list_config_files. Returns: str, the file's raw text (UTF-8). Errors: raises FileNotFoundError when the file does not exist, and raises PermissionError (from _safe_path) when relative_path resolves outside the config directory, uses a disallowed extension, or targets secrets.yaml/.storage.

files_write_config_fileA

Overwrite or create one config file under /config with new content.

Resolves relative_path via _safe_path, YAML-checks content first unless validate_yaml=False or the extension isn't .yaml/.yml, then creates parent directories as needed and writes the file, replacing any previous content at that path.

Use when: no rollback point for the previous content is needed. Not for: keeping a rollback point — use git_safe_write_with_checkpoint, which commits the pre-write state first; ESPHome device YAML — use esphome_write_config. Returns: dict {"success": True, "path": ...} on success, or {"success": False, "error": ...} when validate_yaml catches invalid YAML before writing. Errors: raises PermissionError (from _safe_path) for a path outside the config directory, a disallowed extension, or secrets.yaml/.storage; returns {"success": False, "error": ...} instead of raising for invalid YAML. Limits: no backup is taken — the previous content is permanently lost. Does not reload Home Assistant.

files_list_config_filesA

Recursively list config files with allowed extensions under /config.

Resolves subdirectory (default the config root) under HA_CONFIG_PATH, recurses with Path.rglob('*'), and returns config-root-relative paths for files whose extension is in .yaml/.yml/.json/.txt, skipping secrets.yaml and .storage/.

Use when: discovering which config files exist before reading or writing one. Not for: reading a file's content once you have its path — use files_read_config_file. Returns: list[str] of config-root-relative file paths. Limits: output can be large for the /config root; a subdirectory that resolves (after following symlinks) outside /config returns an empty list instead of listing files outside the config directory.

files_validate_yaml_contentA

Check YAML syntax for a string without writing anything.

Parses content with a Home-Assistant-tolerant YAML loader that accepts !include*/!secret/!env_var/!input as opaque values, and reports only whether parsing succeeded and the top-level type.

Use when: checking a YAML snippet's syntax before calling files_write_config_file or automations_set_automation_config. Not for: full HA schema validation — use system_check_config; HA tags here are accepted but not resolved, so only syntax is checked, not HA schema validity. Returns: dict {"valid": True, "type": ...} (top-level type name only, not the parsed content) or {"valid": False, "error": ...}. Errors: returns {"valid": False, "error": str(e)} for a YAML parse error rather than raising.

files_delete_config_fileA

Permanently delete one config file under /config after an explicit confirmation.

Without confirm=True returns a confirmation prompt and does not resolve or touch relative_path at all. With confirm=True, resolves relative_path via _safe_path and calls Path.unlink(); there is no backup or trash in this tool — deletion is immediate and irreversible from here alone.

Use when: removing a YAML/JSON/txt file that HA no longer needs, once that removal is confirmed. Not for: keeping the ability to undo — commit the config to git first (git_git_commit_all) or write through git_safe_write_with_checkpoint so a rollback stays possible. Returns: dict {"success": True, "deleted": ...} when confirmed, otherwise a confirmation prompt. Errors: returns {"error": "confirmation_required", "message": ..., "action": ...} when confirm is false; raises FileNotFoundError when the file does not exist, and raises PermissionError (from _safe_path) for a path outside the config directory, a disallowed extension, or secrets.yaml/.storage. Limits: requires confirm=True; the deletion runs immediately with no undo once confirmed.

files_append_to_config_fileA

Append text to the end of an existing config file.

Resolves relative_path via _safe_path, reads its current text, appends content after a newline, YAML-checks the combined text only when validate_yaml=True and the extension is .yaml/.yml, then writes the combined text back.

Use when: adding raw YAML/JSON/txt lines that already match the file's existing list indentation. Not for: automations — use automations_set_automation_config, which edits by config id instead of a raw text append. Returns: dict {"success": True, "path": ...} on success, or {"success": False, "error": ...} when validate_yaml=True and the combined text fails to parse. Errors: raises FileNotFoundError when the file does not exist, and raises PermissionError (from _safe_path) for a path outside the config directory, a disallowed extension, or secrets.yaml/.storage. Limits: validate_yaml defaults to False, so an invalid append is written without warning unless explicitly checked.

git_git_init_configA

Initialize a git repository in the HA config directory.

Creates a git repo at HA_CONFIG_PATH via git.Repo.init unless a .git/ directory already exists there, writes a default .gitignore (secrets.yaml, .storage/, .db, home-assistant.log) when none exists, and makes one initial commit adding that .gitignore.

Use when: preparing /config before using any other git_* tool or git_safe_write_with_checkpoint for the first time. Returns: dict {"status": "initialized"|"already_initialized", "path": ...}.

git_git_statusA

Show git status of the HA config directory.

Calls _repo() for the /config git repo and returns the active branch, staged/modified/untracked file lists (repo.index.diff, repo.untracked_files) and an overall dirty flag.

Use when: checking what changed in /config before committing or writing a file. Returns: dict {"branch", "staged", "modified", "untracked", "is_dirty"}. Errors: raises RuntimeError (from _repo()) when gitpython is not installed or no git repo exists yet at HA_CONFIG_PATH — run git_git_init_config first.

git_git_commit_allA

Stage and commit every change in the HA config directory.

Calls _repo(), stages everything with git add -A, and commits message unless nothing is dirty, in which case no commit is made.

Use when: creating a checkpoint before a risky change to /config. Not for: writing one file and checkpointing it in a single call — use git_safe_write_with_checkpoint. Returns: dict {"status": "committed", "sha", "message"}, or {"status": "nothing_to_commit"} when the working tree is clean. Errors: raises RuntimeError (from _repo()) when gitpython is not installed or no git repo exists yet — run git_git_init_config first.

git_git_logA

List recent commits in the HA config git repository.

Calls _repo() and returns up to limit commits from repo.iter_commits, most recent first, with short SHA, message, author name and ISO commit date.

Use when: reviewing recent config changes before a rollback or diff. Returns: list[dict] {"sha", "message", "author", "date"}. Errors: raises RuntimeError (from _repo()) when gitpython is not installed or no git repo exists yet — run git_git_init_config first. Limits: limit caps the number of commits returned; no further pagination is offered.

git_git_diffA

Show unstaged changes, or one commit's stat summary.

Without sha, calls repo.git.diff() for the unified diff of unstaged changes to tracked files in /config, excluding staged changes and untracked new files (see git_git_status). With sha, calls git show --stat <sha> for the commit header and per-file changed-line counts, not the actual patch.

Use when: reviewing what changed before committing, or summarising one past commit. Returns: str, the raw diff or stat text. Errors: raises RuntimeError (from _repo()) when no git repo exists; raises an exception from gitpython when sha does not resolve to a commit. Limits: output is raw, unformatted text and can be large for big diffs.

git_git_rollback_fileA

Restore one file to its state at a specific commit.

Refuses a relative_path that resolves outside /config (_resolve_within_config) before running anything, and without confirm=True returns a safety prompt instead of touching the file; with confirm=True it calls repo.git.checkout(sha, '--', relative_path), replacing the file's on-disk content with the version from sha and losing any uncommitted changes to that file.

Use when: undoing an accidental edit to a single file. Not for: resetting the whole config tree — use git_git_rollback_to_commit. Returns: dict {"status": "restored", "file", "to"} on success. Errors: returns {"error": "invalid_path"|"path_outside_config", ...} when relative_path escapes /config; returns {"error": "confirmation_required", ...} when confirm is not True; raises RuntimeError (from _repo()) when no git repo exists. Limits: requires confirm=True; uncommitted changes to the target file are permanently lost once it runs.

git_git_rollback_to_commitA

Hard-reset the entire HA config directory to a previous commit.

Without confirm=True returns a safety prompt naming the current head commit; with confirm=True calls repo.git.reset('--hard', sha), which discards every commit and uncommitted change made after sha.

Use when: reverting /config entirely after a bad batch of changes, and the target commit is already known. Not for: restoring a single file — use git_git_rollback_file. Returns: dict {"status": "reset", "to": sha} on success. Errors: returns {"error": "confirmation_required", "message": ..., "action": ...} when confirm is not True; raises RuntimeError (from _repo()) when no git repo exists. Limits: requires confirm=True. WARNING: every commit and uncommitted change made after sha is permanently and irreversibly lost.

git_git_create_branchA

Create a new git branch from the current commit and switch to it.

Calls repo.create_head(branch_name) then branch.checkout(); uncommitted changes carry over onto the new branch, and live /config files now follow it.

Use when: starting an isolated set of changes without touching the current branch's commit history. Not for: switching to a branch that already exists — use git_git_checkout_branch. Returns: dict {"status": "created_and_checked_out", "branch": ...}. Errors: raises an exception from gitpython when a branch named branch_name already exists; raises RuntimeError (from _repo()) when no git repo exists.

git_git_checkout_branchA

Switch the HA config git repository to an existing branch.

Calls repo.git.checkout(branch_name), which replaces every tracked file under /config with that branch's committed version — the live configuration Home Assistant reads from changes as soon as this returns.

Use when: switching between prepared configurations that are tracked as branches. Not for: creating a branch that does not exist yet — use git_git_create_branch. Returns: dict {"status": "switched", "branch": ...}. Errors: raises an exception from gitpython when branch_name does not exist, or when uncommitted local changes would conflict with the target branch's files; raises RuntimeError (from _repo()) when no git repo exists. Limits: no confirm parameter; a conflicting uncommitted change blocks the checkout rather than being silently discarded (plain git behaviour), but a non-conflicting one carries over onto the new branch.

git_git_list_branchesA

List all local branches in the HA config git repository.

Calls _repo() and returns every local branch name from repo.branches.

Returns: list[str] of local branch names. Errors: raises RuntimeError (from _repo()) when gitpython is not installed or no git repo exists yet — run git_git_init_config first.

git_safe_write_with_checkpointA

Write one config file after committing a checkpoint of the prior state.

Stages and commits every uncommitted change under /config as a checkpoint commit (only when the tree is dirty), then calls the same write_config_file logic files_write_config_file uses for relative_path/content, and finally stages and commits that change with commit_message (or a default message) if the write succeeded.

Use when: overwriting a config file while keeping a git-based rollback point, unlike a plain overwrite. Not for: a write without a checkpoint — use files_write_config_file; ESPHome device YAML — use esphome_write_config. Returns: dict — the underlying write result ({"success": True, "path": ...} or {"success": False, "error": ...}), plus git_sha/ git_message when the new-content commit was made. Errors: raises RuntimeError (from _repo()) when no git repo exists — run git_git_init_config first; returns {"success": False, "error": ...} unchanged when YAML validation fails, in which case the checkpoint commit of the prior dirty state (if any) still happened, but no new-content commit is made. Limits: does not reload Home Assistant; same file-extension and location limits as files_write_config_file.

ws_get_statesA

Get all entity states over the WebSocket API in one call.

Sends get_states and waits up to timeout seconds for the matching result message; this can be faster than the HTTP /api/states endpoint on large installs since it avoids per-entity HTTP overhead.

Use when: fetching every entity's state on a large installation. Not for: a filtered or paginated state list — use entities_list_entities. Returns: the list of state dicts from HA's result.result. Errors: raises RuntimeError when the WebSocket handshake or the result message does not arrive within timeout, or when a result message arrives but is not successful. Limits: blocks for up to timeout seconds (default 10), including the initial handshake.

ws_call_serviceA

Call a Home Assistant action over WebSocket and return its response data.

Sends call_service with return_response=True always set, so actions that support a response (e.g. weather.get_forecasts, calendar.get_events) return it; actions without one (light.turn_on, most control actions) fail with a validation error. domain/service must match [A-Za-z0-9_]+ (ADR-0006 D3) or the call is refused first. Refuses hassio.addon_stop/app_stop/addon_stdin/app_stdin against nexus's own add-on (self_protection.is_own_addon); addon_restart/ app_restart stay allowed. Outright refuses the eight services services_call_service gates behind confirm (ADR-0006 D5) — none support a response (F1).

Use when: the action's response payload is needed, not just the changed states. Not for: a plain control action, or one of the eight guarded services — use services_call_service for both. Returns: raw WS result: {success, result: {context, response}} on success, or a failure dict from HA; {"success": False} if no result message arrives. Errors: raises RuntimeError on a handshake timeout; {"error": "invalid_service_name"} for a malformed domain/service; {"error": "self_addon_hassio_service_blocked", "message": ...} for a blocked hassio.* case; {"error": "guarded_service_refused", "message": ..., "use": "services_call_service"} for a guarded service. Limits: blocks for up to timeout seconds (default 10), including the initial handshake.

ws_render_templateA

Render a Jinja2 template through HA's WebSocket render_template subscription.

Sends render_template; HA acknowledges the subscription with a null result, then streams the rendered value in a follow-up event. This waits up to timeout seconds for that event and returns its result.

Use when: the WebSocket transport itself is specifically required. Not for: a one-shot render — use services_render_template, a plain HTTP call with no subscription semantics. Returns: the rendered template value from the event's result field. Errors: raises RuntimeError when the template itself errors (e.g. an undefined variable), when the WebSocket handshake does not complete within timeout, or when no event arrives within timeout. Limits: blocks for up to timeout seconds (default 10), including the initial handshake.

ws_listen_state_changesA

Passively wait for and collect state_changed events for one entity.

Subscribes to HA's state_changed event type, which has no server-side per-entity filter, and counts only events matching entity_id toward count, so unrelated entities' events do not displace the target's. Returns early once count matching events arrive, or whatever arrived once timeout elapses.

Use when: waiting for a specific entity to change state, e.g. to confirm an action took effect. Not for: any entity's events — use ws_listen_events with event_type='state_changed'; a one-shot trigger condition — use ws_subscribe_trigger. Returns: list of dicts with entity_id, old_state, new_state, last_changed. Errors: raises RuntimeError when the WebSocket handshake does not complete within timeout. Limits: blocks for up to timeout seconds, including the initial handshake; collects at most count events.

ws_listen_eventsA

Passively wait for and collect events of one HA event type.

Subscribes to event_type via subscribe_events and collects up to count events, returning early once that many arrive or whatever arrived once timeout elapses.

Use when: observing any event type, e.g. integration or automation events not tied to a single entity's state. Not for: state changes on one specific entity — use ws_listen_state_changes. Returns: list of raw event payloads as HA sent them. Errors: raises RuntimeError when the WebSocket handshake does not complete within timeout. Limits: blocks for up to timeout seconds, including the initial handshake; collects at most count events.

ws_get_configA

Get Home Assistant's own configuration over WebSocket.

Sends get_config and waits up to timeout seconds for the matching result message.

Use when: reading HA's location, unit system, version and component list over the WebSocket transport. Not for: the same data over HTTP — use history_get_ha_config. Returns: HA's config dict from result.result (location, unit_system, version, components, ...). Errors: raises RuntimeError when the WebSocket handshake or the result message does not arrive within timeout, or when a result message arrives but is not successful. Limits: blocks for up to timeout seconds (default 10), including the initial handshake.

ws_subscribe_triggerA

Passively wait for a Home Assistant trigger definition to fire once.

Sends subscribe_trigger with the given trigger and waits up to timeout seconds for the matching event.

Use when: waiting for a specific trigger condition (state, time, numeric state, ...) rather than polling. Not for: raw state_changed events on one entity — use ws_listen_state_changes. Returns: the trigger's event context dict when it fires, or None if timeout elapses first. Errors: raises RuntimeError when the WebSocket handshake does not complete within timeout. Limits: blocks for up to timeout seconds, including the initial handshake.

blueprints_list_blueprintsA

List all installed blueprints for a domain over the WebSocket API.

Calls the blueprint/list WebSocket command via ha._ws_call for the given domain and returns Home Assistant's response unchanged; nothing is read from disk directly here.

Use when: enumerating what blueprints exist under /config/blueprints/ before importing, substituting or deleting one. Returns: dict keyed by blueprint path, each value the blueprint's metadata (name, description, domain, source_url) as returned by HA. Limits: blocks for the WebSocket round trip; the default 10 second response wait in ha._ws_call applies.

blueprints_import_blueprintA

Fetch a blueprint from a URL and validate it without saving it.

Calls the blueprint/import WebSocket command, which has Home Assistant download url and validate its YAML. This only downloads and validates — it does NOT save anything to disk.

Use when: previewing a blueprint (its metadata and validation errors) before deciding to persist it. Not for: persisting the fetched blueprint — pass its raw_data and suggested_filename to blueprints_save_blueprint. Returns: dict with suggested_filename, raw_data (the blueprint YAML text), blueprint.metadata, validation_errors and exists (whether a blueprint already sits at that path). Limits: blocks for the WebSocket round trip plus the remote download time; the default 10 second response wait in ha._ws_call applies.

blueprints_save_blueprintA

Save blueprint YAML to /config/blueprints//.

Calls the blueprint/save WebSocket command with yaml_content as the payload and overwrite mapped to HA's allow_override flag; with overwrite=False (default) it does not replace an existing file at path, and with overwrite=True it does, losing the previous content.

Not for: fetching a blueprint from the internet first — use blueprints_import_blueprint to get raw_data/suggested_filename. Returns: Home Assistant's blueprint/save result (typically an empty success payload). Errors: Home Assistant raises a WebSocket error, surfaced by ha._ws_call as a RuntimeError, when overwrite=False and a file already exists at path. Limits: blocks for the WebSocket round trip; the default 10 second response wait in ha._ws_call applies. No confirm parameter — the only overwrite guard is the overwrite flag itself.

blueprints_delete_blueprintA

Delete an installed blueprint by its relative path.

Calls the blueprint/delete WebSocket command for domain/path; the file under /config/blueprints// is removed and its content is lost, with no backup taken by this tool.

Not for: automations or scripts generated from this blueprint — they keep running with their already-substituted config; use automations_delete_automation or automations_delete_script for those. Returns: Home Assistant's blueprint/delete result (typically an empty success payload). Limits: blocks for the WebSocket round trip; the default 10 second response wait in ha._ws_call applies. No confirm parameter guards this deletion.

blueprints_substitute_blueprintA

Render a blueprint with given inputs into a plain automation or script.

Calls the blueprint/substitute WebSocket command, which resolves input against the blueprint's input: placeholders and returns the resulting config; nothing is saved or reloaded by this tool.

Use when: previewing the concrete triggers/conditions/actions a blueprint would produce before saving it via automations_set_automation_config or automations_set_script_config. Returns: dict with the substituted automation/script YAML content as a dict. Limits: blocks for the WebSocket round trip; the default 10 second response wait in ha._ws_call applies.

calendar_list_calendarsA

List every calendar.* entity known to HA.

Calls GET /api/calendars over HTTP.

Use when: discovering which entity_id to pass to calendar_list_events/calendar_create_event/calendar_delete_event. Not for: the events within a calendar — use calendar_list_events. Returns: list of {"entity_id", "name"} dicts, or an empty list if the response isn't a JSON list.

calendar_list_eventsA

List events on one calendar between start and end.

Calls GET /api/calendars/{entity_id} over HTTP with start/end as query parameters.

Use when: reading a calendar's upcoming or past events for a known date range. Not for: listing the calendar entities themselves — use calendar_list_calendars. Returns: list of event dicts as returned by HA (fields include summary, start, end, uid), or an empty list if the response isn't a JSON list.

calendar_create_eventA

Create a new event on a calendar via the calendar.create_event service.

Maps start/end to the service's start_date_time/end_date_time fields. Calling this twice with identical arguments creates two separate events, since HA assigns each a new uid.

Use when: adding a new event to a calendar that supports creation (local or CalDAV calendars). Not for: removing an event — use calendar_delete_event. Returns: {"entity_id", "summary", "start", "end", "result": ...} where result is the service-call response.

calendar_delete_eventA

Delete a calendar event by its uid via WS calendar/event/delete.

Only works for calendar platforms that declare CalendarEntityFeature.DELETE_EVENT (e.g. local/CalDAV calendars); read-only integrations such as Google Calendar reject it, and this returns ok: False with HA's error instead of raising.

Use when: removing an event or a recurring instance from a calendar that supports deletion. Not for: creating an event — use calendar_create_event; not for read-only calendar integrations, which will fail here regardless of arguments. Returns: {"entity_id", "uid", "result": ..., "ok": True} on success. Errors: {"entity_id", "uid", "ok": False, "error": str(e)} when the platform rejects the deletion or the WS call otherwise raises.

todo_list_todo_listsA

List all todo.* entities currently registered in HA.

Filters ha.get_states() for entity IDs starting with todo..

Use when: discovering which entity_id to pass to todo_list_items/todo_add_item/todo_update_item/todo_remove_item. Not for: the items within a list — use todo_list_items. Returns: list of {"entity_id", "state", "friendly_name"} dicts, one per todo.* entity.

todo_list_itemsA

List items on a todo list, optionally filtered by status.

Calls WS todo/item/list and filters the returned items by status in Python (HA's response shape for this command has varied between "items" dicts and a bare list across versions, both are handled here).

Use when: reading a todo list's current items. Not for: listing the todo entities themselves — use todo_list_todo_lists. Returns: list of item dicts as returned by HA (fields include uid, summary/item text, status).

todo_add_itemA

Add a new item to a todo list via the todo.add_item service.

Sends due_date or due_datetime depending on whether due_date contains a time component ('T' or a space). Calling this twice with the same item text creates two separate items with distinct uids.

Use when: adding a new entry to a todo list. Not for: changing or completing an existing item — use todo_update_item. Returns: {"entity_id", "item", "result": ...} where result is the service-call response.

todo_update_itemA

Update a todo item's text and/or status via the todo.update_item service.

Maps item to the service's rename field. Only the fields you pass (item/status) are sent, so whichever value is omitted is left unchanged on HA's side.

Use when: renaming an item or marking it needs_action/completed. Not for: adding a new item — use todo_add_item; not for removing one — use todo_remove_item. Returns: {"entity_id", "uid", "result": ...} where result is the service-call response.

todo_remove_itemA

Remove an item from a todo list by its uid via the todo.remove_item service.

Use when: permanently deleting an item, e.g. after completing a task you don't want to keep marked completed. Not for: marking an item completed without deleting it — use todo_update_item with status='completed'. Returns: {"entity_id", "uid", "result": ...} where result is the service-call response.

devices_list_devicesA

List all devices with a slimmed set of common fields.

Calls WS config/device_registry/list and projects each entry down to id, name_by_user, name, area_id, manufacturer, model, entry_type, plus config_entries and disabled_by when present.

Use when: you need the device registry without every raw field. Not for: the full unfiltered registry — use areas_list_devices; devices scoped to one area — use devices_list_devices_in_area; fuzzy name-based search — use search_search_devices. Returns: list of slimmed device dicts as described above.

devices_update_deviceA

Update fields on an existing device registry entry.

Calls WS config/device_registry/update; only the parameters you pass are sent, so omitted or null fields are left unchanged.

Use when: renaming a device, moving it to another area, or enabling or disabling it. Returns: dict with device_id and result (the updated device, slimmed like devices_list_devices). Limits: area_id can only be set here, not cleared — there is no parameter to remove an existing area assignment.

devices_remove_deviceA

Remove a device from one of its config entries.

Calls WS config_entries/remove_device with both IDs; if the device belongs to other config entries it keeps existing under those.

Use when: detaching a device from one integration without touching its other config entries. Returns: dict with device_id, config_entry_id and the raw WS result. Limits: both device_id and config_entry_id are required — there is no way to remove a device from every config entry in one call.

devices_list_devices_in_areaA

List devices currently assigned to one area.

Calls WS config/device_registry/list and filters the slimmed device list (see devices_list_devices) down to entries whose area_id matches.

Use when: you need only the devices in one area rather than the whole registry. Not for: the whole device registry — use devices_list_devices or areas_list_devices; fuzzy name-based search — use search_search_devices. Returns: list of slimmed device dicts (see devices_list_devices) whose area_id equals the given area_id. Limits: devices without an area are never returned here.

supervisor_list_addonsA

List every installed add-on with its slug, name, state and version.

Calls Supervisor's GET /addons and projects each entry down to slug, name, state, version, version_latest and update_available.

Use when: getting an overview of installed add-ons and which have updates pending. Not for: full add-on detail (options, ports, boot mode) — use supervisor_get_addon. Returns: {"addons": [{slug, name, state, version, version_latest, update_available}, ...]}. Errors: {"error": "SUPERVISOR_TOKEN not set — Nexus must run as HA add-on for Supervisor API"} when the token env var is missing; {"error": "HTTP <status>", "detail": ...} on a Supervisor API error.

supervisor_get_addonA

Get full Supervisor info for one add-on, with secret option values redacted.

Calls GET /addons/<slug>/info: every field Supervisor stores for that add-on (options schema, current options, ports, boot mode, version, state and more), except options values are replaced with a fixed placeholder wherever the schema marks a field a password, the key name looks like a secret (password/pass/pwd, token, api_key, secret, credential, private, key as a word/suffix), or the value is a URL with inline credentials (scheme://user:pass@host) — covers nexus's own API key and other add-ons' secrets/connection strings alike, recursively through nested groups and lists. An empty/unset value stays empty. Adds redacted_fields: {"path", "reason"} dicts.

Use when: the full add-on record is needed, e.g. before editing its options with supervisor_set_addon_options, which accepts the same placeholder back for an unchanged secret field without overwriting it. Not for: a quick overview across all add-ons — use supervisor_list_addons. Returns: Supervisor's add-on info payload with secret-looking options values replaced by a placeholder, plus redacted_fields. Errors: {"error": "invalid_slug"} for a bad slug; {"error": "SUPERVISOR_TOKEN not set — Nexus must run as HA add-on for Supervisor API"} when the token env var is missing; {"error": "HTTP <status>", "detail": ...} if the slug does not exist.

supervisor_install_addonA

Install an add-on from its slug.

Calls POST /addons/<slug>/install. The add-on must already belong to a repository Supervisor knows about; this does not add repositories. Installing downloads the add-on's image, which reaches outside the HA instance and its host.

Use when: adding a new add-on that is already visible in an installed repository. Not for: starting/stopping an already-installed add-on — use supervisor_start_addon/supervisor_stop_addon. Returns: Supervisor's install-job result. Errors: {"error": "invalid_slug"} for a bad slug; {"error": "SUPERVISOR_TOKEN not set — Nexus must run as HA add-on for Supervisor API"} when the token env var is missing; {"error": "HTTP <status>", "detail": ...} if the slug is unknown. Limits: downloads the add-on image over the network; can take a while on a slow connection.

supervisor_uninstall_addonA

Uninstall an add-on and its persistent data after an explicit confirmation.

Calls POST /addons/<slug>/uninstall. Refuses to run at all against nexus's own add-on (its real slug, or the alias Supervisor resolves to the caller itself — see self_protection.is_own_addon) — checked first, with no Supervisor request made either way, before even the confirmation gate: nexus removing itself is never the right tool for that regardless of confirm. Otherwise, without confirm=True nothing is removed; the call only returns an error asking for confirmation (ADR-0003 D1).

Use when: permanently removing an add-on that is no longer needed. Not for: temporarily stopping it while keeping its data and config — use supervisor_stop_addon. Returns: Supervisor's uninstall-job result when confirmed. Errors: {"error": "invalid_slug"} for a bad slug; {"error": "self_addon_uninstall_blocked", "message": ...} when slug is nexus's own add-on; returns {"error": "confirmation_required", "message": ..., "action": ...} when confirm is false; {"error": "HTTP <status>", "detail": ...} on a Supervisor API error. Limits: WARNING: deletes the add-on's data with no separate backup step; requires confirm=True.

supervisor_start_addonA

Start an installed, stopped add-on.

Calls POST /addons/<slug>/start.

Use when: bringing an installed add-on online after it was stopped. Not for: installing a new add-on — use supervisor_install_addon; for stopping it — use supervisor_stop_addon. Returns: Supervisor's start-job result. Errors: {"error": "invalid_slug"} for a bad slug; {"error": "SUPERVISOR_TOKEN not set — Nexus must run as HA add-on for Supervisor API"} when the token env var is missing; {"error": "HTTP <status>", "detail": ...} if the slug is unknown or already running.

supervisor_stop_addonA

Stop a running add-on.

Calls POST /addons/<slug>/stop. The add-on — e.g. an MQTT broker other integrations depend on — becomes unavailable until started again. Refuses to run at all against nexus's own add-on (by its real slug or the literal alias Supervisor resolves to the caller itself): nexus stopping itself would cut off the very connection carrying this call, with no guarantee the response ever comes back, and — unlike supervisor_restart_addon — leaves nexus down until someone starts it again some other way.

Use when: taking one add-on offline without uninstalling it. Not for: removing it entirely — use supervisor_uninstall_addon; for bringing it back — use supervisor_start_addon; for a brief restart of nexus itself — use supervisor_restart_addon instead, which is allowed. Returns: Supervisor's stop-job result. Errors: {"error": "invalid_slug"} for a bad slug; {"error": "self_addon_stop_blocked", "message": ...} when slug is nexus's own add-on; {"error": "SUPERVISOR_TOKEN not set — Nexus must run as HA add-on for Supervisor API"} when the token env var is missing; {"error": "HTTP <status>", "detail": ...} if the slug is unknown. Limits: interrupts the add-on's availability, and anything depending on it, until it is started again.

supervisor_restart_addonA

Restart an add-on (stop, then start).

Calls POST /addons/<slug>/restart. The add-on — which could be this nexus add-on itself — is briefly unavailable during the restart.

Use when: an add-on needs to pick up new options or recover from a stuck state. Not for: a one-way stop — use supervisor_stop_addon; for restarting Core instead — use supervisor_restart_core. Returns: Supervisor's restart-job result. Errors: {"error": "invalid_slug"} for a bad slug; {"error": "SUPERVISOR_TOKEN not set — Nexus must run as HA add-on for Supervisor API"} when the token env var is missing; {"error": "HTTP <status>", "detail": ...} if the slug is unknown. Limits: briefly interrupts the add-on's availability.

supervisor_update_addonA

Update an add-on to its latest available version.

Calls POST /addons/<slug>/update, which downloads and installs the new version over the network; the previous version is only recoverable from a backup taken beforehand.

Use when: update_available is true for the add-on and the new version should be applied. Not for: reverting an update — restore a backup via supervisor_restore_backup instead; there is no dedicated rollback call. Returns: Supervisor's update-job result. Errors: {"error": "invalid_slug"} for a bad slug; {"error": "SUPERVISOR_TOKEN not set — Nexus must run as HA add-on for Supervisor API"} when the token env var is missing; {"error": "HTTP <status>", "detail": ...} on a failed update. Limits: downloads the new version over the network; no automatic rollback on failure.

supervisor_get_addon_logsA

Get the most recent log lines from one add-on.

Calls GET /addons/<slug>/logs, which returns plain text, and keeps only the last lines lines.

Use when: debugging one add-on's runtime behaviour. Not for: the ESPHome add-on's per-device compile/upload logs — use esphome_get_addon_logs if that distinction matters to the caller. Returns: {"logs": "<joined log lines>"}. Errors: {"error": "invalid_slug"} for a bad slug; {"error": "SUPERVISOR_TOKEN not set or empty response"} when the token is missing; {"error": "HTTP <status>", "detail": ...} on a Supervisor API error.

supervisor_set_addon_optionsA

Replace an add-on's stored options with the given object.

Calls POST /addons/<slug>/options as {"options": options}. Read current values via supervisor_get_addon, modify them, and send the full dict back — overwrites previous options entirely, so omitted fields are lost. A value left as the placeholder for a secret field is swapped for the real stored value first, so echoing it back unchanged never overwrites the secret — a list containing it must keep every item's order/count as read, or the call is refused rather than guessed. Once a placeholder was resolved, a Supervisor error strips detail (it can otherwise echo the rejected payload, secret included). Takes effect after supervisor_restart_addon. Refuses to run against nexus's own add-on — could otherwise lift its own restrictions.

Use when: changing an add-on's configuration programmatically. Not for: reading the current options first — use supervisor_get_addon; for changing nexus's own configuration — use the Home Assistant Supervisor UI instead. Returns: Supervisor's options-update result. Errors: {"error": "invalid_slug"} for a bad slug; self_addon_options_blocked for nexus's own add-on; redaction_marker_list_length_mismatch on a placeholder list-length mismatch; SUPERVISOR_TOKEN not set when the token is missing; {"error": "HTTP <status>"} on a schema-validation or placeholder read-back failure. Limits: does not apply until the add-on is restarted.

supervisor_get_addon_statsA

Get an add-on's current runtime resource usage.

Calls GET /addons/<slug>/stats for CPU, memory, network and disk I/O figures at the moment of the call.

Use when: checking whether an add-on is consuming unexpected resources. Not for: historical usage over time — this returns only a snapshot. Returns: Supervisor's raw stats payload (CPU percent, memory usage/limit, network and block I/O counters). Errors: {"error": "invalid_slug"} for a bad slug; {"error": "SUPERVISOR_TOKEN not set — Nexus must run as HA add-on for Supervisor API"} when the token env var is missing; {"error": "HTTP <status>", "detail": ...} if the add-on is not running.

supervisor_get_supervisor_infoA

Get info about the Supervisor component itself.

Calls GET /supervisor/info for its version, update channel and health flag.

Use when: checking the Supervisor's own version/channel/health, as opposed to Core or the host. Not for: Home Assistant Core details — use supervisor_get_core_info; for the host OS — use supervisor_get_host_info. Returns: Supervisor's raw info payload (version, channel, healthy, and related fields). Errors: {"error": "SUPERVISOR_TOKEN not set — Nexus must run as HA add-on for Supervisor API"} when the token env var is missing.

supervisor_get_core_infoA

Get info about the Home Assistant Core container.

Calls GET /core/info for its version, CPU architecture and machine type.

Use when: checking Core's version/arch, as opposed to the Supervisor or host. Not for: HA's own location/units/component config — use history_get_ha_config. Returns: Supervisor's raw Core info payload (version, arch, machine). Errors: {"error": "SUPERVISOR_TOKEN not set — Nexus must run as HA add-on for Supervisor API"} when the token env var is missing.

supervisor_get_host_infoA

Get info about the host operating system.

Calls GET /host/info for Home Assistant OS version, hostname, kernel and related host-level fields.

Use when: checking the underlying OS/hardware, as opposed to Core or the Supervisor. Not for: Supervisor's own version — use supervisor_get_supervisor_info. Returns: Supervisor's raw host info payload (Home Assistant OS version, hostname, kernel, and related fields). Errors: {"error": "SUPERVISOR_TOKEN not set — Nexus must run as HA add-on for Supervisor API"} when the token env var is missing.

supervisor_restart_coreA

Restart Home Assistant Core through the Supervisor after an explicit confirmation.

Calls POST /core/restart. WARNING: causes downtime for HA Core (and everything depending on it) until it comes back up. Without confirm=True nothing is restarted.

Use when: Core needs restarting on a Supervisor install specifically. Not for: the equivalent call via HA's own service — use system_restart_ha; for rebooting the whole host — use supervisor_restart_host. Returns: Supervisor's restart-job result when confirmed. Errors: returns {"error": "confirmation_required", "message": ..., "action": ...} when confirm is false; {"error": "SUPERVISOR_TOKEN not set — Nexus must run as HA add-on for Supervisor API"} when the token env var is missing. Limits: requires confirm=True; interrupts Core until it restarts.

supervisor_restart_hostA

Reboot the whole host machine after an explicit confirmation.

Calls POST /host/reboot. WARNING: Home Assistant, every add-on (including this nexus add-on) and the host OS go offline for minutes. Without confirm=True nothing is rebooted.

Use when: a host-level change (e.g. a Home Assistant OS update) requires a full reboot. Not for: restarting only Core — use supervisor_restart_core; for restarting one add-on — use supervisor_restart_addon. Returns: Supervisor's reboot-job result when confirmed. Errors: returns {"error": "confirmation_required", "message": ..., "action": ...} when confirm is false; {"error": "SUPERVISOR_TOKEN not set — Nexus must run as HA add-on for Supervisor API"} when the token env var is missing. Limits: requires confirm=True; takes the whole host, including this add-on, offline for minutes — the call itself may not receive a reply.

supervisor_list_backupsA

List every backup Supervisor manages.

Calls GET /backups for the full backup catalogue Supervisor tracks.

Use when: finding a backup's slug before restoring or deleting it, or checking whether a scheduled backup succeeded. Not for: HA Core's own backup.create/backup.create_automatic backups when they were not made through Supervisor — those may not appear here under the same view. Returns: Supervisor's raw backups payload. Errors: {"error": "SUPERVISOR_TOKEN not set — Nexus must run as HA add-on for Supervisor API"} when the token env var is missing.

supervisor_create_backupA

Create a new Supervisor backup, full or partial.

Calls POST /backups/new/full when neither addons nor folders is given, otherwise POST /backups/new/partial with those slugs/folders. Unlike system_create_backup, this never deletes older backups — it only adds a new one.

Use when: a named, partial and/or password-protected backup is needed on a Supervisor install. Not for: a quick backup using the instance's own automatic-backup settings (which may prune old ones) — use system_create_backup. Returns: Supervisor's backup-job result, including the new backup's slug on success. Errors: {"error": "SUPERVISOR_TOKEN not set — Nexus must run as HA add-on for Supervisor API"} when the token env var is missing; {"error": "HTTP <status>", "detail": ...} on a timeout or failure — check supervisor_list_backups before retrying. Limits: a full backup can take minutes; on a timeout error, check supervisor_list_backups before retrying rather than assuming failure.

supervisor_restore_backupA

Restore a full backup after an explicit confirmation.

Calls POST /backups/<slug>/restore/full, which replaces the HA configuration, every add-on with its data, and the backed-up folders with the backup's contents; anything changed since the backup was taken is lost. Core and this nexus add-on restart as part of the restore, so the call may drop the connection before it can reply. Without confirm=True nothing is restored.

Use when: reverting to a known-good state after a failed update or misconfiguration. Not for: restoring only some add-ons/folders — Supervisor's partial restore is not exposed by this tool. Returns: Supervisor's restore-job result when confirmed; the reply may never arrive because the add-on restarts mid-call. Errors: {"error": "invalid_slug"} for a bad slug; returns {"error": "confirmation_required", "message": ..., "action": ...} when confirm is false; {"error": "HTTP <status>", "detail": ...} if the slug or password is wrong. Limits: WARNING: discards every change made since the backup; requires confirm=True.

supervisor_delete_backupA

Permanently delete one backup after an explicit confirmation.

Calls DELETE /backups/<slug>. Without confirm=True nothing is deleted; the call only returns a confirmation prompt. There is no undo once the backup file is gone — a backup is itself the undo mechanism for every other change in this add-on.

Use when: cleaning up a backup that is confirmed to be no longer needed. Not for: any situation where the backup might still be needed — there is no recovery after this call, even with confirm=True. Returns: Supervisor's delete result when confirmed, otherwise a confirmation prompt. Errors: {"error": "invalid_slug"} for a bad slug; returns {"error": "confirmation_required", "message": ..., "action": ...} when confirm is false; {"error": "SUPERVISOR_TOKEN not set — Nexus must run as HA add-on for Supervisor API"} when the token env var is missing; {"error": "HTTP <status>", "detail": ...} if the slug does not exist. Limits: requires confirm=True; deletion is immediate and permanent with no undo once confirmed.

hacs_list_hacs_repositoriesA

List HACS repositories known to this Home Assistant instance.

Calls the hacs/repositories/list WebSocket command, optionally scoped to one category.

Use when: browsing or checking the state of repositories HACS already knows about (installed or not). Not for: repositories not yet added to HACS at all — use hacs_add_custom_repository first. Returns: list of HACS repository dicts as reported by HACS, or {"error": ..., "hint": ...} if the WebSocket call fails. Errors: {"error": str(exception), "hint": "HACS may not be installed, or the WS command name has changed"} when the WebSocket command fails, e.g. because HACS is not installed.

hacs_get_hacs_repositoryA

Get details about a single HACS repository.

Calls the hacs/repository/info WebSocket command for the given repo_id, passed as its repository_id field.

Use when: checking one repository's installed/available version or metadata before installing or updating it. Not for: browsing many repositories at once — use hacs_list_hacs_repositories. Returns: HACS's raw repository-info dict, or {"error": ..., "hint": ...} if the WebSocket call fails. Errors: {"error": str(exception), "hint": "HACS may not be installed, or the WS command name has changed"} when repo_id is unknown or the WebSocket command fails.

hacs_install_hacs_repositoryA

Install a HACS repository, optionally pinning a version.

Calls the hacs/repository/download WebSocket command (HACS has no separate "install" command — download installs when not yet installed, or re-downloads in place when it is), which fetches the repository's release from its source (typically GitHub) — an outbound fetch beyond this HA instance and its host.

Use when: adding a HACS-managed integration/plugin/theme that is already known to HACS (via the default store or hacs_add_custom_repository). Not for: adding a repository HACS does not know about yet — use hacs_add_custom_repository first. Returns: HACS's install result, or {"error": ..., "hint": ...} if the WebSocket call fails. Errors: {"error": str(exception), "hint": "HACS may not be installed, or the WS command name has changed"} when repo_id/version is invalid or the WebSocket command fails. Limits: downloads the release over the network; requires a restart of the affected component for most categories.

hacs_uninstall_hacs_repositoryA

Uninstall a HACS repository.

Calls the hacs/repository/remove WebSocket command (HACS has no separate "uninstall" command), which removes the installed files for repo_id; the integration/plugin/theme stops working until reinstalled.

Use when: removing a HACS-managed component that is no longer needed. Not for: only skipping an update while keeping it installed — there is no such option exposed here. Returns: HACS's remove result, or {"error": ..., "hint": ...} if the WebSocket call fails. Errors: {"error": str(exception), "hint": "HACS may not be installed, or the WS command name has changed"} when repo_id is not installed or the WebSocket command fails.

hacs_update_hacs_repositoryA

Update an installed HACS repository to its latest available version.

HACS has no single "update" WebSocket command. This performs the three calls HACS's own frontend makes for an update: hacs/repository/refresh (re-fetches repository data; always returns {}, no version info), then hacs/repository/info (reads the resulting available_version), then hacs/repository/download with that version — which downloads and installs the newest release over the network; the previous version is only recoverable from a backup taken beforehand.

Use when: pending_upgrade is set for the repository (see hacs_list_hacs_critical_updates) and the new version should be applied. Not for: pinning a specific version instead of the latest — use hacs_install_hacs_repository with version set. Returns: HACS's download result, or {"error": ..., "hint": ...} if any of the three WebSocket calls fails. Errors: {"error": str(exception), "hint": "HACS may not be installed, or the WS command name has changed"} when the refresh or info call fails (the download call is then never made); {"error": "HACS did not report an available_version for this repository", "raw": ...} when info succeeds but has nothing to update to. Limits: downloads the new release over the network; no automatic rollback on failure; three sequential WebSocket round-trips instead of one.

hacs_add_custom_repositoryA

Register a custom repository with HACS so it becomes installable.

Calls the hacs/repositories/add WebSocket command (plural — distinct from the singular hacs/repository/* commands used elsewhere in this namespace) with url as its repository field and category. This only registers the repository — it does not install it.

Use when: a repository is not in HACS's default store and needs adding before it can be installed. Not for: installing an already-registered repository — use hacs_install_hacs_repository. Returns: HACS's add result, or {"error": ..., "hint": ...} if the WebSocket call fails. Errors: {"error": str(exception), "hint": "HACS may not be installed, or the WS command name has changed"} when url/category is invalid or the WebSocket command fails.

hacs_list_hacs_critical_updatesA

List installed HACS repositories that have a pending upgrade available.

Calls the same hacs/repositories/list WebSocket command as hacs_list_hacs_repositories and filters to entries whose pending_upgrade flag is set, despite this tool's name — HACS itself has no separate "critical" severity here.

Use when: finding what needs hacs_update_hacs_repository without filtering the full list manually. Not for: every repository regardless of upgrade state — use hacs_list_hacs_repositories. Returns: list of repository dicts with pending_upgrade truthy, or {"error": ...} if the underlying call fails or returns an unexpected shape. Errors: {"error": str(exception), "hint": ...} when the WebSocket call fails; {"error": "Unexpected HACS response shape", "raw": result} when it succeeds but does not return a list.

energy_get_energy_prefsA

Return the full HA Energy Dashboard preferences.

Calls the WebSocket endpoint energy/get_prefs and returns its payload unchanged, including the configured energy_sources and device_consumption lists.

Use when: you need the current preferences before editing them with energy_save_energy_prefs or one of the energy_add_*/ energy_remove_energy_source helpers. Not for: adding or removing a single source without hand-building the full list — use energy_add_grid_consumption, energy_add_grid_return, energy_add_solar_source, energy_add_battery_source or energy_remove_energy_source instead. Returns: dict with energy_sources (list) and device_consumption (list), exactly as HA stores them. Errors: {"error": "..."} when the WebSocket call raises.

energy_save_energy_prefsA

Save Energy Dashboard preferences via WS energy/save_prefs.

Each of energy_sources/device_consumption you pass replaces the entire corresponding saved list — it is not merged with what's already there. Use energy_add_grid_consumption, energy_add_grid_return, energy_add_solar_source, energy_add_battery_source or energy_remove_energy_source for incremental edits instead of hand-building the full list. currency/energy_per_unit are kept only for backward compatibility and are rejected: HA's currency lives in core config (homeassistant.currency), not this WS schema, and energy_per_unit does not exist in it at all.

Use when: you already hold the full desired energy_sources/ device_consumption list, e.g. from energy_get_energy_prefs. Not for: adding or removing one source — use the energy_add_*/ energy_remove_energy_source helpers, which read-modify-write for you. Returns: {"status": "saved", "result": ..., "fields": [...]} on success. Errors: {"error": "no fields to save", ...} when both list parameters are omitted; {"error": "currency and energy_per_unit are not fields of HA's energy/save_prefs WS schema...", ...} when either deprecated parameter is passed; {"error": str(e), ...} when the WS call raises.

energy_get_energy_infoA

Return Energy Dashboard info such as cost sensors and currency.

Calls the WebSocket endpoint energy/info and returns its payload unchanged.

Use when: you need metadata about the Energy Dashboard (available cost sensor types, currency) rather than the source configuration itself. Not for: the actual source/device list — use energy_get_energy_prefs. Returns: dict as returned by HA's energy/info WS command. Errors: {"error": str(e)} when the WS call raises.

energy_validate_energy_prefsA

Validate the currently saved Energy Dashboard configuration.

Calls the WebSocket endpoint energy/validate, which checks the saved energy_sources/device_consumption for issues (e.g. a statistic ID that no longer exists) without changing anything.

Use when: checking whether the current Energy Dashboard setup has issues, e.g. after editing sources with energy_save_energy_prefs or one of the energy_add_* helpers. Not for: reading the configuration itself — use energy_get_energy_prefs. Returns: dict as returned by HA's energy/validate WS command, listing any detected issues per source. Errors: {"error": str(e)} when the WS call raises.

energy_add_grid_consumptionA

Add a grid consumption flow to the Energy Dashboard's grid source.

Reads the current preferences via ha._ws_call("energy/get_prefs"), appends stat_energy_from (and stat_cost if given) as a new flow_from entry on the existing grid source, creating that grid source first if none exists yet, then saves the updated list via WS energy/save_prefs. Calling it twice with the same stat_energy_from adds a second, duplicate flow entry.

Use when: registering a grid-import sensor as an Energy Dashboard consumption flow. Not for: grid export/solar compensation — use energy_add_grid_return; for a full source-list replacement use energy_save_energy_prefs. Returns: {"status": "added", "stat_energy_from": ..., "result": ...}. Errors: {"error": str(e), "stat_energy_from": ...} when either WS call raises.

energy_add_grid_returnA

Add a grid return (export) flow to the Energy Dashboard's grid source.

Reads the current preferences via ha._ws_call("energy/get_prefs"), appends stat_energy_to (and stat_compensation if given) as a new flow_to entry on the existing grid source, creating that grid source first if none exists yet, then saves via WS energy/save_prefs. Calling it twice with the same stat_energy_to adds a second, duplicate entry.

Use when: registering a solar-export or other grid-return sensor, e.g. solar sold back to the grid. Not for: grid import — use energy_add_grid_consumption; for a full source-list replacement use energy_save_energy_prefs. Returns: {"status": "added", "stat_energy_to": ..., "result": ...}. Errors: {"error": str(e), "stat_energy_to": ...} when either WS call raises.

energy_add_solar_sourceA

Add a solar production source to the Energy Dashboard.

Reads the current preferences, appends a new {"type": "solar", ...} entry to the energy_sources list, and saves it via WS energy/save_prefs. Calling it twice with the same stat_energy_from adds a second, duplicate source.

Use when: registering a solar production sensor as a new Energy Dashboard source. Not for: an existing source's export flow — use energy_add_grid_return; for a full source-list replacement use energy_save_energy_prefs. Returns: {"status": "added", "stat_energy_from": ..., "result": ...}. Errors: {"error": str(e), "stat_energy_from": ...} when either WS call raises.

energy_add_battery_sourceA

Add a battery source to the Energy Dashboard.

Reads the current preferences, appends a new {"type": "battery", ...} entry combining stat_energy_from (discharge) and stat_energy_to (charge) to the energy_sources list, and saves it via WS energy/save_prefs. Calling it twice with the same arguments adds a second, duplicate source.

Use when: registering a home battery's charge and discharge sensors as one Energy Dashboard source. Not for: grid or solar sources — use energy_add_grid_consumption/ energy_add_grid_return/energy_add_solar_source. Returns: {"status": "added", "stat_energy_from": ..., "stat_energy_to": ..., "result": ...}. Errors: {"error": str(e)} when either WS call raises.

energy_remove_energy_sourceA

Remove an energy source identified by its stat_energy_from.

Reads the current preferences, drops any solar/battery/gas/water source whose stat_energy_from matches, also strips matching flow_from entries from the grid source, and saves the resulting list via WS energy/save_prefs. This replaces the whole energy_sources list with one that has the matching entries removed — anything else in the list is preserved as-is.

Use when: undoing an energy_add_solar_source/energy_add_battery_source/ energy_add_grid_consumption call, or dropping a source that no longer exists. Not for: replacing the whole source list at once — use energy_save_energy_prefs. Returns: {"status": "removed", "removed": <count>, "stat_energy_from": ..., "result": ...} on success, or {"status": "not_found", "stat_energy_from": ...} when nothing matched. Errors: {"error": str(e), "stat_energy_from": ...} when either WS call raises.

zones_list_zonesA

List all zone entities with their common location attributes.

Reads all HA states and keeps zone.* entities, projecting each down to entity_id, state, and any of latitude, longitude, radius, friendly_name, passive and icon present in its attributes.

Use when: you need every zone's location and radius, e.g. before checking who is inside one. Returns: list of slimmed zone dicts as described above.

zones_get_zoneA

Get one zone entity's full state and attributes.

Prefixes entity_id with zone. if missing, then fetches it with ha.get_state.

Use when: you need every attribute of a single zone rather than the slimmed list from zones_list_zones. Returns: the full HA state object for the zone (entity_id, state, attributes). Errors: {"error": "<message>", "entity_id": ...} if the zone entity does not exist.

zones_create_zoneA

Create a zone as a UI helper (storage collection), not a YAML zone.

Calls WS zone/create with the given coordinates and radius; only zones created this way can later be changed through zones_update_zone or zones_delete_zone. zone.home (core config) and YAML-defined zones live outside this storage collection and cannot be created here.

Use when: adding a new geofence zone without editing configuration.yaml. Returns: dict with status, name, and the raw WS result. Errors: on failure, returns {"error": "<message>", "hint": "...", "name": ...} instead of raising.

zones_update_zoneA

Update fields on an existing zone helper.

Calls WS zone/update; only the parameters you pass are sent, so omitted fields keep their current value. Only works for zones created via zones_create_zone (UI helpers) — zone.home and YAML-defined zones reject this WS command.

Use when: adjusting a UI-helper zone's coordinates, radius or name. Returns: dict with status, zone_id, and the raw WS result. Errors: on failure (e.g. a YAML zone or zone.home), returns {"error": "<message>", "hint": "...", "zone_id": ...} instead of raising.

zones_delete_zoneA

Delete a zone helper.

Calls WS zone/delete; accepts either the bare helper id or the full zone.<id> entity_id. Only works for zones created via zones_create_zone — zone.home and YAML-defined zones reject this WS command.

Use when: removing a UI-helper zone that is no longer needed. Returns: dict with status, zone_id, and the raw WS result. Errors: on failure, returns {"error": "<message>", "hint": "...", "zone_id": ...} instead of raising.

zones_reload_zonesA

Reload zones defined in configuration.yaml.

Calls service zone.reload over HTTP, which makes Home Assistant re-read YAML-defined zones without a full restart.

Use when: you edited zone YAML and want the change applied, or after zones_create_zone reports that YAML zones aren't supported. Returns: dict with status and the raw service-call result. Errors: on failure, returns {"error": "<message>"} instead of raising.

zones_list_persons_in_zoneA

List person entities currently inside a given zone.

Reads the zone's own persons attribute (maintained by Home Assistant's zone component); falls back to matching each person's state string against the zone only when that attribute is entirely absent, which also special-cases zone.home (Home Assistant always reports "home" there regardless of the zone's friendly_name).

Use when: checking who is currently inside a specific zone. Returns: list of dicts (entity_id, state, friendly_name, latitude, longitude) for persons in the zone; empty list if the zone does not exist.

zones_get_user_locationA

Get one person entity's current location.

Prefixes person_entity_id with person. if missing, then reads its state and location attributes.

Use when: you need just one person's coordinates rather than scanning a zone with zones_list_persons_in_zone. Returns: dict with entity_id, state, latitude, longitude, gps_accuracy, source. Errors: {"error": "<message>", "entity_id": ...} if the person entity does not exist.

labels_list_labelsA

List all labels defined in Home Assistant.

Calls WS config/label_registry/list and returns the result unfiltered; returns an empty list if the WS response is not a list.

Use when: you need label IDs and names before filtering or assigning them to entities or devices. Returns: list of label registry dicts (label_id, name, icon, color, description). Errors: on a WS failure, returns [{"error": "<message>"}] instead of raising.

labels_create_labelA

Create a new label.

Calls WS config/label_registry/create with name and any of icon, color and description you pass; Home Assistant assigns a new label_id, so calling this twice with the same name creates two separate labels.

Use when: you need a new label to tag entities or devices with. Returns: the created label registry dict (label_id, name, icon, color, description). Errors: on a WS failure, returns {"error": "<message>"} instead of raising.

labels_update_labelA

Update fields on an existing label.

Calls WS config/label_registry/update; only the parameters you pass are sent, so omitted fields keep their current value.

Use when: renaming a label or changing its icon, color or description. Returns: the updated label registry dict. Errors: on a WS failure, returns {"error": "<message>"} instead of raising.

labels_delete_labelA

Delete a label from the label registry.

Calls WS config/label_registry/delete with the given label_id and returns Home Assistant's result unchanged.

Use when: a label is no longer needed. Returns: dict with label_id, the raw WS result, and ok (true on success). Errors: on a WS failure, returns {"label_id": ..., "ok": false, "error": "<message>"} instead of raising.

labels_assign_label_to_entityA

Assign a label to an entity, keeping its existing labels.

Reads the entity's current labels list from the entity registry, appends label_id if not already present, and writes the full list back via WS config/entity_registry/update.

Use when: tagging one entity with a label without disturbing labels already on it. Not for: removing a label — use labels_remove_label_from_entity. Returns: dict with entity_id, the resulting labels list, the raw WS result, and ok. Errors: on a WS failure, returns {"entity_id": ..., "label_id": ..., "ok": false, "error": "<message>"}.

labels_remove_label_from_entityA

Remove a label from an entity, keeping its other labels.

Reads the entity's current labels list from the entity registry, drops label_id if present, and writes the remaining list back via WS config/entity_registry/update.

Use when: untagging one entity from a label without touching its other labels. Not for: deleting the label itself everywhere — use labels_delete_label. Returns: dict with entity_id, the resulting labels list, the raw WS result, and ok. Errors: on a WS failure, returns {"entity_id": ..., "label_id": ..., "ok": false, "error": "<message>"}.

labels_assign_label_to_deviceA

Assign a label to a device, keeping its existing labels.

Reads the device's current labels list from the device registry, appends label_id if not already present, and writes the full list back via WS config/device_registry/update.

Use when: tagging one device with a label without disturbing labels already on it. Not for: removing a label — use labels_remove_label_from_device. Returns: dict with device_id, the resulting labels list, the raw WS result, and ok. Errors: on a WS failure, returns {"device_id": ..., "label_id": ..., "ok": false, "error": "<message>"}.

labels_remove_label_from_deviceA

Remove a label from a device, keeping its other labels.

Reads the device's current labels list from the device registry, drops label_id if present, and writes the remaining list back via WS config/device_registry/update.

Use when: untagging one device from a label without touching its other labels. Not for: deleting the label itself everywhere — use labels_delete_label. Returns: dict with device_id, the resulting labels list, the raw WS result, and ok. Errors: on a WS failure, returns {"device_id": ..., "label_id": ..., "ok": false, "error": "<message>"}.

labels_list_entities_with_labelA

List entities that currently have a given label assigned.

Reads the entity registry over WebSocket and keeps rows whose labels list contains label_id.

Use when: finding everything tagged with one label, e.g. before a bulk action. Returns: list of entity registry dicts that have the label. Errors: on a WS failure, returns [{"error": "<message>"}] instead of raising.

labels_list_devices_with_labelA

List devices that currently have a given label assigned.

Reads the device registry over WebSocket and keeps rows whose labels list contains label_id.

Use when: finding everything tagged with one label, e.g. before a bulk action. Returns: list of device registry dicts that have the label. Errors: on a WS failure, returns [{"error": "<message>"}] instead of raising.

labels_list_categoriesA

List categories defined for a given registry scope.

Calls WS config/category_registry/list with scope and returns the result unfiltered; returns an empty list if the WS response is not a list.

Use when: you need category IDs for one scope, e.g. before tagging automations. Returns: list of category registry dicts (category_id, name, icon) for the given scope. Errors: on a WS failure, returns [{"error": "<message>"}] instead of raising.

labels_create_categoryA

Create a category within a registry scope.

Calls WS config/category_registry/create with scope and name, plus icon if given; Home Assistant assigns a new category_id, so calling this twice with the same name creates two separate categories.

Use when: you need a new category to group items within one scope, e.g. automations. Returns: the created category registry dict. Errors: on a WS failure, returns {"error": "<message>"} instead of raising.

labels_update_categoryA

Update fields on an existing category.

Calls WS config/category_registry/update; only the parameters you pass are sent, so omitted fields keep their current value.

Use when: renaming a category or changing its icon within its scope. Returns: the updated category registry dict. Errors: on a WS failure, returns {"error": "<message>"} instead of raising.

labels_delete_categoryA

Delete a category from a registry scope.

Calls WS config/category_registry/delete with scope and category_id and returns Home Assistant's result unchanged.

Use when: a category is no longer needed within its scope. Returns: dict with scope, category_id, the raw WS result, and ok. Errors: on a WS failure, returns {"scope": ..., "category_id": ..., "ok": false, "error": "<message>"}.

search_search_entitiesA

Fuzzy-rank entities by entity_id, friendly_name and device_id.

Scores every entity against query with substring match (score 1.0) or a sequence-similarity ratio, keeps only scores above 0, and returns the top limit matches sorted descending.

Use when: you don't know the exact entity_id and want a ranked guess from a name fragment. Returns: list of dicts (entity_id, friendly_name, state, device_id, score) up to limit entries. Limits: entities that score exactly 0 are dropped entirely, not just deprioritised.

search_search_devicesA

Fuzzy-rank devices by name, name_by_user, manufacturer and model.

Scores every device from the device registry against query, keeps only scores above 0, and returns the top limit matches sorted descending.

Use when: you don't know a device's exact id and want a ranked guess from a name fragment. Not for: an exact, unranked device list — use devices_list_devices, areas_list_devices or devices_list_devices_in_area. Returns: list of dicts (id, name, name_by_user, manufacturer, model, area_id, score) up to limit entries. Limits: devices that score exactly 0 are dropped entirely; a WS failure yields an empty list rather than an error.

search_search_areasA

Fuzzy-rank areas by name.

Scores every area from the area registry against query, keeps only scores above 0, and returns the top limit matches sorted descending.

Use when: you don't know an area's exact id and want a ranked guess from a name fragment. Not for: an exact, unranked area list — use areas_list_areas. Returns: list of dicts (area_id, name, floor_id, icon, score) up to limit entries. Limits: areas that score exactly 0 are dropped entirely; a WS failure yields an empty list rather than an error.

search_deep_searchA

Fuzzy-search entities, devices and areas together in one ranked list.

Scores states (tagging automation.* entities as kind 'automation', others as 'entity'), devices and areas against query the same way as the single-kind search tools, merges all matches, and returns the top limit sorted descending.

Use when: you don't know whether what you're looking for is an entity, device or area. Not for: results scoped to one kind — use search_search_entities, search_search_devices or search_search_areas. Returns: list of dicts tagged with kind ('entity'/'automation'/ 'device'/'area'), each with kind-specific fields plus score, up to limit entries.

search_find_relatedA

Return an entity's device, area, floor and sibling entities.

Looks up entity_id in the entity registry, resolves its device (falling back to the device's area if the entity itself has none) and area/floor, then collects other entities on the same device and other entities/devices in the same area.

Use when: exploring what else is connected to one entity before changing or troubleshooting it. Returns: dict with entity_id, device_id, area_id, floor_id, device, area, same_device_entities, same_area_entities. Errors: {"entity_id": ..., "error": "entity not found in registry"} if the entity isn't in the registry, or {"entity_id": ..., "error": "<message>"} on a WS failure.

search_find_unused_entitiesA

Heuristically list entities that look unused or orphaned.

Flags entities whose state has been 'unavailable' or 'unknown' for more than 7 days (or has no last_changed at all), plus any entity-registry entries with no device_id — which normally means helpers, automations and template entities, not proof of disuse.

Use when: hunting for cleanup candidates, always reviewing each result before deleting anything. Returns: list of dicts (entity_id, state, last_changed, device_id, reasons) — reasons explains which heuristic(s) matched. Limits: purely heuristic; the 7-day unavailability threshold and a missing device_id are weak signals, not confirmation that an entity is truly unused.

search_find_orphan_devicesA

List devices with no entities associated with them in the entity registry.

Compares every device's id against the set of device_id values referenced by entity-registry entries and returns devices that no entity points to.

Use when: hunting for device-registry entries that may be safe to remove, always reviewing each result first. Returns: list of dicts (id, name, name_by_user, manufacturer, model, area_id, config_entries) for devices with no referencing entity. Limits: a WS failure on either registry silently yields an empty underlying list rather than an error, which can under-report orphans.

integrations_list_flow_handlersA

List every integration domain that supports a config flow.

Calls GET /api/config/config_entries/flow_handlers over HTTP for the domains HA can set up through the UI-style flow (as opposed to YAML-only integrations).

Use when: checking whether a domain can be installed via integrations_start_config_flow before attempting it. Not for: domains already configured — use system_list_integrations. Returns: list of domain strings, e.g. ["shelly", "hue", ...]. Errors: raises httpx.HTTPStatusError if the HA API request fails.

integrations_list_flows_in_progressA

List config flows that were started but not yet finished.

Calls the config_entries/flow/progress WebSocket command.

Use when: finding a flow_id left over from an earlier integrations_start_config_flow call, e.g. one waiting on discovery. Not for: flows already completed into a config entry — use system_list_integrations. Returns: list of in-progress flow dicts (flow_id, handler, step_id, context, and related fields). Errors: raises RuntimeError if the underlying WebSocket call fails (e.g. auth or WS-level error).

integrations_start_config_flowA

Start a new config flow for an integration domain.

Calls POST /api/config/config_entries/flow with {"handler": handler, "show_advanced_options": show_advanced_options}; HA has no WebSocket command for this. Each call creates a new, distinct flow.

Use when: beginning to set up a new integration through the same step-by-step flow the HA UI uses. Not for: editing an already-configured entry — use integrations_start_options_flow. Returns: the first step: {flow_id, step_id, data_schema, errors, ...}. Pass flow_id into integrations_submit_config_flow_step with the user's answers. Errors: raises httpx.HTTPStatusError if handler is not a valid flow-handler domain.

integrations_submit_config_flow_stepA

Submit user input for the current step of a config flow.

Calls POST /api/config/config_entries/flow/{flow_id} with user_input. What this does depends entirely on the integration domain driving the flow: it may just advance to the next form, or it may validate credentials against the integration's own device/cloud service and create or overwrite a real config entry that HA loads. HA does not signal in advance which step is the last one, so any submitted step — not only a visibly "final" one — can be the one that creates the entry.

Use when: providing the values a config-flow step asked for. Not for: reading the current step without submitting anything — use integrations_get_config_flow; cancelling a flow before it finishes — use integrations_abort_config_flow. Returns: the next step (form), a step with errors, or the finished config entry. The returned step's last_step field is True only when the integration explicitly declares this is the final step, and None otherwise — most integrations leave it None even on their actual last step, so None does not mean more steps remain. Errors: raises httpx.HTTPStatusError if flow_id is unknown or expired. Limits: the integration handling this domain may reach an external device or cloud service while validating user_input; a config entry can be created without warning on any step.

integrations_abort_config_flowA

Abort a config flow that has not been finished yet.

Calls DELETE /api/config/config_entries/flow/{flow_id}. Nothing was persisted by an unfinished flow, so this discards only the flow's in-progress state, not a config entry.

Use when: cancelling a setup that was started by mistake or is no longer wanted. Not for: removing a completed integration — use integrations_remove_integration. Returns: HA's abort response for the flow. Errors: raises httpx.HTTPStatusError if flow_id is unknown or already finished.

integrations_get_config_flowA

Get the current state of a config flow without advancing it.

Calls GET /api/config/config_entries/flow/{flow_id}.

Use when: checking a flow's current step/schema again, e.g. after losing the earlier response. Not for: providing the step's answers — use integrations_submit_config_flow_step. Returns: the flow's current step payload, same shape as integrations_start_config_flow's result. Errors: raises httpx.HTTPStatusError if flow_id is unknown or expired.

integrations_remove_integrationA

Remove (uninstall) an integration's config entry after an explicit confirmation.

Calls DELETE /api/config/config_entries/entry/{entry_id} — there is no config_entries/remove WebSocket command. HA unloads the integration and deletes its entry; any devices/entities it owned typically go with it. Without confirm=True nothing is removed.

Use when: an integration is no longer wanted and should be fully uninstalled, not just disabled. Not for: keeping the entry but pausing it — use integrations_disable_integration. Returns: HA's removal result when confirmed, otherwise a confirmation prompt. Errors: returns {"error": "confirmation_required", "message": ..., "action": ...} when confirm is false; raises httpx.HTTPStatusError if entry_id does not exist. Limits: requires confirm=True; deletes the entry and its devices/entities with no separate backup step.

integrations_disable_integrationA

Disable an integration's config entry without removing it.

Calls the config_entries/disable WebSocket command with disabled_by="user". The entry and its devices/entities stay registered but stop loading until re-enabled.

Use when: pausing an integration temporarily while keeping its configuration and registry entries intact. Not for: permanently deleting the entry — use integrations_remove_integration; to bring it back — use integrations_enable_integration. Returns: the config_entries/disable result. Errors: raises RuntimeError if the underlying WebSocket call fails (e.g. entry_id unknown).

integrations_enable_integrationA

Re-enable a previously disabled integration's config entry.

Calls the config_entries/disable WebSocket command with disabled_by=None, which HA treats as clearing the disabled state.

Use when: bringing back an integration disabled via integrations_disable_integration. Not for: setting up a brand-new integration — use integrations_start_config_flow. Returns: the config_entries/disable result. Errors: raises RuntimeError if the underlying WebSocket call fails (e.g. entry_id unknown).

integrations_start_options_flowA

Start the options flow for an existing config entry.

Calls POST /api/config/config_entries/options/flow, passing entry_id as handler — HA's options-flow API reuses the config-flow request shape and documents handler as "the entry_id" in this context. Each call creates a new, distinct flow.

Use when: changing an already-configured integration's settings through its own options UI/schema. Not for: configuring a brand-new integration — use integrations_start_config_flow. Returns: the first step: {flow_id, step_id, data_schema, errors, ...}. Pass flow_id into integrations_submit_options_flow_step. Errors: raises httpx.HTTPStatusError if entry_id does not exist or the integration has no options flow.

integrations_submit_options_flow_stepA

Submit a step of an options flow.

Calls POST /api/config/config_entries/options/flow/{flow_id} with user_input. What this does depends entirely on the integration domain: an intermediate step just advances the form, while the step that finishes the flow applies the new options to the existing config entry, replacing its previous options. HA does not signal in advance which step is the last one, so any submitted step — not only a visibly "final" one — can be the one that overwrites the options.

Use when: providing the values an options-flow step asked for. Not for: reading the current step without submitting — there is no separate "get options flow" tool; call integrations_start_options_flow again to restart it; cancelling a flow before it finishes — use integrations_abort_options_flow. Returns: the next step (form), a step with errors, or the entry's updated result. The returned step's last_step field is True only when the integration explicitly declares this is the final step, and None otherwise — most integrations leave it None even on their actual last step, so None does not mean more steps remain. Errors: raises httpx.HTTPStatusError if flow_id is unknown or expired. Limits: any submitted step, not only a visibly "final" one, may overwrite the entry's previous options; the integration may reach an external device or cloud service while validating the submitted values.

integrations_abort_options_flowA

Abort an options flow that has not been finished yet.

Calls DELETE /api/config/config_entries/options/flow/{flow_id}. The entry's existing options are untouched, since nothing was applied by an unfinished flow.

Use when: cancelling an options edit started by mistake or no longer wanted. Not for: cancelling a new-integration setup flow instead — use integrations_abort_config_flow. Returns: HA's abort response for the flow. Errors: raises httpx.HTTPStatusError if flow_id is unknown or already finished.

integrations_update_integration_entryA

Update selected properties of an existing config entry.

Calls the config_entries/update WebSocket command with only the fields given here (title, pref_disable_new_entities, pref_disable_polling) — omitted fields keep their previous stored value, but any field that is given replaces the previous one, which is then lost.

Use when: renaming an integration's entry or changing its entity-discovery/polling preferences without going through its options flow. Not for: settings specific to the integration itself (its actual options schema) — use integrations_start_options_flow. Returns: the config_entries/update result. Errors: raises RuntimeError if the underlying WebSocket call fails (e.g. entry_id unknown).

voice_list_pipelinesA

List all Assist pipelines plus the preferred pipeline id.

Calls WS assist_pipeline/pipeline/list and returns its payload unchanged.

Use when: you need every configured pipeline, e.g. to pick one for voice_set_preferred_pipeline or before editing one with voice_update_pipeline. Not for: a single pipeline's full detail — use voice_get_pipeline. Returns: {"pipelines": [...], "preferred_pipeline": "<id>"}.

voice_get_pipelineA

Get a single Assist pipeline by id, or the preferred one if omitted.

Calls WS assist_pipeline/pipeline/get, passing pipeline_id only when given.

Use when: you need one pipeline's full configuration (engines, languages) rather than the whole list. Not for: every pipeline at once — use voice_list_pipelines. Returns: dict with the pipeline's engine/language fields, as returned by HA.

voice_create_pipelineA

Create a new Assist pipeline via WS assist_pipeline/pipeline/create.

Every parameter is forwarded as-is to HA; engine parameters are entity IDs of the relevant provider (stt.*, tts.*, wake_word.*) rather than free-form names. Calling this twice with the same name creates two separate pipelines with distinct IDs, since HA assigns a new ID each time.

Use when: setting up a new voice pipeline with a specific combination of conversation/STT/TTS/wake-word engines. Not for: changing an existing pipeline — use voice_update_pipeline. Returns: the created pipeline dict, as returned by HA (includes its new id). Limits: engine parameters must already be installed entity IDs; discover them with voice_list_stt_engines, voice_list_tts_engines, voice_list_wake_word_engines and voice_list_conversation_agents first.

voice_update_pipelineA

Update an existing Assist pipeline's fields via WS assist_pipeline/pipeline/update.

HA's WS API requires the full set of fields on every update call, so this first fetches the current pipeline with WS assist_pipeline/pipeline/get and fills in any parameter left as None from that current state before sending the update — only the parameters you actually pass are changed; the previous value of any field you omit is lost from this call's perspective and replaced by whatever assist_pipeline/pipeline/get returned for it.

Use when: changing one or more fields of an existing pipeline. Not for: creating a new pipeline — use voice_create_pipeline. Returns: the updated pipeline dict, as returned by HA.

voice_delete_pipelineA

Delete an Assist pipeline via WS assist_pipeline/pipeline/delete.

HA rejects deleting the pipeline currently marked preferred — call voice_set_preferred_pipeline with a different id first in that case.

Use when: permanently removing a pipeline that is no longer needed. Not for: the preferred pipeline without switching preference first, and not for temporarily disabling a pipeline (HA has no such state). Returns: HA's WS response for assist_pipeline/pipeline/delete (typically empty on success).

voice_set_preferred_pipelineA

Set the default Assist pipeline, used when no pipeline is specified.

Calls WS assist_pipeline/pipeline/set_preferred.

Use when: changing which pipeline Assist uses by default. Not for: reading the current preference — use voice_list_pipelines, whose response includes preferred_pipeline. Returns: HA's WS response for assist_pipeline/pipeline/set_preferred (typically empty on success).

voice_list_stt_enginesA

List installed speech-to-text engines as their stt.* entities.

Filters ha.get_states() for entity IDs starting with stt..

Use when: discovering which STT engine entity ID to pass to voice_create_pipeline/voice_update_pipeline. Not for: TTS or wake-word engines — use voice_list_tts_engines/ voice_list_wake_word_engines. Returns: list of {"entity_id", "state", "attributes"} for each stt.* entity.

voice_list_tts_enginesA

List installed text-to-speech engines as their tts.* entities.

Filters ha.get_states() for entity IDs starting with tts..

Use when: discovering which TTS engine entity ID to pass to voice_create_pipeline/voice_update_pipeline. Not for: STT or wake-word engines — use voice_list_stt_engines/ voice_list_wake_word_engines. Returns: list of {"entity_id", "state", "attributes"} for each tts.* entity.

voice_list_wake_word_enginesA

List installed wake-word detection engines as their wake_word.* entities.

Filters ha.get_states() for entity IDs starting with wake_word..

Use when: discovering which wake-word entity ID to pass to voice_create_pipeline/voice_update_pipeline. Not for: STT or TTS engines — use voice_list_stt_engines/ voice_list_tts_engines. Returns: list of {"entity_id", "state", "attributes"} for each wake_word.* entity.

voice_list_conversation_agentsA

List conversation agents available for a pipeline's conversation step.

Calls WS conversation/agent/list and returns its payload unchanged.

Use when: discovering which conversation_engine value to pass to voice_create_pipeline/voice_update_pipeline. Not for: STT/TTS/wake-word engines — use voice_list_stt_engines/ voice_list_tts_engines/voice_list_wake_word_engines. Returns: dict as returned by HA's conversation/agent/list WS command.

themes_list_themesA

List all Lovelace themes registered with the frontend.

Calls WS frontend/get_themes and returns Home Assistant's response unchanged.

Use when: you need every theme's name plus which one is active before switching or editing. Returns: dict with themes (name to variable-map), default_theme, and default_dark_theme.

themes_get_themeA

Get one theme's CSS variable map by name.

Calls WS frontend/get_themes and looks up name in the result.

Use when: inspecting a single theme's variables rather than the whole registry from themes_list_themes. Returns: dict with name and variables (the CSS variable map). Errors: {"error": "Theme '<name>' not found", "available": [...]} if the name isn't registered.

themes_set_active_themeA

Set the active Lovelace frontend theme.

Calls service frontend.set_theme with name, and mode when it is 'light' or 'dark'; any other mode value is silently omitted from the call.

Use when: switching which theme the frontend displays. Returns: the raw result of the frontend.set_theme service call. Limits: mode values other than 'light'/'dark' are dropped rather than rejected.

themes_reload_themesA

Reload theme files from the themes directory.

Calls service frontend.reload_themes, making Home Assistant re-read every YAML file under <config>/themes/.

Use when: after themes_create_theme, themes_update_theme or themes_delete_theme writes a file with reload=False, or after editing a theme file outside nexus. Returns: dict with status: 'reloaded'.

themes_create_themeA

Create a new Lovelace theme file.

Writes themes/<name>.yaml as {<name>: variables}. The file is only loaded by the frontend if configuration.yaml has frontend: themes: !include_dir_merge_named themes. Fails instead of overwriting unless overwrite=True.

Use when: adding a brand-new theme. Not for: changing an existing theme in place — use themes_update_theme. Returns: dict with success, path, and reloaded (present when reload=True). Errors: {"success": false, "error": "Theme '<name>' already exists. Pass overwrite=True to replace."} when the file exists and overwrite is false; {"success": false, "error": "invalid_theme_name", "detail": ...} when name contains '/' or a backslash, starts with '.', or is blank. Limits: name must not contain '/' or a backslash, start with '.', or be blank.

themes_update_themeA

Update an existing Lovelace theme file.

With merge=True (default), shallow-merges the given variables into the existing top-level keys — a passed modes key replaces the whole modes block rather than merging inside it; with merge=False, replaces the entire variable set. Fails if the theme file doesn't exist yet.

Use when: changing some or all variables on a theme that already exists. Not for: a theme that doesn't exist yet — use themes_create_theme. Returns: dict with success, path, merged, and reloaded (present when reload=True). Errors: {"success": false, "error": "Theme '<name>' not found at <path>"} when the file doesn't exist; {"success": false, "error": "invalid_theme_name", "detail": ...} when name contains '/' or a backslash, starts with '.', or is blank.

themes_delete_themeA

Delete a theme file.

Removes themes/<name>.yaml from disk if it exists.

Use when: a theme is no longer needed. Returns: dict with success and deleted (the removed path), plus reloaded when reload=True. Errors: {"success": false, "error": "Theme '<name>' not found at <path>"} when the file doesn't exist; {"success": false, "error": "invalid_theme_name", "detail": ...} when name contains '/' or a backslash, starts with '.', or is blank.

themes_list_theme_filesA

List YAML theme files present on disk under themes/.

Scans <config>/themes/ recursively for .yaml/.yml files, returning their paths relative to the config directory; returns an empty list if the directory doesn't exist yet.

Use when: a theme exists on disk but isn't showing up in themes_list_themes (not yet loaded). Returns: list of file paths relative to the Home Assistant config directory.

card_builder_list_cardsA

List every Card Builder card stored on this Home Assistant instance.

Calls the card_builder/cards/list WebSocket command and returns the raw collection: each entry carries id, name, description, config (the DocumentData block tree), version, tags and categories.

Use when: discovering existing cards before reading one in full with card_builder_get_card or editing one with card_builder_update_card. Returns: list of card dicts, in storage order, unfiltered.

card_builder_get_cardA

Get one Card Builder card by id, including its full config.

Fetches the whole card collection via card_builder/cards/list and matches on id or the legacy card_id field client-side — there is no dedicated get-by-id WebSocket command.

Use when: inspecting or copying one card's config before calling card_builder_update_card or card_builder_renderer_card_config. Returns: the matching card dict (same shape as one entry from card_builder_list_cards). Errors: {"error": "not_found", "card_id": ...} when no card matches.

card_builder_create_cardA

Create a new Card Builder card from a DocumentData config.

Sends config and the metadata fields to card_builder/cards/create, which assigns a new id server-side (confirmed in upstream storage.py: every create path generates a fresh uuid4) — repeating this call with identical arguments creates a second, distinct card rather than updating the first.

Use when: saving a card built with card_builder_build_from_recipe or card_builder_make_template_card's underlying recipe. Not for: changing an existing card — use card_builder_update_card. Returns: the created card dict, including its new id. Limits: run card_builder_validate_config on config first; this tool does not validate the block tree before sending it.

card_builder_update_cardA

Update fields of an existing Card Builder card.

Sends only the parameters that are not omitted to card_builder/cards/update; every omitted parameter's prior value in storage is left untouched, but any parameter that is supplied (including config) fully replaces the previous value for that field with no way to recover it afterwards.

Use when: renaming a card, editing its config, or retagging it. Not for: creating a new card — use card_builder_create_card. Returns: the updated card dict as returned by the WebSocket command.

card_builder_delete_cardA

Permanently delete one Card Builder card by id.

Calls card_builder/cards/delete; Home Assistant's WebSocket handler returns an empty payload on success. Any dashboard still referencing this card_id via custom:card-builder-renderer-card will show a broken/empty card afterwards — this tool does not check for or update such references.

Use when: removing a card that is no longer used on any dashboard. Returns: {"status": "deleted", "card_id": ..., "result": ...} on success. Errors: on failure, returns {"status": "error", "card_id": ..., "error": <exception text>} instead of raising.

card_builder_list_style_presetsA

List every reusable Card Builder style preset.

Calls card_builder/style_presets/list and returns the raw collection: each entry has id, name, description, data (the CSS-style configuration blob) and, if present, extends_preset_id.

Use when: picking an existing preset to extend, or checking presets before creating a new one with card_builder_create_style_preset. Returns: list of style-preset dicts, unfiltered.

card_builder_create_style_presetA

Create a new reusable Card Builder style preset.

Sends data and the metadata fields to card_builder/style_presets/create, which assigns a new id server-side (confirmed in upstream storage.py: every create path generates a fresh uuid4) — repeating this call creates a second, distinct preset rather than updating the first.

Use when: packaging a reusable set of style properties (e.g. a card theme) to apply across multiple cards. Not for: changing an existing preset — use card_builder_update_style_preset. Returns: the created style-preset dict, including its new id.

card_builder_update_style_presetA

Update fields of an existing Card Builder style preset.

Sends only the parameters that are not omitted to card_builder/style_presets/update; any parameter that is supplied (including data) fully replaces the previous value for that field, with no way to recover the prior value afterwards.

Use when: adjusting an existing preset's style data or metadata. Not for: creating a new preset — use card_builder_create_style_preset. Returns: the updated style-preset dict as returned by the WebSocket command.

card_builder_delete_style_presetA

Permanently delete one Card Builder style preset by id.

Calls card_builder/style_presets/delete. Any card whose style data references this preset via extends_preset_id keeps that dangling id — this tool does not check for or update such references.

Use when: removing a preset that is no longer extended by any card or other preset. Returns: {"status": "deleted", "style_preset_id": ..., "result": ...} on success. Errors: on failure, returns {"status": "error", "style_preset_id": ..., "error": <exception text>} instead of raising.

card_builder_list_css_custom_propertiesA

List every registered CSS custom property (@property registration).

Calls card_builder/css_custom_properties/list and returns the raw collection: each entry has id, name, syntax (e.g. <color>), initial_value and inherits.

Use when: checking which custom properties already exist before registering a new one with card_builder_create_css_custom_property. Returns: list of CSS-custom-property dicts, unfiltered.

card_builder_create_css_custom_propertyA

Register a new CSS custom property (@property) for use in card styles.

Sends the four fields to card_builder/css_custom_properties/create, which assigns a new id server-side (confirmed in upstream storage.py: every create path generates a fresh uuid4) — repeating this call registers a second, distinct property rather than updating the first.

Use when: defining an animatable/typed CSS variable (e.g. a themeable accent color) that card styles can reference by name. Returns: the created CSS-custom-property dict, including its new id.

card_builder_delete_css_custom_propertyA

Permanently delete one registered CSS custom property by id.

Calls card_builder/css_custom_properties/delete. Any card style still referencing this property's name keeps that reference — the browser falls back to an unset CSS variable — this tool does not check for or update such references.

Use when: removing a custom property that is no longer used by any card style. Returns: {"status": "deleted", "custom_property_id": ..., "result": ...} on success. Errors: on failure, returns {"status": "error", "custom_property_id": ..., "error": <exception text>} instead of raising.

card_builder_list_mediaA

List files and folders in the Card Builder media directory.

Calls card_builder/media/list, scoped to www/card_builder/<path>.

Use when: checking what's already uploaded before calling card_builder_upload_media or card_builder_delete_media. Returns: dict with the media-browser entries HA's WS handler returns for that path (files and sub-folders).

card_builder_upload_mediaA

Upload base64-encoded bytes as a file in the Card Builder media directory.

Decodes content_base64 and writes it under www/card_builder/<path>/ <filename> via card_builder/media/upload. filename must be a bare name (no /, \, or ..) with an allowed extension — .png, .jpg, .jpeg, .gif, .webp, .svg, .avif (case-insensitive). A .svg filename gets its decoded content sanitized (script/handler/ unsafe-URL stripping, element-count cap) — see sanitize_svg. The file becomes **public** under /local/ with **no authentication**, same origin as the HA frontend. Upstream's _write_media_file writes with no existence check, so uploading onto an existing filename/ path silently overwrites it, with no backup.

Use when: the file bytes are already in memory (e.g. generated inline). Not for: a file already on the HA config filesystem — use card_builder_upload_media_from_path; a remote image — use card_builder_upload_image_from_url; raw SVG you'd rather not base64-encode — use card_builder_upload_svg. Returns: {reference, path, url} — reference is the cb-media://local/card_builder/<filename> URI for a block-image's mediaReference prop. Errors: {"error": "extension_not_allowed" | "invalid_base64" | "file_too_large" | "invalid_svg" | ...} (plus sanitize_svg errors) when validation or sanitization rejects the input. Limits: decoded content over _MAX_MEDIA_UPLOAD_BYTES (15 MiB) is refused.

card_builder_upload_media_from_pathA

Read a local file under the HA config directory and upload it as Card Builder media.

local_path must resolve (after following symlinks) under <config>/www or <config>/media, and have an image/SVG extension — see _ALLOWED_MEDIA_EXTENSIONS. Anything else (e.g. secrets.yaml, /data/options.json, a sibling directory) is refused before the file is read. .svg files are sanitized (script/event-handler/unsafe-URL stripping) before upload — see sanitize_svg. The uploaded file becomes public under Home Assistant's /local/ path with no authentication. Upstream's _write_media_file writes with no existence check, so uploading onto a path/filename that already holds a file silently overwrites it, with no backup.

Use when: re-publishing a file that already exists on the config filesystem (e.g. under www/) into the Card Builder media library. Not for: bytes already in memory — use card_builder_upload_media; a remote URL — use card_builder_upload_image_from_url. Returns: {reference, path, url} on success, same shape as card_builder_upload_media. Errors: {"error": "invalid_path" | "path_not_allowed" | "extension_not_allowed" | "file_not_found" | "invalid_svg" | ...} (plus the sanitize_svg errors) when the source path is outside the allowed roots, has a disallowed extension, doesn't exist, or fails sanitization.

card_builder_upload_svgA

Sanitize SVG markup and upload it to the Card Builder media directory.

svg_content must start with <svg or <?xml. .svg is appended to filename if missing; the result is stored under www/card_builder/<path>/<filename>. svg_content is always sanitized first: <script>, <style>, <foreignObject>, <iframe>, <embed>, <object> and other non-presentation elements are stripped with their subtree, along with every on*= handler and any href/xlink:href pointing at javascript: or an external/ data:image/svg+xml URL — see sanitize_svg for the allowlist. This matters because the file becomes public, unauthenticated, under /local/, where an unsanitized SVG opened directly executes embedded script as stored XSS into an admin session. _write_media_file writes with no existence check, so uploading onto an existing path/ filename silently overwrites it, with no backup.

Use when: publishing generated or hand-written SVG markup as media. Not for: an SVG file on disk — use card_builder_upload_media_from_path; a remote SVG URL — use card_builder_upload_image_from_url. Returns: {reference, path, url} — reference is the cb-media://local/card_builder/<filename> URI for a block-image's mediaReference prop. Errors: {"error": "not_svg" | "file_too_large" | "path_not_allowed" | "svg_too_complex"} on invalid, unsafe, or oversized input. Limits: capped at _MAX_MEDIA_UPLOAD_BYTES (15 MiB), then _SVG_MAX_ELEMENTS elements after parsing.

card_builder_upload_image_from_urlA

Download an image from an http(s) URL and upload it to the Card Builder media library.

Only http/https schemes are accepted. The response must declare an image/* Content-Type (covers image/svg+xml) and stay within _MAX_URL_IMAGE_BYTES, else nothing is uploaded. image/svg+xml is sanitized (see sanitize_svg) regardless of filename, since the remote server controls the bytes. The file becomes public under /local/ with no authentication, and an existing path/ filename is silently overwritten.

The URL and every redirect hop are resolved and rejected on a loopback, link-local, unspecified, multicast or other reserved address (incl. ::ffff:127.0.0.1) — host_network: true means 127.0.0.1/localhost here can reach host services that trust it as a local peer. Private LAN ranges stay allowed (e.g. a camera snapshot on your own network).

Use when: mirroring a remote image into the media library. Not for: bytes already in memory — use card_builder_upload_media; a file on disk — use card_builder_upload_media_from_path. Returns: {reference, path, url}. Errors: {"error": "scheme_not_allowed" | "target_not_allowed" | "dns_resolution_failed" | "too_many_redirects" | "content_type_not_allowed" | "file_too_large" | "download_failed" | "invalid_svg" | ...}. Limits: 30-second timeout, _MAX_URL_IMAGE_BYTES (15 MiB) cap, up to _MAX_URL_REDIRECTS (5) redirects, each re-validated.

card_builder_delete_mediaA

Permanently delete one file from the Card Builder media directory.

Calls card_builder/media/delete with path relative to www/card_builder/. Any card whose mediaReference points at this file (e.g. via block-image or block-weather-background) will fail to load it afterwards — this tool does not check for or update such references.

Use when: removing an uploaded image/SVG that no card uses anymore. Returns: {"status": "deleted", "path": ..., "result": ...} on success. Errors: on failure, returns {"status": "error", "path": ..., "error": <exception text>} instead of raising.

card_builder_renderer_card_configA

Build the Lovelace card config dict that renders a Card Builder card.

Pure computation — assembles {"type": "custom:card-builder-renderer-card", "card_id": ...} plus the optional slot_entities/slot_actions keys; makes no call to Home Assistant.

Use when: embedding an existing Card Builder card on a dashboard. Not for: adding the resulting config to a dashboard — pass it as card_config to dashboards_add_card_to_section (sections views) or dashboards_add_card_to_view (masonry/panel views). Returns: {"type": "custom:card-builder-renderer-card", "card_id": ..., "slot_entities": {...}, "slot_actions": {...}} — the latter two keys are omitted when not provided.

card_builder_list_block_typesA

List every block type from the embedded Card Builder schema (BLOCK_TYPES).

Reads the module-level BLOCK_TYPES constant synced from upstream Card Builder (see card_builder_check_schema_sync); makes no call to Home Assistant.

Use when: discovering which block types exist before writing a recipe for card_builder_build_from_recipe. Not for: full prop details of one type — use card_builder_get_block_schema. Returns: list of {type, category, label, accepts_children, requires_entity, prop_count}, one entry per block type.

card_builder_get_block_schemaA

Get the full embedded schema for one Card Builder block type.

Looks up block_type in the module-level BLOCK_TYPES constant and adds its style targets from STYLE_TARGETS; makes no call to Home Assistant.

Use when: checking a block's exact prop names, types, defaults, enum values, and supported entity domains before writing a recipe. Returns: {type, category, label, accepts_children, requires_entity, props, notes, supported_domains, style_targets, ...} — the same entry as in BLOCK_TYPES plus style_targets. Errors: {"error": "unknown_block_type", "block_type": ..., "known": [...]} when block_type isn't in the embedded schema.

card_builder_list_button_toggle_featuresA

List the feature IDs accepted by block-button-toggle / block-select-menu.

Reads the module-level FEATURE_DEFINITIONS constant; makes no call to Home Assistant. Feature IDs are namespaced by domain — e.g. climate_hvac_mode for an AC, cover_state for a blind, light_power for a bulb.

Use when: picking an explicit feature value for a block-button-toggle/block-select-menu prop instead of the default "auto", which lets Card Builder pick the first available feature for the entity at runtime. Returns: list of {domain, id, label} dicts.

card_builder_list_style_categoriesA

List CSS style categories with their property names and unit conventions.

Reads the module-level STYLE_CATEGORIES constant; makes no call to Home Assistant. Property names are camelCase (e.g. flexDirection, backgroundColor) — anything else is silently discarded by Card Builder's CSS resolver.

Use when: looking up the exact property names/units for a style category before hand-writing a styles/dz_styles blob. Not for: ready-to-use presets — use card_builder_list_style_snippets. Returns: list of {category, properties, length_units, legacy_aliases, notes} dicts.

card_builder_list_style_targetsA

List the style targets (sub-components) one block type supports.

Looks up block_type in STYLE_TARGETS (defaulting to the single "block" target); makes no call to Home Assistant. Example: block-entity-field-state has state and unit targets so you can colour the number and the unit differently.

Use when: styling a sub-component of a block (e.g. a slider's thumb) rather than the whole block. Returns: {block_type, targets} where targets is the list of valid keys for that block's styles dict. Errors: {"error": "unknown_block_type", "block_type": ...} when block_type isn't in the embedded schema.

card_builder_list_style_snippetsA

List built-in Card Builder style snippets by name and style category.

Reads the module-level STYLE_SNIPPETS constant; makes no call to Home Assistant.

Use when: browsing ready-made style presets (padding, flex layout, typography scale) before composing them with card_builder_build_styles. Not for: the full property list per category — use card_builder_list_style_categories; the full body of one snippet — use card_builder_get_style_snippet. Returns: list of {name, categories} dicts, where categories are the style-category keys that snippet sets.

card_builder_get_style_snippetA

Fetch one built-in style snippet wrapped in the full target/container envelope.

Looks up name in STYLE_SNIPPETS and wraps it as {target: {containers: {container: <snippet>}}}; makes no call to Home Assistant.

Use when: assigning exactly one snippet to a block's styles without composing several via card_builder_build_styles. Returns: {<target>: {containers: {<container>: <snippet>}}} — ready to assign to a block's styles directly. Errors: {"error": "unknown_snippet", "name": ..., "known": [...]} when name isn't a known snippet.

card_builder_build_stylesA

Compose a styles object from one or more built-in snippets plus optional overrides.

Merges each named entry from STYLE_SNIPPETS in order, then extra, at the property level — later entries override earlier ones for the same category/property; makes no call to Home Assistant.

Use when: assembling a block's styles/dz_styles from reusable presets instead of hand-writing the full envelope. Returns: {<target>: {containers: {<container>: {<category>: {<prop>: <value>, ...}, ...}}}}. Errors: {"error": "unknown_snippet", "name": ..., "known": [...]} when a name in snippet_names isn't a known snippet.

card_builder_check_schema_syncA

Compare the embedded block schema against upstream Card Builder's main branch on GitHub.

Fetches custom_components/card_builder/manifest.json and frontend/src/common/blocks/loader.ts from raw.githubusercontent.com/{UPSTREAM_REPO}/main over HTTP and diffs the upstream version/block list against this module's BLOCK_TYPES and UPSTREAM_SCHEMA_SYNC constants. Reaches outside the HA instance and its host.

Use when: a recipe that used to work stops producing the expected card — the upstream integration may have shipped a breaking schema change. Returns: {status: "ok"|"drift"|"fetch_failed", upstream_version, embedded_version, version_matches, missing_block_types, extra_embedded_block_types, advice, embedded_schema, ...}. Errors: {"status": "fetch_failed", "error": <exception text>, "embedded": ...} when the manifest request itself fails (a timeout or network error); a failed loader fetch instead sets loader_fetch_error and still returns status. Limits: two GitHub requests with a 10-second timeout each.

card_builder_recipe_guideA

Get the embedded how-to for building Card Builder cards programmatically.

Returns the static _RECIPE_GUIDE_MD constant; makes no call to Home Assistant.

Use when: starting a card build and needing the DocumentData shape, prop-wrapping rules, slots, or recipe shorthand before calling card_builder_build_from_recipe. Not for: UX/visual guidance — use card_builder_design_principles. Returns: markdown text covering DocumentData layout, the block tree, entity inheritance, slots, drop-zones, dashboard embedding, and the recipe shorthand consumed by card_builder_build_from_recipe.

card_builder_design_principlesA

Get the embedded UX design playbook for Card Builder cards.

Returns the static _DESIGN_PRINCIPLES_MD constant; makes no call to Home Assistant.

Use when: deciding hierarchy, state feedback, spacing, typography, or layout choices for a card, before or after using card_builder_recipe_guide for the mechanics. Not for: HOW to build the block tree itself — use card_builder_recipe_guide. Returns: markdown text covering hierarchy, state feedback via binding, spacing rhythm, typography scale, semantic colors, layout choice (grid vs flow vs absolute), state badges, background images, empty states, and anti-patterns that produce flat-feeling cards.

card_builder_list_design_patternsA

List curated UX design patterns, each pairing a recipe recommendation with the reasoning behind it.

Reads the module-level DESIGN_PATTERNS constant; makes no call to Home Assistant.

Use when: browsing available design patterns before picking one by hand, rather than letting card_builder_design_for_intent score them. Returns: list of pattern dicts, each with name, intent_keywords, domains, label, description, ux_notes, recommended_template, anti_patterns.

card_builder_get_design_patternA

Get one curated design pattern by name, in full.

Looks up name in the module-level DESIGN_PATTERNS constant; makes no call to Home Assistant.

Use when: reading the full rationale/anti-patterns for one pattern already picked (e.g. via card_builder_design_for_intent). Returns: same fields as one entry from card_builder_list_design_patterns. Errors: {"error": "unknown_pattern", "name": ..., "known": [...]} when name isn't a known pattern.

card_builder_design_for_intentA

Score curated design patterns against a free-text intent and recommend the top match.

Scores each entry in DESIGN_PATTERNS by domain match (weight 5) and intent-keyword overlap (weight 1.5 per hit against intent.lower()), then returns the top scorer plus up to three runners-up; makes no call to Home Assistant.

Use when: turning a user's free-text card request into a concrete pattern/template recommendation. Not for: the full pattern body — call card_builder_get_design_pattern(name) on the recommendation; the underlying design rules — call card_builder_design_principles. Returns: {intent, domain, entity_id, recommendation, score, label, description, ux_notes, recommended_template, anti_patterns, next_steps, alternatives}, or {..., "recommendation": None, "note": ...} when nothing scores above zero.

card_builder_build_from_recipeA

Materialise a recipe shorthand into a full DocumentData (config) dict.

Builds a canvas root wrapping one block-container, recursively turns recipe["blocks"] into the block tree via _build_block_tree (auto-inserting block-drop-zone children for layout blocks and auto-wrapping raw prop scalars in {"value": ...}), and returns the assembled {version, rootId, slots, blocks} dict. Pure computation — makes no call to Home Assistant.

Use when: turning a recipe (hand-written or from card_builder_get_card_template) into the config to pass to card_builder_create_card/card_builder_update_card. Not for: hand-crafted low-level DocumentData — assemble that directly instead; a template-driven one-shot creation — use card_builder_make_template_card. Returns: a dict ready to pass as config to card_builder_create_card. Errors: raises ValueError when recipe["root_slot"] isn't defined in recipe["slots"], when a block in recipe["blocks"] has an unknown or internal type, or when a non-container block type is given children. Limits: run card_builder_validate_config on the result before saving — this tool does not validate the produced tree itself.

card_builder_validate_configA

Run lightweight structural validation on a Card Builder config (DocumentData).

Checks version, rootId presence, that every block has a known type, that parent/child links are mutually consistent, that entity-required blocks resolve an entity provider (inherited, slot, or fixed) by walking up the tree, and that prop values use the {value: ...}/{binding: ...} wrapper Card Builder requires. Pure computation — makes no call to Home Assistant and does not check against the live upstream schema (see card_builder_check_schema_sync for that).

Use when: sanity-checking a config before card_builder_create_card/card_builder_update_card. Returns: {ok: bool, errors: [...], warnings: [...], block_count, slot_count} — ok is false only when errors is non-empty; warnings flags renamed/unwrapped/unknown props without failing.

card_builder_list_card_templatesA

List built-in Card Builder recipe templates (CARD_RECIPES).

Reads the module-level CARD_RECIPES constant; makes no call to Home Assistant.

Use when: browsing available templates before previewing one with card_builder_get_card_template or instantiating it with card_builder_make_template_card. Returns: list of {name, label, description, domains} dicts.

card_builder_get_card_templateA

Resolve one built-in template into a full DocumentData config, without saving anything.

Calls the template's recipe function and, if it returned a recipe shorthand rather than a full DocumentData, runs it through card_builder_build_from_recipe. Makes no call to Home Assistant.

Use when: inspecting or hand-editing a template's config before calling card_builder_create_card yourself. Not for: saving the card directly — use card_builder_make_template_card to skip this step. Returns: the full DocumentData config dict for the template. Errors: {"error": "unknown_template", "name": ..., "known": [...]} when name isn't a known template.

card_builder_make_template_cardA

Resolve a built-in template and save it as a new Card Builder card in one call.

Resolves template the same way as card_builder_get_card_template, then passes the config straight to card_builder_create_card — which assigns a new id server-side, so repeating this call creates a second, distinct card.

Use when: turning a built-in template into a saved card without the separate preview/create steps. Not for: previewing the config first without saving — use card_builder_get_card_template; a fully custom recipe — use card_builder_build_from_recipe and card_builder_create_card directly. Returns: the created card dict, including its new id. Use that id with card_builder_renderer_card_config(card_id, slot_entities= {<slot>: ...}) to place the card on a dashboard. Errors: {"error": "unknown_template", "template": ..., "known": [...]} when template isn't a known template.

snapshot_get_snapshotA

Return a single filtered snapshot combining HA states, registries and config.

Reads live states via ha.get_states() and, depending on include, the area/floor/device/entity registries and config entries over HTTP in one call, applies domains/area_id filtering and limit/offset pagination to the states list, and returns one dict keyed by section name. Every call in this path is a read; nothing here writes to HA.

Use when: a client needs several registries and/or states together and should not spend several round-trips assembling that context. Not for: a single registry without filtering — use entities_list_entities or ws_get_states for a plain state list, or areas_list_devices/ devices_list_devices for a plain device list. Returns: dict keyed by requested section (states, areas, floors, devices, entities, integrations, config), plus _meta (echoed filters and per-section counts) and _states_total (pre-pagination count) when states is included. Errors: {"error": "unknown_include", "unknown": [...], "valid": [...]} when include names a section outside the valid set. Limits: limit/offset paginate only the states section; every other section is always returned in full.

snapshot_get_area_snapshotA

Return states, devices and entities for one area in a single call.

Convenience wrapper that calls snapshot_get_snapshot with include=["states", "devices", "entities", "areas"] and area_id fixed to the given area; it adds no filtering beyond summary.

Use when: exploring or controlling everything in one physical area without composing snapshot_get_snapshot's include/area_id arguments by hand. Not for: a snapshot spanning several areas or other sections — call snapshot_get_snapshot directly; entity registry rows without state values — use areas_get_area_entities; live state values without registry context — use areas_get_area_states. Returns: same dict shape as snapshot_get_snapshot with include=["states", "devices", "entities", "areas"]. Limits: no pagination; every state/device/entity in the area is returned.

esphome_list_devicesA

List ESPHome devices from YAML configs, the HA device registry and online status.

Combines <name>.yaml files under /config/esphome/ with matching HA device-registry entries (identified via ESPHome config entries, identifiers domain, or manufacturer as a fallback). A device's connected status comes from its own entities' states (entity registry device_id match): any entity in a state other than "unavailable" means connected, since ESPHome entities share one per-config-entry availability flag (homeassistant/components/esphome/entity.py) — not from a binary_sensor.*_api_connection_status entity, which is not guaranteed to exist.

Use when: getting an overview of every ESPHome device, whether or not it currently has a matching HA device. Not for: one device's entities — use esphome_get_device_entities. Returns: {"yaml_configs": [...], "ha_devices": [...], "online": <int>, "offline": <int>}, where each ha_devices entry's connected is True, False, or None (no known entities/states yet). Errors: ha_devices becomes [{"error": str(e)}] if reading the HA device registry raises; entity-registry/config-entry/state lookups are silently skipped (treated as empty) on error instead of failing the whole call.

esphome_get_configA

Read one ESPHome device's YAML config from /config/esphome/.

Resolves name to <name>.yaml under _ESPHOME_DIR, rejecting path separators/leading dots/paths that escape that directory.

Use when: inspecting a device's current configuration before editing it with esphome_write_config or one of the esphome_lvgl_* editors. Not for: a device's HA entities — use esphome_get_device_entities. Returns: {"name": <filename>, "content": <yaml text>}. Errors: {"error": "Invalid device name: ..."} for a path-escaping name; {"error": "Not found: ...", "esphome_dir": ...} when the file doesn't exist.

esphome_write_configA

Write a full ESPHome device YAML config to /config/esphome/, overwriting any existing file.

Validates YAML syntax first (HA custom tags !secret/!include/ !lambda/!extend/!remove pass through unchanged) and only writes if that succeeds. This replaces the whole file — there is no merge with the previous content and, unlike git_safe_write_with_checkpoint, no checkpoint commit is made first, so the previous content is not recoverable through this tool.

Use when: saving a complete device config you already have in full, e.g. after fetching and editing it with esphome_get_config. Not for: a git-checkpointed config write — use git_safe_write_with_checkpoint; for a generic /config file write use files_write_config_file; for a single LVGL widget edit use esphome_lvgl_add_widget/esphome_lvgl_delete_widget instead of hand-editing the whole YAML text. Returns: {"success": True, "name": ..., "path": ..., "bytes": ...} on success; a remote external_components:/packages: source (github:///gitlab:///codeberg:///git:///http(s)://, or a dict with a url) adds "warning" (review before esphome_compile_device, which fetches and runs it) and "external_sources": [...]; a config with none, or only local (type: local, bare-path, !include) ones, gets neither key. Errors: {"success": False, "error": "YAML validation failed: ..."} for invalid YAML; {"success": False, "error": "Invalid device name: ..."} for a path-escaping name.

esphome_get_device_entitiesA

Get every HA entity belonging to one ESPHome device.

Slugifies device_name (lowercase, spaces/dashes to underscores) and, if a device-registry entry's own slugified name matches, matches entities by that device's device_id (precise: immune to one device's slug being a substring of another's). Falls back to matching entity registry entries whose platform is "esphome" and whose entity_id contains the slug when no device-registry entry matches (or that lookup fails).

Use when: inspecting a specific device's exposed entities and their current state. Not for: the device list itself — use esphome_list_devices. Returns: list of {"entity_id", "name", "domain", "state", "attributes", "disabled"} dicts. Errors: [{"error": str(e)}] when reading the entity registry or states raises.

esphome_compile_deviceA

Compile ESPHome firmware for a device via the dashboard's /compile WebSocket route.

Blocks until the compile process exits (~60-180s). Compatible with the "ESPHome Device Builder" add-on (esphome/device-builder): /compile keeps the same spawn wire protocol as the old dashboard, now backed by its firmware job queue. A first build for a platform fetches PlatformIO packages from the internet before compiling. only_generate=True is rejected outright (see Errors) — Device Builder ignores that field and always runs a full build (ADR-0004 D4); it stays in the signature only for input-shape compatibility.

Use when: building firmware before esphome_upload_device. Not for: checking config validity only — use esphome_validate_config, which is faster and skips package downloads. Returns: {"device", "action": "compile", "exit_code", "success", "log_tail", "log_lines"}. Errors: {"error": "esphome_unsupported_option", ...} for only_generate=True (no I/O); {"error": "Invalid device name: ..."} for a path-escaping or blocked (e.g. 'secrets') name; otherwise one of esphome_dashboard.DashboardError's stable codes — esphome_unreachable/esphome_auth_required add diagnosis (see esphome_ping_dashboard); timeout adds log_tail/log_lines/ job_may_still_be_running (always True — do not retry, check esphome_get_addon_logs); esphome_command_failed adds dashboard_error_code/details. Limits: blocks up to timeout seconds; log_lines truncates the log.

esphome_validate_configA

Validate an ESPHome device's YAML config without compiling it.

Uses the devices/validate command on Device Builder's newer multiplexed /ws protocol (github.com/esphome/device-builder, docs/API.md) — the legacy /validate route from the old ESPHome dashboard no longer exists. Unlike esphome_compile_device, this never builds firmware or fetches PlatformIO packages. If the dashboard needs a username/password, this fails fast instead of hanging (no credential wiring exists here).

Use when: checking a config's validity quickly, e.g. before esphome_compile_device. Not for: a full firmware build — use esphome_compile_device; not for LVGL-only structural checks — use esphome_lvgl_validate, which runs without the dashboard. Returns: {"device", "action": "validate", "success", "result", "log_tail", "log_lines"}. Errors: {"error": "Invalid device name: ..."} for a path-escaping or blocked (e.g. 'secrets') name; otherwise one of esphome_dashboard.DashboardError's stable codes — esphome_auth_required (credentials this tool cannot supply) and esphome_unreachable add diagnosis (see esphome_ping_dashboard); timeout adds log_tail/log_lines/job_may_still_be_running (always False — validation enqueues no job); esphome_command_failed adds dashboard_error_code/details.

esphome_upload_deviceA

Flash previously compiled firmware to an ESPHome device via the dashboard's /upload WebSocket route.

Requires the device to already be built (esphome_compile_device) and, for OTA, reachable with a matching OTA password. Without confirm=True returns a confirmation prompt and performs no I/O (ADR-0004 D5) — this overwrites the running firmware with no automatic rollback if broken. Same "ESPHome Device Builder" (esphome/device-builder) spawn wire protocol as esphome_compile_device, on /upload.

Use when: deploying a compiled build to the device, once confirmed. Not for: building the firmware — use esphome_compile_device first. Returns: {"device", "action": "upload", "exit_code", "success", "log_tail", "log_lines"} on completion. Errors: {"error": "confirmation_required", "message", "action"} when confirm is false (checked first, before name is resolved); {"error": "Invalid device name: ..."} for a path-escaping or blocked (e.g. 'secrets') name; otherwise one of esphome_dashboard.DashboardError's stable codes — esphome_unreachable/esphome_auth_required add diagnosis (see esphome_ping_dashboard); timeout adds log_tail/log_lines/ job_may_still_be_running (always True — do not retry, check esphome_get_addon_logs); esphome_command_failed adds dashboard_error_code/details. Limits: requires confirm=True; blocks up to timeout seconds; no rollback if the upload succeeds but firmware is broken.

esphome_clean_mqttA

Remove stale MQTT discovery entries for an ESPHome device, through HA's own MQTT integration.

Skips with zero network calls when the config has no mqtt: section. Otherwise resolves the node name (esphome.name, with substitutions:) and mqtt.discovery_prefix (default "homeassistant"). With a matching HA device, reads topics via WS mqtt/device/debug_info; otherwise briefly mqtt/subscribes to {prefix}/+/{node_name}/# and collects retained topics. Clears each topic via the mqtt.publish service, payload="" and retain=True -- MQTT's own way to delete a retained message. Never touches the ESPHome dashboard, which has no MQTT-topic-clearing command.

Use when: a removed/renamed device's old MQTT discovery entries still linger in Home Assistant. Not for: a config with no mqtt: section; firmware artifacts -- use esphome_compile_device. Returns: {"device", "action": "clean_mqtt", "skipped": True, "reason": ...} with no mqtt: section; otherwise {"success": <bool>, "method": "debug_info"|"wildcard_subscribe", "topics_cleared": [...], "count": <int>}, plus "errors": [...] on partial failures. Errors: {"error": "..."} for an invalid/missing device file, an unresolvable esphome.name/mqtt.discovery_prefix, or a WebSocket/ service-call failure. Limits: the wildcard fallback only collects for min(timeout, 3) seconds -- may miss a slow message or catch an unrelated topic.

esphome_get_addon_infoA

Get the ESPHome add-on's status, version and update availability via the Supervisor API.

The add-on slug is discovered dynamically from the live /addons list (see _discover_esphome_slug) rather than guessed from a fixed set of hashes — the hash prefix in <hash>_esphome differs per add-on-store repository/installation.

Use when: checking whether the ESPHome add-on is installed, running, and up to date. Not for: log output — use esphome_get_addon_logs. Returns: {"slug", "name", "state", "version", "version_latest", "update_available", "ingress_url"}. Errors: {"error": "ESPHome add-on not found. Tried: [...]"} when no matching add-on slug responds, or when SUPERVISOR_TOKEN is unset.

esphome_get_addon_logsA

Get the ESPHome add-on's recent log output.

Fetches raw text logs via the Supervisor API and returns the last lines lines. Shows compile errors, OTA status and device connection events. The add-on slug is discovered dynamically — see esphome_get_addon_info.

Use when: diagnosing why esphome_compile_device/esphome_upload_device/ esphome_validate_config failed, or checking recent device activity. Not for: any other add-on's logs — use supervisor_get_addon_logs with its slug instead. Returns: {"slug": ..., "logs": "<text>", "total_lines": <int>}. Errors: {"error": "ESPHome add-on not found. Tried: [...]"} when no matching slug responds; {"error": "HTTP <status>"} for a non-404 HTTP error; {"error": str(e)} for any other failure.

esphome_ping_dashboardA

Check whether the ESPHome Device Builder dashboard responds.

Resolves where the dashboard is (esphome_dashboard.DashboardLocator, ADR-0004 D2) — an explicit ESPHOME_DASHBOARD_URL (mode "explicit") if set, else in add-on mode the installed ESPHome add-on's own site-ingress port, always dialled at http://127.0.0.1:<ingress_port> (mode "supervisor_ingress") — then calls GET /ping there. A False reachable here does not necessarily mean the add-on itself is down; see diagnosis/advice for what to check next.

Use when: diagnosing a connection failure from esphome_compile_device/esphome_validate_config/esphome_upload_device, or confirming the dashboard is reachable before calling one of them. Not for: add-on version/update status — use esphome_get_addon_info. Returns: {"reachable": True, "url": ..., "mode": "explicit"| "supervisor_ingress", "result": {...}} (the raw /ping JSON) on success. Errors: never raises. On failure: {"reachable": False, "error": <stable code>, "message": ...} — "esphome_not_configured" (neither ESPHOME_DASHBOARD_URL nor the add-on's own info could be resolved) has no url/mode; "esphome_unreachable"/"esphome_auth_required" add url, mode and a diagnosis: {"mode", "dashboard_url", "slug", "addon_state", "ingress", "ingress_port", "advice"} built from the ESPHome add-on's own GET /addons/<slug>/info (slug/addon_state/ ingress/ingress_port are None outside supervisor_ingress mode).

esphome_lvgl_list_devicesA

List ESPHome devices whose YAML config has an lvgl: section.

Parses every device YAML under /config/esphome/ (tolerating parse errors by skipping that device) and reports the ones with LVGL display support.

Use when: finding which devices have an LVGL screen before inspecting or editing its pages/widgets. Not for: page detail on one device — use esphome_lvgl_get_pages. Returns: list of {"device", "pages": <count>, "page_ids": [...]}.

esphome_lvgl_get_pagesA

Get the LVGL pages configured on an ESPHome device.

Parses the device's YAML and reads the lvgl: section's pages and displays[0].default_page.

Use when: getting page IDs, background colors and widget counts before drilling into one page with esphome_lvgl_get_page_widgets. Not for: the widgets on one specific page — use esphome_lvgl_get_page_widgets. Returns: {"device": ..., "default_page": ..., "pages": [{"id", "bg_color", "widget_count"}, ...]}. Errors: {"error": "..."} when the file can't be found/parsed, or when there is no lvgl: section in the device config.

esphome_lvgl_get_page_widgetsA

Get all LVGL widgets on one page of an ESPHome device.

Parses the device's YAML and summarises each widget on the requested page: type, ID, position and key properties. Lambda callback values are shown as the literal string <lambda> (opaque here — use esphome_get_config to see the full source).

Use when: inspecting an existing page's widget tree before adding or removing a widget. Not for: page-level metadata only — use esphome_lvgl_get_pages. Returns: {"device", "page", "widget_count", "widgets": [...]}. Errors: {"error": "..."} when the file can't be found/parsed, when there is no lvgl: section, or when page_id doesn't exist.

esphome_lvgl_get_stylesA

Get the LVGL theme and style definitions from an ESPHome device config.

Parses the device's YAML and reads the lvgl: section's theme, style_definitions and gradients keys.

Use when: checking what theme/styles a device's LVGL UI currently uses before referencing a style name in a new widget. Not for: page/widget content — use esphome_lvgl_get_pages/ esphome_lvgl_get_page_widgets. Returns: {"device", "theme", "style_definitions", "gradients"}. Errors: {"error": "..."} when the file can't be found/parsed, or when there is no lvgl: section in the device config.

esphome_lvgl_validateA

Validate an ESPHome device's LVGL structure client-side, without the dashboard.

Checks for duplicate page/widget IDs and default_page references that don't exist among the parsed pages. This is a structural check only — it does not validate widget properties or ESPHome component correctness.

Use when: a quick local pre-check after editing LVGL pages/widgets, before a full esphome_validate_config or esphome_compile_device. Not for: full component/property validation — use esphome_validate_config. Returns: {"device", "valid": <bool>, "pages": <count>, "widgets": <count>, "issues": [...]}. Errors: {"error": "...", "valid": False} when the file can't be found/parsed, or when there is no lvgl: section in the device config.

esphome_lvgl_add_widgetA

Add an LVGL widget to a page on an ESPHome device and save the whole config.

Appends {widget_type: properties} to the page's widgets list, then rewrites the entire device YAML file via yaml.dump — comments, blank lines and YAML anchors/aliases elsewhere in the file are NOT preserved. A <file>.bak copy of the previous content is written first so the original formatting can be recovered manually. Lambda callbacks (on_click, on_value_changed) are not supported here — add them manually via esphome_get_config/esphome_write_config. Calling this twice with the same arguments adds two separate widgets.

Use when: adding one widget to an existing LVGL page without hand-editing the full YAML. Not for: removing a widget — use esphome_lvgl_delete_widget; not for lambda callbacks or other structural edits — use esphome_get_config/esphome_write_config. After adding, run esphome_lvgl_validate/esphome_validate_config, then esphome_compile_device and esphome_upload_device to deploy. Returns: {"success": True, "name": ..., "bytes": ..., "backup": ..., "added": <widget_type>, "to_page": <page_id>} on success. Errors: {"error": "..."} when the file can't be found/parsed, when there is no lvgl: section, when page_id doesn't exist, or when the save itself fails ({"success": False, "error": ...}). Limits: rewrites and overwrites the whole file; only the pre-write content is recoverable, via the .bak copy.

esphome_lvgl_delete_widgetA

Delete an LVGL widget by id from a page on an ESPHome device and save the whole config.

Removes the matching widget from the page's widgets list, then rewrites the entire device YAML file via yaml.dump — comments, blank lines and YAML anchors/aliases elsewhere in the file are NOT preserved. A <file>.bak copy of the previous content is written first so the original formatting can be recovered manually.

Use when: removing one widget from an existing LVGL page. Not for: adding a widget — use esphome_lvgl_add_widget. After deleting, run esphome_lvgl_validate/esphome_validate_config, then esphome_compile_device and esphome_upload_device to deploy. Returns: {"success": True, "name": ..., "bytes": ..., "backup": ..., "deleted": <widget_id>, "from_page": <page_id>} on success. Errors: {"error": "..."} when the file can't be found/parsed, when there is no lvgl: section, when page_id/widget_id doesn't exist, or when the save itself fails ({"success": False, "error": ...}). Limits: rewrites and overwrites the whole file; only the pre-write content is recoverable, via the .bak copy.

statistics_list_statistic_idsA

List recorder statistic IDs of the requested type.

Calls WS recorder/list_statistic_ids and returns one entry per statistic the recorder tracks, with its source and unit.

Use when: discovering which entities have long-term statistics before calling statistics_get_statistics or statistics_get_statistics_metadata. Not for: raw short-term state history — use history_get_state_history instead. Returns: list of {"statistic_id", "name", "source", "unit", "has_sum", "has_mean"} dicts. Errors: [{"error": "..."}] when statistic_type is not 'sum'/'mean', when the WS response isn't a list, or when the WS call raises.

statistics_get_statisticsA

Get aggregated recorder statistics for one or more IDs over a time range.

Calls WS recorder/statistics_during_period with start/end parsed into UTC timestamps, converts each row's epoch start back to an ISO string, and rounds numeric aggregates to 4 decimals.

Use when: analysing energy/temperature/etc. trends over hours, days, weeks or months using the recorder's pre-aggregated data. Not for: raw short-term state changes between two points in time — use history_get_state_history instead. Returns: {"period", "start", "end", "types", "data": {statistic_id: [{"start": <iso>, "sum": ..., "mean": ..., ...}, ...]}}. Errors: {"error": "..."} for an empty statistic_ids, an invalid period/types value, an unparsable start/end, a non-dict WS response, or when the WS call raises.

statistics_get_energy_statisticsA

Get sum statistics for every energy-related sensor over the last N days.

Auto-discovers 'sum' statistic IDs via WS recorder/list_statistic_ids, keeps only those whose unit is an energy/volume unit (kWh, MWh, Wh, m³, ft³, L, gal — instantaneous power sensors in 'W' are excluded since a 'sum' statistic on a power sensor is not a meaningful energy value), then fetches sum/change via WS recorder/statistics_during_period for the requested window. This is a convenience wrapper around statistics_get_statistics.

Use when: a quick overview of overall energy consumption trends is needed without first listing statistic IDs by hand. Not for: a hand-picked set of statistic IDs or non-energy sensors — use statistics_get_statistics directly. Returns: {"days", "period", "statistic_count", "data": {statistic_id: {"unit": ..., "rows": [{"start": <date>, "change": ..., "sum": ...}, ...]}}}, or {"message": "..."} when no energy statistic IDs are found. Errors: {"error": "days must be between 1 and 365"} for an out-of-range days; {"error": "..."} when either WS call raises or returns an unexpected shape.

statistics_get_statistics_metadataA

Get metadata (unit, source, name) for specific recorder statistic IDs.

Calls WS recorder/get_statistics_metadata and returns one entry per requested ID.

Use when: you already know the statistic IDs and only need their unit/source/name, without their historical values. Not for: the actual aggregated values — use statistics_get_statistics. Returns: list of {"statistic_id", "name", "source", "unit", "has_sum", "has_mean"} dicts. Errors: [{"error": "..."}] when the WS response isn't a list or the WS call raises.

discover_tool_searchA

Fuzzy search the Nexus tool catalogue by name and description.

Scores every mounted tool's name + description against query with a BM25-lite ranking (term frequency/inverse document frequency plus a small boost when a query word appears in the tool name itself) and returns the top top_k matches.

Use when: finding the right tool name before calling it, instead of keeping the whole tool surface in working memory. Not for: a single tool's full documentation once you have its name — use discover_get_tool_doc. Returns: list of {"name", "namespace", "summary", "score", "access"} dicts, highest score first; empty list if nothing scores above zero. access is "read", "write" or "destructive" (ADR-0002/0003 annotation class).

discover_list_namespacesA

List every mounted Nexus tool namespace with its tool count.

Groups the current tool index by namespace (the mount prefix parsed from server.py, e.g. "card_builder", "entities") and counts entries.

Use when: getting an overview of which domains exist before narrowing a discover_tool_search call with its namespace parameter. Not for: the tools within one namespace — use discover_tool_search with that namespace. Returns: list of {"namespace", "count"}, most populated first.

discover_get_tool_docA

Get one tool's full description, parameter schema and MCP annotations.

Looks the tool up by exact name in the current index and returns its full (un-truncated) docstring alongside the same inputSchema and annotations an MCP client sees from tools/list.

Use when: reading a specific tool's full contract after finding its name with discover_tool_search. Not for: searching by keyword — use discover_tool_search. Returns: {"name", "namespace", "description", "input_schema", "annotations", "access"}. input_schema is the tool's JSON-schema parameter dict; annotations is the four MCP hints plus title as a plain dict, or None for a tool whose module has not yet declared them. access is "read", "write" or "destructive" (ADR-0002/0003 annotation class), computed fail-closed even when annotations is None. Errors: {"error": "not_found", "name": name} when no tool with that exact name is in the index.

discover_refresh_indexA

Force-rebuild the in-memory tool search index.

Drops the cached index and rebuilds it from _ROOT.list_tools(). Only nexus's own in-process cache is affected — nothing in HA changes.

Use when: tools were mounted or changed at runtime after the index was first built (normally only relevant during development, since server.py mounts every namespace once at startup). Not for: routine searches — discover_tool_search/ discover_list_namespaces/discover_get_tool_doc already rebuild the index lazily on first use. Returns: {"status": "rebuilt", "tools": <count>}.

Prompts

Interactive templates invoked by user choice

NameDescription
card_builder_design_dashboardSet context for designing a whole Home Assistant dashboard.
card_builder_design_cardSet context for designing one Card Builder card for an entity domain.
card_builder_pick_templateHelp an AI client choose the right pre-built template for an entity.

Resources

Contextual data attached and managed by the client

NameDescription

No resources

TDQS

A3.9/5.0

Scored across 323 tools

Disambiguation4/5

Given 323 tools, overlap is surprisingly well managed: descriptions extensively use 'Use when'/'Not for' cross-references (e.g. entities_turn_on vs helpers_set_input_boolean vs services_call_service, entities_set_value vs helpers_set_input_number) to steer selection. There are still confusable clusters — areas_list_devices vs devices_list_devices vs devices_list_devices_in_area, and the HTTP vs WS transport duplicates (services_call_service vs ws_call_service, history_get_ha_config vs ws_get_config) — but they are documented rather than ambiguous.

Naming Consistency4/5

Strong, near-uniform namespace_prefix_verb_noun convention (areas_list_areas, entities_turn_on, supervisor_restart_addon, card_builder_create_card), making the surface scannable despite its size. Minor deviations exist, most notably the redundant git_git_* double prefix (git_git_status, git_git_init_config) and a few oddities like discover_refresh_index.

Tool Count1/5

323 tools is an extreme mismatch for any single server, far beyond the 50+ threshold, and forces the agent to lean on discover_tool_search just to navigate its own surface. Even with good organization, this volume guarantees a tiny per-call footprint of relevance and heavy cognitive overhead.

Completeness4/5

Coverage across the Home Assistant domain is remarkably broad — entities, devices, areas, labels, automations/scripts/scenes, dashboards, supervisor/add-ons, HACS, ESPHome, energy, voice, calendar, todo, statistics/history, git, files and zones all have lifecycle operations. A few acknowledged gaps (no area update tool, no partial Supervisor restore, no options-flow read) exist but agents can work around them.

Maintenance

ActivityMaintained
ResponsivenessSlow