# The relay

How a browser or phone on the Borago Board cloud reaches your own desktop app, what travels over that connection, and what never relays.

The cloud board has no Docker, no model runner and stores no key that could decrypt a credential. Anything that can only happen on the user's machine is asked of the desktop app over a single connection the desktop opens to the cloud, called the relay. Everything else on the cloud board is read from the synced board and works with the desktop switched off. This page lists which is which.

## The connection

| Property | Value |
|---|---|
| Direction | Outbound from the desktop to the cloud service, over the same encrypted transport as sync. The desktop is never reached from outside |
| What listens on the user's network | Nothing. No port is opened and no firewall rule is needed for the relay |
| When it is open | Whenever cloud sync is on and the desktop is signed in. It reconnects on its own after an outage |
| Who may use it | An account with an active paid plan or trial, not deactivated, and only its one linked desktop. See [Pricing](/pricing/) |
| Surfaces that use it | The cloud board in a browser and the phone at board.boragosoft.com. The desktop app and a browser on the local network talk to the desktop directly and never need it |

Every relayed request names a project or a task by the identity that is the same on every device, never by a row number, since the cloud and the desktop number their rows independently.

## What relays

Each of these runs on the desktop when pressed on the cloud board, and behaves exactly as the desktop's own button does.

| Action | Notes |
|---|---|
| The container terminal | A shell in the project's container, executed by the desktop and forwarded to your browser or phone. Persistent tabs per project. Ends when the tab is closed, the shell exits or the desktop app closes. See [The terminal, scripts and the file browser](/docs/guides/terminal-scripts-and-files/) |
| Container lifecycle | Start, stop, restart, rebuild, list, start all, stop all, and start, stop or restart of one container in the project's family by name. Restart and rebuild recreate the container and show the same confirmation on every surface when that would discard uncommitted work. See [Containers](/docs/reference/containers/) |
| Project scripts | Run, stop, test an unsaved script, and see which scripts are running. Output streams back as it happens. Every run is forwarded, not only the ones the phone started, so a build started at the desk can be watched from the sofa. Leaving the page does not stop a run |
| Chat | Sending a message, proposing tasks and creating the approved tasks. The three calls that spend money. Pressing Stop reaches the desktop and ends the model call. See [Chat to tasks](/docs/guides/chat-to-tasks/) |
| A provider API key | Saving, clearing or verifying one, and checking which credential a project has. The typed key crosses the connection once, in memory, and the desktop encrypts it. See [Security](/security/) |
| One project secret | One field at a time, encrypted by the desktop under the account key the cloud does not store |
| One environment variable | One name and value pair at a time. A browser cannot see the stored set, so it never writes the whole list. A blank value removes exactly that name |
| Linking a saved key from the vault | Not relayed, and listed here because it looks as if it should be. A link is the name of a vault entry, not a credential, so it needs no key and no desktop awake |
| The firewall rule | Reading whether the project's container can reach the policy proxy, and adding or removing the one allow rule. An administrator prompt can appear on the desktop because of a press made on a phone. Where the desktop cannot ask for a password, a terminal opens there for the user's own sudo, and failing that the command is returned as text and nothing runs |
| Connect a repository | The GitLab sign-in that provisions a deploy key. The user reads a code on one screen and approves on another. The access token never crosses the connection. There is no GitHub sign-in. See [Connecting a repository](/docs/guides/connecting-a-repository/) |
| Resume the queue | The **Resume** button on a held To Do column. The queue and its timers live on the desktop. See [The queue and its holds](/docs/reference/queue-and-holds/) |
| Stop a run | The run is a process on the desktop. The phone can see it running, so it can stop it. Starting a run deliberately does not relay. Dragging a card to To Do lets the desktop's queue pick it up instead |
| Creating the project folder | The desktop creates a workspace subfolder under its own project folder and tells the browser the path. The machine that owns the filesystem chooses |
| The generated Docker files preview | Generated on the desktop, so the text shown is the text that lands on disk. The editors are read-only until the desktop answers |
| Self-hosted model servers | Checking which are online, verifying one, and downloading a model onto one. A self-hosted server is on the user's own network, so only the desktop can reach it |

## What is read from sync, with the desktop asleep

These rows sync, so the cloud serves them itself. Nothing on this list needs the desktop connected.

| Data | Notes |
|---|---|
| The board, projects and tasks | Including whether a task is running right now and how long the current run has been going |
| Comments, questions and answers | Answering a question on the phone unblocks the run on the desktop through sync |
| Notes | No model and no container, so notes read and write everywhere |
| Chat history | Listing, reading and deleting a conversation. Only a new turn needs the desktop |
| Notifications and their read state | Reading one anywhere clears it everywhere |
| Saved keys in the vault | Listed by name so one can be linked. No screen anywhere shows a value |
| Project settings | Every synced field, the git identity included. Secrets and environment variables are stored as ciphertext under a key the cloud never stores, so the cloud board shows none of them |
| The port check, half of it | Whether another project on the board claims a host port is answered by the cloud. Whether the port can be bound on the desktop is not checked from the cloud, and the desktop's own check has the last word at start |

## What never relays, by design

| Capability | Why |
|---|---|
| Browsing the desktop's filesystem | A directory listing is an arbitrary read of the whole machine. It is offered only inside the desktop window. The need it served is met by letting the desktop create the folder, above |
| Writing the generated Docker files into a folder | It creates directories on the host |
| Running the agent on the cloud | The cloud holds no credential that could call a model, and giving it one would be a different product billed to someone else |
| Reading a stored secret's value | The desktop can reveal an environment variable that is not marked write-only, one row at a time, and nothing else. The cloud browser or the phone never gets a value back, since the cloud never stores the key that would decrypt one, and the desktop otherwise decrypts a secret only at the moment a process starts |
| Dictation | Local by design. Audio never leaves the device. This is the one control hidden rather than disabled on the cloud, because nothing could ever enable it there |
| Docker disk cleanup | A wrong cleanup is unrecoverable, and the desktop's Settings is where its disk is managed |
| The file browser inside the container | The composer's Insert explorer needs the container, and the cloud has none. It reports that the desktop is needed rather than showing an empty folder. A path mention in a message still works from the phone, because the turn that reads it runs on the desktop |

## The rule for every control

A control whose work happens on the desktop is shown on every surface and disabled with one reason while the desktop is away. The reason reads "Your desktop app is not connected. Open it (with cloud sync on) to use this." A hidden button is indistinguishable from a feature that does not exist and has nowhere to put that sentence. A request that arrives while the desktop is away fails with a message naming the fix, not with "not available".

## What the phone knows about the desktop

While the desktop is connected, the cloud board shows the state of the machine that actually runs the containers, not of the phone. That covers which containers are running, whether Docker is installed and gVisor is available, the daemon's CPU architecture, and which project queues are paused and why, with the blocked task named by title. It is refreshed every few seconds and at once when a container starts or stops. Anything the desktop has not reported is shown as unknown, never as missing, and a disconnected desktop reports nothing, so a phone never raises a Docker alarm about a machine it cannot see.

## One desktop per account

The desktop sends a random installation id at sign-in, not derived from hardware or from any account, and the account links exactly one. A second desktop signing in is told another desktop is linked and must confirm a takeover. After that the cloud refuses sync and relay connections from the replaced desktop.

The replaced desktop's local board keeps working. Its sync stops, the Settings Account category and the profile dot say why, and a notification in the bell says that cloud sync stopped because another desktop is now linked. Its relay connection is refused until the next sign-in there, which takes the link back. What it changed while unlinked is pushed when it links back. Browser and phone sign-ins never touch the link. See [Cloud sync](/docs/reference/cloud-sync/) and [Switching accounts on one machine](/docs/guides/switching-accounts/).

Related: [Cloud sync, browser and phone](/docs/guides/cloud-sync-browser-and-phone/), [Cloud, phone and what needs the desktop online](/docs/for-ai/cloud-phone-and-the-desktop/), [Containers](/docs/reference/containers/), [Cloud sync](/docs/reference/cloud-sync/), [Security](/security/).
