Create or Update Script
ha_config_set_scriptCreate, update, run, or stop Home Assistant scripts and sequences, including converting blueprint-backed scripts to standalone.
Instructions
Create or update a Home Assistant script.
MUST call ha_get_skill_guide OR refer to your locally installed skills first.
Prefer native actions (choose / if, wait_for_trigger, repeat,
for:) 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.
automation-actions.md, triggers-and-conditions.md and
template-guidelines.md ship under skill_content by default.
Scripts use 'sequence', NOT 'trigger' or 'action'; for trigger-based execution use ha_config_set_automation.
MODES (pick one):
python_transform: surgical edits to an existing script. Requires config_hash from ha_config_get_script(), e.g. python_transform="config['sequence'].append({'delay': {'seconds': 5}})"
config: new scripts or full restructures. Needs 'sequence' (regular) or 'use_blueprint' {path, input} (blueprint-based).
take_control_of_blueprint: convert a blueprint-backed script into a standalone one. Takes no config of its own.
run (alone with script_id): 'start' runs the script (optional variables), 'stop' stops its running executions. Write config changes in a separate call first: Home Assistant signals no completion of the script reload a write triggers.
EXAMPLES:
Create: ha_config_set_script(script_id="blink_light", config={"alias": "Light Blink", "sequence": [{"action": "light.turn_on", "target": {"entity_id": "light.living_room"}}, {"delay": {"seconds": 2}}, {"action": "light.turn_off", "target": {"entity_id": "light.living_room"}}]})
From a blueprint: ha_config_set_script(script_id="notification_script", config={"alias": "My Notification Script", "use_blueprint": {"path": "notification_script.yaml", "input": {"message": "Hello World"}}})
Take control: ha_config_set_script(script_id="notification_script", take_control_of_blueprint=True)
TAKE CONTROL is one-way: later blueprint edits stop reaching the script; to change an input value, update 'use_blueprint.input' instead. It does NOT free the blueprint — Home Assistant keeps counting the converted script as a user, so deleting that blueprint stays refused until the script is removed. To preview the rendering without writing anything, use ha_manage_blueprints(action="substitute", domain="script", 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 script sequence actions new script write save take control blueprint detach unlink standalone convert run start stop execute
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| run | No | Run control, used alone with script_id (no config, python_transform or take_control_of_blueprint): 'start' runs the script (script.turn_on; returns once it has started, without waiting for it to finish), 'stop' stops its running executions (script.turn_off). Stopping does not disable the script; Home Assistant has no script enable/disable. | |
| wait | No | Wait for script to be queryable before returning. Set to False for bulk operations. | |
| config | No | Script configuration dictionary. Mutually exclusive with python_transform. | |
| category | No | Category ID to assign to this script. Use ha_config_get_category(scope='script') to list available categories, or ha_config_set_category() to create one. | |
| script_id | Yes | Script identifier — bare storage key ('morning_routine') or entity_id form ('script.morning_routine'); a leading 'script.' prefix is stripped before lookup. | |
| variables | No | With run='start': values for the script's fields, passed to the run as its variables. | |
| config_hash | No | Config hash from ha_config_get_script for optimistic locking. Required for python_transform; optional for config updates (validates before full replacement if provided). | |
| 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 script config. Mutually exclusive with config. WARNING: Expressions with infinite loops will hang the server. Examples: Simple: python_transform="config['sequence'][0]['data']['message'] = 'Hello'" Pattern: python_transform="for step in config['sequence']: if step.get('alias') == 'My Step': step['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 script into an editable standalone one -- the UI's "Take control". Renders the blueprint with its current inputs and saves the result over the same script, which keeps its script_id, alias and description and then has its own sequence and no 'use_blueprint'. Mutually exclusive with config and python_transform. |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
No arguments | |||