Skip to main content
Splintist
SYSTEMS & HOMELAB  ·  22 Jun 2026  ·  5 min read

How I run my smart home with Claude Code

My smart home runs on Home Assistant, on a VM on my NAS. The important part for this post is that the whole configuration is a git repository. Automations, packages, dashboards, a couple of custom components I had built, all of it in version control. That one decision is what makes the rest possible, because I can point Claude Code at the repo and treat my house like any other codebase.

I've got around 90 automations in there now, and a good chunk of them I described in plain language and let Claude write.

The loop

It's boring in a good way. I describe what I want, Claude edits the YAML or Python and commits it one feature at a time, and to check its work it queries my live Home Assistant over the API (does this entity exist, what state is it in). For dashboards, where you actually need to see the thing, it edits the config, pushes it, then screenshots the live dashboard with Playwright so it can look at what it made. An AI can't see your UI unless you give it eyes, and that's how I give it eyes.

Deploying is its own small ritual. The running Home Assistant keeps its own copy of the config, so the flow is: commit, push, pull on the HA box, reload. There's a gotcha buried in that, and it took me a while to internalize: if you edit a file and reload before Home Assistant has pulled the change, it's still reading the old copy and it looks like your edit failed. Runtime changes through the API are instant. File changes only land after the pull. Worth knowing before you lose twenty minutes to it.

To keep Claude on the rails I have a house-rules file it reads every time (use entity IDs not device IDs, user-facing text in German, one commit per feature, and a short list of things it must ask before touching, like anything to do with presence or security). On top of that I built a few custom slash commands for house work: /plan to plan a change and interview me first, /validate to check the whole config, /cleanup to hunt duplicate or dead automations.

A few real examples

The cheap-sensor trick. My washing machine isn't smart. It's a dumb machine plugged into a Zigbee power plug. So an automation watches the plug and flags the wash as done when the power drops and stays down while the door's still shut:

# packages/waschmaschine.yaml
trigger:
  - platform: numeric_state
    entity_id: sensor.waschmaschine_power
    below: 2            # watts
    for: "00:03:00"     # ...for 3 minutes
condition:
  - condition: state
    entity_id: binary_sensor.waschmaschine_tuer
    state: "off"        # door still closed
action:
  - service: input_boolean.turn_on
    target: { entity_id: input_boolean.waschmaschine_fertig }

That flag drives a hint tile on the dashboard. Same trick for the coffee machine. This is the bread and butter of Home Assistant, and exactly the kind of fiddly template logic Claude is good at writing from one line of description.

The timer that fought me. My ask was simple:

We use the kitchen voice assistant constantly for timers. Let's build an automation that pushes a timer to our phones as a notification, so we can see the state of it there too.

It was not simple, because the voice unit keeps its timers to itself and doesn't expose them like normal entities. My side of that conversation was a lot of "didn't work" and "no timer rang." The git log tells the whole grind:

Add: Voice PE Timer with Phone-Notification
Fix: Voice PE Timer per Conversation-Sentence
Refactor: voice_timer_bridge custom_component instead of Intercept
Fix: manifest integration_type + requirements
Debug: dump service + entity_registry listener for re-wrap

Six commits and eventually a small custom integration to re-wrap the timers into something Home Assistant could see. Not glamorous, but that's the honest texture of this stuff, and having Claude push through the sixth attempt is genuinely useful.

The lesson that stuck

Here's the one I'd want a beginner to hear. I wanted to say "plan potatoes for tonight" to the kitchen and have it set the meal plan and add the ingredients to our shopping list. My first instinct was to let the language-model brain handle it directly. It went like this:

Me:      plan Kartoffeln für heute
Kitchen: "Done, planned potatoes and added the ingredients to your list."
Reality: nothing was planned. nothing was added.

No error. Just a confident, cheerful report of work it hadn't done.

The fix was to stop asking the model to do the action and wire specific spoken sentences straight to the meal-planner instead, deterministically. Now "plan X for today" runs actual code every time.

That's the whole lesson in one story. A language model with no real tool behind it will happily tell you it did something it didn't. For anything that just chats, that's fine. For anything that has to actually happen in the real world, wire it to run deterministically and don't trust the narration. My voice setup now splits exactly on that line: a fast, reliable built-in brain for controlling the house, and the fancy AI only as a fallback for open questions.

Where it's great and where it isn't

Claude is great at the repetitive stuff (bulk migrations, adding descriptions, templating with safe defaults), at writing a whole feature package or a small custom component from a description, and at debugging when I paste it a log or a trace and ask why something's slow.

Where it struggles is honest and consistent: subtle YAML and template bugs that look completely right and quietly do nothing, language codes that have to be exactly de-DE and not de, frontend quirks you only catch on a real phone, and hardware or firmware limits it can't touch (it can work around a wedged voice puck, it can't reflash it).

What holds all of this together across dozens of sessions is memory. Claude keeps notes on the decisions and the gotchas, so the next session doesn't re-learn that card-mod is silently broken or that the timers live on the device. That, plus git, is why the setup stays coherent instead of turning into a pile of one-off hacks.

If your Home Assistant config isn't in git yet, that's the first move. Everything above only works because the house is a repo :)