The short version: bootstrap authority and normal request authority are different

The Node creates a persistent bootstrap key under the local AgentSight configuration directory. On Unix, the file is created with mode 0600. The binding URL carries that key only so the browser can identify the Node and ask it to mint a capability. The browser then uses the capability—not the bootstrap key—for ordinary snapshot, overview, session-read, and session-message requests.

Controller relay follows the same principle with a shorter lifetime. Controller authorizes a semantic action, the Node relay client mints a local capability valid for 60 seconds for that action and optional session, and the relayed request is forwarded to the same Node HTTP protocol. The Node remains the final capability-enforcement boundary.

The credential lifecycle

CredentialCreated or supplied byWhere it livesWhat it can doLifetime
Node bootstrap keyagentsight bindPersistent private Node config; temporarily present in the binding URL fragment.Pair a Direct browser and mint Node capabilities; authenticate the Node relay connection.Survives Node restarts until the local key is replaced.
Direct browser capabilityNode capability endpoint after Direct pairingBrowser Direct-connection state and Node capability store.node.info, evidence.read, session.read, and session.message.Requested for 12 hours by the v1.0.30 browser client.
Relay capabilityNode relay client after Controller authorizes the requested route/actionNode-local capability state for the relayed operation.One semantic action, optionally restricted to one session.60 seconds in the v1.0.30 relay client.
Optional synced Direct configurationSigned-in user opt-inController D1 as ciphertext plus IV; decrypted only with the Controller secret and user/Node-derived key.Restore a compact Direct endpoint/bootstrap configuration in another browser.Until the account copy is deleted or replaced.

The binding key is put in a URL fragment, not a query string

cmd_bind.rs serializes action=bind, protocol version, Node endpoint, and token after #. The unit test explicitly checks that the generated binding URL contains no query string. This is a meaningful boundary: standard browsers process URI fragments client-side and do not send the fragment as part of the HTTP request for the page.

That design reduces accidental disclosure to the hosted page request path, but it does not make a binding URL harmless. Anything that can read the full URL before the browser consumes it—clipboard history, screenshots, shell history, another local process, or a person you send it to—can potentially obtain bootstrap authority. Treat the complete binding link as a secret until pairing is complete.

Direct pairing immediately exchanges bootstrap authority for scoped authority

The browser first normalizes the supplied Direct endpoint to an HTTP(S) origin with no embedded credentials, path, query, or fragment. It probes /api/v1/info with the bootstrap key, then POSTs to /api/v1/capabilities asking for the four normal Direct actions and a 12-hour TTL. The returned cap_...token becomes the credential used by the browser's normal Node client.

This makes a leaked normal Direct capability materially different from a leaked bootstrap key. The capability is bounded by action and expiry. The bootstrap key can mint new capabilities and therefore should be exposed more narrowly. Do not copy the bootstrap key into automation or long-lived browser configuration when a scoped capability is enough.

Direct still means the browser talks to the Node

A Direct connection performs browser fetch() calls against the configured Node endpoint and supplies the capability in the Authorization header. The frontend marks loopback and local address spaces explicitly for browser local-network handling. A Direct endpoint can be loopback, a private address, or an HTTPS hostname; the browser has to be able to reach it.

The Node's --app-url determines the allowed browser origin for Direct access. If the Node listens on an unspecified address such as 0.0.0.0 or ::, AgentSight requires an explicit browser-reachable --endpoint instead of pretending the wildcard listen address is a usable URL. These checks solve endpoint identity and browser access; they do not provide network-layer encryption for a plain HTTP endpoint.

Relay changes the transport, not the Node protocol

With the default hosted app, agentsight bind also starts a WebSocket relay connection to the Controller. The Node authenticates that outbound connection with its bootstrap credential. Controller can then forward only an allowlisted subset of the Node protocol: capability minting internally, snapshot, overview, one-session reads, and session messages. Arbitrary Node paths and query shapes are rejected by the relay client before local forwarding.

For normal relayed data and control operations, the relay client does not forward the persistent bootstrap key. It maps the request to a semantic action, mints a 60-second Node-local capability, and forwards the request to the local Node with that capability. The implementation also bounds concurrent relay requests to eight, sets a 24-second request timeout, and caps a relay response at 16 MiB.

Detailed payloads can transit Controller relay without becoming Controller history

“Node-authoritative” does not mean a relayed response never crosses Controller. A snapshot or session response requested through Relay necessarily transits the relay path while that request is active. The architecture boundary is persistence: Controller coordinates the request and the response can exist in runtime memory, while detailed Node payloads are not stored as a Controller telemetry history.

This distinction matters when choosing a deployment mode. If the requirement is that detailed evidence never transit the hosted relay, use Local or a Direct path you control. If managed remote connectivity is acceptable, Relay provides a constrained path while the Node remains authoritative for the session data.

Cloud-synced Direct configuration is explicit and encrypted, but it is still bootstrap material

Direct configuration stays in the current browser by default. AgentSight also has an explicit signed-in opt-in that can save a compact Direct configuration for use from another browser. The Controller code encrypts that configuration with AES-256-GCM. The encryption key is derived with HKDF-SHA-256 from a 32-byte Controller secret plus the user and Node identifiers; those identifiers are also bound as authenticated additional data.

D1 stores ciphertext, IV, and version rather than plaintext Direct configuration. That is a storage protection boundary, not an argument that the synced configuration is low-value. The decrypted object still contains the endpoint and bootstrap access key, so enabling cross-browser sync deliberately moves recoverable bootstrap material into the hosted coordination path.

Choose the connection mode from the trust requirement

RequirementPreferReason
One machine; no hosted coordination neededLocalNo Controller account or remote transport is required.
Browser can reach the Node over loopback, LAN, VPN, or your HTTPS endpointDirectThe browser reads the Node directly with a scoped capability.
Need hosted identity, organization discovery, roles, or managed remote connectivityController-managed / RelayController authorizes access and relays the bounded Node protocol when Direct is unavailable.
Detailed runtime payload must not transit AgentSight-hosted infrastructureLocal or DirectDo not use Relay for the payload path; keep connectivity under your control.

What not to infer from the design

A capability system does not make an exposed HTTP Node safe on an untrusted network; transport security and endpoint exposure are separate controls. A URL fragment reduces server-side request leakage but does not protect a copied binding URL from whoever can read it. Encrypted cross-browser Direct sync protects stored plaintext in D1 but still places recoverable bootstrap material behind the Controller secret and account authorization. Finally, Relay being non-authoritative storage does not mean payload bytes never transit Relay memory.

Primary sources