$npx -y skills add dcb/homeassistant-claude-kit --skill setup-infrastructureRun when setting up this repo for the first time, configuring HA connection, or verifying the infrastructure still works. Trigger phrases: "set up my HA", "configure connection", "first time setup", "run setup", "reconnect to HA", "my token stopped working", "verify my setup".
| 1 | # Setup Infrastructure |
| 2 | |
| 3 | This skill configures the mechanical layer: HA API connectivity, SSH access, and |
| 4 | initial config pull. It is **idempotent** — run it any time to verify or repair the |
| 5 | connection without affecting your actual configuration. |
| 6 | |
| 7 | ## Step 1: Data Consent & Privacy Mode |
| 8 | |
| 9 | **Only ask once per session.** If the user already consented during an earlier invocation |
| 10 | of this skill in the same conversation, skip this step entirely. |
| 11 | |
| 12 | **1a. Data consent** — Before reading any Home Assistant data, inform the user: |
| 13 | |
| 14 | > "This skill will connect to your Home Assistant instance and read your entity registry, |
| 15 | > automation configs, and documentation files. This data is sent to Anthropic's API as |
| 16 | > part of this Claude conversation. See PRIVACY.md for full details. |
| 17 | > Continue? (yes / no)" |
| 18 | |
| 19 | If the user says no, stop here and explain they can still use the repo manually. |
| 20 | |
| 21 | **1b. Privacy mode offer** — Only ask if consent was given. Only ask once per session. |
| 22 | |
| 23 | First check if privacy mode is already active: `test -f .claude/privacy-patterns`. If it is, |
| 24 | say "Privacy mode is already enabled" and skip the offer. |
| 25 | |
| 26 | If not active, ask: |
| 27 | |
| 28 | > "Would you like to enable privacy mode? This blocks Claude from directly reading your |
| 29 | > credentials, personal data files, and runtime state. Setup still works — shell commands |
| 30 | > handle connectivity. You can toggle this later with `make privacy-on` / `make privacy-off`. |
| 31 | > Enable privacy mode? (yes / no)" |
| 32 | |
| 33 | If yes: `cp .claude/privacy-patterns.example .claude/privacy-patterns` |
| 34 | If no: proceed without it. |
| 35 | |
| 36 | ## Step 2: Check .env |
| 37 | |
| 38 | Check whether `.env` exists in the repo root: |
| 39 | |
| 40 | ```bash |
| 41 | test -f .env && echo "exists" || echo "missing" |
| 42 | ``` |
| 43 | |
| 44 | **If missing:** Tell the user to copy `.env.example` to `.env` and fill in: |
| 45 | |
| 46 | | Variable | Description | Example | |
| 47 | |----------|-------------|---------| |
| 48 | | `HA_TOKEN` | Long-lived access token (HA → Profile → Security → Long-Lived Access Tokens) | `eyJ...` | |
| 49 | | `HA_URL` | Your HA URL (local or remote) | `http://homeassistant.local:8123` | |
| 50 | | `HA_HOST` | SSH hostname, IP, or SSH config alias | `homeassistant.local` or `ha` | |
| 51 | | `SSH_USER` | SSH add-on user (usually `root`) | `root` | |
| 52 | | `HA_REMOTE_PATH` | Remote config directory (see note below) | `/config/` or `/homeassistant/` | |
| 53 | | `VITE_GO2RTC_URL` | go2rtc URL (camera streams) — leave empty if not using cameras | `http://homeassistant.local:1984` | |
| 54 | |
| 55 | > **HA_REMOTE_PATH note:** HA OS with the SSH add-on typically uses `/homeassistant/`, |
| 56 | > while HA Container/Supervised uses `/config/`. If unsure, the SSH test in Step 4 will |
| 57 | > auto-detect the correct path. |
| 58 | |
| 59 | **IMPORTANT:** The `.env` file must NOT use inline comments on value lines (e.g. |
| 60 | `HA_HOST=foo # comment`). Makefile's `include` treats everything after `=` as the value, |
| 61 | including `# ...` text. Use only full-line comments (lines starting with `#`). |
| 62 | |
| 63 | Wait for the user to fill in `.env` before continuing. |
| 64 | |
| 65 | **If exists and privacy mode is OFF:** Load the values and proceed. |
| 66 | |
| 67 | **If exists and privacy mode is ON** (`test -f .claude/privacy-patterns`): |
| 68 | Tell the user: "Privacy mode is active — I can't read `.env` directly. Please verify it |
| 69 | has `HA_TOKEN`, `HA_URL`, `HA_HOST`, `SSH_USER` filled in. The next step will validate |
| 70 | your connection." Then proceed to Step 3 — the curl test validates the values work via |
| 71 | `source .env` (shell sourcing is intentionally not blocked by privacy mode). |
| 72 | |
| 73 | ## Step 3: Validate HA API Token |
| 74 | |
| 75 | Test the HA API is reachable: |
| 76 | |
| 77 | ```bash |
| 78 | source .env && curl -sf -H "Authorization: Bearer $HA_TOKEN" "$HA_URL/api/" | python3 -c "import sys,json; d=json.load(sys.stdin); print('HA version:', d.get('version','unknown'))" |
| 79 | ``` |
| 80 | |
| 81 | - **Success:** Print the HA version and continue. |
| 82 | - **Failure:** Show the curl error. Common fixes: |
| 83 | - Token expired → generate a new one at HA → Profile → Security |
| 84 | - Wrong URL → check if HA is running, try `http://` vs `https://` |
| 85 | - Network unreachable → ensure you're on the same network, or check VPN/Nabu Casa |
| 86 | |
| 87 | ## Step 4: Validate SSH Connectivity |
| 88 | |
| 89 | Test SSH access (required for `make pull` / `make push`). |
| 90 | |
| 91 | **IMPORTANT:** Always include `$SSH_USER@` in the SSH command. The `.env` has a separate |
| 92 | `SSH_USER` variable (usually `root`) — do NOT connect as the local macOS/Linux user. |
| 93 | |
| 94 | ```bash |
| 95 | source .env && ssh -o ConnectTimeout=5 -o BatchMode=yes "$SSH_USER@$HA_HOST" "echo ok" 2>&1 |
| 96 | ``` |
| 97 | |
| 98 | - **Success (`ok`):** Continue to auto-detect `HA_REMOTE_PATH`. |
| 99 | - **`Permission denied (publickey)`:** SSH key not authorized. Run: |
| 100 | ```bash |
| 101 | source .env && ssh-copy-id "$SSH_USER@$HA_HOST" |
| 102 | ``` |
| 103 | Or manually add `~/.ssh/id_rsa.pub` (or `id_ed25519.pub`) to the SSH add-on's |
| 104 | authorized keys in HA Settings → Add-ons → SSH & W |