|
| 1 | +# Fork Development Workflow |
| 2 | + |
| 3 | +This branch (`addon-repo`) is the **default branch** on this fork. It serves as the HA add-on repository for testing PR branches on a real Home Assistant instance. |
| 4 | + |
| 5 | +**PRs are NOT based on this branch.** Feature branches go to `upstream/master` independently. This branch is always force-pushed to mirror whatever feature branch is being tested. |
| 6 | + |
| 7 | +> **A backup of this file lives at `~/.ha-mcp-fork-dev.md`.** |
| 8 | +> If `git reset --hard` wipes it, restore with: `cp ~/.ha-mcp-fork-dev.md ~/ha-mcp-fork/FORK-DEV.md` |
| 9 | +
|
| 10 | +## TL;DR — Use the Script |
| 11 | + |
| 12 | +The full restore + rename workflow is automated in `local/apply-fork-overrides.sh` (gitignored, survives `git reset --hard`; backup at `~/.ha-mcp-fork-overrides.sh`). |
| 13 | + |
| 14 | +```bash |
| 15 | +# Bump Fork-Dev (default cycle): |
| 16 | +./local/apply-fork-overrides.sh --pr 1126 --bump fork-dev |
| 17 | + |
| 18 | +# Bump NabuForkDev (when explicitly requested): |
| 19 | +./local/apply-fork-overrides.sh --pr 1184 --bump nabu --version dev4 |
| 20 | + |
| 21 | +# Smoke-test without pushing: |
| 22 | +./local/apply-fork-overrides.sh --pr 1184 --bump nabu --no-push |
| 23 | +``` |
| 24 | + |
| 25 | +Without `--version`, the script auto-increments the chosen addon's `dev<N>`. It runs the verification grep at the end and exits non-zero if any rename was missed — so when upstream adds a new identifier (like `oauth.py` arriving via PR #1184), the failure is loud and you add a new sed pattern to the script. |
| 26 | + |
| 27 | +The rest of this document describes what the script does, for cases where you need to debug or run a step manually. |
| 28 | + |
| 29 | +## Two Addons Live Here |
| 30 | + |
| 31 | +This repository ships **two** HA add-ons — both must be configured correctly each cycle: |
| 32 | + |
| 33 | +| Addon | Directory | Renamed To | Purpose | |
| 34 | +|-------|-----------|------------|---------| |
| 35 | +| **Fork-Dev** | `homeassistant-addon-dev/` | `Fork-Dev` | Main MCP server (the thing under PR test) | |
| 36 | +| **NabuForkDev** | `homeassistant-addon-webhook-proxy/` | `NabuForkDev` | Remote-access webhook proxy | |
| 37 | + |
| 38 | +Both addon configs are restored to their upstream defaults by `git reset --hard`, so each cycle re-applies the rename + version + url + (Fork-Dev only) `image:` removal. |
| 39 | + |
| 40 | +## Version Bumping Rule |
| 41 | + |
| 42 | +**Every addon-repo update bumps the dev version of exactly one addon — never both at once.** |
| 43 | + |
| 44 | +- **Default:** bump Fork-Dev (`homeassistant-addon-dev/config.yaml`). NabuForkDev's version stays put. |
| 45 | +- **When user explicitly asks** (e.g., "bump nabu fork dev too" / "push NabuForkDev to dev1"): bump NabuForkDev instead. Fork-Dev's version stays put. |
| 46 | + |
| 47 | +Versions follow `dev<N>` (currently Fork-Dev around dev100, NabuForkDev at dev0). HA Supervisor only rebuilds the addon whose version changed, so leaving the other one alone avoids spurious rebuilds. |
| 48 | + |
| 49 | +## How It Works |
| 50 | + |
| 51 | +1. HA Supervisor clones this repo's default branch (`addon-repo`) |
| 52 | +2. It scans the repo for addon directories, finds both `homeassistant-addon-dev/config.yaml` (Fork-Dev) and `homeassistant-addon-webhook-proxy/config.yaml` (NabuForkDev) |
| 53 | +3. For Fork-Dev, it builds the Docker image from `homeassistant-addon-dev/Dockerfile` and runs the code from `homeassistant-addon-dev/src/ha_mcp/` |
| 54 | +4. For NabuForkDev, it builds from `homeassistant-addon-webhook-proxy/Dockerfile` (no `image:` field upstream — already builds locally) |
| 55 | + |
| 56 | +## Dual `src/` Directories - READ THIS |
| 57 | + |
| 58 | +The repo has **two separate `src/ha_mcp/` directories**: |
| 59 | + |
| 60 | +``` |
| 61 | +ha-mcp-fork/ |
| 62 | + src/ha_mcp/ <-- repo root source (what PRs modify) |
| 63 | + homeassistant-addon-dev/src/ha_mcp/ <-- addon source (what HA actually runs) |
| 64 | +``` |
| 65 | + |
| 66 | +**The Dockerfile copies from `homeassistant-addon-dev/src/`, NOT from the root `src/`.** If you only edit files in the root `src/`, the addon will still run the OLD code. You must always sync changes into `homeassistant-addon-dev/src/ha_mcp/`. |
| 67 | + |
| 68 | +This is the #1 cause of "I pushed but the old code is still running" issues. |
| 69 | + |
| 70 | +## Switching to a Different PR Branch |
| 71 | + |
| 72 | +```bash |
| 73 | +git -C ~/ha-mcp-fork checkout addon-repo |
| 74 | +git -C ~/ha-mcp-fork fetch upstream |
| 75 | +git -C ~/ha-mcp-fork fetch upstream pull/<PR>/head:pr-<PR> --force |
| 76 | + |
| 77 | +# Reset to upstream/master, then merge the PR on top |
| 78 | +git -C ~/ha-mcp-fork reset --hard upstream/master |
| 79 | +git -C ~/ha-mcp-fork merge pr-<PR> --no-ff -m "Merge branch 'pr-<PR>' into addon-repo" |
| 80 | +``` |
| 81 | + |
| 82 | +### After `git reset --hard` - CRITICAL STEPS |
| 83 | + |
| 84 | +The reset wipes addon-specific files that don't exist on feature branches. You **must** restore them: |
| 85 | + |
| 86 | +```bash |
| 87 | +# 1. Restore this documentation (gets wiped by reset!) |
| 88 | +cp ~/.ha-mcp-fork-dev.md FORK-DEV.md |
| 89 | + |
| 90 | +# 2. Restore the README banner |
| 91 | +# Add at the very top of README.md: |
| 92 | +# > **This is a personal fork.** See [`FORK-DEV.md`](FORK-DEV.md) for the addon-repo workflow. |
| 93 | + |
| 94 | +# 3. Copy build files into the Fork-Dev addon directory |
| 95 | +cp pyproject.toml homeassistant-addon-dev/ |
| 96 | +cp uv.lock homeassistant-addon-dev/ |
| 97 | +cp homeassistant-addon/start.py homeassistant-addon-dev/ |
| 98 | + |
| 99 | +# 4. Copy source code (the critical sync step!) |
| 100 | +rm -rf homeassistant-addon-dev/src/ha_mcp |
| 101 | +cp -r src/ha_mcp homeassistant-addon-dev/src/ha_mcp |
| 102 | + |
| 103 | +# 5. Fix the Dockerfile (upstream references wrong path) |
| 104 | +sed -i 's|COPY homeassistant-addon/start.py|COPY start.py|' homeassistant-addon-dev/Dockerfile |
| 105 | + |
| 106 | +# 6. Fork-Dev config.yaml — homeassistant-addon-dev/config.yaml: |
| 107 | +# - Remove the `image:` line (forces local build instead of pulling from ghcr.io) |
| 108 | +# - name: "Fork-Dev" |
| 109 | +# - url: "https://github.com/kingpanther13/ha-mcp-fork" |
| 110 | +# - version: bump dev<N> → dev<N+1> (UNLESS this cycle is bumping NabuForkDev instead) |
| 111 | + |
| 112 | +# 7. NabuForkDev config.yaml — homeassistant-addon-webhook-proxy/config.yaml: |
| 113 | +# - name: "NabuForkDev" |
| 114 | +# - url: "https://github.com/kingpanther13/ha-mcp-fork" |
| 115 | +# - slug: "ha_mcp_webhook_proxy" → "ha_mcp_webhook_proxy_dev" |
| 116 | +# - version: keep current dev<N> unchanged (UNLESS user asked to bump this one) |
| 117 | +# - No `image:` field upstream, so nothing to remove |
| 118 | + |
| 119 | +# 8. NabuForkDev custom-component renames — REQUIRED so it can coexist with the |
| 120 | +# prod webhook-proxy on the same HA instance (different slug, different |
| 121 | +# custom_component domain, different file paths). Apply EVERY cycle, since |
| 122 | +# git reset --hard wipes them too: |
| 123 | +cd ~/ha-mcp-fork/homeassistant-addon-webhook-proxy |
| 124 | + |
| 125 | +# 8a. Rename the integration directory (HA loads custom_components by dir name == domain) |
| 126 | +git mv mcp_proxy mcp_proxy_dev |
| 127 | + |
| 128 | +# 8b. Edit Dockerfile: COPY mcp_proxy /opt/mcp_proxy → COPY mcp_proxy_dev /opt/mcp_proxy_dev |
| 129 | + |
| 130 | +# 8c. Bulk-rewrite identifiers in start.py — covers paths, ALL notification IDs |
| 131 | +# (mcp_proxy_restart, mcp_proxy_update, mcp_proxy_regen_stuck, …), |
| 132 | +# domain checks and config-flow handler: |
| 133 | +sed -i \ |
| 134 | + -e 's|/opt/mcp_proxy|/opt/mcp_proxy_dev|g' \ |
| 135 | + -e 's|/config/custom_components/mcp_proxy|/config/custom_components/mcp_proxy_dev|g' \ |
| 136 | + -e 's|/config/\.mcp_proxy_config\.json|/config/.mcp_proxy_dev_config.json|g' \ |
| 137 | + -e 's|"mcp_proxy_restart"|"mcp_proxy_dev_restart"|g' \ |
| 138 | + -e 's|"mcp_proxy_update"|"mcp_proxy_dev_update"|g' \ |
| 139 | + -e 's|"mcp_proxy_regen_stuck"|"mcp_proxy_dev_regen_stuck"|g' \ |
| 140 | + -e 's|domain") == "mcp_proxy"|domain") == "mcp_proxy_dev"|g' \ |
| 141 | + -e 's|"handler": "mcp_proxy"|"handler": "mcp_proxy_dev"|g' \ |
| 142 | + start.py |
| 143 | +# After running, verify with: grep -nE '"mcp_proxy[^"]*"' start.py |
| 144 | +# Every match must end in `_dev` or `_dev_…`. |
| 145 | + |
| 146 | +# 8d. Rewrite identifiers in the renamed integration (covers oauth.py from |
| 147 | +# PR #1184 — OAUTH_BASE and SECRET_FILE): |
| 148 | +sed -i \ |
| 149 | + -e 's|DOMAIN = "mcp_proxy"|DOMAIN = "mcp_proxy_dev"|g' \ |
| 150 | + -e 's|/config/\.mcp_proxy_config\.json|/config/.mcp_proxy_dev_config.json|g' \ |
| 151 | + -e 's|OAUTH_BASE = "/api/mcp_proxy/oauth"|OAUTH_BASE = "/api/mcp_proxy_dev/oauth"|g' \ |
| 152 | + -e 's|/config/\.mcp_proxy_oauth_secret|/config/.mcp_proxy_dev_oauth_secret|g' \ |
| 153 | + mcp_proxy_dev/__init__.py mcp_proxy_dev/config_flow.py mcp_proxy_dev/oauth.py |
| 154 | + |
| 155 | +# 8e. Edit mcp_proxy_dev/manifest.json: |
| 156 | +# - "domain": "mcp_proxy" → "mcp_proxy_dev" |
| 157 | +# - "name": "MCP Webhook Proxy" → "MCP Webhook Proxy (NabuForkDev)" |
| 158 | + |
| 159 | +# 8f. Edit mcp_proxy_dev/strings.json + mcp_proxy_dev/config_flow.py + |
| 160 | +# mcp_proxy_dev/oauth.py (consent-page <h1>): |
| 161 | +# - all "MCP Webhook Proxy" user-visible titles → "MCP Webhook Proxy (NabuForkDev)" |
| 162 | + |
| 163 | +# 8g. Patch DOCS.md to match — replace `/api/mcp_proxy/oauth`, |
| 164 | +# `/config/.mcp_proxy_oauth_secret`, `/config/custom_components/mcp_proxy/`, |
| 165 | +# and `/config/.mcp_proxy_config.json` with their `_dev` equivalents. |
| 166 | + |
| 167 | +# 8h. Final verification — every command below must print nothing: |
| 168 | +grep -rnE 'mcp_proxy"|ha_mcp_webhook_proxy"|/config/custom_components/mcp_proxy/|/config/\.mcp_proxy_config\.json|/config/\.mcp_proxy_oauth_secret|/api/mcp_proxy/oauth|/opt/mcp_proxy"' . | grep -v __pycache__ |
| 169 | +``` |
| 170 | + |
| 171 | +### Why These Files Are Needed |
| 172 | + |
| 173 | +| File | Why | |
| 174 | +|------|-----| |
| 175 | +| `homeassistant-addon-dev/pyproject.toml` | Dockerfile `COPY pyproject.toml` - needed for `uv sync` | |
| 176 | +| `homeassistant-addon-dev/uv.lock` | Dockerfile `COPY uv.lock` - pinned dependencies | |
| 177 | +| `homeassistant-addon-dev/start.py` | Dockerfile `COPY start.py /` - addon entrypoint | |
| 178 | +| `homeassistant-addon-dev/src/ha_mcp/` | Dockerfile `COPY src/` - the actual server code | |
| 179 | +| `homeassistant-addon-dev/Dockerfile` | Must use `COPY start.py /` not `COPY homeassistant-addon/start.py /` | |
| 180 | +| `homeassistant-addon-webhook-proxy/mcp_proxy_dev/` | Integration directory renamed from `mcp_proxy/` so HA registers it under domain `mcp_proxy_dev` (HA loads custom_components by dir name == domain). Without this, NabuForkDev collides with the prod webhook-proxy. | |
| 181 | +| `homeassistant-addon-webhook-proxy/Dockerfile` | `COPY mcp_proxy_dev /opt/mcp_proxy_dev` (matches renamed dir) | |
| 182 | +| `homeassistant-addon-webhook-proxy/config.yaml` | `slug: ha_mcp_webhook_proxy_dev` so HA Supervisor treats it as a separate addon from the prod webhook-proxy | |
| 183 | +| `FORK-DEV.md` | This file - backup at `~/.ha-mcp-fork-dev.md` | |
| 184 | + |
| 185 | +The upstream Dockerfile is designed for CI builds where the build context is the repo root. When HA Supervisor builds locally, the build context is `homeassistant-addon-dev/` itself, so all paths must be relative to that directory. |
| 186 | + |
| 187 | +### Fork-Dev config.yaml: `image` Field |
| 188 | + |
| 189 | +- **With `image:` field**: HA pulls a pre-built image from ghcr.io (upstream code, NOT your branch) |
| 190 | +- **Without `image:` field**: HA builds locally from the Dockerfile (your branch code) |
| 191 | +- For testing fork branches, the `image:` field **must be removed** |
| 192 | + |
| 193 | +NabuForkDev's upstream config has no `image:` field — nothing to remove there. |
| 194 | + |
| 195 | +## Forcing a Rebuild |
| 196 | + |
| 197 | +HA Supervisor only rebuilds the addon whose version changed. To trigger a rebuild of one addon: |
| 198 | + |
| 199 | +- Bump that addon's `version:` in its `config.yaml` (default cycle: Fork-Dev only). |
| 200 | +- Force-push to `addon-repo` (safe — this branch is never a PR base). |
| 201 | +- HA Supervisor will detect the version change and offer a rebuild for that specific addon. |
| 202 | + |
| 203 | +## Full Deploy Workflow (Copy-Paste) |
| 204 | + |
| 205 | +```bash |
| 206 | +# Fetch latest |
| 207 | +git -C ~/ha-mcp-fork checkout addon-repo |
| 208 | +git -C ~/ha-mcp-fork fetch upstream |
| 209 | +git -C ~/ha-mcp-fork fetch upstream pull/<PR>/head:pr-<PR> --force |
| 210 | + |
| 211 | +# Reset and merge PR |
| 212 | +git -C ~/ha-mcp-fork reset --hard upstream/master |
| 213 | +git -C ~/ha-mcp-fork merge pr-<PR> --no-ff -m "Merge branch 'pr-<PR>' into addon-repo" |
| 214 | + |
| 215 | +# Restore docs and Fork-Dev addon files |
| 216 | +cd ~/ha-mcp-fork |
| 217 | +cp ~/.ha-mcp-fork-dev.md FORK-DEV.md |
| 218 | +cp pyproject.toml homeassistant-addon-dev/ |
| 219 | +cp uv.lock homeassistant-addon-dev/ |
| 220 | +cp homeassistant-addon/start.py homeassistant-addon-dev/ |
| 221 | +rm -rf homeassistant-addon-dev/src/ha_mcp |
| 222 | +cp -r src/ha_mcp homeassistant-addon-dev/src/ha_mcp |
| 223 | +sed -i 's|COPY homeassistant-addon/start.py|COPY start.py|' homeassistant-addon-dev/Dockerfile |
| 224 | + |
| 225 | +# Edit homeassistant-addon-dev/config.yaml: |
| 226 | +# - remove `image:` line |
| 227 | +# - name: "Fork-Dev" |
| 228 | +# - url: fork |
| 229 | +# - bump version (or hold if NabuForkDev is the bump target this cycle) |
| 230 | + |
| 231 | +# Edit homeassistant-addon-webhook-proxy/config.yaml: |
| 232 | +# - name: "NabuForkDev" |
| 233 | +# - slug: "ha_mcp_webhook_proxy_dev" |
| 234 | +# - url: fork |
| 235 | +# - hold version (or bump if user requested) |
| 236 | + |
| 237 | +# Apply NabuForkDev coexistence renames (every cycle, since reset wipes them): |
| 238 | +cd ~/ha-mcp-fork/homeassistant-addon-webhook-proxy |
| 239 | +git mv mcp_proxy mcp_proxy_dev |
| 240 | +sed -i 's|COPY mcp_proxy /opt/mcp_proxy|COPY mcp_proxy_dev /opt/mcp_proxy_dev|' Dockerfile |
| 241 | +sed -i \ |
| 242 | + -e 's|/opt/mcp_proxy|/opt/mcp_proxy_dev|g' \ |
| 243 | + -e 's|/config/custom_components/mcp_proxy|/config/custom_components/mcp_proxy_dev|g' \ |
| 244 | + -e 's|/config/\.mcp_proxy_config\.json|/config/.mcp_proxy_dev_config.json|g' \ |
| 245 | + -e 's|"mcp_proxy_restart"|"mcp_proxy_dev_restart"|g' \ |
| 246 | + -e 's|domain") == "mcp_proxy"|domain") == "mcp_proxy_dev"|g' \ |
| 247 | + -e 's|"handler": "mcp_proxy"|"handler": "mcp_proxy_dev"|g' \ |
| 248 | + start.py |
| 249 | +sed -i \ |
| 250 | + -e 's|DOMAIN = "mcp_proxy"|DOMAIN = "mcp_proxy_dev"|g' \ |
| 251 | + -e 's|/config/\.mcp_proxy_config\.json|/config/.mcp_proxy_dev_config.json|g' \ |
| 252 | + mcp_proxy_dev/__init__.py mcp_proxy_dev/config_flow.py |
| 253 | +# Then by hand: edit mcp_proxy_dev/manifest.json (domain, name) + |
| 254 | +# mcp_proxy_dev/strings.json (titles) + mcp_proxy_dev/config_flow.py (titles) |
| 255 | +# to "MCP Webhook Proxy (NabuForkDev)" — see step 8e/8f above. |
| 256 | +cd ~/ha-mcp-fork |
| 257 | + |
| 258 | +# Add README banner (above existing content): |
| 259 | +# > **This is a personal fork.** See [`FORK-DEV.md`](FORK-DEV.md) for the addon-repo workflow. |
| 260 | + |
| 261 | +git -C ~/ha-mcp-fork add -A |
| 262 | +git -C ~/ha-mcp-fork commit -m "chore: reset addon-repo to upstream master + PR #<PR> only, dev<N>" |
| 263 | +git -C ~/ha-mcp-fork push origin addon-repo --force |
| 264 | +``` |
| 265 | + |
| 266 | +## When User Asks to Bump NabuForkDev Instead |
| 267 | + |
| 268 | +If a cycle's request is "bump nabu casa proxy too" / "push NabuForkDev to dev<N>": |
| 269 | + |
| 270 | +1. Same merge + restore steps as above. |
| 271 | +2. **Hold** Fork-Dev's `version:` at its current value. |
| 272 | +3. **Bump** NabuForkDev's `version:` to the next dev number. |
| 273 | +4. Commit message reflects the bump target, e.g., `chore: addon-repo refresh, NabuForkDev dev<N>`. |
0 commit comments