# Home Assistant OpenCode Rules

You are working directly within a Home Assistant installation. Your working directory is `/homeassistant`, which is the live Home Assistant configuration directory.

## CRITICAL: User Consent and Scope Rules

You MUST follow these rules strictly:

1. **Never exceed the user's request** - Do exactly what the user asks, nothing more. Do not "improve" or "enhance" beyond the stated scope.

2. **Never make changes without explicit approval** - Before modifying ANY file:
   - Show the user exactly what you plan to change
   - Wait for their explicit confirmation ("yes", "go ahead", "do it", etc.)
   - If they haven't approved, DO NOT proceed

3. **Ask, don't assume** - If the user's request is ambiguous:
   - Ask clarifying questions first
   - Present options and let them choose
   - Never guess at their intent

4. **Read-only by default** - When investigating or troubleshooting:
   - Only read files and gather information
   - Present findings and recommendations
   - Wait for user instruction before making any changes

5. **One change at a time** - When making approved changes:
   - Make the minimum change needed
   - Show what was changed
   - Let the user verify before proceeding to any next step

6. **No unsolicited modifications** - Never:
   - "Clean up" code the user didn't ask about
   - Add features they didn't request
   - Refactor working configurations
   - Fix issues they haven't mentioned

7. **Respect "no"** - If a user declines a suggestion, do not:
   - Repeat the suggestion
   - Make the change anyway
   - Try to convince them otherwise

## Environment Context

- You are running inside the OpenCode app
- The current directory (`/homeassistant`) contains the live Home Assistant configuration
- Changes to YAML files here directly affect the Home Assistant instance
- If add-on folder access is enabled, `/addons` and `/addon_configs` are available for Home Assistant add-on development. Treat `/addon_configs` as sensitive and only inspect or modify these folders when the user explicitly asks.
- You may have access to MCP tools for interacting with Home Assistant (check with the user)

## Home Context

The add-on assembles context about *this specific installation* and loads it before the user's first message. You do not need to fetch any of it. Depending on the user's settings, some or all of these are present:

- **Install briefing** — a generated snapshot: Home Assistant version, areas, entity counts per domain, how the configuration is split up, which custom components are installed. It is orientation, **not live state** — re-check anything current with the MCP tools or `hab`. It may be absent or partial when Home Assistant was still starting.
- **`AGENTS.local.md`** — the user's own standing instructions, if they created that file. Follow them. This file (`AGENTS.md`) takes precedence where the two conflict, and the consent and safety rules above are never overridden.
- **Decision notes** — decisions the user has confirmed about their setup, injected as a short digest.

### Decision Notes

Decision notes record *why* an installation is the way it is. That reasoning cannot be recovered by re-reading the YAML, which is exactly why it is worth storing.

**When a request conflicts with a note**, say so before acting. Never silently reverse a recorded decision — tell the user which note applies and ask whether they want to change it.

**The digest is a summary, not the whole record.** It states how many active notes it is showing; when that is fewer than the total, the notes it left out are still in force. `recall_decisions` is the authority. Before changing something that looks deliberate, odd, or redundant — an inverted switch, a disabled integration, a duplicate-looking entity — check there first. An empty search result means *that query* found nothing, never that nothing was decided; search again in different words, or with no query at all, before concluding a thing is safe to "fix".

**To read more**, use `recall_decisions`. The injected digest carries only the decisions themselves; the rationale and the superseded history are retrieved on demand. Check it when a note looks relevant but you need the reasoning, or when the user asks what was decided before.

**To record**, offer first and then wait. Say what you would store, in the words you would store it, and call `remember_decision` with `user_approved: true` only after the user agrees. A general instruction to "remember this" for the current task is not approval to write a permanent note; asking costs one sentence.

Worth recording:
- Deliberate removals and disables ("that integration was removed because it fought with X")
- Intentional deviations from the obvious approach, and why
- Things to leave alone
- Constraints that will still be true in six months

Not worth recording — do not write these:
- What you did this session, or how you troubleshot something. **This is not a session log.**
- Anything already readable from the configuration files
- Anything the user has not explicitly approved

**Pinning** (`pin: true`) keeps a note in the digest when older notes stop fitting. It is for the small number of constraints where being forgotten causes real damage — something deliberately removed, something that must be left alone. Ask for the pin as well as for the note, and use it rarely: pinning everything pins nothing.

**Never** put passwords, tokens, or any value from `secrets.yaml` into a note. The tool rejects them, and a note is sent to the model in every future session.

## Home Assistant Interaction Model

There are three primary, safe ways to interact with Home Assistant:

### 1. Configuration Files (YAML)
The standard way to define and customize Home Assistant behavior:
- Automations, scripts, scenes, and blueprints
- Integration and sensor configurations
- Templates, packages, and customizations
- Dashboard (Lovelace) definitions

These files are designed for user editing and are the source of truth for your Home Assistant setup.

### 2. MCP Tools (Runtime API)
Real-time interaction with the running Home Assistant instance:
- Query current entity states and history
- Control devices and call services
- Validate configurations
- Diagnose issues and detect anomalies
- Report OpenCode/HA agent capability status with `get_agent_capabilities`

### Native Home Assistant LLM Platform
Home Assistant is developing a native `llm` integration where Core integrations and custom integrations can expose curated tools through `<integration>/llm.py` and registered LLM APIs. New Home Assistant builds may also expose those APIs over native MCP endpoints such as `/api/mcp/<API ID>`; the built-in Assist API uses `/api/mcp/assist`. This is complementary to OpenCode MCP, not a replacement.

- If the optional `homeassistant_native` MCP server is available, prefer it for requests that fit the configured native Home Assistant LLM API because those tools are curated by Home Assistant.
- Use OpenCode MCP for configuration editing, safe writes, validation, admin/dev workflows, screenshots, updates, ESPHome, `hab`, Zigbee tasks, add-on development, and Home Assistant documentation lookup.
- Use `get_agent_capabilities` or `ha://agent/capabilities` to check whether the running HA instance reports the native `llm` component and native MCP endpoints.
- Use `get_home_context` for compact area/domain/entity understanding before broad state dumps.
- Use `get_ha_llm_development_guide` when helping develop or review a custom integration's native `<integration>/llm.py` provider.
- Do not assume this add-on can register tools directly with HA's native `llm` platform; native tool registration is internal to HA integrations/custom integrations. The add-on can consume configured native LLM APIs through native MCP when Home Assistant exposes them.

### 3. hab CLI (Home Assistant Builder)
A CLI tool designed for AI agents to manage Home Assistant. Run `hab` commands via the terminal:
- **Entity management**: `hab entity list`, `hab entity get light.living_room`, `hab entity logbook sensor.power --start 2h`
- **Service calls**: `hab action call light.turn_on --entity light.living_room --data '{"brightness": 200}'`
- **Service calls that answer with data**: add `--return-response`, e.g. `hab action call weather.get_forecasts --entity weather.home --data '{"type":"daily"}' --return-response`. Without the flag Home Assistant refuses the call outright
- **Automation CRUD**: `hab automation list`, `hab automation create`, `hab automation delete`
- **Dashboard management**: `hab dashboard list`, `hab dashboard view create`
- **Area/floor/zone/label**: `hab area list`, `hab area create "Kitchen"`
- **Helpers**: `hab helper list`, `hab helper create`
- **Scripts**: `hab script list`, `hab script create`
- **Scenes**: `hab scene list`, `hab scene create`, `hab scene activate "Movie Time"`
- **Blueprints**: `hab blueprint list`
- **Backups**: `hab backup list`, `hab backup create`
- **System**: `hab system info`, `hab system health`, `hab overview`
- **Devices**: `hab device list`
- **People**: `hab person list`, `hab person create`, `hab person update`
- **Categories**: `hab category list`, `hab category assign --entity light.kitchen`
- **To-do lists**: `hab todo list`, `hab todo item list todo.shopping`, `hab todo item add todo.shopping "Milk"`
- **Notifications**: `hab notification list`, `hab notification create --message "Hello" --title "Alert"`
- **Integrations**: `hab integration list`, `hab integration reload hue`, `hab integration disable mqtt`
- **Repairs**: `hab repairs list`, `hab repairs ignore <issue_id>`
- **Events**: `hab event list`, `hab event fire my_custom_event --data '{"key": "value"}'`
- **Templates**: `hab template render --expression "{{ states('sensor.temperature') }}"`
- **Search**: `hab search related`

`hab` outputs human-readable text by default. Use `--json` for structured JSON output (ideal for parsing).
`hab` is pre-authenticated via the Supervisor token - no login required.
Run `hab --help` or `hab <command> --help` for full usage details.

<!-- HAB_LIVE_HELP_START -->
```
Home Assistant Builder (hab) is a CLI utility designed for LLMs
to build and manage Home Assistant configurations.

Interactive sessions default to human-readable text. Non-interactive sessions default to JSON.

Start with 'hab guide' for workflow-level guidance optimized for LLM and agent usage.

Usage:
  hab [command]

Getting Started:
  auth         Manage authentication
  capability   Inspect runtime capabilities
  guide        Display built-in usage guides
  overview     Show an overview of the Home Assistant instance
  schema       Show machine-readable command schema

Registry:
  area         Manage areas
  device       Manage devices
  entity       Manage entities
  floor        Manage floors
  label        Manage labels
  person       Manage persons
  search       Search for items and relationships
  zone         Manage zones

Automation:
  action       Call actions (services)
  automation   Manage automations
  blueprint    Manage blueprints
  category     Manage categories
  helper       Manage groups, templates, and other helpers
  scene        Manage scenes
  script       Manage scripts

Dashboard:
  dashboard    Manage dashboards

Other:
  backup       Manage backups
  calendar     Manage calendar events
  diagnostics  Manage diagnostics handlers
  energy       Manage energy dashboard settings
  esphome      Manage ESPHome devices
  event        Manage Home Assistant events
  integration  Manage integrations
  network      Manage network settings
  notification Manage persistent notifications
  repairs      Manage Home Assistant repairs
  system       Manage system
  template     Work with Home Assistant templates
  thread       Manage Thread credentials
  todo         Manage to-do list items
  update       Update hab to the latest version
  version      Show version information

Additional Commands:
  help         Help about any command

Flags:
      --config string       Path to config directory (default: ~/.config/home-assistant-builder)
  -h, --help                help for hab
      --json                Use JSON output instead of human-readable text
      --skip-update-check   Skip automatic update check on startup
      --text                Use human-readable text output
      --verbose             Show verbose output

Use "hab [command] --help" for more information about a command.
```
<!-- HAB_LIVE_HELP_END -->

**Use configuration files when:** defining behavior, creating automations, setting up integrations
**Use MCP tools when:** checking current state, safe config writing, anomaly detection, entity diagnostics
**Use hab CLI when:** managing dashboards, areas, helpers, backups, blueprints, and bulk admin operations

### 4. zigporter CLI (Zigbee Toolkit)
A CLI for Zigbee device management in Home Assistant. Handles cascade renames (updating entity IDs across automations, scripts, scenes, and all Lovelace dashboards atomically), device inspection, stale device cleanup, and Zigbee mesh visualization.

**Cascade rename** — zigporter's unique value: when you rename an entity or device, it automatically patches every reference in automations, scripts, scenes, and Lovelace dashboards. `hab` can rename a single entity/device but does NOT cascade to references.

Key commands:
- **Cascade rename**: `zigporter rename-entity light.old_id light.new_id --apply`, `zigporter rename-device "Old Name" "New Name" --apply`
- **Device inventory**: `zigporter list-devices --json`, `zigporter list-z2m --json` (requires Z2M config)
- **Device inspection**: `zigporter inspect "Device Name" --json`, `zigporter inspect sensor.entity_id --json`
- **Stale device management**: `zigporter stale "Device" --action remove`, `zigporter stale "Device" --action ignore`
- **Post-migration cleanup**: `zigporter fix-device "Device" --apply`
- **Connectivity check**: `zigporter check`
- **ZHA export**: `zigporter export --output devices.json`
- **Mesh visualization**: `zigporter network-map --format table` (terminal), `zigporter network-map --output mesh.svg` (SVG file)

**Output format**: Use `--json` on listing/inspect commands for structured output (ideal for AI parsing). Rename commands output diffs and confirmation text.

zigporter is pre-authenticated via the Supervisor token. Z2M commands (`list-z2m`, `network-map --backend z2m`) require Z2M URL configuration in the add-on settings.

**Important limitations**:
- `rename-entity` / `rename-device` do NOT patch Jinja2 template expressions (e.g. `{{ states('old.id') }}`). A warning is printed listing affected files — inform the user these need manual review after renaming.
- The `migrate` command is inherently interactive (requires physical device actions) and must NOT be used by AI agents.
- Dry-run is the default for renames — always preview before using `--apply`.

<!-- ZIGPORTER_LIVE_HELP_START -->
```
                                                                                
 Usage: zigporter [OPTIONS] COMMAND [ARGS]...                                   
                                                                                
 Migrate Zigbee devices between ZHA and Zigbee2MQTT. Supports both ZHA → Z2M    
 (default) and Z2M → ZHA (--direction z2m-to-zha).                              
                                                                                
╭─ Options ────────────────────────────────────────────────────────────────────╮
│ --version             -v        Show version and exit.                       │
│ --install-completion            Install completion for the current shell.    │
│ --show-completion               Show completion for the current shell, to    │
│                                 copy it or customize the installation.       │
│ --help                -h        Show this message and exit.                  │
╰──────────────────────────────────────────────────────────────────────────────╯
╭─ Commands ───────────────────────────────────────────────────────────────────╮
│ setup          Create or update the configuration file in the zigporter      │
│                config directory.                                             │
│ check          Verify that all requirements are in place before migrating.   │
│ export         Export current ZHA devices, entities, areas, and automation   │
│                references to JSON.                                           │
│ export-z2m     Export current Z2M devices, entities, areas, and automation   │
│                references to JSON.                                           │
│ list-z2m       List all devices currently paired with Zigbee2MQTT.           │
│ list-devices   List all Home Assistant devices across all integrations.      │
│ migrate        Interactive wizard to migrate devices between ZHA and         │
│                Zigbee2MQTT.                                                  │
│ inspect        Show all automations, scripts, scenes, and dashboard cards    │
│                that depend on a device.                                      │
│ rename-entity  Rename an entity ID and update all references in automations, │
│                scripts, scenes, and dashboards.                              │
│ rename-device  Rename a device and cascade the change to all its entities,   │
│                automations, scripts, scenes, and dashboards.                 │
│ stale          Identify and manage offline/stale devices across all          │
│                integrations.                                                 │
│ fix-device     Remove stale ZHA device entries left behind after migration   │
│                to Zigbee2MQTT.                                               │
│ network-map    Show Zigbee mesh topology with signal strength (LQI) for each │
│                device.                                                       │
╰──────────────────────────────────────────────────────────────────────────────╯
```
<!-- ZIGPORTER_LIVE_HELP_END -->

**Use zigporter CLI when:** renaming entities/devices with cascade updates, inspecting Zigbee devices across integrations, cleaning up stale or post-migration devices, visualizing the Zigbee mesh

### 5. Internal Directories (OFF-LIMITS)
Home Assistant manages internal state in directories like `.storage/`. These are:
- Not designed for direct access
- Subject to change without notice
- Potentially dangerous to modify

**Never access internal directories directly - use configuration files or MCP tools instead.**

## RESTRICTED: Internal Home Assistant Directories

**NEVER read, modify, or directly interact with these internal directories:**

| Directory | Contains | Use Instead |
|-----------|----------|-------------|
| `.storage/` | Entity/device/area registries, auth, system state | MCP: `get_devices`, `get_areas`, `get_entity_details` |
| `.cloud/` | Home Assistant Cloud state | N/A - managed by HA Cloud |
| `deps/` | Python dependency cache | N/A - managed by HA Core |
| `tts/` | Text-to-speech cache | N/A - managed by TTS integration |
| `home-assistant_v2.db` | History SQLite database | MCP: `get_history`, `get_logbook` |
| `home-assistant.log` | Raw system logs | MCP: `get_error_log` |

These contain internal Home Assistant state that:
1. Is managed exclusively by Home Assistant core
2. Can corrupt your installation if modified incorrectly
3. May be overwritten by Home Assistant at any time
4. Has no stable schema or format guarantees

**For information that seems to require internal access, there is always a proper alternative:**
- Need entity details? -> Read configuration files OR use `get_entity_details`
- Need device info? -> Use `get_devices` MCP tool
- Need to check history? -> Use `get_history` MCP tool
- Need to see errors? -> Use `get_error_log` MCP tool

## File Structure Knowledge

### Configuration Files (Primary Interface - Read/Write with User Approval)
These are the user-facing configuration files - the primary way to define Home Assistant behavior:

- `configuration.yaml` - Main configuration file
- `automations.yaml` - Automation definitions (if using UI or split config)
- `scripts.yaml` - Script definitions
- `scenes.yaml` - Scene definitions
- `secrets.yaml` - Sensitive values (NEVER commit or expose)
- `customize.yaml` - Entity customizations
- `groups.yaml` - Group definitions
- `packages/` - Package-based configuration splits
- `blueprints/` - Automation and script blueprints
- `custom_components/` - Custom integrations (HACS or manual)
- `www/` - Static files served at /local/
- `themes/` - Custom themes
- `*.yaml` in root - Any user-created YAML configuration

**These files are designed for editing** and are equally valid as MCP tools for research and changes.

### Internal Directories (OFF-LIMITS - Never Access Directly)
- `.storage/` - Internal registries and state (use MCP tools)
- `.cloud/` - Cloud authentication (managed by HA)
- `deps/` - Python dependencies (managed by HA)
- `tts/` - TTS cache (managed by HA)
- `__pycache__/` - Python bytecode (managed by Python)
- `home-assistant_v2.db` - History database (use MCP `get_history`)
- `home-assistant.log` - Logs (use MCP `get_error_log`)

## Working with YAML on the Command Line (`yq`)

To read, query, or convert YAML from the shell, use **`yq`** (the mikefarah/Go tool, pre-installed on `PATH`). It is the correct tool because it tolerates Home Assistant's custom tags — `!include`, `!secret`, `!env_var`, `!input`, and the `!include_dir_*` family.

**Do NOT reach for `python3 -c "import yaml"` (PyYAML) or Ruby's YAML for HA config** — both crash with a constructor error on the very first `!include`/`!secret`, because those tags are Home Assistant extensions, not standard YAML. `yq` parses them with no setup.

### Read / query (always safe — never errors on HA tags)

```
yq '.homeassistant.latitude' configuration.yaml      # Print a nested value
yq '.automation | tag' configuration.yaml            # Inspect the tag itself -> !include
yq 'keys' configuration.yaml                          # List top-level keys
yq -o=json '.' configuration.yaml | jq '.sensor'      # Convert to JSON to pipe into jq
```

Note: output and JSON conversion strip the tag — `!secret home_latitude` prints as `home_latitude`. Use `| tag` when you need to see the tag. Never round-trip a file *through* JSON and back; that permanently loses every `!include`/`!secret`.

### Writing / editing

Prefer the sanctioned write path: **`write_config_safe`** (MCP — validates, backs up, and blocks accidental content loss) or read the full file and use the editor. Reserve `yq -i` for quick, low-risk edits, and only with these two caveats in mind:

1. **A custom tag sticks to the value you overwrite.** `yq -i '.homeassistant.latitude = 52.37'` on a `!secret`-tagged node produces the corrupt `latitude: !secret 52.37`. When replacing a tagged value, reset the tag in the *same* expression:
   ```
   yq -i '(.homeassistant.latitude tag = "") | .homeassistant.latitude = 52.37' configuration.yaml
   ```
   To *add* a secret reference, set the tag explicitly: `yq -i '.http.api_key = "my_api_key" | .http.api_key tag = "!secret"' configuration.yaml`
2. **`yq -i` strips blank separator lines** (and collapses inline-comment spacing) across the whole file. No data is lost, but diffs are noisier. When a clean, minimal diff matters, use the editor instead.

### Validation is not a syntax check

`yq` only confirms YAML *parses*. To validate a Home Assistant *configuration* (resolving `!include`/`!secret` and checking integration schemas), use `check_config_syntax` / `write_config_safe` (MCP), not `yq`.

## YAML Style Guide (MANDATORY)

All YAML written or modified MUST follow the official Home Assistant YAML Style Guide.
Reference: https://developers.home-assistant.io/docs/documenting/yaml-style-guide/

A Prettier formatter is configured for this environment and will auto-format files on save.
However, Prettier only enforces a subset of the rules below. You are responsible for following
ALL rules, especially those Prettier cannot enforce (marked with *).

### Indentation

2 spaces. Tabs are forbidden.

```yaml
# Good
example:
  one: 1

# Bad
example:
    bad: 2
```

### Booleans *

Only `true` and `false` in lowercase. Never use `Yes`, `No`, `On`, `Off`, `TRUE`, etc.

```yaml
# Good
one: true
two: false

# Bad
one: True
two: on
three: yes
```

### Strings

Double quotes for strings. Single quotes are not allowed.

```yaml
# Good
example: "Hi there!"

# Bad
example: 'Hi there!'
```

**Exceptions** (no quotes needed): entity IDs, area IDs, device IDs, platform types,
trigger types, condition types, action names, device classes, event names, attribute names,
and values from a fixed set of options (e.g., `mode`).

```yaml
# Good
actions:
  - action: light.turn_on
    target:
      entity_id: light.living_room
      area_id: living_room
    data:
      message: "Hello!"
      transition: 10

# Bad - don't quote entity IDs and action names
actions:
  - action: "light.turn_on"
    target:
      entity_id: "light.living_room"
```

### Sequences (Lists) *

Use block style. Flow style `[1, 2, 3]` must not be used.
Block sequences must be indented under their key.

```yaml
# Good
options:
  - 1
  - 2
  - 3

# Bad
options: [1, 2, 3]

# Bad - not indented under key
options:
- 1
- 2
```

### Mappings *

Block style only. Flow style `{ key: val }` must not be used.

```yaml
# Good
example:
  one: 1
  two: 2

# Bad
example: { one: 1, two: 2 }
```

### Null Values *

Use implicit null (just `key:` with no value). Never use `null` or `~`.

```yaml
# Good
initial:

# Bad
initial: null
initial: ~
```

### Comments

Capitalized, with a space after `#`, indented to match current level.

```yaml
# Good
example:
  # This is a comment
  one: true

# Bad
example:
# Comment at wrong indent
  #Missing space
  #lowercase start
  one: true
```

### Multiline Strings

Use literal `|` (preserves newlines) or folded `>` (joins lines) block scalars.
Avoid `\n` in strings. Prefer no-chomp (`|`, `>`) unless you need strip (`|-`, `>-`).

```yaml
# Good
message: |
  Hello!
  This is a multiline
  notification message.

# Good - folded
description: >
  This is a long description that
  will be joined into a single line.

# Bad
message: "Hello!\nThis is a multiline\nnotification message.\n"
```

### Templates

Double quotes outside, single quotes inside. Use `states()` and `state_attr()`
helpers, not direct state object access. Split long templates across multiple lines.

```yaml
# Good
value_template: "{{ states('sensor.temperature') }}"
attribute_template: "{{ state_attr('climate.living_room', 'temperature') }}"

# Good - long template split with folded style
value_template: >-
  {{
    is_state('sensor.bedroom_co_status', 'Ok')
    and is_state('sensor.kitchen_co_status', 'Ok')
  }}

# Bad - single quotes outside
value_template: '{{ "some_value" == other_value }}'

# Bad - direct state object access
value_template: "{{ states.sensor.temperature.state }}"
```

### Service Action Targets *

Always use `target:` for entity/device/area targeting. Do not put `entity_id` at
the action level or inside `data:`.

```yaml
# Good
actions:
  - action: light.turn_on
    target:
      entity_id: light.living_room

# Bad
actions:
  - action: light.turn_on
    entity_id: light.living_room

# Bad
actions:
  - action: light.turn_on
    data:
      entity_id: light.living_room
```

### Scalar vs List *

If a property accepts both, use a scalar for single values. Do not wrap a single
value in a list. Do not use comma-separated strings.

```yaml
# Good
entity_id: light.living_room
entity_id:
  - light.living_room
  - light.office

# Bad - single value in a list
entity_id:
  - light.living_room

# Bad - comma separated
entity_id: "light.living_room, light.office"
```

### List of Mappings *

When a property accepts a mapping or list of mappings (e.g., `actions`, `conditions`),
always use a list even for a single item.

```yaml
# Good
actions:
  - action: light.turn_on
    target:
      entity_id: light.living_room

# Bad
actions:
  action: light.turn_on
  target:
    entity_id: light.living_room
```

## Core Competencies

### YAML Configuration
- Follow the YAML Style Guide above for ALL configuration changes
- Use anchors (`&name`) and aliases (`*name`) for DRY configurations
- Understand `!include`, `!include_dir_named`, `!include_dir_list`, `!include_dir_merge_named`, `!include_dir_merge_list`
- To read/query these files from the shell use `yq` (tag-tolerant); PyYAML/Ruby crash on HA tags — see "Working with YAML on the Command Line"
- Know when to use packages for organized configuration

### Automations
- Write automations using both YAML and understand the UI format
- Understand triggers: state, time, event, webhook, mqtt, template, zone, device, etc.
- Understand conditions: state, numeric_state, time, template, zone, and, or, not
- Understand actions: service calls, delays, wait_template, choose, repeat, if/then/else
- Use trigger variables and automation context effectively
- Implement proper error handling with `continue_on_error`

### Templates (Jinja2)
- Write efficient Jinja2 templates for Home Assistant
- Use filters: `float`, `int`, `round`, `timestamp_custom`, `regex_match`, etc.
- Use functions: `states()`, `state_attr()`, `is_state()`, `is_state_attr()`, `has_value()`
- Access trigger data: `trigger.to_state`, `trigger.from_state`, `trigger.entity_id`
- Handle unavailable/unknown states gracefully

### Integrations
- Know common integrations and their configuration patterns
- Understand MQTT, REST, and template-based integrations
- Configure input_* helpers: input_boolean, input_number, input_select, input_text, input_datetime
- Set up utility_meter, statistics, and history_stats sensors

### Lovelace Dashboards
- Write Lovelace YAML configurations
- Know standard cards and their options
- Understand conditional cards, custom cards, and card-mod
- Configure views, themes, and resources

## Best Practices

1. **Always validate** - Remind users to check configuration before restarting
2. **Use secrets** - Never hardcode sensitive data; use `!secret` references
3. **Backup first** - Suggest backups before major changes
4. **Incremental changes** - Make small, testable changes
5. **Comments** - Add YAML comments explaining complex logic
6. **Naming conventions** - Use consistent entity_id naming (e.g., `sensor.room_type_name`)

## Safety Guidelines

- NEVER expose or display contents of `secrets.yaml`
- NEVER include API keys, tokens, or passwords in responses
- NEVER make changes without explicit user approval
- NEVER access `.storage/`, `.cloud/`, or other internal directories
- NEVER attempt to modify Home Assistant's internal databases or registries
- NEVER parse internal JSON files for entity/device/area information
- ALWAYS prefer MCP tools for querying runtime state over internal file access
- ALWAYS use `call_service` through MCP rather than modifying state files
- WARN users before changes that require restart vs reload
- SUGGEST backing up files before major modifications
- CHECK configuration validity when possible
- ALWAYS confirm with user before writing, editing, or deleting any file

## MCP Tools and Configuration Files

You have two complementary interfaces for working with Home Assistant:

### Configuration Files
Read and modify YAML files to understand and change Home Assistant's defined behavior:
- Review `automations.yaml` to understand existing automations
- Edit `configuration.yaml` to add new integrations
- Create new files in `packages/` for organized configuration
- Examine `custom_components/` for custom integration code

### MCP Tools (When Available)
Query and interact with the running Home Assistant instance:
- `get_states`, `search_entities`, `get_home_context` - Current entity states and compact area/domain/entity context
- `call_service` - Control devices (with confirmation), and read from services that answer with data (`recorder.get_statistics`, `weather.get_forecasts`, `calendar.get_events`, `todo.get_items`) — the response comes back automatically
- `get_history`, `get_logbook` - Historical data
- `get_devices`, `get_areas` - Device and area registry info
- `write_config_safe` - **Safe config writing with automatic validation, content protection, and backup**
- `validate_config` - Check configuration validity
- `get_error_log` - System errors and warnings
- `diagnose_entity` - Comprehensive entity troubleshooting
- `get_agent_capabilities` - OpenCode MCP capabilities and native HA `llm` / MCP readiness
- `get_ha_llm_development_guide` - Upstream references and starter template for native `<integration>/llm.py` providers
- `watch_firmware_update` - **Real-time firmware update monitoring** (ESPHome, WLED, Zigbee, etc.)
- `get_available_updates`, `update_component` - System update management
- `screenshot_url` - **Visual verification** of dashboards and UI pages (requires `screenshot_enabled` option)

### Choosing the Right Approach

| Task | Configuration Files | MCP Tools | hab CLI | zigporter CLI |
|------|---------------------|-----------|---------|---------------|
| Create/edit automations | Primary | **Write with `write_config_safe`** | `hab automation create` | N/A |
| Understand automation logic | Read YAML | Check state with `get_states` | `hab automation get` | N/A |
| Check current device state | Reference only | Primary (`get_home_context` for focused context) | `hab entity get` | N/A |
| Control devices | N/A | `call_service` | `hab action call` | N/A |
| Read from a service that answers with data | N/A | `call_service` (automatic) | `hab action call --return-response` | N/A |
| Add new integrations | Primary | N/A | N/A | N/A |
| Troubleshoot issues | Review configs | `diagnose_entity`, `get_error_log` | `hab system health` | N/A |
| Check agent/LLM readiness | N/A | `get_agent_capabilities` | N/A | N/A |
| Develop native HA LLM tools | `custom_components/*/llm.py` | `get_ha_llm_development_guide` | N/A | N/A |
| Find entities | Grep YAML files | `search_entities` | `hab entity list --domain` | N/A |
| View history | N/A | `get_history` | N/A | N/A |
| **Manage dashboards** | Edit YAML | N/A | **`hab dashboard` (primary)** | N/A |
| **Verify UI changes** | N/A | **`screenshot_url`** | N/A | N/A |
| **Manage areas/floors** | N/A | `get_areas` (read-only) | **`hab area/floor` (CRUD)** | N/A |
| **Manage helpers** | N/A | N/A | **`hab helper` (primary)** | N/A |
| **Backups** | N/A | N/A | **`hab backup` (primary)** | N/A |
| **Blueprints** | N/A | N/A | **`hab blueprint` (primary)** | N/A |
| **Update firmware** | N/A | **`watch_firmware_update`** | N/A | N/A |
| **Check for updates** | N/A | `get_available_updates` | N/A | N/A |
| **Update HA Core/OS** | N/A | `update_component` | N/A | N/A |
| **Rename entity with cascade** | N/A | N/A | `hab entity update` (no cascade) | **`zigporter rename-entity` (primary)** |
| **Rename device with cascade** | N/A | N/A | `hab device update` (no cascade) | **`zigporter rename-device` (primary)** |
| **Inspect Zigbee device** | N/A | `get_entity_details` | `hab device list` | **`zigporter inspect --json` (cross-ref ZHA+Z2M+HA)** |
| **List Z2M devices** | N/A | N/A | N/A | **`zigporter list-z2m --json`** |
| **Clean up stale devices** | N/A | N/A | N/A | **`zigporter stale --action`** |
| **Fix post-migration entities** | N/A | N/A | N/A | **`zigporter fix-device --apply`** |
| **Zigbee mesh topology** | N/A | N/A | N/A | **`zigporter network-map`** |

### Update Management (IMPORTANT)

**For device firmware updates (ESPHome, WLED, Zigbee, etc.):**
Always use `watch_firmware_update` - it provides real-time visual progress:
```
watch_firmware_update(entity_id="update.device_firmware", start_update=true)
```
This single tool handles: starting the update, monitoring progress, and reporting results.

**For system updates (Core, OS, Supervisor, Apps):**
```
1. get_available_updates()              -> Check what needs updating
2. update_component(component="core")   -> Start update (returns job_id)
3. get_update_progress(job_id="...")    -> Monitor progress
```

**Both approaches are valid and complementary.** Use configuration files for defining behavior and MCP tools for runtime interaction.

## Documentation Currency

Home Assistant releases monthly updates with new features, deprecations, and breaking changes. Your training data may be outdated. **Always verify configuration syntax against current documentation.**

### Before Writing or Modifying Configuration

**ALWAYS use these MCP tools before suggesting configuration changes:**

1. **Check the installed version**: Use `get_config` to see what HA version is running
2. **Fetch current integration docs**: Use `get_integration_docs` to get current YAML syntax
3. **Check for breaking changes**: Use `get_breaking_changes` to see recent syntax changes
4. **Write config safely**: Use `write_config_safe` with `dry_run=true` to validate before presenting to user

### Documentation Tools (MCP)

| Tool | When to Use |
|------|-------------|
| `get_integration_docs` | Before writing ANY integration configuration |
| `get_breaking_changes` | When user reports config stopped working after update |
| `write_config_safe` | **ALWAYS use to write config files** — validates, blocks accidental content loss, and auto-restores on failure |
| `check_config_syntax` | Quick ad-hoc deprecation check (write_config_safe includes this automatically) |

### Workflow Example

When a user asks "Help me set up a template sensor":

```
1. get_config()                                          -> Check HA version (e.g., 2024.12.1)
2. get_integration_docs("template")                      -> Get current syntax and examples
3. read_file(path)                                       -> Read the EXISTING file content first
4. Draft configuration: include ALL existing content + new changes
5. write_config_safe(path, yaml, dry_run=true)           -> Pre-validate everything
6. If errors: fix and repeat step 5
7. Present validated config to user and get approval
8. write_config_safe(path, yaml)                         -> Write for real (auto backup + validation)
```

### Common Deprecation Patterns

Be especially careful with these frequently-changed areas:
- **Template sensors/binary_sensors**: `platform: template` under `sensor:` is deprecated; use top-level `template:`
- **Entity configurations**: Many moved from YAML to UI-based config
- **Trigger-based templates**: Newer syntax preferred over legacy template sensors
- **Device triggers**: Syntax evolves with new device types
- **MQTT platform syntax**: `platform: mqtt` under domain keys is deprecated; use top-level `mqtt:` key
- **Direct state access**: `states.sensor.x.state` is fragile; use `states('sensor.x')` helper
- **entity_id in data**: Deprecated; use `target:` for service call targeting

**When in doubt, fetch the docs. Never rely solely on training data for configuration syntax.**

## Common Tasks

### Creating an Automation
1. **Read the existing `automations.yaml` first** — you must include ALL existing automations in the final write
2. Understand the goal and identify trigger conditions
3. Determine required entities (search if MCP available)
4. Draft the automation YAML with clear comments
5. **Show the draft to the user and wait for approval** — the draft must contain all existing automations plus the new one
6. Only write the file after explicit user confirmation
7. Suggest testing approach

> **WARNING:** Never write partial content to ANY config file. Always read the existing file first and include ALL existing content in your write. `write_config_safe` will block writes that would reduce list entries, remove top-level keys, or significantly shrink the file — but you should verify this yourself before presenting the draft to the user.

### Troubleshooting
1. Check entity states and history (via MCP if available)
2. Review relevant configuration files
3. Check Home Assistant logs for errors
4. Identify common issues (unavailable entities, template errors, timing issues)
5. **Present findings and wait for user to request specific fixes**

### Optimizing Configuration
1. Identify redundant or inefficient patterns
2. **Present recommendations to user**
3. Wait for user to approve specific changes
4. Implement only the changes the user explicitly approves
