Adom Bridge
Public Made by Adomby adom
Adom Bridge unleashes your AI onto your full PC: full power, full safety. The AI breaks out of the container it runs in and onto your real machine, managing and running your entire laptop as you: launch apps, move files, drive any window, control KiCad, Fusion 360 or your real signed-in browser. Works with any AI, cloud or local (Claude Desktop, Claude Code, Codex), no Hydrogen required. Bridge and its bridges are an operating system for AI, with managed Node and Python runtimes, and a human-onl
ab core implements fusion_start + fusion_dismiss_blocking_dialogs itself, so the bridge cannot own its own verbs (breaks #32, wedges Fusion on the seat dialog)
ab core implements fusion_start + fusion_dismiss_blocking_dialogs itself, so the bridge cannot own its own verbs
TL;DR: ab intercepts two fusion_* verbs and answers them from core instead of forwarding to the fusion360 bridge. That breaks bridge ownership, strips a contract John asked every bridge to implement today, and actively wedges Fusion by WM_CLOSE-ing a modal that only answers to its buttons. Proven with a side-by-side runtime receipt, not inference.
John's framing when I reported this to him (2026-08-19), and it is the right one: "ab is just supposed to be an operating system. a bridge is supposed to OWN all of its own verbs. ab is supposed to be agnostic."
The receipt
Same machine (AdomLapper), same minute, same Fusion process. Two paths, two different implementations.
Direct to the fusion360 bridge on its own port (bridge_list reports 61606), POST /command {"command":"start"}:
keys: success, output, addinConnected, alreadyRunning, startKind, progress, timings,
resolvedPath, windowEtiquette, _hint
startKind : warm
addinConnected : True
output : Fusion 360 is already running.
progress : {"phase":"launch","stepLabel":"Fusion is already running - reusing it",
"percent":100,"elapsedSec":0,"estimatedSec":0,"etaSec":0,
"confidence":"measured","startKind":"warm",
"measured":{"phase":"launch","seconds":0.3,"startKind":"warm"}}
dialogsDismissed present: False
Via adom-bridge fusion_start:
keys: _hint, addinReady, alreadyRunning, dialogsDismissed, dialogsRemaining, dismissHint,
durationMs, elapsedMs, mainThreadResponsive, pid, resolvedPath, source, status
startKind : (absent)
progress : (absent)
source : already-running-via-bridge
Different key sets, different semantics (addinConnected vs addinReady), and the bridge's own fields are absent. The bridge handler never runs.
Corroborating evidence:
dialogsDismissed/dismissHinthave never existed in the fusion-bridge repo.git log -S dialogsDismissedreturns empty across the entire history.- The fusion-bridge repo does not implement
fusion_dismiss_blocking_dialogsat all - it only references the verb name in_hintstrings. Yetadom-bridge-cli commandsdocuments it underfusion360.lifecyclewithmaxAttemptsdefault 5, and live responses show exactly 5 attempts. adom-bridge-cli help fusion_startdocuments returns (pid,elapsedMs,dialogsDismissed[]) that the bridge'sdescribe.pydoes not declare. The bridge declares{success, addinReady, status}.
Why this is not cosmetic
1. It strips the progress contract John opened today
adom/fusion-bridge#32 asks every bridge to return a measured progress block (percent + ETA + cold/warm + confidence) on every slow verb. fusion_start is the slow verb that triggered that issue - the "cold start can take a couple of minutes" string came from this path.
The fusion bridge now implements it: rolling measured history per (phase, startKind) on disk, p50/p90, estimates revised as a run proceeds. Verified working - fusion_state on ConfRoomROG reports "on this machine Fusion starts in cold 53s (measured)", and a live launch narrowed 0% -> 37% -> 74% with ETA 53s -> 33s -> 13s.
None of that reaches a caller through adom-bridge fusion_start, because ab answers first. The bridge can implement the contract perfectly and the front door still returns a shrug. Whatever ab does here, it cannot satisfy #32 for launch without either forwarding to the bridge or reimplementing per-machine measured history in core - which is exactly the work that belongs in the bridge.
2. ab's dialog patterns wedge Fusion on the Autodesk seat dialog
ab classifies "Active Sessions Exceeded" as a startup-picker and sends WM_CLOSE at it five times:
"dialogsDismissed": [
{"attempt": 1, "hwnd": 5968692, "pattern": "startup-picker", "title": "Fusion360"},
... 5 identical entries ...
],
"dialogsRemaining": [{"className": "Qt683QWindowIcon", "hwnd": 5968692,
"rect": {"width": 1646, "height": 702}}],
"dismissHint": "Blocking dialogs remain AND the deterministic pattern match couldn't clear
them. YOU (the AI) must take over."
This dialog is a decision, not a nuisance: its options suspend or shut down Fusion on the user's other machine. It ignores Escape and WM_CLOSE by design - it wants a button pressed. So the sweep logs five "dismissals" of a dialog that never moved, then hands the human a manual recovery script.
Observed cost: ConfRoomROG sat blocked behind it while the Fusion Dashboard waited 378s per surface and failed three surfaces in a row with "Fusion did not become ready". Same dialog then appeared on AdomLapper (a 1235x375 variant - it renders at different sizes per display).
The fusion bridge classifies this correctly today (session_conflict_decision, matching "active sessions exceeded" / "more sessions running than are allowed") and, since 1.9.74, auto-resolves it in the background via UIA Invoke of Continue, screenshot-verified against the parent's ownedPopupCount. ab never consults any of it.
Note the general hazard, since it will bite other bridges: ab's pattern label was confidently wrong, and the confident wrong label is worse than no label. It made five failed WM_CLOSEs look like five successful dismissals in the response.
The ask
Preferred, and the one that matches the stated architecture:
Stop intercepting
fusion_*. Forwardfusion_startandfusion_dismiss_blocking_dialogsto the bridge that declares thefusion_prefix, the way every otherfusion_*verb is routed. The bridge already implements both behaviours (launch + wait-for-add-in + background-launch invariant + seat resolution), and it owns the knowledge ab is missing.If a core convenience wrapper must stay, make it forward and pass through rather than replace: return the bridge's own payload (including
progress,timings,startKind) and add ab-level fields alongside, never instead. A caller must never lose bridge fields by using the front door.Either way, please do not carry app-specific dialog patterns in core. Dialog classification belongs to the bridge that knows the app. If ab wants a sweep, call the bridge's classifier.
Secondary, and useful regardless: source: "already-running-via-bridge" reads as if the bridge answered when it did not. Whatever ab ends up doing, please make provenance unambiguous (e.g. implementedBy: "ab-core" | "bridge:fusion360"), so a bridge author can tell at a glance whose code produced a response. Diagnosing this took a direct-to-port comparison that most bridge authors will not think to run.
Happy to take the fusion side of whichever shape you pick - if you forward, I will make sure fusion_start on the bridge covers everything ab's version does today (it already does the launch, the add-in wait, the background-launch invariant, and now the seat dialog).
Filed from the fusion-bridge thread. Related: adom/fusion-bridge#32 (measured progress contract).