Skip to content
Agentmart
Submit a tool

hass-declarative

Manages Nix-owned HA automations, scenes, scripts, and entity identity.

Skill by edmundmiller

IndexedMIT★ 80
Write a review

Install

Works with Claude Code, Claude apps, Codex, Cursor, Gemini CLI, GitHub Copilot, VS Code, OpenCode, Goose, Windsurf. Read the repository before you give any tool access to your data.

npx agentmarket install skill/edmundmiller-hass-declarative

Asks which of your tools to add it to (Claude Code, Codex, Cursor, VS Code, Windsurf, Gemini CLI, Claude Desktop) and shows the change first. See https://agentmart.dev/cli.

Get the weekly diff

The weekly diff: one email a week with new agent tools, notable updates and grade changes, plus security alerts for tools you follow. Double opt-in, one-click unsubscribe.

We use your email only for this newsletter. Privacy

About

Manages Nix-owned HA automations, scenes, scripts, and entity identity. Use for domain edits, ensureEnabled assertions, or orphan-sweep debugging.

No reviews yet. Installed it? Reviews come from verified installers only. How reviews work

Permissions

What this skill can do and what it asks for, from its SKILL.md and code. Checked Oct 25, 2026.

Tools
No tools found
Secrets
None asked for
Install scripts
None found

Network hosts it talks to 1

  • codeload.github.com · found in install command

Files it touches

  • ~/.claude/skills/hass-declarative

What's inside

Skill name
hass-declarative
Description
Manages Nix-owned HA automations, scenes, scripts, and entity identity. Use for domain edits, ensureEnabled assertions, or orphan-sweep debugging.
License
MIT
Instructions
195 lines in SKILL.md · view on GitHub

Files (2)

  • SKILL.md
  • entity-lifecycle.md · references/

SKILL.md (first lines)

# HA Declarative Entity Management

All HA automations, scenes, and scripts are defined in Nix under
`modules/services/hass/_domains/`. A post-deploy sweep service removes
anything not in the declared set.

## Architecture

```
_lib.nix                       ← shared helpers (ensureEnabled)
_domains/                      ← domain files (Nix modules)
  ambient.nix                  ← lighting schedules, plant lights
  aranet.nix                   ← CO2 monitoring
  conversation.nix             ← voice intents
  lighting.nix                 ← adaptive lighting, AL sleep mode
  modes.nix                    ← DND, guest mode, everything_off script
  sleep/default.nix            ← bedtime flow, wake detection, 8Sleep sync
  tv.nix                       ← TV idle timer, sleep timer
  vacation.nix                 ← presence-based vacation mode

sweep-unmanaged.nix            ← extracts declared IDs at build time
sweep-unmanaged.py             ← runtime: removes orphans via WS API
_tests/eval-automations.nix    ← structural assertions (flake check)
```

## Entity Identity

How HA maps Nix config → entity registry:

| Domain     | Nix declaration                  | Entity ID                 | Unique ID (registry)  |
| ---------- | -------------------------------- | ------------------------- | --------------------- |
| automation | `id = "winding_down";`           | `automation.winding_down` | Same as `id` field    |
| scene      | `name = "Good Morning";`         | `scene.good_morning`      | HA-generated UUID     |
| script     | `script.everything_off = {...};` | `script.everything_off`   | Same as attribute key |

Scene slugs: HA lowercases the name and replaces spaces/hyphens with
underscores. Keep names ASCII-alphanumeric + spaces to avoid slug surprises.

## Adding Entities

### Automation

Add to the `automation = lib.mkAfter (ensureEnabled [...])` list in the
appropriate domain file. Every automation **must** have a unique `id` field
— the sweep service uses it.

**Always wrap with `ensureEnabled`** (from `_lib.nix`) — it injects
`initial_state = true` so automations re-enable on HA restart. Without it,
HA silently persists "off" state from the entity registry and automations
stay disabled forever. The eval test catches missing wrappers at build time.

```nix
{ lib, ... }:
let
  inherit (import ../_lib.nix) ensureEnabled;
in {
  services.home-assistant.config.automation = lib.mkAfter (ensureEnabled [
    {
      alias = "Human-Readable Name";
      id = "unique_snake_case_id";
      description = "What it does";
      trigger = { platform = "time"; at = "22:00:00"; };
      condition = [];
      action = [{ action = "scene.turn_on"; target.entity_id = "scene.foo"; }];
    }
  ]);
}
```

Individual automations can override with `initial_state = false` if ever needed
(the `//` merge gives right-hand precedence), but we never want this in practice.

### Scene

Add to `scene = lib.mkAfter [...]`. Scenes use `name` as their identity.

```nix
{
  name = "My Scene";
  icon = "mdi:icon-name";
  entities = {
    "light.some_light" = "on";
    "switch.some_switch" = "off";
  };
}
```

### Script

Add to `script = lib.mkAfter {...}` (attrset, not list). The attribute
key becomes the entity_id.

```nix
my_script_key = {
  alias = "Human Name";
  icon = "mdi:icon";
  sequence = [{ action = "light.turn_off"; target.entity_id = "light.foo"; }];
};
```

Or directly on config: `script.my_key = {...};` (as in `modes.nix`).

## Removing Entities

1. Delete from the domain `.nix` file
2. Deploy (`hey nuc`)
3. `hass-sweep-unmanaged` service auto-removes the orphan from HA's entity registry

No manual cleanup needed. Check sweep results:

```bash
hey nuc-service hass-sweep-unmanaged
ssh nuc "sudo journalctl -u hass-sweep-unmanaged --no-pager -n 30"
```

## Sweep Service

`sweep-unmanaged.nix` creates a systemd oneshot that runs after HA starts.

From edmundmiller/dotfiles, MIT.

More from edmundmiller/dotfiles

Signals

Stars
80
Forks
6
Open issues
4
Last commit (this folder)
Sep 6, 2026 (1 month ago)

From GitHub (fetched Oct 24, 2026).

Details

License
MIT
First seen
Oct 24, 2026
Last checked
Oct 24, 2026

More from edmundmiller

Cite this page

hass-declarative skill. Agent Mart. https://agentmart.dev/skills/edmundmiller-hass-declarative (last updated 2026-10-24)