From home-assistant-dev
Home Assistant core internals — event bus, state machine, service registry, and integration loading. Use when asking about the hass object, event propagation, state management, service registration, or how integrations load.
How this skill is triggered — by the user, by Claude, or both
Slash command
/home-assistant-dev:ha-architectureThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Home Assistant runs on a single-threaded asyncio event loop. All code shares this loop — blocking it freezes automations, the UI, and entity updates.
Home Assistant runs on a single-threaded asyncio event loop. All code shares this loop — blocking it freezes automations, the UI, and entity updates.
Every integration receives HomeAssistant instance (hass) — the central hub for all core systems:
from homeassistant.core import HomeAssistant
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
# hass.bus — Event bus for pub/sub communication
# hass.states — State machine for entity states
# hass.services — Service registry for actions
# hass.config — System config (location, units, timezone)
...
The nervous system of Home Assistant. All component communication flows through events.
from homeassistant.core import callback, Event
# Fire an event
hass.bus.async_fire("my_custom_event", {"key": "value"})
# Listen for events (@callback = sync, no I/O allowed)
@callback
def handle_event(event: Event) -> None:
entity_id = event.data.get("entity_id")
new_state = event.data.get("new_state")
unsub = hass.bus.async_listen("state_changed", handle_event)
entry.async_on_unload(unsub) # Always clean up on unload
Key events: state_changed, homeassistant_start, homeassistant_stop, call_service, automation_triggered.
Tracks current state of every entity. States are immutable snapshots.
state = hass.states.get("sensor.temperature")
if state is not None:
value = state.state # Always a string
attrs = state.attributes # Dict of attributes
last_changed = state.last_changed
Special state values: "unavailable" (coordinator failed/device offline), "unknown" (no data yet).
Services (now called "actions" in UI) control devices. Register in async_setup, not async_setup_entry:
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
async def handle_action(call: ServiceCall) -> None:
entity_id = call.data.get("entity_id")
await do_something(entity_id)
hass.services.async_register(DOMAIN, "my_action", handle_action)
return True
configuration.yamlmanifest.json loaded firstasync_setup(hass, config) called (if present)async_setup_entry(hass, entry) calledasync_setup_entrySingle-threaded event loop: All async code shares one loop. Never block it.
Immutable state: hass.states.get() returns a frozen snapshot.
Integration isolation: Each integration manages its lifecycle via config entries. Store coordinator in entry.runtime_data (not hass.data).
npx claudepluginhub l3digitalnet/claude-code-plugins --plugin home-assistant-devDevelops custom Home Assistant integrations including config flows, entities, platforms, manifest.json, and device registry. Prevents common errors in coordinators, async setup, and entity registration.
Provides best practices for Home Assistant automations, helpers, scripts, and dashboards. Guides on avoiding templates, using native constructs, and safe refactoring.
Applies agentic design patterns (tool use, routing, planning, exception handling, memory) to Home Assistant for smart home automation and IoT orchestration.