# Connection topology

Adom Bridge (Adom Bridge) connections are not one-to-one. One desktop can talk to many cloud
containers, many desktops can share a single container, and both can be true at the
same time. This page explains the pieces and the three shapes they form.

![Connection topology: one-to-many, many-to-one, many-to-many](topology.svg)

## The pieces

There are three moving parts:

- **Adom Bridge (Adom Bridge)**: the app running on a Windows machine (your laptop, an Azure
  VM, a conference-room PC). It connects *outward* to relays.
- **Relay**: a WebSocket server running *inside each cloud container*
  (`adom-bridge-cli serve`). From outside the container it is reached through the
  container's cloud proxy path, `/proxy/8765/`.
- **CLI**: the `adom-bridge` command-line tool inside the container. It talks to its
  own local relay, which forwards each command to a connected Adom Bridge and returns the
  Adom Bridge's JSON response.

So the path for a cloud command is: CLI (in container) -> local relay -> Adom Bridge (on the
Windows machine) -> back the same way.

## One desktop, many containers

A single Adom Bridge can connect out to several relays at once. Each relay is a **server
entry** in Adom Bridge's Connections panel, and each entry has its own live status
(`connected`, `reconnecting`, or `disconnected`). Entries persist in
`~/.adom/config.json`, and a supervisor inside the GUI re-checks every 30 seconds
and auto-reconnects any entry with `autoConnect: true`.

Servers can be added from the GUI, or programmatically:

```bash
adom-bridge-cli server_add '{"name":"hydrogen-workspace","url":"ws://localhost:8765","autoConnect":true}'
adom-bridge-cli server_list      # every entry with its live status
adom-bridge-cli server_remove '{"name":"hydrogen-workspace"}'
```

## Many desktops, one container

One relay can hold **several** ADs at the same time: a laptop, a VM, a
conference-room box. Each Adom Bridge identifies itself with a **clientName**, resolved in
this order: the `--client-name <name>` launch flag, then the Settings field
(`config.json` key `client_name`), then the OS hostname.

From the container, discover who is connected:

```bash
adom-bridge-cli targets
# -> {count, targets:[{name, hostname, version, os, connectedAt}]}
```

Then address one machine, or all of them:

```bash
adom-bridge-cli --target AdomLapper desktop_screenshot_screen   # one named machine
adom-bridge-cli --target all bridge_list                        # every Adom Bridge at once
```

`--target` is a global flag (it goes before the verb), matches case-insensitively
against `clientName` and then `hostname`, and can be defaulted with the
`ADOM_TARGET` environment variable (the flag wins). A `--target all` call returns
`{broadcast:true, targets:[...], results:{<name>: <verb result>}, summary:{total, ok, failed}}`,
and a timeout or failure on one Adom Bridge is isolated to that Adom Bridge's entry in `results`.

**No-target behavior**: with exactly one Adom Bridge connected, no `--target` is needed.
With multiple ADs connected and no target, the call fails with
`{error:"ambiguous_target", connected:[...], _hint}` (exit code 1) rather than
guessing which box you meant. A name that matches nothing fails with
`{error:"target_not_found", requested, connected:[...]}`.

An Adom Bridge that reconnects under the same name evicts only its own stale connection;
differently named machines always coexist on the relay.

## Many to many

The two shapes compose. Because any Adom Bridge can hold multiple server entries, and any
relay can hold multiple ADs, the overall topology is many-to-many: your laptop can
sit on container A's relay and container B's relay, while container A's relay also
holds your VM.

## Peers: what one Adom Bridge can do about the others

From one Adom Bridge's GUI, the Connections panel shows the *other* ADs on the same relay as
an expandable peer list under each server entry. Per peer you can:

- **Info**: view the peer's details.
- **Screenshot**: capture the peer's screen.
- **Boot**: kick the peer off the relay. This is a transient kick, not a ban: a
  healthy peer's supervisor reconnects it within about 30 seconds.
- **Block / Unblock**: a per-peer denylist. A blocked peer's GUI-sourced commands
  (screenshot, boot, info) are rejected by your Adom Bridge, so a shared machine on the same
  relay cannot drive yours. Your own cloud containers and local CLI are never
  affected by the denylist.

## Worked example

Setup: one laptop (`AdomLapper`) and one VM (`AzureVM`), both connected to
container A's relay. The laptop is *also* connected to container B's relay.

From **container A** (two ADs on its relay, so a target is required):

```bash
adom-bridge-cli targets                          # shows AdomLapper and AzureVM
adom-bridge-cli desktop_list_windows             # FAILS: ambiguous_target, lists both
adom-bridge-cli --target AzureVM desktop_list_windows   # routed to the VM only
adom-bridge-cli --target all hd_status           # both boxes, results keyed by name
```

From **container B** (only the laptop on its relay, so no target needed):

```bash
adom-bridge-cli desktop_screenshot_screen        # goes to AdomLapper
```

Meanwhile the laptop's Connections panel shows two server entries (container A and
container B), each with its own status, and under container A's entry it lists
`AzureVM` as a peer that it can inspect, screenshot, boot, or block.

## See also

- [skills/MULTI_AD_ADDRESSING.md](../skills/MULTI_AD_ADDRESSING.md): naming,
  targeting, and relay-routing internals.
- [skills/SKILL.md](../skills/SKILL.md): "Connection Management" for the full
  `server_add` / `server_list` / `targets` reference.
