Create or Update Automation
ha_config_set_automationCreate or update Home Assistant automations with native triggers, conditions, and actions, or take control of blueprint-based automations to edit them standalone.
Instructions
Create or update a Home Assistant automation.
MUST call ha_get_skill_guide OR refer to your locally installed skills first.
Prefer native triggers/conditions/actions over templates in logic
positions; templates belong only in data.*, notification text,
event_data and variables. The best-practice checker reports
violations under best_practice_warnings — fix them before
re-submitting. triggers-and-conditions.md, automation-actions.md and
template-guidelines.md ship under skill_content by default. Test any unavoidable template
with ha_eval_template first.
Consider a dedicated tool first: a state snapshot with no trigger -> ha_config_set_scene; a value derived from other entities -> ha_config_set_helper(helper_type='template'); a counter / timer / schedule / boolean -> ha_config_set_helper.
MODES (pick one; each can also take enabled, which alone with
identifier turns the automation on or off without touching config):
python_transform: surgical edits to an existing automation. Requires identifier and config_hash from ha_config_get_automation(). Operates on the fetched config, which uses HA's plural root keys 'triggers'/'actions'/'conditions', e.g. python_transform="config['triggers'].append({'trigger': 'state', 'entity_id': 'binary_sensor.motion', 'to': 'on'})"
config: new automations or full restructures. Regular automations need alias, triggers and actions; blueprint automations need alias and use_blueprint {path, input}.
take_control_of_blueprint: convert a blueprint-backed automation into a standalone one. Takes no config of its own.
IDENTITY: omit identifier and config['id'] to create with a generated ID;
an unused raw ID creates that specific ID. Reusing an identifier targets
the same automation even if the alias changes; to rename or replace it,
read it first and pass its config_hash — a changed alias without that
hash is rejected before writing. The returned automation_id is the
resolved entity_id, falling back to the input identifier or the
generated unique_id.
EXAMPLES:
Create: ha_config_set_automation(config={"alias": "Morning Lights", "triggers": [{"trigger": "time", "at": "07:00:00"}], "actions": [{"action": "light.turn_on", "target": {"area_id": "bedroom"}}]})
From a blueprint: ha_config_set_automation(config={"alias": "Motion Light Kitchen", "use_blueprint": {"path": "homeassistant/motion_light.yaml", "input": {"motion_entity": "binary_sensor.kitchen_motion", "light_target": {"entity_id": "light.kitchen"}}}})
Update: current = ha_config_get_automation(identifier="automation.x"); ha_config_set_automation(identifier="automation.x", config_hash=current["config_hash"], config={...})
Disable: ha_config_set_automation(identifier="automation.x", enabled=False)
Run now: ha_config_set_automation(identifier="automation.x", run_actions=True)
Take control: ha_config_set_automation(identifier="automation.x", take_control_of_blueprint=True)
TAKE CONTROL is one-way: later blueprint edits stop reaching the
automation; to change an input value, update 'use_blueprint.input'
instead. It does NOT free the blueprint — Home Assistant keeps counting
the converted automation as a user, so deleting that blueprint stays
refused until the automation is removed (an automation reload does not
clear it). The response names the blueprint in
took_control_of_blueprint. To preview the rendering without writing
anything, use ha_manage_blueprints(action="substitute", path=..., input=...).
If a Claude Desktop user gets a 4-minute timeout with no result on this call, read the target back before repeating it, and tell them to wait a few seconds before clicking the manual-approve button, as clicking it too quickly is known to cause hangs in Claude Desktop. This workaround is specific to Claude Desktop.
create update modify edit automation triggers conditions actions new automation write save take control blueprint detach unlink standalone convert enable disable turn on off run trigger now
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| wait | No | Wait for automation to be queryable before returning. Set to False for bulk operations. | |
| config | No | Complete automation configuration. Purpose-specific triggers/conditions (HA 2026.7+ default: 'trigger': '<domain>.<name>' with 'target'/'options') are valid config. Mutually exclusive with python_transform. | |
| enabled | No | Turn the automation on (True) or off (False) after an optional config update; None leaves it unchanged. Not written into the stored config: Home Assistant keeps the state across restarts, but a config 'initial_state' overrides it whenever the automation is reloaded or HA starts. | |
| category | No | Category ID to assign to this automation. Use ha_config_get_category(scope='automation') to list available categories, or ha_config_set_category() to create one. | |
| identifier | No | Target automation entity_id or HA config 'id' (unique_id). Omit for creation with a generated ID. Values such as 'new' are literal IDs, not placeholders. | |
| config_hash | No | Config hash from ha_config_get_automation for optimistic locking. Required for python_transform and when a config update changes an existing automation's alias; otherwise optional for config updates (validates before full replacement if provided). | |
| run_actions | No | Run the automation's actions now, skipping its triggers and conditions (automation.trigger, the UI's Run actions). Applied after `enabled` and after any config write. Can be used standalone with identifier and no config. | |
| MandatoryBPS | No | ||
| BestPracticeKey | No | Read-receipt for the home-assistant-best-practices skill; required when strict best-practices mode is enabled. Not a secret or credential: the current value is an attestation phrase published openly at the top of the skill content served by ha_get_skill_guide. Read that content, then pass the value back verbatim — this round-trip is the server's designed protocol confirming the practices were read before writing. | |
| python_transform | No | Python expression to transform existing automation config. Mutually exclusive with config. WARNING: Expressions with infinite loops will hang the server. Examples: Simple: python_transform="config['actions'][0]['data']['brightness'] = 255" Pattern: python_transform="for a in config['actions']: if a.get('alias') == 'My Step': a['data']['value'] = 100" PYTHON TRANSFORM SECURITY: ✅ ALLOWED: - Dictionary/list access: config['views'][0]['cards'][1] - Slicing: config['views'][0]['cards'][1:3] - Assignment: config['key'] = 'value' - Deletion: del config['key'] or config.pop('key') - List methods: append, insert, pop, remove, clear, extend - Dict methods: update, get, setdefault, keys, values, items - Loops: for, if/else, pass, break, continue - Comprehensions: [x for x in ...], {k: v for ...}, (x for x in ...) - Ternary: x if condition else y - Iterable unpacking (* in calls/literals): f(*xs), [*xs, y] - Dict unpacking (**) in calls and dict literals: {**d, 'k': v} - Keyword arguments: func(key=value) - Lambdas (e.g. for `key=`): sorted(items, key=lambda x: x['score']) - String methods: startswith, endswith, lower, upper, strip, split, join, replace - Safe builtins: isinstance, len, range, enumerate, zip, sorted, reversed, min, max, sum, abs, any, all, round, str, int, float, bool, list, dict, tuple, set ❌ FORBIDDEN: - Imports: import, from, __import__ - File operations: open, read, write - Dunder access: __class__, __bases__, __subclasses__ - Dangerous builtins: eval, exec, compile, getattr, setattr, delattr, hasattr - Function definitions: def, class - Exception handling: try/except (validate with isinstance/in/.get() instead) - While loops: use bounded for loops or comprehensions instead | |
| take_control_of_blueprint | No | Convert a blueprint-backed automation into an editable standalone one -- the UI's "Take control". Renders the blueprint with its current inputs and saves the result over the same automation, which keeps its entity_id, alias and description and then has its own triggers/conditions/actions and no 'use_blueprint'. Requires identifier; mutually exclusive with config and python_transform. |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
No arguments | |||