Initial sync: memory, agents, commands, and gitignore

Syncs project memory, custom agents, and commands across machines.
Excludes secrets (settings.json), session state, and runtime files.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Chris
2026-06-11 09:19:24 -05:00
commit 33cab10cef
47 changed files with 1229 additions and 0 deletions
+15
View File
@@ -0,0 +1,15 @@
- [SSH directly to VMs](feedback_ssh_directly.md) — Use csader@VM_IP, not qm guest exec through Proxmox hosts
- [HA API access patterns](reference_ha_api_access.md) — REST/WebSocket APIs for automations, entity registry, history
- [Verify before bulk delete](feedback_verify_before_bulk_delete.md) — Confirm entities are actual duplicates before mass removal
- [Pixel 10 Pro Fold for notifications](user_notification_phone.md) — Use notify.mobile_app_pixel_10_pro_fold, not iPhone or notify.chris
- [House orientation & shade positions](user_house_orientation.md) — West door (225-315°), east windows (45-135°), per-shade close values
- [HA automation patterns](reference_ha_automation_patterns.md) — API patterns, scene save/restore, categories, weather/azimuth
- [NR migration status](project_nr_migration.md) — Which flows are in NR vs HA after 2026-03-28 migration
- [Backup before HA updates](feedback_backup_before_updates.md) — Always use backup:true when running update.install on add-ons
- [MantelMount control via Bond RF](reference_mantelmount.md) — Bond RF entities, contact sensor mapping, run-then-direction sequence
- [Zulip on VM 103](reference_zulip.md) — crew.chrissader.com, tus upload fix, post-start.sh after recreate
- [Caddyfile edits must preserve inode](feedback_caddyfile_inode.md) — Use sed/tee, not Python write(); restart container if inode broken
- [Check for stale/duplicate entities](feedback_stale_entity_check.md) — Re-paired devices create new entities; old named ones go stale and silently fail
- [HA Blue SSH access](reference_ha_blue_ssh.md) — Port 2222, user csader (not root), id_ed25519 key
- [HACS and Mushroom on HA Blue](reference_hacs_mushroom.md) — HACS, Mushroom, weatheralerts install details
- [Never use "new" as automation ID](feedback_automation_ids.md) — Use unique numeric IDs when creating automations via REST API
@@ -0,0 +1,11 @@
---
name: Never use "new" as automation ID
description: Creating HA automations via API with id "new" overwrites existing automations that also have id "new"
type: feedback
---
When creating automations via `POST /api/config/automation/config/new`, HA assigns the literal ID "new". If you create a second automation the same way, it overwrites the first.
**Why:** The bird waterer automation got overwritten by the hail automation because both had id "new".
**How to apply:** Always use a unique numeric ID (e.g., timestamp-based like `1712800000001`) when creating automations via the REST API. After creating with `/new`, immediately re-save with a proper ID and delete the "new" entry.
@@ -0,0 +1,11 @@
---
name: Always backup before HA add-on updates
description: Use backup:true parameter when running update.install on HA add-ons
type: feedback
---
Always pass `backup: true` when calling `update.install` on HA add-ons. This creates a snapshot before each update.
**Why:** User explicitly requested this as standard practice — safety net in case an update breaks something.
**How to apply:** Any time running firmware/add-on updates via the HA API, include `"backup": true` in the service call data.
@@ -0,0 +1,11 @@
---
name: Caddyfile edits must preserve inode
description: Python open().write() breaks Docker bind mounts by creating new inodes — use sed -i or tee instead
type: feedback
---
Never edit the Caddyfile (or any Docker bind-mounted file) with Python's `open(path, 'w').write()` — it creates a new inode and Docker keeps reading the old one.
**Why:** Docker bind mounts track the original file inode. Python's write creates a new file, so `caddy reload` reads stale content. This caused hours of debugging where Caddy appeared to ignore config changes.
**How to apply:** Use `sed -i` for substitutions or `cat newfile | tee /path/to/file > /dev/null` for full rewrites. If the inode is already broken, restart the container (`docker restart caddy`) to re-mount. Always verify with `docker exec caddy cat /etc/caddy/Caddyfile` after edits.
@@ -0,0 +1,11 @@
---
name: SSH directly to VMs
description: User prefers direct SSH to VMs (csader@IP) instead of going through Proxmox qm guest exec
type: feedback
---
SSH directly to VMs using `csader@<VM_IP>` instead of routing through Proxmox hosts with `qm guest exec`. Root SSH is blocked on VMs — use csader user with sudo when needed.
**Why:** User explicitly corrected this approach twice. Going through Proxmox is slower and unnecessary when direct SSH works.
**How to apply:** For any VM operations (.134, .122, .146, .172), SSH as csader directly. Only use Proxmox host SSH (root@.66/.67/.68) for host-level operations like `qm list`, `pct list`, `pct exec` for LXCs.
@@ -0,0 +1,11 @@
---
name: Check for stale/duplicate entities when automations partially fail
description: HA automations that notify but don't actuate devices — look for duplicate entities from re-paired devices
type: feedback
---
When an HA automation fires (notifications work) but device actions silently fail, check for duplicate entities. Devices that get re-paired create new entities with raw addresses (e.g., `switch.0xa4c138...`) while the old named entity goes stale.
**Why:** Chicken sprinkler automation sent notifications fine but `switch.turn_on` went to a dead entity. The working device had a new entity with a Zigbee address. Silent failure — no error in HA.
**How to apply:** When debugging partial automation failures, list all entities matching the device name and check `last_changed` dates. If the named entity hasn't changed in days but a raw-address entity is active, the device was re-paired. Fix by removing the stale entity and renaming the live one.
@@ -0,0 +1,11 @@
---
name: Verify duplicates before bulk entity cleanup
description: User wants confirmation that entities are actual duplicates before mass deletion
type: feedback
---
When cleaning up stale/duplicate HA entities, verify each `_N` suffixed entity actually has a newer counterpart before removing it. Don't assume all `_2` entities are stale — some may be the current active version if there's no `_3`.
**Why:** User stopped a bulk delete of 44 `_2` entities — only 5 of them were confirmed duplicates with `_3` counterparts. The other 39 were the active versions.
**How to apply:** Before any bulk entity cleanup, cross-reference suffixed entities to confirm duplicates exist. Only remove entities with a confirmed newer counterpart.
@@ -0,0 +1,29 @@
---
name: Node-RED flows still active
description: Which NR flows remain active vs migrated to HA after 2026-03-28 migration
type: project
---
Node-RED migration completed 2026-03-28. Most flows migrated to HA automations.
**Still in Node-RED (do not duplicate in HA):**
- Follow Me Alexa — Alexa device-specific voice command routing
- Presence — Room-level BLE/motion/bed presence tracking feeding input_select helpers
- Home Security System — Alarm mode handling (migration planned but needs discussion on triggers)
- Flow 1 — Alexa actionable notification support for theater mode
**Migrated to HA (disable in NR):**
- Goodnight, Lights, Climate, Blinds, Theater Mode, Wake Up
- Lights sub-flows (2026-03-28): Main Switch→Haiku Light, 3-way→Haiku Light, Auto Garage Lights (ratgdo doors), Outdoor+Garage Light Sync, Christmas Spheres Timer
**Deleted from NR:**
- Chicken Sprinkler, LLM Vision, Automatic Lights
**Why:** Consolidating automations into HA for easier management. NR Presence flow is foundational and complex — stays in NR for now.
**How to apply:** When working on automations, check whether the flow is in NR or HA to avoid conflicts. Presence-related input_selects are set by NR — HA automations can read them but shouldn't write to them.
**Removed integrations (2026-03-28):**
- Zigbee Lock Manager — replaced by Z2M direct, Lockly also removed (timeouts on battery lock)
- Neato, Konnected, Telegram — no entities, ghost integrations
- Front door lock codes managed on keypad, not via HA (Yale Assure SL sleeps too aggressively for remote code management)
@@ -0,0 +1,26 @@
---
name: Home Assistant API access patterns
description: How to query HA automations, entity registry, history, and other data not available via MCP tools
type: reference
---
The HA MCP tools (`mcp__home-assistant__*`) cover device control, entity states, and live context — but NOT automations, entity registry, history, logbook, or traces.
For those, use the HA APIs directly:
- **REST API** (via curl): `http://192.168.86.36:8123/api/...` with Bearer token from `.mcp.json` (`home-assistant.headers.Authorization`)
- `GET /api/states` — all entity states (filter by entity_id prefix for automations, etc.)
- `GET /api/config/automation/config/<id>` — full automation config (triggers, conditions, actions) by numeric ID from entity attributes
- `GET /api/history/period/<timestamp>?filter_entity_id=...` — historical state changes
- `GET /api/logbook/<timestamp>?entity=...` — logbook entries
- **WebSocket API** (`ws://192.168.86.36:8123/api/websocket`): needed for entity registry operations
- `config/entity_registry/remove` — delete stale/duplicate entities
- `config/entity_registry/list` — full entity registry (very large response)
- Requires `websockets` Python package (installed on Mac)
- **IMPORTANT**: Must set `max_size=10*1024*1024` on `websockets.connect()` — the entity registry response exceeds the default 1MB limit
- **Trace API** (`/api/trace/<entity_id>`): may return non-standard JSON or 404. Wrap in try/except and check raw response before parsing.
- **Auth token**: Available as `$HA_TOKEN` env var (set in settings.local.json). Use `Bearer $HA_TOKEN` in curl, or `os.environ['HA_TOKEN']` in Python.
**How to apply:** When user asks about automations, entity cleanup, or historical data, use these APIs rather than saying the MCP can't do it. Always use these patterns from the main conversation — subagents may not have Bash access.
@@ -0,0 +1,30 @@
---
name: HA automation management patterns
description: How to create/update HA automations via REST/WS API, scene save/restore, categories, and established patterns
type: reference
---
Automation configs are updated via POST (not PUT):
`POST http://192.168.86.36:8123/api/config/automation/config/<numeric_id>`
Key patterns established:
- **Notifications**: `notify.mobile_app_pixel_10_pro_fold` with `"image"` for snapshots and `"clickAction"` for deep links
- **TTS**: `tts.speak` targeting `tts.home_assistant_cloud` with `media_player_entity_id` (not deprecated `tts.google_translate_say`)
- **Sun azimuth**: `sun.sun` attribute `azimuth` for directional triggers (west door = 225-315°, east windows = 45-135°). East shades have NO temp condition; front door shade still requires >80°F.
- **Weather conditions**: `sensor.openweathermap_condition` states: sunny, clear-night, partlycloudy, cloudy, rainy, pouring, snowy, fog, lightning, lightning-rainy
- **Scene save/restore**: `scene.create` with `snapshot_entities` to save state, `scene.turn_on` to restore. Used for Theater Mode and Climate thermostat save/restore.
- **Enabling/disabling automations**: WebSocket API `config/entity_registry/update` with `disabled_by: null` to enable, `disabled_by: user` to disable
- **Categories**: WebSocket `config/category_registry/create` (scope: automation) and `config/entity_registry/update` with `categories: {automation: cat_id}`
**Automation categories** (scope: automation):
- Sprinklers, Shades & Blinds, Cameras & Security, Home Theater, Lights, 3D Printers, Garage, Fans, Climate, Routines, Severe Weather
**Gotchas:**
- Don't trigger Theater Mode on TV power — TV turns on for non-movie use. Only trigger via `input_boolean.theater_mode` toggle.
- Battery-powered Zigbee devices (locks) sleep aggressively — service calls that need a response (code queries) will timeout. Lock/unlock works because Z2M queues commands.
- Always use `backup: true` when calling `update.install` on add-ons.
- Wind gust entity is `sensor.openweathermap_wind_gust` (NOT `_wind_gust_speed`).
- `weather.get_forecasts` requires `?return_response` when called via REST API. Response is at `d['service_response']['weather.openweathermap']['forecast']`.
- Template references to NWS alerts must handle empty alerts list: use `| first | default({})` pattern, not `[0]`.
**How to apply:** Reference these patterns when creating or modifying HA automations.
@@ -0,0 +1,14 @@
---
name: HA Blue SSH access
description: How to SSH into Home Assistant Blue — port 2222, user csader, not root
type: reference
---
SSH to HA Blue: `ssh -p 2222 csader@192.168.86.36`
- Port 2222 (SSH add-on)
- User `csader` — root is blocked by AllowUsers
- Key: `~/.ssh/id_ed25519` (ed25519, csader@chrissader.com)
- Use `sudo` for privileged operations (e.g., HACS install)
**How to apply:** When needing to run commands on HA Blue directly (install HACS, check custom_components, etc.), use this SSH path.
@@ -0,0 +1,13 @@
---
name: HACS and Mushroom on HA Blue
description: HACS v2026.1.0 and Mushroom v5.1.1 installed on HA Blue, plus weatheralerts integration
type: reference
---
**HACS** (v2026.1.0): Installed 2026-04-04 via SSH (`sudo wget -O - https://get.hacs.xyz | sudo bash -`). Configured via HA UI with GitHub OAuth.
**Mushroom** (v5.1.1): Installed via HACS WebSocket API (`hacs/repository/download`, repo id `444350375`). Used on Mobile Dashboard Home view for greeting card with dynamic weather/alert display.
**Weatheralerts** (v2026.1.0): Installed via HACS 2026-04-11. Configured for Williamson County (zone TXZ173, county TXC491). 90s poll interval, 20s timeout. Entity: `sensor.weatheralerts_williamson_txz173_txc491`.
**How to apply:** If HACS disappears after an HA update, re-run the install script via SSH and re-add the integration in the UI. Mushroom and weatheralerts should survive since the files persist in custom_components.
@@ -0,0 +1,21 @@
---
name: MantelMount control via Bond RF bridge
description: How the MantelMount is controlled in HA — Bond RF entities, contact sensor mapping, command sequence
type: reference
---
MantelMount is controlled via a Bond RF bridge. No native HA integration — uses assumed_state entities.
**Entities:**
- `light.mm_down_up` — "Run Button" — toggle starts/stops the motor
- `fan.mm_run` — direction control. ON = down, OFF = up
- `binary_sensor.tv_mount_angle_contact` — Zigbee door/tilt sensor. ON = mount down/extended, OFF = mount up/retracted
**Command sequence:** Toggle run button FIRST, then set direction 1s later. This is how the MM controller works — run first, then direction.
**Automation** (`automation.mantelmount_up_down`):
- Triggers on Samsung TV on/off
- TV-off condition: `switch.tv_power` (Zigbee power strip L4) must be on
- Uses contact sensor as guard (skip if already in correct position) and for retry verification after 20s
**How to apply:** When modifying mantel mount automation, always preserve run-then-direction sequence and contact sensor verification.
@@ -0,0 +1,17 @@
---
name: Zulip on VM 103
description: Zulip chat server config, tus upload fix, Caddy/Authelia setup at crew.chrissader.com
type: reference
---
Zulip runs on VM 103 (192.168.86.122) port 8085, accessible at crew.chrissader.com.
**Compose**: `/opt/docker/stacks/zulip/` (project name `zulip-docker` in `.env` to preserve volumes)
**Caddy**: Uses `route` block with `@exempt path /api/* /json/* /user_uploads/*` matcher and `reverse_proxy @exempt` before `forward_auth`. The `route` directive is critical — without it, Caddy reorders directives and runs `forward_auth` first regardless of source order. The `handle` block approach also doesn't work. Authelia also has bypass rules for the same paths as belt-and-suspenders.
**Tus upload fix**: Zulip's puppet overwrites `/etc/nginx/zulip-include/app` on container start. The tus location block needs `proxy_redirect http://crew.chrissader.com https://crew.chrissader.com;` added (inlined proxy config, no `include proxy`). Without this, tusd generates `http://` Location headers and browsers block the PATCH as mixed content.
**How to apply:** After any `docker compose up` that recreates the zulip container, run `/opt/docker/stacks/zulip/post-start.sh` to re-apply the nginx fix.
**LOADBALANCER_IPS**: Includes `172.26.0.0/16` (Docker bridge) so nginx trusts `X-Forwarded-Proto` from Caddy.
@@ -0,0 +1,16 @@
---
name: House window orientations and shade close positions
description: Window shade orientations, azimuth ranges, and fully-closed position values per shade
type: user
---
Chris's front door faces due west. The sun hits it in the afternoon/evening. Auto Front Door Shade automation uses azimuth 225°-315° range.
Living room window shades (1-5) face east. Sun-Tracking automation uses azimuth 45°-135° range. No temperature condition — fires on sun angle + clear weather only.
Fully closed shade positions (not all are 100%):
- Shades 1 & 2: position 100
- Shades 3 & 4: position 35
- Shade 5: position 60
House is in Round Rock, TX (zip 78681).
@@ -0,0 +1,9 @@
---
name: Chris uses Pixel 10 Pro Fold for HA notifications
description: Primary notification target is notify.mobile_app_pixel_10_pro_fold, not iPhone 15 or notify.chris
type: user
---
Chris's primary phone is a Pixel 10 Pro Fold. Use `notify.mobile_app_pixel_10_pro_fold` for HA push notifications — not `notify.chris` (broken/legacy) or `notify.mobile_app_iphone_15`.
For HA companion app deep links, use `clickAction` with dashboard paths like `/mobile-dashboard/sprinklers`. Snapshots attach via `"image": "/api/image_proxy/image.<entity>"`.