Skip to main content
Foundation launchers don’t need a hardcoded server URL. Each Buttress server announces itself on the LAN, and bound launchers pick the strongest matching server for each generator type.

How it works

Every Buttress server runs a UDP transport on port 8089:
  • ANNOUNCE — broadcast every 5 seconds with the server’s serverInfo (capabilities, generators, auth status).
  • QUERY — a launcher can broadcast a query and the server unicasts a RESPONSE back. Response delays are randomized to avoid storms when many servers reply at once.
The transport binds a receive socket on 0.0.0.0:8089 for incoming queries, and one send socket per local broadcast interface so each subnet broadcast leaves on the right NIC.

Announcement payload

serverInfo includes a generators[] array with per-backend hardware capabilities computed once at startup:
Foundation launchers filter announcements by generator type (LLM, STT, MLX, GGML TTS, ONNX STT, ONNX TTS) and prefer the highest-scoring server that runs the requested backend. A Vector Store brick asks for ggml-llm as well — its embedding and tokenizer contexts run on the LLM backend — so any server announcing that type is a candidate. functions appears only on servers with local functions enabled, and carries presence and count only — never the tool list, which would not fit in a UDP datagram.

Capability score

The score is a 0-100 number combining: A laptop with no GPU scores around 15-25; a workstation with an RTX 4090 lands near 80-90.

Trust model

Bound servers and unbound servers both announce, but launchers treat them differently:
  • Unbound servers (authentication.required = false) appear as untrusted endpoints. They are still usable from manual / public clients, but bound launchers ignore them.
  • Bound servers (authentication.required = true) are trusted only when their serverId is in the workspace’s bound-server list and the announcement is signed by the matching per-server announce key the workspace registered at bind time.

Signed announcements

Each Buttress server has its own Ed25519 announce keypair, generated by bricks buttress bind. The public half is registered with the BRICKS cloud and surfaced to launchers via myWorkspaceButtress.buttressServers[].serverPublicKey; the private half stays in ~/.bricks-cli/buttress/state.json on the server host. Every UDP ANNOUNCE and RESPONSE from a bound server carries a signature over { t, d, ts }. Launchers verify the signature against the registered key with a 30-second replay window — packets without a valid signature never enter the endpoint pool. This closes the spoof vector where a LAN peer could re-announce a bound serverId and try to receive a workspace bearer token. The wire protocol version bumped to 2.0 for signed traffic. Launchers and servers running protocol 1.0 silently drop 2.0 packets and vice versa, so old/new combinations co-exist by going dark rather than swapping unsigned trust. To upgrade an existing bound server, re-run bricks buttress bind (which mints a new announce keypair) and restart bricks-buttress.

Manual override

When auto-discovery is impractical (devices on a different subnet, or a cloud-hosted Buttress server), each LLM/STT brick in BRICKS Controller’s Config Editor lets you switch from Auto to Manual and type the WebSocket URL directly. See Use Buttress from Foundation.

HTTP fallback

A launcher can also query a known IP directly over HTTP:
The endpoint returns the same serverInfo payload as the UDP ANNOUNCE. Foundation launchers use this path internally when UDP broadcast is blocked (some enterprise Wi-Fi networks).

Troubleshooting

Next steps

Workspace binding

How a server’s kid and bound-server list are issued.

Use from Foundation

Per-brick connection settings: Auto vs Manual, strategy, fallback.