
Share this article
Three years ago, I started my Home Assistant journey the way most of us do: with enthusiasm, a handful of Zigbee bulbs, and absolutely no plan. Fast forward to January 2026, and I was staring at a 2,312-line automations.yaml file, wondering how it had all gone so wrong.
Then I discovered something that changed everything: AI-assisted home automation management.
It started with a simple question: "Why do I have three copies of the same automation?"
I had been adding smart devices incrementally for years. A motion sensor here, a TRV there, a few blinds, some presence detection. Each addition meant a new automation, usually copied from an existing one and tweaked. The mobile app made it easy to add things but impossible to see the big picture.
My Home Assistant had become a reflection of my own scattered decisions: 47 automations, 3,997 entities (1,637 of them disabled), duplicate integrations, references to a phone I had replaced two years ago, and a kitchen blinds automation that somehow ballooned to 636 lines of YAML.
Something had to change.
I had been using Claude for coding tasks, but the idea of using it for home automation management seemed novel. Then I discovered the emerging ecosystem of MCP (Model Context Protocol) servers designed specifically for Home Assistant integration.
The landscape was surprisingly mature:
What struck me was the philosophy shift these tools represented. Instead of AI being a voice assistant that turns lights on and off, these tools positioned AI as a management layer - something that could audit, plan, and help maintain complex configurations.
I set up a Docker-based staging environment on port 8124, pulled my production config, and started asking Claude to analyze what I had built.
The results were sobering.
My "Dan Presence" automation existed three times, all with the same ID. In Home Assistant, duplicate IDs mean only one actually executes - but I had no way of knowing which. The dishwasher notification automation? Two copies. "Both away" detection? Duplicated.
| Automation | Duplicates |
|-----------------------------|------------|
| Dan Presence | 3x |
| Dishwasher States | 2x |
| Both Away | 2x |
Remember that Pixel 6a I replaced? My configuration certainly did. The notify.mobile_app_pixel_6a service was referenced 31 times across automations and scripts. Every notification I thought was being sent was silently failing because the target device no longer existed.
The dishwasher finished notification. The washing machine alert. The heating status updates. All broken. All silently failing.
During one debugging session with Claude, I finally untangled the device history:
This discovery was crucial - I had been chasing the wrong device the whole time, and it explained why some notifications worked while others did not. The correct mapping should have been:
NOTIFY_LIV: notify.mobile_app_pixel_9a
NOTIFY_DAN: notify.mobile_app_pixel_10_pro_xl
But more on that token syntax later - it becomes the foundation of the solution.
The crown jewel of technical debt was my kitchen blinds automation: 636 lines of YAML handling:
It worked, technically. But it was unmaintainable, untestable, and I had no memory of why half the conditions existed.
| Issue | Details |
|---|---|
| Tuya + SmartLife | Same devices in both integrations |
| Ring integration + Ring MQTT addon | Duplicate setup |
| 6 unconfigured HACS components | Installed but never set up |
| 578 disabled mobile_app entities | Old phones creating entity sprawl |
The solution that emerged was a GitOps-style workflow for Home Assistant configuration:
┌─────────────────────────────────────────────────────────────────┐
│ Dev Machine │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Claude Code │ │
│ │ ┌─────────────┐ ┌──────────────┐ ┌──────────────┐ │ │
│ │ │ ha-mcp │ │ Git Repo │ │ hass-cli │ │ │
│ │ │ (MCP Tools) │ │ (Version │ │ (Bash) │ │ │
│ │ └──────┬──────┘ │ Control) │ └──────┬───────┘ │ │
│ └─────────┼─────────┴──────────────┴─────────┼────────────┘ │
│ │ │ │
└────────────┼───────────────────────────────────┼─────────────────┘
▼ ▼
┌─────────────────────┐ ┌─────────────────────┐
│ Docker Staging │ │ Production HA │
│ localhost:8124 │ │ 192.168.1.217 │
└─────────────────────┘ └─────────────────────┘
The key insight was separating concerns:
This meant I could ask Claude to analyze my automations, suggest consolidations, and even generate new YAML - all without touching my production system until I was confident in the changes.
The research revealed an interesting split in the community. Privacy-conscious users gravitate toward local solutions like Home-LLM, which runs optimized models under 5B parameters on modest hardware (even a Mac Mini M4 works beautifully). Meanwhile, cloud options like Google Generative AI offer 14x better cost-performance than OpenAI for voice assistant use cases.
For management tasks, the cloud-based Claude Code with MCP integration proved invaluable. The ability to search, analyze, and suggest across thousands of entities requires context windows that local models struggle with.
The most useful insight came from analyzing the .storage/core.restore_state file. This file contains last_triggered timestamps for every automation and script. With a simple jq query, I could see:
automation.boiler_automation_heating_control_simpleautomation.utility_automation_heating_boostscript.script_bedroom_stop_airconThis data-driven approach to identifying dead code was something I never could have done manually. Claude could process this data, cross-reference it with entity registries, and tell me exactly what was safe to remove.
The research also uncovered modern dashboard patterns I had missed:
My current dashboard had bugs I never noticed: duplicate toggle buttons, wrong room entities (the Guest Room section was showing Office controls), and missing rooms entirely. The AI-assisted audit caught all of these.
The audit produced a prioritized cleanup plan:
The cleanup plan was useful, but it only solved the immediate problem. What about the next time I upgrade my phone? Would I be hunting through YAML files to update 31 references again?
This question led to what became the most interesting outcome of the entire project: an automation build system inspired by software development practices.
The core problem was repetition. Device service names like notify.mobile_app_pixel_6a were hardcoded everywhere. When the device changed, every reference broke. The solution was borrowed from software engineering: token substitution.
Instead of hardcoding device services, automations would reference tokens:
# Instead of this:
service: notify.mobile_app_pixel_6a
data:
message: "Dishwasher finished"
# Write this:
service: \${NOTIFY_LIV}
data:
message: "Dishwasher finished"
The tokens are defined in a single _tokens.yaml file:
# _tokens.yaml
NOTIFY_LIV: notify.mobile_app_pixel_9a
NOTIFY_DAN: notify.mobile_app_pixel_10_pro_xl
NOTIFY_ALL: notify.all_phones
PERSON_DAN: person.dan
PERSON_LIV: person.liv
The next time Liv upgrades her phone, I change one line. That is it. The 31-reference nightmare becomes a one-line fix.
Token substitution was just the start. Claude and I identified patterns that repeated across automations: the same notification sequences, the same conditional checks, the same trigger configurations.
This led to reusable action blocks:
# _blocks.yaml
notify_both_critical:
- service: \${NOTIFY_DAN}
data:
message: "\${MESSAGE}"
data:
priority: high
- service: \${NOTIFY_LIV}
data:
message: "\${MESSAGE}"
data:
priority: high
notify_dan_only:
- service: \${NOTIFY_DAN}
data:
message: "\${MESSAGE}"
Automations reference these blocks with a special syntax:
action:
\$ACTION{notify_both_critical}:
MESSAGE: "The dishwasher has finished"
The build script expands this into the full action sequence, with the message substituted in.
With token substitution and reusable blocks in place, the next step was organization. Instead of one massive automations.yaml file, automations live in category directories:
automations/
├── _tokens.yaml # Device and entity tokens
├── _blocks.yaml # Reusable action/condition blocks
├── presence/
│ ├── dan_arrives.yaml
│ ├── liv_arrives.yaml
│ └── both_away.yaml
├── appliances/
│ ├── dishwasher.yaml
│ ├── washing_machine.yaml
│ └── dryer.yaml
├── heating/
│ ├── morning_boost.yaml
│ └── away_setback.yaml
└── lighting/
├── motion_triggers.yaml
└── sunset_routines.yaml
A Python build script marshals everything back into the single automations.yaml that Home Assistant expects:
_tokens.yaml_blocks.yaml\${NOTIFY_DAN} becomes the actual service)\$ACTION{notify_both_critical} becomes the full action list)automations.yamlThis is CI/CD for home automation. The source files are human-readable and DRY. The output is what Home Assistant needs.
The build system transforms how I think about automation maintenance:
| Problem | Old Approach | New Approach |
|---|---|---|
| Phone upgrade | Find and update 31 references | Change one line in _tokens.yaml |
| New notification pattern | Copy-paste action blocks | Reference \$ACTION{pattern_name} |
| Finding an automation | Search through 2,312-line file | Browse category directories |
| Understanding dependencies | Manual code review | Token file shows all device references |
_tokens.yaml tells you exactly which devices and entities are used across all automations.
With the audit complete and the build system designed, Claude and I developed a comprehensive implementation plan. The key insight was staging: certain things had to be fixed before others could begin.
Nothing else could proceed until these were resolved:
This phase was marked as "blocking" because starting dashboard work with broken automations would just create more problems.
With the critical bugs fixed:
The first new dashboard targets our Fire HD 10 tablet mounted in the kitchen:
A separate dashboard optimized for phones:
For browser access:
Cross-cutting concerns:
One pattern that emerged from the planning was a proper notification system. Instead of fire-and-forget notifications that disappear if you miss them, we designed a slot-based notification center:
# Helper entities
counter.notification_unread: 0-99 badge count
input_text.notification_slot_1: 255 character limit
input_text.notification_slot_2: 255 character limit
# ... up to slot 10
input_text.notification_slot_10: 255 character limit
When a notification fires:
counter.notification_unreadUsers can:
This solves the problem of missing important notifications when away from the dashboard. The badge persists until you acknowledge it.
Home Assistant's input_text helper has a 255-character limit, which seems restrictive. But the slot approach has advantages:
For a household notification system, 10 slots of 255 characters is plenty.
The tooling setup evolved significantly through the project. What started as Docker-based staging eventually moved to direct production access with proper safeguards.
Danm72/Homeassistant repositoryThe original plan involved a Docker staging environment, but in practice the workflow simplified:
The staging environment remains available for risky changes, but most work happens directly against production with Git as the safety net.
Having ha-mcp connected means Claude can:
# Check if an automation is working
> "Is the dishwasher notification automation triggering?"
[Claude queries automation state, last_triggered, checks logs]
# Debug a problem
> "Why aren't the living room lights responding?"
[Claude checks entity states, automation traces, Zigbee network]
# Make changes safely
> "Disable the broken heating automation until I fix it"
[Claude disables automation, confirms state change]
This is fundamentally different from copying YAML snippets back and forth. Claude has actual visibility into the system state.
What started as a tech debt cleanup project evolved into something more interesting: a vision for AI-assisted smart home management.
The tools exist today to have AI:
This is not about voice assistants that turn lights on and off. This is about AI as a co-pilot for complex system management.
If you are considering AI tools for your Home Assistant setup, here is what I learned:
Start with an audit, not new features. The most valuable AI assistance was not generating new automations - it was analyzing what I already had and finding problems. You cannot improve what you do not understand.
Use MCP servers for real integration. ha-mcp provides 82 tools that let Claude directly interact with your instance. This is fundamentally different from copying YAML back and forth - Claude can query state, check logs, and verify changes.
Treat device references as configuration, not code. Token substitution (\${NOTIFY_DAN} instead of notify.mobile_app_pixel_10_pro_xl) means device changes become single-line updates. This principle alone would have saved me hours of debugging.
Data-driven decisions work. The last_triggered timestamps in .storage/core.restore_state are pure gold. Let AI process this data to find dead code. I found automations that had not run in 28 months.
Version control everything. Git is not just for code. Your Home Assistant config deserves the same treatment. When something breaks, git diff tells you exactly what changed.
Plan in phases with dependencies. Phase 0 (prerequisites) exists for a reason. Trying to build new dashboards while automations are broken just compounds problems.
The iterative conversation matters. Some of the best insights came from clarifying questions. "Wait, whose phone was that?" led to understanding the entire notification problem differently.
The project has evolved from "help me understand my setup" to a structured implementation plan:
Immediate (Phase 0):The build system is the key investment. Once _tokens.yaml and the preprocessing script are in place, future device changes become trivial. The phone upgrade problem is permanently solved.
What surprised me most about this project was the iterative nature of discovery. The initial goal was simple: understand what I had built. But each session with Claude revealed new problems and new solutions:
The AI did not just find problems - it helped design systems to prevent them from recurring. That shift from reactive debugging to proactive architecture is where the real value emerged.
Three years of accumulated decisions created a mess. A few weeks of AI-assisted work created not just a cleanup plan, but a fundamentally better way to manage the system going forward. The smart home of the future is not just automated - it is intelligently managed, version-controlled, and designed for change.
Continue reading similar content

I wrote four bash scripts to orchestrate Claude Code agents in parallel. Three days later: 236 files changed, 271 commits, and a fully migrated codebase.

Part 5 of my Home Assistant AI journey: I promised to build auto-create automations. Instead, I shipped 6 releases in 3 days - none of which were the feature I said I'd build.

Part 4 of my Home Assistant AI journey: How I turned the automation-finder Python script into a proper HA integration with config flow, sensors, and services.