> ## Documentation Index
> Fetch the complete documentation index at: https://docs.embedder.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Remote hardware bridge

> Expose serial ports, debug probes, and files on another machine to Embedder through an authenticated remote hardware bridge over the network.

`embedder-bridge` is a Rust service for hardware attached to another machine. The agent stays on your workstation while serial data, flash commands, managed debug processes, and file transfers cross an authenticated WSS connection.

Bridge Protocol `1.1.0` is separate from the headless JSON-RPC protocol `0.19.9`.

## Choose a deployment

| Deployment                      | Command                                | Network path                                                                   |
| ------------------------------- | -------------------------------------- | ------------------------------------------------------------------------------ |
| Temporary LAN bridge            | `embedder bridge start`                | Listens on `0.0.0.0:4849` and advertises over mDNS                             |
| Relay-enrolled temporary bridge | `embedder bridge start --relay`        | LAN listener plus outbound relay registration when the config is first created |
| Linux or macOS service          | `sudo embedder bridge install-service` | A new config uses a loopback listener plus outbound relay registration         |
| Manual binary                   | `embedder-bridge --config <path> run`  | Uses the TOML file exactly                                                     |

The CLI carries a platform-specific bridge binary and extracts it below the Embedder application directory. `install-service` copies that binary to `/usr/local/bin/embedder-bridge`.

## Start a temporary LAN bridge

On the machine with the hardware:

```bash theme={"system"}
embedder bridge start
```

The command writes its first config to `~/.embedder/bridge/config.toml`, stores state under `~/.embedder/bridge/state`, and starts a detached process.

```text theme={"system"}
Bridge running on 0.0.0.0:4849 (pid 23104).
```

From your workstation:

```bash theme={"system"}
embedder bridge discover
```

Discovery browses `_embedder-bridge._tcp.local`. The bridge advertises:

* Its configured name
* Port
* Protocol version
* SPKI fingerprint
* `mode=light`

If multicast DNS is unavailable, use the address directly in later commands.

## Pair over the LAN

<Steps>
  <Step title="Open a pairing window on the bridge host">
    ```bash theme={"system"}
    embedder-bridge --config ~/.embedder/bridge/config.toml pair
    ```

    The command prints a Crockford Base32 code. It is valid for two minutes, is single use, and allows five attempts.
  </Step>

  <Step title="Redeem the code from the workstation">
    ```bash theme={"system"}
    embedder bridge pair 192.0.2.25:4849 \
      --name bench \
      --code 8N4K2W7Q
    ```

    You may replace the direct address with an exact mDNS instance name:

    ```bash theme={"system"}
    embedder bridge pair embedder-lab-pi --code 8N4K2W7Q
    ```
  </Step>

  <Step title="Verify the fingerprint">
    The workstation prints the SPKI fingerprint returned during pairing. Compare it with `embedder-bridge status` on the bridge host before accepting it as trusted.
  </Step>

  <Step title="Test the saved pairing">
    ```bash theme={"system"}
    embedder bridge status
    embedder bridge doctor bench
    ```

    `doctor` checks the pinned connection, serial enumeration, common flash and debug binaries, and a file-transfer round trip.
  </Step>
</Steps>

The workstation stores the bridge address, SPKI pin, client ID, and issued token in `~/.embedder/bridges.json`. The file is set to mode `0600` where supported. The bridge stores only an Argon2 hash of the client token.

## Install a relay service

Run this on the bridge host:

```bash theme={"system"}
sudo embedder bridge install-service
```

The installer:

1. Copies the bundled binary to `/usr/local/bin`.
2. Preserves an existing config or creates one.
3. Creates the state directory.
4. Installs and starts a service.
5. Configures the production relay URL.

The generated config binds to `127.0.0.1:4849`. Remote clients reach it through the relay rather than an inbound LAN port.

### Linux service

Linux uses:

```text theme={"system"}
/etc/embedder-bridge/config.toml
/var/lib/embedder-bridge
/etc/systemd/system/embedder-bridge.service
```

The installer creates a system user named `embedder-bridge`, adds it to `dialout` and `plugdev`, sets the state directory to mode `0700`, and enables the systemd service.

```bash theme={"system"}
journalctl -u embedder-bridge -f
```

The unit sets `NoNewPrivileges`, protects home directories, restricts realtime scheduling, and locks the process personality.

### macOS service

macOS uses:

```text theme={"system"}
/usr/local/etc/embedder-bridge/config.toml
/usr/local/var/embedder-bridge
/Library/LaunchDaemons/dev.embedder.bridge.plist
/usr/local/var/log/embedder-bridge.log
```

The launch daemon starts at boot and keeps the process alive.

### Override install paths

```bash theme={"system"}
sudo embedder bridge install-service \
  --bin-dir /opt/embedder/bin \
  --state-dir /srv/embedder-bridge
```

The config directory and service file location stay platform-defined.

## Claim the relay enrollment

On first service start, the bridge connects to:

```text theme={"system"}
wss://relay-service-prod.embedder.com/api/v1/bridges/connect
```

It sends the SPKI fingerprint plus operating-system, architecture, memory, and bridge-version metadata. The relay returns a setup code. Open the Bridges page in the Embedder app, add a bridge, and enter that code.

After the claim, the bridge stores:

* A bridge ID
* A relay credential
* The relay setup state

It then maintains up to four outbound relay pool connections. Client traffic still runs inside the bridge's pinned TLS session. The relay carries bytes but does not replace SPKI verification.

<Warning>
  A non-loopback `ws://` relay URL is rejected. Use `wss://` outside localhost, even though the inner bridge session is also encrypted.
</Warning>

Run this on the bridge host to ask the relay to remove the registration:

```bash theme={"system"}
embedder-bridge --config /etc/embedder-bridge/config.toml deregister
```

## Bridge configuration

The binary reads TOML and rejects unknown fields.

```toml /etc/embedder-bridge/config.toml theme={"system"}
name = "lab-bench"
bind = "127.0.0.1"
port = 4849
state_dir = "/var/lib/embedder-bridge"
exec_allowlist = []
relay_url = "wss://relay-service-prod.embedder.com"
instruments_enabled = true
probe_interrogation_enabled = true
```

| Field                         | Default                          | Behavior                                            |
| ----------------------------- | -------------------------------- | --------------------------------------------------- |
| `name`                        | `$HOSTNAME` or `embedder-bridge` | mDNS and status name                                |
| `bind`                        | `127.0.0.1`                      | TCP listener address                                |
| `port`                        | `4849`                           | TCP listener port                                   |
| `state_dir`                   | `/var/lib/embedder-bridge`       | Identity, clients, staging, audit, and relay files  |
| `exec_allowlist`              | `[]`                             | Allowed executable names; empty permits any program |
| `relay_url`                   | unset                            | Enables relay setup or registration                 |
| `relay_bridge_id`             | unset                            | Optional fixed relay bridge ID                      |
| `relay_credential_file`       | state directory                  | Optional credential-file override                   |
| `instruments_enabled`         | `false`                          | Advertises the scripts capability                   |
| `hardware_descriptor`         | unset                            | Optional board and target descriptor                |
| `probe_interrogation_enabled` | `false`                          | Enables active probe inventory                      |
| `auto_update`                 | `false`                          | Accepted for old configs but ignored                |

Changing `bind` away from loopback enables mDNS advertisement. Every session still requires pairing or relay authentication.

## Manage the bridge from the CLI

On the bridge host, `embedder-bridge` can run the service, show status and diagnostics, open pairing, manage clients, remove relay enrollment, or reset its identity.

On the workstation, `embedder bridge` can discover, pair, list, remove, test, and execute against saved bridges. See the [CLI reference](/headless/cli-reference#bridge-commands) for the complete command syntax and options.

<Warning>
  `embedder-bridge reset-identity` changes the SPKI fingerprint and revokes every client. Re-pair all workstations after running it.
</Warning>

`bridge exec` defaults to a 10-minute timeout. The command runs in the bridge staging directory. A requested working directory must remain inside staging.

When `exec_allowlist` is nonempty:

* The first argv element must appear in the list.
* Shell mode is disabled.

Every execution writes an audit record with the client ID, argv, exit code, and timeout state.

## Protocol limits

Bridge Protocol `1.1.0` enforces:

| Resource                       | Limit          |
| ------------------------------ | -------------- |
| Control frame                  | 64 KiB         |
| Binary frame                   | 256 KiB        |
| Channels per session           | 32             |
| Active sessions                | 4              |
| In-flight requests per session | 64             |
| Upload                         | 512 MiB        |
| Download                       | 64 MiB         |
| Control messages               | 200 per second |
| Execution timeout              | 30 minutes     |
| Baud rate                      | 10,000,000     |

Text frames carry control messages. Binary frames use a one-byte kind, four-byte little-endian channel, and payload. The defined binary kinds are serial, file upload, and tunnel.

The bridge advertises `serial`, `exec`, `proc`, and `tunnel`. It advertises `scripts` only when `instruments_enabled` is true.

## Security model

* TLS uses a stable bridge key and client-side SPKI pinning.
* Pairing codes are hashed at rest and expire after two minutes.
* Client tokens are 32 random bytes and stored as Argon2 hashes on the bridge.
* Authentication failures trigger exponential lockout after the third failure, capped at one hour.
* The first post-TLS message must be `hello`; any other message is rejected.
* LAN and relay sessions use the same authenticated bridge protocol.
* File working directories are confined to staging.
* Serial output uses bounded queues and drops data instead of allowing unbounded memory growth.

Pairing authorizes remote command execution by design. Use a dedicated operating-system account, an `exec_allowlist`, and device permissions that match the intended lab access.

## Troubleshooting

<AccordionGroup>
  <Accordion title="Discovery finds nothing">
    mDNS only runs when the bridge binds outside loopback. Check `bind`, UDP multicast between the hosts, and the `_embedder-bridge._tcp.local` service. Pair directly with `host:port` when multicast is blocked.
  </Accordion>

  <Accordion title="The bridge identity changed">
    The pinned SPKI key differs from the current bridge. Confirm whether the state directory or identity was reset. Remove and re-pair only after verifying the new fingerprint on the bridge host.
  </Accordion>

  <Accordion title="Serial ports are missing">
    On Linux, confirm that the service user belongs to `dialout` and that USB probe udev rules grant `plugdev` access. `embedder-bridge diagnose` prints the hardware inventory visible to the service.
  </Accordion>

  <Accordion title="A flash command is rejected">
    Check `exec_allowlist`. An empty list permits programs; a nonempty list must contain the exact first argv element. Shell execution is unavailable while that list is active.
  </Accordion>

  <Accordion title="Relay enrollment never completes">
    Read the service log for the setup code, confirm outbound WSS access to the relay, and claim the current code in the Embedder app. Expired setup codes are replaced automatically.
  </Accordion>

  <Accordion title="Doctor reports no flasher or GDB server">
    Install `probe-rs` and either OpenOCD or J-Link GDB Server on the bridge host. The service process must be able to find them on its PATH.
  </Accordion>
</AccordionGroup>

<Card title="CLI reference" icon="terminal" href="/headless/cli-reference">
  Check every bridge command and option.
</Card>
