app
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
← Commit history
README.md+60−1@@ -290,7 +290,66 @@ Adom Bridge serves a couple of small pages on its loopback HTTP API (the stable - **`http://127.0.0.1:24680/verbs`** is a browsable API Explorer: every verb, grouped into tabs by category and with one tab per installed bridge, each with a plain-English description and a copy-to-clipboard curl command. The footer tooltip in the laptop GUI links straight to it. `GET /health`, `/status`, and `/commands` return the same information as JSON. -- **Web integration (detection).** A page served from `https://wiki.adom.inc` (and only that origin) can `fetch('http://127.0.0.1:24680/health')` to detect whether Adom Bridge is running, so the wiki can light up actions like "open this component in KiCad." The security is deliberately tight: Adom Bridge returns CORS headers only for the exact origin `https://wiki.adom.inc` (never a wildcard, never a user-provisionable `*.adom.cloud` host) with a loopback-Host check to defeat DNS rebinding, and it handles the Private-Network-Access preflight. A web origin may reach only the read-only detection endpoints; `POST /command` is refused for every web origin, so no verb can change the machine from a web page. The planned launch and send actions will each require a native Adom Bridge consent dialog. **Try it live:** [talking to Adom Bridge from a web page](docs/web-control.md) is a working harness that detects your running Adom Bridge, reads its status, and shows the "open KiCad" wall refusing a machine-changing call. Full model: the `adom-bridge-web-integration` skill.+- **Web integration (detection).** A page served from `https://wiki.adom.inc` (and only that origin) can `fetch('http://127.0.0.1:24680/health')` to detect whether Adom Bridge is running, so the wiki can light up actions like "open this component in KiCad." The security is deliberately tight: Adom Bridge returns CORS headers only for the exact origin `https://wiki.adom.inc` (never a wildcard, never a user-provisionable `*.adom.cloud` host) with a loopback-Host check to defeat DNS rebinding, and it handles the Private-Network-Access preflight. A web origin may reach only the read-only detection endpoints; `POST /command` is refused for every web origin, so no verb can change the machine from a web page. The planned launch and send actions will each require a native Adom Bridge consent dialog. Full model: the `adom-bridge-web-integration` skill; the mechanism and the security layers, with diagrams: [talking to Adom Bridge from a web page](docs/web-control.md).++**Try it live.** If you are reading this on `https://wiki.adom.inc` on a machine running Adom Bridge, the panel below actually reaches into it. The buttons make real `fetch()` calls to `http://127.0.0.1:24680`: it detects your running Adom Bridge, reads its status, and hits `POST /command` so you can watch the "open KiCad" wall refuse a machine-changing call. It also prints this frame's own origin, so you can see for yourself that only `https://wiki.adom.inc` is allowed in.++<div id="ab-demo" style="font-family:system-ui,-apple-system,Segoe UI,sans-serif;border:1px solid #30363d;border-radius:10px;background:#0d1117;color:#e6edf3;padding:18px;margin:18px 0;max-width:760px">+ <div style="display:flex;align-items:center;gap:10px;margin-bottom:6px">+ <span id="ab-dot" style="width:12px;height:12px;border-radius:50%;background:#484f58;display:inline-block"></span>+ <strong style="font-size:16px">Adom Bridge web control demo</strong>+ </div>+ <div style="font-size:12px;color:#8b949e;margin-bottom:14px">+ This frame's origin: <code id="ab-origin" style="color:#00e6dc">checking…</code>+ · API: <code style="color:#8b949e">http://127.0.0.1:24680</code>+ </div>+ <div style="display:flex;flex-wrap:wrap;gap:8px;margin-bottom:14px">+ <button id="ab-detect" style="background:#00b8b0;color:#04211f;border:0;border-radius:6px;padding:8px 14px;font-weight:600;cursor:pointer">Detect Adom Bridge</button>+ <button id="ab-status" style="background:#1c2128;color:#e6edf3;border:1px solid #30363d;border-radius:6px;padding:8px 14px;cursor:pointer">Read status</button>+ <button id="ab-kicad" style="background:#1c2128;color:#e6edf3;border:1px solid #30363d;border-radius:6px;padding:8px 14px;cursor:pointer">Try to open KiCad (should be blocked)</button>+ </div>+ <pre id="ab-log" style="background:#010409;border:1px solid #21262d;border-radius:6px;padding:12px;font-size:12px;line-height:1.5;max-height:300px;overflow:auto;white-space:pre-wrap;margin:0;color:#c9d1d9">Ready. Click "Detect Adom Bridge" to begin.</pre>+ <script>+ (function () {+ var AB = "http://127.0.0.1:24680";+ var log = document.getElementById("ab-log");+ var dot = document.getElementById("ab-dot");+ document.getElementById("ab-origin").textContent = location.origin || "(null: sandboxed frame)";+ function line(msg, color) {+ var t = new Date().toLocaleTimeString();+ log.textContent += "\n[" + t + "] " + msg;+ if (color) { log.style.color = color; }+ log.scrollTop = log.scrollHeight;+ }+ function reset() { log.textContent = "-"; log.style.color = "#c9d1d9"; }+ document.getElementById("ab-detect").onclick = function () {+ reset(); line("GET " + AB + "/health ...");+ fetch(AB + "/health").then(function (r) { return r.ok ? r.json() : Promise.reject("HTTP " + r.status); })+ .then(function (j) {+ if (j && j.service === "adom-bridge") { dot.style.background = "#00b8b0"; line("Adom Bridge is RUNNING on this machine. service=" + j.service, "#7ee787"); line(JSON.stringify(j, null, 2)); }+ else { line("Reached something, but it is not Adom Bridge: " + JSON.stringify(j), "#e6c86c"); }+ })+ .catch(function (e) { dot.style.background = "#484f58"; line("No Adom Bridge reachable (" + e + ").", "#8b949e"); line("Either it is not installed/running here, or this frame's origin is not https://wiki.adom.inc (the only origin it answers)."); });+ };+ document.getElementById("ab-status").onclick = function () {+ reset(); line("GET " + AB + "/status ...");+ fetch(AB + "/status").then(function (r) { return r.ok ? r.json() : Promise.reject("HTTP " + r.status); })+ .then(function (j) { dot.style.background = "#00b8b0"; line("Status (read-only, allowed from the web):", "#7ee787"); line(JSON.stringify(j, null, 2)); })+ .catch(function (e) { line("status failed: " + e, "#f0883e"); });+ };+ document.getElementById("ab-kicad").onclick = function () {+ reset(); line("POST " + AB + "/command {kicad_open_board} - expecting REFUSED ...");+ fetch(AB + "/command", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ app: "kicad", command: "kicad_open_board", args: {} }) })+ .then(function (r) { return r.json().then(function (j) { return { status: r.status, body: j }; }); })+ .then(function (res) {+ if (res.status === 403 || (res.body && res.body.errorCode === "web_forbidden")) { line("REFUSED, as designed. HTTP " + res.status + " errorCode=" + (res.body && res.body.errorCode), "#7ee787"); line("This is the safety wall: a web page cannot run a machine-changing verb. The consent-gated action phase will change this to 'ask the human in Adom Bridge first'."); line(JSON.stringify(res.body, null, 2)); }+ else { line("UNEXPECTED: POST /command was NOT refused (HTTP " + res.status + "). Please report this.", "#f85149"); line(JSON.stringify(res.body, null, 2)); }+ })+ .catch(function (e) { line("The browser blocked the POST before Adom Bridge answered (" + e + ").", "#e6c86c"); line("That is also a refusal: with no CORS grant for a non-allowlisted origin, page JS cannot read the response."); });+ };+ })();+ </script>+</div> ## Versioning