master
Colby Knox Publish 0.3.30 ed6a0ea

name: hydrogen-adom-bridge-triage description: >- Triage Adom Bridge (ab) when a Hydrogen workspace cannot reach it, including ab crashing on boot after a bad release: crash.log first, out-of-band checks, reinstall. Use when ab won't connect, no desktop client connected, ab never starts, or the bridge keeps dying.

Parent skill: hydrogen-adom-bridge (works with hydrogen-doctor, hydrogen-key-values, adom-bridge)

Triage: Adom Bridge won't connect

ping returning "No desktop client connected" tells you only that the desktop half is absent. It does not tell you whether ab is uninstalled, signed out, misconfigured, or installed and crash-looping. Those need opposite fixes, and the last one is invisible from the container unless you go looking for it.

The failure that motivated this skill. ab 2.0.91 panicked on startup, died in under a second, and was respawned by Hydrogen's supervisor every ~30-60s — 367 times over ~3 hours. From the container it looked exactly like "the user never installed it." The user's own words were "when I launch it from the Windows menu it never actually starts." The fix was one version newer on the wiki. Time wasted before reading crash.log: most of the session.

The ladder — cheapest first, and read crash.log EARLY

1. Which half is broken? (container-side, free)

curl -sf http://127.0.0.1:8766/health     # connectedClients, usingDefaultToken
adom-bridge --ai-thread "<your thread>" ping
adom-bridge --ai-thread "<your thread>" targets

connectedClients: 0 with a healthy relay ⇒ the container is fine; every remaining step is about the desktop. Do not start reconfiguring the container.

2. Ask Hydrogen — it can see the host while ab is dead

Hydrogen's control API (127.0.0.1:47084, port from ~/.adom/hydrogen-ports.json) is reachable from the workspace and does not depend on ab:

curl -s http://127.0.0.1:47084/diagnostics/all | python3 -m json.tool

Look for the adom-bridge-direct check. Its failure text names the cause and carries a fix field. Note it probes ab's direct API, so read the port caveat in Gotchas below before trusting a "silent range" message.

3. Read ab's crash log. Do this before touching any config.

This is the step that collapses a long session into two minutes.

What Windows path From a WSL2 workspace
Crash log %LOCALAPPDATA%\Adom Bridge\crash.log /mnt/c/Users/<user>/AppData/Local/Adom Bridge/crash.log
Install dir %LOCALAPPDATA%\Adom Bridge\ same, without crash.log
Direct-API port %USERPROFILE%\.adom\direct-api-port /mnt/c/Users/<user>/.adom/direct-api-port
Embedded marker %LOCALAPPDATA%\Adom Bridge\embedded.json same
Server list %USERPROFILE%\.adom\config.json /mnt/c/Users/<user>/.adom/config.json
C="/mnt/c/Users/<user>/AppData/Local/Adom Bridge/crash.log"
ls -l "$C"      # mtime is the whole story
tail -40 "$C"

Read the mtime first. A crash.log modified seconds or minutes ago means ab is crash-looping right now — it is installed, it is being launched, and it is dying. That single fact rules out the entire "not installed / not signed in / wrong URL" branch you were about to explore.

A crash loop looks like one repeating panic with a marching clock:

[2026-08-31 19:44:04] PANIC: panicked at src\carbon_runtime.rs:113:5:
there is no reactor running, must be called from the context of a Tokio 1.x runtime
[2026-08-31 19:44:55] PANIC: panicked at src\carbon_runtime.rs:113:5:
...

Useful shape checks:

grep -c "PANIC" "$C"                                   # how bad
grep -n "PANIC" "$C" | head -3                         # when it STARTED
grep -v "carbon_runtime\|no reactor running" "$C" | tail   # other panic classes

A panic in a path under src\... is ab's own code — i.e. a shipped regression, not a broken machine. A panic inside .cargo\registry\... is a dependency/host-environment issue and usually a different story.

4. Compare the installed build against the wiki

"/mnt/c/Users/<user>/AppData/Local/Adom Bridge/adom-bridge-cli.exe" --version
adom-wiki release list adom/adom-bridge          # newest version + assets

A -dirty suffix in the installed version means it was built locally, not installed from a signed wiki release — common on a developer's own machine and a strong hint that it is ahead of, or diverged from, anything published.

If the installed build is older than the wiki's newest and crash.log shows a repeating panic, the newer release is the fix. Go to step 5.

5. Install the newer release

adom-wiki release download adom/adom-bridge <version>     # verifies integrity
sha256sum ./Adom.Bridge_<version>_windows_x64-setup.exe    # confirm independently

cp ./Adom.Bridge_<version>_windows_x64-setup.exe /mnt/c/Users/<user>/AppData/Local/Temp/
cd /mnt/c/Users/<user>/AppData/Local/Temp
/mnt/c/Windows/System32/taskkill.exe /F /IM adom-bridge.exe   # release the mmap lock
./Adom.Bridge_<version>_windows_x64-setup.exe /S /NOLAUNCH
tr -d '\r' < ./adom-bridge-install.log | tail -20              # [START]...[DONE]

Use /NOLAUNCH when Hydrogen manages ab (the usual case in a Hydrogen workspace — see the hd-managed marker in the install dir). Hydrogen's supervisor spawns ab itself with --embedded --start-hidden --relay-url ... --session-token ...; let it, or you get a standalone instance that the single-instance logic then fights.

6. Verify — three independent signals, not one

sleep 45                                                     # let the supervisor respawn
/mnt/c/Windows/System32/tasklist.exe /FI "IMAGENAME eq adom-bridge.exe"
curl -sf http://127.0.0.1:24680/health                       # {"service":"adom-bridge","pid":...}
adom-bridge --ai-thread "<thread>" targets                   # name, os, version
ls -l "$C"                                                   # crash.log mtime must STOP advancing

The crash.log mtime going quiet is the one that proves you fixed the loop rather than catching ab between crashes. Give it more than one crash interval before declaring success.

The out-of-band channels (why you are not blind)

When ab is dead you have not lost the host — you have lost one route to it.

  1. Hydrogen's control API — 127.0.0.1:47084, always up if Hydrogen is running. Diagnostics, ports, container state. See hydrogen-api.

  2. WSL2 interop (Windows hosts) — a Hydrogen Windows workspace is a WSL2 distro, so /mnt/c is the real Windows filesystem and Windows .exes are directly executable from the workspace:

    ls /mnt/c/Users                                   # is it mounted?
    cat /proc/sys/fs/binfmt_misc/WSLInterop           # "enabled"?
    /mnt/c/Windows/System32/tasklist.exe              # proof it works
    

    This is how you read crash logs, check versions, and run an installer without ab. On macOS/Linux Hydrogen hosts this section does not apply; use the platform bootstrap's equivalent and the control API.

Do NOT do these while guessing

Every one of these was tried during the incident above. None helped, and the first two left changes that had to be reverted.

Don't Why
register_container when Hydrogen already manages ab Creates a second connection to the same workspace relay alongside the managed hydrogen entry — a duplicate path the user sees in the Connections list. It also writes three cloud keys, not one. Check for the managed entry / the hd-managed marker first.
Rotate the relay auth token For a cloud container the auth model is the Adom account, not a relay token — setup_desktop deliberately emits auth_token: "". Rotating adds a mismatch failure mode to a system that is already broken, and the relay's usingDefaultToken warning assumes a directly-exposed port, which a proxied container relay is not.
Conclude "not installed" / "not signed in" from ping alone Indistinguishable from a crash loop without reading crash.log.
Restart the relay, re-register, re-sign-in as a first move All container-side; none of them touch a desktop process that is panicking.

Reverting a mistaken register_container

If you (or a previous agent) registered a container that should not exist, removing it locally is not enough — ab re-reads the cloud profile at boot, at sign-in, and hourly, so a local-only removal comes back. Remove both:

TOK=$(cat /var/run/adom/api-key)

# 1. cloud profile (the authoritative copy)
curl -s -X PATCH https://carbon.adom.inc/user/hydrogen/settings \
  -H "Authorization: Bearer $TOK" -H 'Content-Type: application/json' \
  -d '{"key":"bridge.container.<id>","value":null}'

# 2. ab's local list
adom-bridge --ai-thread "<thread>" \
  server_remove '{"name":"<name>","reason":"<why>"}'

register_container writes bridge.container.<id>, bridge.last_slug, and bridge.enabled. bridge.last_slug will be left pointing at the entry you just deleted; null it too. Its previous value is not recoverable — which is the real argument for not calling register_container speculatively.

Verify with server_list and by re-reading hydrogen_preferences.settings (see hydrogen-key-values). Removing a relay entry you are talking through severs your own transport (adom/adom-bridge#387) — check ping's transport field first; if it says direct-http you are on the loopback API and a relay entry removal cannot cut you off.

Gotchas that cost time

  • ab's direct API is on 24680 (stable since ab 2.0.27); 47200-47209 is legacy. A diagnostic that probes only the legacy range can report ab unreachable when it is merely elsewhere. %USERPROFILE%\.adom\direct-api-port is authoritative (written at bind, removed on clean shutdown), so a stale file plus a silent port is itself a crash signal.
  • The 2.0.92 installer reserves 24680-24689 via netsh excludedportrange (best-effort, needs elevation) to stop Windows HNS grabbing the range.
  • Caller identity is mandatory. Verbs refuse with errorCode: caller_identity_required unless you pass --ai-thread "<a name the user would recognize>". Gated verbs additionally need a per-call reason. See adom-bridge-caller-identity.
  • embedded.json with entered_via: "launch-flag" plus a dead Hydrogen makes ab exit by design ("no hanging chad"). Pre-1.8.74 builds did not delete the stale marker, leaving ab unlaunchable — a different crash-on-boot cause with the same symptom, so confirm which one crash.log actually shows.

When it is genuinely not a crash

If crash.log is old and quiet and no ab process exists, you are in ordinary setup territory: installed? signed in? does the workspace's connection appear in the Connections list? Then follow adom-bridge / adom-bridge-auth. The point of this skill is to make you prove that before you go there.