← Commit history

Delete skills/hydrogen-ports

Kyle Bergstedt ·770c0cc77e ·1mo ago ·parent 10bca52
1 file changed −259
skills/hydrogen-ports/SKILL.mddeleted−259
@@ -1,259 +0,0 @@-----name: hydrogen-ports-description: How Hydrogen does port forwarding between your WSL2 workspace and your Windows machine — WSL2's automatic `0.0.0.0` localhost-forwarding (no port map to declare), the code-server `/proxy/<port>/` URL pattern that exposes any internal port, the port-forward registry for `127.0.0.1`-only services that WSL2 won't auto-forward, and the PortMappingsDialog UI. Use when the user asks "why isn't my server reachable", "how do I expose port X", "what's localhost:7380", "register a port", "auto-forward a port", or "the dynamic port dialog". Trigger words — port forwarding, ports, ah ports, container port, proxy port, code-server proxy, /proxy/, port mappings dialog, port hints, auto forward, expose port, register port, host port, dynamic port, ports.json, PortConfig, port resolver, localhost port not working.------# Hydrogen Ports — forwarding workspace services to your Windows host--The Hydrogen workspace is the WSL2 distro `Adom-Workspace`.-There is **no port mapping to declare** — WSL2 auto-forwards listeners for you.-Any service that binds `0.0.0.0:<port>` inside the distro is reachable at-`localhost:<sameport>` on Windows automatically. code-server itself binds-`0.0.0.0:7380`, so `localhost:7380` on Windows just works. For browser-facing-HTTP/WS, code-server's `/proxy/<port>/` URL pattern is still preferred and still-exposes any internal port. For the cases WSL2 auto-forward can't cover-(`127.0.0.1`-only listeners, or when auto-forward is flaky), Hydrogen's port-forward-registry creates a real host-side proxy on demand.--## The first rule: bind `0.0.0.0`--| Bind address inside distro | Reachable on Windows? |-|----------------------------|------------------------|-| `0.0.0.0:N` (all interfaces) | YES — `localhost:N` automatically |-| `127.0.0.1:N` (loopback only) | NO — WSL2 won't forward it |--So before you do anything else: **make your service bind `0.0.0.0`.** For most-dev servers that's a flag (`--host 0.0.0.0`, `vite --host`, `HOST=0.0.0.0`,-`server.address("0.0.0.0")`). Once it binds `0.0.0.0`, it auto-forwards — no-registration needed.--## The code-server proxy URL pattern--Any service listening on port N inside the distro is reachable at:--```-http://localhost:7380/proxy/N/-```--This works for HTTP services. WebSockets work too (`ws://localhost:7380/proxy/N/`).-No port mapping needed, and it works for `0.0.0.0` AND `127.0.0.1`-bound-services (code-server is inside the distro, so it reaches loopback listeners-that Windows can't). This is the preferred path for anything you open in a-browser.--Examples:-- Your dev server on port 5173 → `http://localhost:7380/proxy/5173/`-- The relay HTTP server on port 8766 → `http://localhost:7380/proxy/8766/`-- adom-vscode's API on port 8821 → `http://localhost:7380/proxy/8821/`--**This is how everything-inside-the-distro reaches everything-outside.** Inside-the distro, services that need to talk to "the host" use `127.0.0.1:<port>` —-WSL2 mirrored networking shares loopback with the Windows host — for Hydrogen's own-services (Hydrogen's live control URL is in `~/.adom/hydrogen-control-url`), and the proxy-URL for everything else.--## The port-forward registry (for what auto-forward can't cover)--Auto-forward handles the common case. You still need the registry — Hydrogen's-port-forward registry, serviced by the port-watcher daemon (see-`hydrogen-port-watcher`) — when:--- The service binds **`127.0.0.1` only** and you can't change it (some OAuth-  callback servers, some native tools). WSL2 won't auto-forward loopback-only-  listeners; the registry creates a real host proxy that reaches them through-  code-server.-- WSL2 localhost-forwarding is **lagging or broken** for a port (a real Hydrogen-  failure mode: "code-server alive in distro but Windows can't reach-  127.0.0.1:7380"). The registry gives a reliable host-side proxy that doesn't-  depend on WSL2's forwarder.--Decision order:-1. **Bind `0.0.0.0`** → auto-forwarded, done.-2. Can't bind `0.0.0.0` (loopback-only), or auto-forward is unreliable →-   **register the port** so Hydrogen proxies it.--### Register a port (from inside your workspace)--```bash-# Tell Hydrogen: "please bind localhost:5555 on Windows and forward into the distro"-adom-cli port-forward register 5555 --name "oauth-cb" --reason "127.0.0.1-only oauth callback" --visibility external-```--Visibility options:-- `external` — bind `localhost:5555` on Windows via an Hydrogen-managed proxy AND-  keep the `/proxy/` URL working. Best for OAuth callbacks, native clients,-  loopback-only servers.-- `internal` — proxy URL only, no host binding. Best for webview panels that-  don't need a separate host port.-- `either` — let Hydrogen decide based on heuristics (defaults to external).--### Unregister-```bash-adom-cli port-forward unregister 5555-```--### List-```bash-adom-cli port-forward list-```--## The Port Mappings dialog--Open via: Hydrogen Adom menu → "Port Mappings", or `POST http://127.0.0.1:47084/setup/panel/show`-then navigate to the Ports tab. Shows:--- **Auto-forwarded ports** — `0.0.0.0` listeners WSL2 is mirroring to Windows-- **Registered ports** — anything you've registered via `port-forward register`-  (Hydrogen-managed host proxies, for loopback-only / unreliable cases)--Each row shows the direct URL (`http://localhost:<port>`) AND the proxy URL-(`http://localhost:7380/proxy/<port>/`). Click either to open in your browser-via the Browser Picker.--## Hydrogen's host-side port registry--Hydrogen reads/writes its host-side port assignments at-`%APPDATA%\hydrogen-desktop\ports.json`. The `PortConfig` struct-(`hydrogen-control/src/ports.rs`) holds exactly four service ports —-`code_server`, `proxy`, `control`, `cdp` — plus the bind `hostname`. There are-no relay-WS / relay-HTTP host ports in `PortConfig`: under WSL2 the relay binds-**8765 (WS) / 8766 (HTTP) inside the distro**, reached at the same port on-Windows (mirrored loopback) or via `/proxy/8766/`, and discovered from-`~/.adom/cli-relay-ports.json` inside the distro. There is no host 47081/47082-listener.--Defaults (you can override via ports.json):--| Service | Default host port |-|---------|-------------------|-| code-server | 7380 |-| Discovery server | 47080 |-| Reverse proxy (`proxy`) | 47083 |-| Hydrogen control API (`control`) | 47084 |-| WebView2 CDP (`cdp`) | 47085 |-| KiCad bridge | **dynamic** (adom-bridge-cli picks at bridge launch) |-| Fusion bridge | **dynamic** (adom-bridge-cli picks at bridge launch) |-| Puppeteer bridge | **dynamic** (adom-bridge-cli picks at bridge launch) |--**Conflict resolution is NOT "next sequential port."** On startup-`PortConfig::resolve_available()` checks `proxy`, `control`, and `cdp`; if a-preferred fixed port is taken, Hydrogen binds an **ephemeral `127.0.0.1:0`** port (the-OS hands back a guaranteed-free one outside any HNS reservation) and persists it-to `ports.json`. It does **not** walk to 47086, 47087, … — HNS reserves-contiguous chunks invisible to netstat, so a walk would march into the next-reserved block. `code_server` is **exempt** and never resolved (it's tied to the-distro's mirrored port). So a busy box does NOT predictably land on-47083/47085 — the AI must discover the live ports.--**Never hardcode `127.0.0.1:9001` in distro code** — that was the old default-and has since moved. To find the real runtime ports, hit **`GET /ports`** on the-control API (default `127.0.0.1:47084`) — it returns-`{code_server, proxy, control, cdp, hostname}` straight from the resolved-`PortConfig` (`hydrogen-app/src/lib.rs` `get_ports`). `ports.json` is the single source-of truth every consumer reads.--## Discovering Hydrogen itself: the three-rung ladder--Because `control`/`proxy`/`cdp` can rebind to ephemeral ports, anything that-needs to FIND a running Hydrogen walks this ladder (static defaults are only-rung zero, never an assumption):--1. **Local files (authoritative when present).**-   - Windows side: `%APPDATA%\hydrogen-desktop\ports.json` (written every-     launch by `resolve_available()`).-   - Inside the distro: `~/.adom/hydrogen-control-url` (full live control URL)-     and `~/.adom/hydrogen-ports.json` (all four ports), both stamped by-     Hydrogen into the workspace. Adom Bridge's own direct API is at-     `~/.adom/direct-api-port` (stable 24680 since ab 2.0.27, legacy 47200) and the relay at-     `~/.adom/cli-relay-ports.json` (8765 WS / 8766 HTTP).-2. **Verify liveness AND identity.** A port answering `/health` is not proof-   it is THIS install: a zombie from an uninstalled copy can still be serving-   (a real observed failure). `GET /buildinfo` returns `instance_id`, `pid`,-   and `install_path`; check they match what you expect before trusting a-   discovered port.-3. **Cloud KV (works even when local files are unreachable).** On every-   launch, and every 4 hours after, Hydrogen publishes its live runtime-   identity to the Adom cloud KV (Carbon):--   - Key: `hydrogen.runtime.<machine>` (machine = lowercase-     `COMPUTERNAME`, sanitized to `[a-z0-9_]`).-   - Value: a JSON string:-     `{host, control, proxy, cdp, code_server, instance_id, pid, install_path, version, ts}`.-   - Read it: `GET https://carbon.adom.inc/user` (session token or API key-     auth) then `body.hydrogen_preferences.settings["hydrogen.runtime.<machine>"]`.-   - Freshness: compare `ts` (unix seconds) to now; the heartbeat refreshes it-     every 4 hours, so a `ts` older than ~5 hours means that instance is-     probably gone. Always confirm by hitting `/buildinfo` on the advertised-     port and matching `instance_id`.--   Adom Bridge publishes its container connection the same way-   (`bridge.container.<id>`, legacy `desktop.container.<id>` until ab's rename ships). This is what lets a cloud container, another-   machine, or a fresh install find the user's running desktop apps without-   port scanning.--## Inside vs outside — which URL to use--| You're calling from | To reach a service on port N | Use |-|---------------------|------------------------------|-----|-| Distro shell / app | Another distro service | `http://localhost:N` |-| Distro app | The Windows host | `http://127.0.0.1:N` (WSL2 mirrored networking shares loopback with the host — no gateway IP, no firewall rule) |-| Windows browser | A `0.0.0.0`-bound distro service | `http://localhost:N` (auto-forwarded) |-| Windows browser | Any distro service (HTTP/WS) | `http://localhost:7380/proxy/N/` (proxy URL, preferred) |-| Windows browser | A `127.0.0.1`-only distro service | `http://localhost:N` (only after `port-forward register ... external`) |-| Distro | Hydrogen's own control API (on Windows host) | `$(cat ~/.adom/hydrogen-control-url)` → `http://127.0.0.1:<dynamic>` (port is dynamic per launch) |--## Common bugs--**"My dev server at port 5173 doesn't load in Chrome"**-- Most likely it's bound `127.0.0.1` only. Restart it bound to `0.0.0.0`-  (e.g. `vite --host`) and it auto-forwards to `localhost:5173`.-- OR use the proxy URL: `http://localhost:7380/proxy/5173/`.-- If it IS on `0.0.0.0` but still unreachable, WSL2's forwarder may be lagging —-  register it: `adom-cli port-forward register 5173 --visibility external`.--**"OAuth callback fails with refused connection"**-- The provider is hitting `http://localhost:5555/callback` but the callback-  server is loopback-only inside the distro, so WSL2 doesn't forward it.-- Register first: `adom-cli port-forward register 5555 --visibility external --reason "oauth callback"`.-- Hydrogen auto-detects callback URLs and starts a proxy for them automatically in-  many cases (see Hydrogen log for `[oauth] Callback port X detected`), but-  registering explicitly is the reliable path.--**"`localhost:7380` shows nothing / code-server unreachable from Windows"**-- code-server is alive in the distro but WSL2 localhost-forwarding wedged (a-  real Hydrogen-logged failure mode). The port-forward registry / port-watcher-  daemon installs a host-side proxy to recover this — see `hydrogen-port-watcher`.-  Or restart Hydrogen to re-establish the forward.--## Related skills--- `hydrogen-networking` — the broader picture: `0.0.0.0` auto-forward, hostnames,-  proxy architecture, relay vs direct connect, firewall rules, NEVER do these-- `hydrogen-port-watcher` — the retained daemon that registers `127.0.0.1`-only-  listeners and covers WSL2 auto-forward gaps-- `hydrogen-container` — what's inside the workspace reachable on which port-- `hydrogen-desktop-sse` — the workspace API which runs on these ports-- `hydrogen-browser-picker` — what happens when you click a port-mappings URL--## Bridge ports are dynamic--KiCad, Fusion 360, Puppeteer, and any 3rd-party bridges no longer have known-fixed ports. When a bridge launches, **adom-bridge-cli picks an available port at-runtime** and registers it. To find a running bridge's current port, query-adom-bridge-cli:--```bash-adom-bridge-cli status-# Look at desktop.apps.<bridge>.bridgePort-```--Or use the bridge directly via adom-bridge-cli CLI — you don't need the port at all:--```bash-adom-bridge-cli kicad_open_board '{"path":"..."}'  # adom-bridge-cli routes to the right port-adom-bridge-cli browser_eval '{"js":"..."}'-```--This means **old code or skill examples that hardcoded fixed bridge ports-(8771 / 8773 / 8851) are stale.** Use the adom-bridge-cli CLI or `status` lookup-instead.