Closed general

Cross-machine approval relay for same-owner bridges

John Lauer · 3mo ago ·closed by John Lauer

When one person owns several ab machines (laptop + conference room PC + VMs), an approval needed on machine B can only be granted at machine B's screen. Today that meant a RustDesk session into the conference room PC just to click one approval that the same human, already authenticated on his laptop's ab, was standing by to grant.

Request (nice-to-have): approval relay across a user's own bridges: a pending approval on any of my machines appears in the approvals panel of my OTHER connected bridges (same relay account), clearly labeled with the origin machine, grantable from wherever I actually am. Scope it to same-owner bridges only.

4 Replies

John Lauer · 3mo ago

Acknowledged as a real pain (the RustDesk-into-the-conference-room-to-click-one-button story is exactly the cost), and the design is sketchable now even though it lands after the 615/616 approvals-surface rework it depends on.

The shape that fits ab's existing architecture: pending approvals become first-class STATE (the 615/616 rework makes them a queue rather than a transient dialog), and a machine with a pending approval publishes it to the relay it is connected to. Every OTHER ab of the same account on that relay renders it in its approvals panel, labeled with the origin machine ("ConfRoomROG asks: run_script ... The AI says: ..."), and a grant there is relayed back and applied by the ORIGIN machine through the exact same one-grant-path chokepoint every local surface uses (apply_shell_auto_approve), so the cleanup contract (drain pending, dismiss dialogs, clear toasts) holds on the machine that asked.

Two constraints that must hold, flagged now so the eventual implementation respects them:

  1. Same-owner proof must be REAL, not self-reported. The existing per-peer machinery (_requesterName) is self-asserted and explicitly documented as best-effort; a remote GRANT is a different animal from a remote screenshot and needs the relay to stamp a verified same-account identity on the approval relay messages, not trust a peer's claim. That is relay-side work, and it is the reason this cannot be a quick patch.

  2. The grant stays human-only end to end. A relayed approval is still a human clicking a button in an ab window; nothing about relaying lets any AI touch the grant path. The origin machine treats a verified remote grant exactly like a local click, no wider.

Parked behind 615/616 (shipping tonight and next respectively), with this sketch as the design record. When the approvals queue exists, the relay hop is an incremental step rather than a rewrite.

John Lauer · 2mo ago

Good idea, real pain (a RustDesk session to click one button is exactly the kind of thing ab exists to remove), and I am not building it yet - it needs a decision, not just an implementation.

Why it is not a small change. The whole permission model rests on "the human at THAT machine grants for THAT machine". Relaying an approval to another machine moves the trust anchor from physical presence to same relay account, and that is a different security property. It is probably an acceptable one - the relay is already authenticated, and a person who owns both boxes can already drive either - but it should be chosen deliberately rather than arrived at.

What would have to be true for me to be comfortable:

  • The prompt must name the machine, unmissably. Approving "run_script" on your laptop when the command will execute on ConfRoomROG is a footgun unless the target machine is the loudest thing in the dialog. Today's prompts assume "here".
  • One approval, one machine. A relayed grant must not become a fleet-wide grant. The 24 hr / Auto forms are the risky ones - "Auto mode, relayed" would silently mean every machine.
  • The relay must not become an approval oracle. It forwards; it never decides, never caches a decision, and an offline machine's pending approval must not be grantable by a third box that happens to be online.
  • Provenance survives the hop. The caller-identity chain (thread, container, delegate) already rides commands; a relayed approval has to carry it or the remote human approves an anonymous request.

The pieces exist: the relay already does targeted send_and_wait, ab already has a pending-approvals store and a peer panel with per-peer blocking. So this is plumbing plus a careful prompt, not new infrastructure.

Deferring to John on whether cross-machine approval is a property he wants ab to have at all. If yes, I would build it approval-at-a-time (allow_once only, no relayed Auto/24hr), with the machine name leading the prompt, and revisit the durable forms after it has been used in anger.

John Lauer · 2mo ago

Folding this into the Adom Mesh plan — John flagged it as a natural fit for the mesh system we're starting next week (after the current release train). The mesh already has an "Execution authorization" layer that keeps cross-device shell behind a human approval; approval-relay is the extension that lets the human's one approval reach the node that needs it (same-owner, device-key-verified nodes only, decision stays human-made, and the deciding node sees which node + which aiThread it's approving for). Recorded in the mesh doc; picking it up with that work rather than as a standalone change now.

John Lauer · 2mo ago

Shipped, as part of the Adom Mesh work: 2.1.44 (fan-out + decide-from-any-box) and 2.1.45 (the machine chip). Closing this one; the constraints from the 2026-08-30 reply are each met, and here is how.

What happens now. Every permission prompt ab raises (shell/Tier-2, generic grant, web-page consent) is mirrored to Hydrogen when embedded AND to every mesh peer of the same account. Each peer renders it in its own permission stack with the origin machine as the loudest element: an ON CONFROOMROG chip on the card (this-machine prompts say THIS MACHINE), and the Hydrogen dialog body carries machine + machineNodeId too (hydrogen issue 1166 asks ah to render it the same way). Deciding on any box sends the decision back to the ORIGIN over the mesh; the origin applies it through the same chokepoint every local surface uses (resolve_permission_decision -> apply_shell_auto_approve), so drain/dismiss/toast cleanup happens on the machine that asked. A decision anywhere dismisses the card everywhere (verified live: John's Deny on Hydrogen cleared AdomLapper's and ConfRoomROG's stacks).

The constraints.

  • Same-owner proof must be REAL, not self-reported. Mesh peers are discovered from the account's Carbon KV directory (the signed-in session writes its own desktop.runtime.<machine>.bridge record with its ed25519 node id); inbound mesh connections are accepted ONLY from node ids in that directory, and the transport is iroh QUIC with node-key authentication end to end. A box that is not signed into your account cannot appear in the directory and cannot connect. This is not the best-effort _requesterName path.
  • One approval, one machine. A decision is addressed to one request id on one origin node. Choosing Auto on a remote card grants Auto on THAT origin machine only; nothing is fleet-wide, and the deciding box's own grant state is untouched.
  • The relay must not become an approval oracle. The hc relay carries nothing here: mirror + decision travel peer to peer over the mesh (or, when embedded, over the loopback Hydrogen control API). No server-side component ever holds or forwards a grant.
  • Human-only stays human-only. The remote card is a human surface; the mesh perm_resolve message is accepted only from a directory peer and applies a decision a human clicked there. No AI path was added.

Where to see it. Mesh is opt-in (Settings > Adom Mesh, or settings_set {mesh_enabled:true}); the Mesh view (header button, or desktop_ui_panel {panel:"mesh",action:"show"}) draws the boxes and their direct/relay edges. Phase P0 is same-LAN direct; cross-network hole punching arrives with the Adom-hosted relay (P1). Design: docs/adom-mesh.md in the repo.

John Lauer closed this · 2mo ago

Log in to reply.