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

# OHO machines and environments

> You choose where your agents' work runs.

This area decides **where** a company's agent work runs and **what it runs in**. It covers
connected OHO machines (a company's own orchestrator host), the Olyros Cloud pool, a
bring-your-own Google Cloud project, and the runtime images that tasks start from. Everything
sits in the client app sidebar group **Orchestration**, under three entries whose labels do not
match the model names:

| Sidebar label | Route | What it is |
| - | - | - |
| **Environments** | `/execution` | The execution backends gallery (`ExecutionBackend` rows shown as `executionEnvironments`): Olyros Cloud, "Your cloud" (BYO GCP), and one card per OHO. |
| **Runtime Images** | `/environments` | The `Environment` model: a `process` or `docker` runtime with env vars, secrets and a timeout. Cloud worker images live at `/environments/cloud-images`. |
| **Connections** | `/oho/connect` | The OHO connection page: how to run `oho connect`, pending registrations, connected instances. |

The approval link an OHO prints, `/oho/approve/:token`, sits outside the company prefix. Executors,
cloud tasks, work items and the OHO pull loop are on
[Cloud tasks and executors](https://user-docs.olyrosstudios.com/cloud-tasks-and-executors.md). Sandboxes are on
[Sandboxes](https://user-docs.olyrosstudios.com/sandboxes.md). Skill execution on an OHO is on [Skills](https://user-docs.olyrosstudios.com/skills.md).

## What it does

**Connect an OHO machine.** An OHO is a local orchestrator a company runs on its own machine.
Running `oho connect --server <url>` calls `POST /api/oho/register`, which creates an
`OhoRegistration` in status `pending` with a token that expires after 10 minutes. The CLI
prints a verification URL, `/oho/approve/<token>`, and polls
`GET /api/oho/register/{token}/status`. A signed-in user opens the URL and approves it with
`approveOhoRegistration`. Approval creates an `OhoInstance` in the active company and issues a
device token and a refresh token. The next status poll hands both to the OHO once and clears
them from the server. A new registration from the same machine expires any older pending one.
Registration statuses are `pending`, `approved`, `rejected` and `expired`.

**Presence.** The OHO then holds a WebSocket to `/api/oho/ws`, authenticated by its device
token in the handshake headers. Connecting marks the instance `online`. A background tracker
runs every 60 s and marks an instance `offline` when its last heartbeat is older than 90 s.
Instance statuses are `pending`, `online`, `offline`, `degraded` and `revoked`. Each instance's
status is mirrored onto its backend row, so it shows up in the Environments gallery.

**Token rotation.** Device tokens rotate every 7 days while the OHO is connected, committed on
the OHO's acknowledgement, and the old token works for a 5-minute grace period. An OHO can also refresh its
tokens with `POST /api/oho/refresh` and revoke itself with `POST /api/oho/self-revoke`, which
`oho disconnect` calls. `rotateOhoCredentials` asks for an immediate rotation; it refuses a
revoked or disconnected instance.

**Revoke, rename, diagnose.** `revokeOhoInstance` is permanent: it clears the tokens, sets the
instance and its backend to `revoked`, and closes the socket after sending `instance.revoked`. `renameOhoInstance` sets the
display name. Diagnostics runs `testOhoConnectivity`, `requestOhoSync`, `testOhoEventFlow`
(a test task's lifecycle events), `testOhoExecution` (mocked, no model calls) and
`testOhoEnvironment` (builds an agent's image and runs a trivial prompt), and lists the host's
**outstanding evictions** (a table at the bottom of the tab, with Refresh): `sandbox.destroy` calls the server still owes it for sandboxes that
were moved away or force-deleted while it was unreachable (`pendingEvictions`), delivered when
the host reconnects and retried on heartbeats, up to five attempts.

**What an OHO runs.** An OHO reports its local agents, executors and runtimes when it connects
(`OhoAgent` rows, `source` `local`). `assignAgentToOho` pushes a cloud agent's config to it
(`source` `cloud`) and `removeAgentFromOho` removes it. Task dispatch is on
[Cloud tasks and executors](https://user-docs.olyrosstudios.com/cloud-tasks-and-executors.md).

**Execution backends.** Every place work can run is an `ExecutionBackend` in a `BackendPool`.
Providers are `oho`, `server`, `gcp` and `aws`; ownership is `platform` or `tenant`. Backend
statuses are `pending`, `verifying`, `online`, `offline`, `degraded` and `revoked`. The
Environments gallery (`executionEnvironments`) shows the company's own backends plus the
platform backends it is entitled to, in three kinds of card:

* **Olyros Cloud.** All entitled platform `gcp`/`aws` pools merged into one card with the
  reserved id `olyros-cloud`. Its status is the best of the set, and its active count is the
  company's own in-flight runs only.
* **Your cloud.** One card per bring-your-own GCP backend, with its own lifecycle status.
* **OHO.** One card per connected OHO.

Revoked backends and the internal `server` worker are never shown. Each card shows
month-to-date execution hours. The detail page `/execution/:backendId` always has Overview,
Usage and Settings tabs. OHO cards add System Info, Recent Tasks and Diagnostics; Your cloud
adds Storage & Images and Diagnostics; Olyros Cloud adds Storage & Images. `environmentRuns`
and `environmentSandboxes` list the runs and sandboxes placed there.

**Placement.** The selector tries the agent's "Runs on" pin (`setAgentBackend`), then the
company default (`setCompanyDefaultBackend`), then all attached backends, filtered by status,
capabilities and entitlement, least busy first. A pin or default to a backend the company is not
entitled to is refused when set, and a dispatch to one fails rather than falling back to an OHO.

**Olyros Cloud switch.** `setOlyrosCloudEnabled` turns Olyros-hosted placement on or off for
the company (`olyros_cloud_enabled`, default on). When it is off the Olyros Cloud card shows as
disabled and cloud work is refused with "Olyros Cloud is turned off for your company."
`olyrosCloudAccess` returns whether the company is entitled, whether the switch is on, and
whether it may connect its own cloud.

**Bring your own GCP project.** `connectByocGcpBackend(projectId, region, displayName)` creates
a company-owned pool and a `pending` backend and returns a provisioning script for the customer
to run in their own project. `verifyByocGcpBackend` runs the verification ladder (`full=false`
is the quick check) and moves the backend to `online` on success. A failed first verify returns
it to `pending`; a failed re-verify of a live backend moves it to `degraded`. `setByocGcpCaps`
sets two courtesy caps, maximum concurrent runs and maximum run duration, enforced at dispatch;
the customer's own GCP budget alert remains the real cost control. `revokeByocGcpBackend` is terminal and idempotent: placement stops at once,
in-flight runs are reaped, credentials and grants are removed, and the slot frees for a new
connect.

**Runtime images (the `Environment` model).** An environment is a named runtime of `type`
`process` or `docker`, with a Dockerfile (required for `docker`), build args, env vars,
secrets and a `timeout_seconds`. Agents reference one as `default_environment_id` and as
`sandbox_environment_id`, and cloud tasks carry an `environment_id`. Each change that alters a
field bumps `version`. Secrets are stored encrypted. Queries return their key names only, and
`revealEnvironmentSecret` returns one value and writes an audit row first.
`duplicateEnvironment` copies an environment, naming it `<name>-copy`, `<name>-copy-2` and so on
when no name is given. `deleteEnvironment` is a soft delete (`is_active` false). The name stays
taken, and `environments(includeDeleted: true)` still lists it. The `dockerfileWarnings` field
flags `ENTRYPOINT`, `CMD`, `USER` and `VOLUME` lines, which the OHO overrides.

**Cloud worker images.** `/environments/cloud-images` lists the company's built worker images
per repository (`cloudWorkerImages`), one group for the Olyros-hosted pool and one for a BYO
project. `deleteCloudWorkerImage(backendId, digest)` deletes an older image; the current one is
refused. Without an entitled online GCP backend the page reports the list as unavailable.

## Who can use it

Role labels follow the roles table on [Company settings](https://user-docs.olyrosstudios.com/company-settings.md).

* **Any company member** can view everything here, approve or reject a registration, revoke,
  rename and diagnose an OHO, rotate its credentials, assign agents to it, set an agent's
  "Runs on" pin, set the company default backend, and connect, verify, cap and revoke a BYO GCP
  backend. These operations check membership only.
* **Editor or admin** (`environment.manage`) can create, update, duplicate and delete runtime
  images and reveal a secret. Create, update and duplicate need a company admin only in the
  Dockerfile case below.
* **Company admin** (`environment.manage_dockerfile`) is needed to set or change a Dockerfile
  when the company holds a GCP entitlement, because that Dockerfile is built on the platform.
  Without a GCP entitlement an editor may set it, since it builds on the company's own OHO.
* **Editor or admin** (`executor.manage`) can delete a cloud worker image.
* **Company admin** (`oho.manage`) can allow an OHO to run skill code
  (`setOhoSkillExecutionAllowed`). Approval alone does not make an OHO a skill runner.
* **Company admin** (`company.manage`) can flip the Olyros Cloud switch.
* **Company admin** (`oho.manage`) can upgrade an OHO (`upgradeOhoInstance`), use Upgrade all
  and Force, and switch the company to the early-release channel. Every member sees versions,
  badges and upgrade history.
* `ohoRegistrationByToken` has no explicit gate: any authenticated user holding the token can
  read that registration. The OHO's own endpoints use its tokens, not a user session.

**Platform-admin prerequisites (admin app).** A platform admin grants the company access to an
Olyros Cloud pool on the admin app's billing company page (`/billing/:companyId`, Olyros Cloud
tab), and turns on the company's cloud-execution capability (`cloud_execution_enabled`, default
off). Connecting your own GCP project needs that capability and the server flag
`byoc_gcp_enabled`, which is off by default. Without it the BYO mutations answer "Bring-your-own
GCP execution is not available." and the gallery shows the connect tile as "Coming soon". Pools
are managed in the admin app under `/execution/pools`. The OHO release policy and the
minimum-version enforcement switch are platform-admin settings. No plan or tier gate exists beyond these.

## How to configure it

**Install OHO on a machine**

OHO (the Olyros Home Orchestrator) is a service a company runs on its own Linux machine
(bare Ubuntu or WSL2) so that agent work runs there. It runs as an ordinary user, never as
root, and keeps its configuration, database and logs under `~/.olyros/`. Agents run in Docker
containers, so Docker should be installed and the OHO user added to the `docker` group.

1. Install the published package with the one-line installer, as the user that will run OHO:
   ```bash theme={null}
   curl -LsSf https://pkgs.olyrosstudios.com/oho.sh | sh
   ```
   It installs the latest release into a versioned layout that OHO can later upgrade by
   itself and puts the `oho` command on the path. Prefixing the `sh` with
   `OHO_VERSION=<x.y.z>` pins a release. Installing with `pip install olyros-oho` or
   `uv tool install olyros-oho` also works for a try-out, but such an install cannot upgrade
   itself (see Upgrading an OHO below).
2. Create the configuration with `oho init`, an interactive wizard that asks for the instance
   name, the number of parallel tasks, the Olyros server URL and the port of the local web UI,
   and writes `~/.olyros/oho-config.yaml`. `oho config options` lists every setting.
3. Start it: `oho start` runs in the foreground, `oho start --background` as a daemon. `oho
   stop` stops it, `oho status` shows the process, the version and the cloud connection. To run
   OHO as a system service that restarts on failure, `oho service install` writes the systemd
   unit (`--user` for a user unit).
4. `oho logs last --follow` follows the most recent task log; `oho logs list` lists the logs.

**Connect an OHO (sidebar: Orchestration > Connections, `/oho/connect`)**

1. On the machine, run `oho connect --server <url>` with your Olyros server URL, the command
   the page shows. This calls `POST /api/oho/register`. OHO prints the approval URL and opens
   it in a browser when one is available (`--no-browser` only prints it).
2. Open the approval URL (`/oho/approve/<token>`) within 10 minutes while signed in to
   the company that should own it, and choose Approve: `approveOhoRegistration`. Reject calls
   `rejectOhoRegistration`. An expired or already-handled registration is refused.
3. OHO picks up its credentials on its next poll, stores them under `~/.olyros/` and prints the
   company it joined. Restart OHO (`oho stop` then `oho start`, or restart the service) to
   activate the connection; `oho status` then names the company. It appears as an OHO card
   under Orchestration > Environments and in the connected list on Connections.
4. To disconnect from the machine, run `oho disconnect`: it clears the stored credentials and
   revokes the instance on the server. To disconnect from the server side, choose Revoke on
   Connections: `revokeOhoInstance`. Either way, connecting the machine again takes a new
   `oho connect` and a new approval.

**Manage an OHO (sidebar: Orchestration > Environments, `/execution/:backendId`)**

1. Rename it on the Settings tab: `renameOhoInstance`. Run checks on the Diagnostics tab.
2. As a company admin, allow it to run skill code on the Settings tab or under Settings >
   General (`/settings/general`): `setOhoSkillExecutionAllowed`.

**Choose where work runs**

1. Company default: Settings > General (`/settings/general`), "Default "Runs on"":
   `setCompanyDefaultBackend(backendId)`. Clear it with no backend.
2. Per agent: the agent's "Runs on" field in the agent builder: `setAgentBackend`.
3. Olyros Cloud on or off (company admin): the switch on the Olyros Cloud card under
   Orchestration > Environments: `setOlyrosCloudEnabled(enabled)`.

**Connect your own GCP project (Orchestration > Environments > Connect your cloud,
`/execution/connect/gcp`)**

1. Enter the GCP project id, the region and an optional display name:
   `connectByocGcpBackend`. The project id must be 6 to 30 characters, start with a lowercase
   letter, use lowercase letters, digits and hyphens, and not end with a hyphen. The region must
   look like `us-central1`. A company may hold one verified BYO backend, and a project already
   claimed by another company is refused.
2. Run the returned provisioning script in your project.
3. Verify: `verifyByocGcpBackend(backendId, full)`. A second verify while one is running is
   refused. Re-verify later from the card.
4. Optionally set caps on the card's Settings tab: `setByocGcpCaps`. Each value must be a
   positive integer, or empty to clear it.
5. To disconnect, use the type-the-name Revoke on the Settings tab: `revokeByocGcpBackend`.

**Create a runtime image (sidebar: Orchestration > Runtime Images, `/environments`)**

1. Choose New (`/environments/new`) and fill the form: `createEnvironment`. The name is 1 to
   100 characters of letters, digits, hyphens and underscores, unique among the company's
   environments, deleted ones included. The description is under 500 characters. `type` is
   `process` or `docker`; `docker` needs a Dockerfile under 100 KB.
2. Set `timeoutSeconds` between 30 and 7200. Volumes are rejected, because host mounts belong to
   the execution host.
3. Add secrets as `KEY` = value. Keys must match `^[A-Z][A-Z0-9_]*$`, appear once, and not
   repeat an env var name. Values cannot be empty.
4. Edit at `/environments/:environmentId/edit`: `updateEnvironment`. The submitted secret list
   replaces the stored one; a key sent without a value keeps its old value.
5. Duplicate or delete from the list: `duplicateEnvironment`, `deleteEnvironment`.
6. Reclaim old cloud images at `/environments/cloud-images`: `deleteCloudWorkerImage`.

## Upgrading an OHO

An OHO tells the client which version it runs, the platform tells it which version it should run,
and a company admin can upgrade it from the client app with no shell or sudo on the machine.

**Release catalogue and policy (admin app).** An hourly job reads the public package index
`https://pkgs.olyrosstudios.com/simple/olyros-oho/` into the release catalogue (`oho_releases`:
version, wheel, sha256, release-notes link). Pre-releases and local `+build` versions are ignored,
and rows are never deleted. Publishing a release changes nothing for customers by itself. A
platform admin sets the **release policy** on the admin app's **OHO Releases** page
(`/oho-releases`, Execution group) with three pointers, each a version in the catalogue:

| Pointer | Effect |
| - | - |
| Minimum version | An OHO below it shows **Upgrade required**. |
| Current version | What every company is offered. An OHO below it shows **Update available**. Moving it back pulls a bad release: the badge disappears for everyone. |
| Early release version | Optional candidate, offered only to companies on the early-release channel. |

The pointers must satisfy minimum ≤ current ≤ early; a version missing from the catalogue or a
wrong order is refused with a message. The page also lists the catalogue, the companies on the
early channel, and a **Sync now** button that reads the index immediately.

**Early-release channel (Company Settings).** Settings > General has an **OHO early release
channel** switch (`updateCompanySettings(ohoReleaseChannel:)`, `stable` or `early`, default
`stable`). On `early`, the company's OHOs are offered the early release version when it is newer
than current. Olyros uses this to test a candidate on its own OHOs before promoting it to current.
Clearing the early pointer stops the offer; nothing is downgraded.

**Badges.** Each OHO gets `offeredVersion`, `upgradeAvailable` and `upgradeRequired`. The badge
(**Upgrade required** in red, else **Update available**) appears on the OHO card and table row in
Environments, in the OHO detail header, and on each instance on Connections. Its hover text names
the offered version and says "(early release)" on the early channel. An OHO running a dev build
compares on its public version; an unparseable version shows no badge.

**Upgrade button.** On the OHO's Settings tab the **Version** row shows the installed and offered
version and an **Upgrade** button for holders of `oho.manage` (release notes are visible to platform
admins in the admin app only, because the notes live in a private repository). It is
enabled when all of these hold:

* the OHO is online;
* it advertises the `self_upgrade` capability, which it does only when its readiness check passes;
* a newer version is offered;
* no upgrade is already open for it.

The button asks for confirmation naming the source and target version, then calls
`upgradeOhoInstance(ohoInstanceId, targetVersion)`. The server checks the same conditions, that the
target is in the catalogue, and that it is not older than the installed version (a downgrade needs
`allowDowngrade`, which the client does not offer). It records an `oho_upgrades` row and sends the
OHO the version only. The Upgrade action on a Connections card opens this Settings tab.

**Busy OHOs and force.** The OHO refuses while it runs a task, a sandbox invocation or a skill.
The client then offers **Force**, a second confirmation where you type the OHO's name. Once an
upgrade is accepted the OHO stops taking new work; new sandbox invocations and skill runs are
refused with "upgrading" until it restarts.

**Progress and history.** Below the Version row a stepper follows the upgrade: requested,
acknowledged, installing, verifying, switching, restarting, then succeeded, rolled back, failed or
timed out. It refreshes with the page's 5-second poll. A failure or rollback shows the OHO's
message and log tail. The history lists past upgrades with who asked, when, from and to, outcome
and duration (`upgrades` on the instance, newest first).

**Upgrade all.** The Environments gallery has an **Upgrade all** action with one confirmation that
lists each OHO and its target. The client upgrades the eligible OHOs one at a time, waits for each
to finish, and stops at the first failure. There is no server-side batch.

**Upgrade required versus enforcement.** "Upgrade required" is a badge only: by default an OHO
below the minimum still receives work. A platform admin can turn on minimum-version enforcement
(platform setting `oho_enforce_minimum_version`, default off, audited as
`platform.oho_enforce_minimum_version.set`). With it on, new **sandbox runs and skill runs** on an OHO below the minimum,
or reporting no parseable version, are refused with `OHO <name> is on <version>, below the
minimum <min>; upgrade it from Environments` ("upgrade it on the host" when the version is
unknown). Cloud
tasks pulled by the OHO are not gated yet.

**When an upgrade fails.** The OHO installs the new version beside the old one and smoke-tests it
before switching, so a failed download or install leaves the running version untouched and is
reported as `failed`. After the switch it restarts in place and must reconnect and have its
capabilities acknowledged within 120 seconds. If it does not, or it crash-loops, it switches back
to the previous version automatically and reports `rolled_back`. Right before the switch it copies
its local database to `oho.db.pre-<version>` in its data directory (the newest two are kept). The
copy is never restored automatically; the rollback message names it. An upgrade with no answer
within 3 minutes, or no progress for 20 minutes, becomes `timed_out` ("check the host").

**Hosts that cannot upgrade themselves.** An OHO installed the old way (`uv tool install`), a dev
checkout, or a host whose systemd unit does not run `~/.local/bin/oho` with `Restart=always` or
`on-failure` does not advertise `self_upgrade`. Its Version row lists the readiness reasons the
OHO reports (for example "ExecStart points at /opt/oho/bin/oho …") and a **How to upgrade** panel
with the two manual commands. The one-time move to the managed layout is
`curl -LsSf https://pkgs.olyrosstudios.com/oho.sh | sh` on the host, after which
`oho self-upgrade --check` shows the same readiness report.

## Limits and defaults

| Setting | Default or limit | Where enforced |
| - | - | - |
| Registration expiry | 10 minutes | registration service |
| Heartbeat timeout | offline after 90 s without a heartbeat, checked every 60 s | presence tracker |
| Device token rotation | every 7 days, 5-minute grace for the old token | token rotation and presence tracker |
| `skill_exec_allowed` on a new OHO | false | `OhoInstance` model |
| `olyros_cloud_enabled` | true | company settings |
| `cloud_execution_enabled` | false, set by a platform admin | company settings |
| `byoc_gcp_enabled` | false | server config |
| Size classes | `standard` (2 vCPU, 4 GiB) and `large` (4 vCPU, 16 GiB); default `standard` | size classes |
| Cloud job timeout | default 3600 s, maximum 86400 s | size classes |
| Environment `type` | `process` | `Environment` model |
| Environment `timeout_seconds` | 600; allowed 30 to 7200 | model and resolver validation |
| Environment name | 1 to 100 characters, `[a-zA-Z0-9_-]` | resolver validation |
| Dockerfile size | under 100 KB | resolver validation |
| Description | under 500 characters | resolver validation |
| `environmentRuns` recent list | 10 by default, clamped to 1 to 50 | execution queries |
| OHO release catalogue sync | hourly, plus Sync now in the admin app | `oho_release_catalogue_sync` job |
| `oho_release_channel` | `stable` | company settings |
| Open upgrades per OHO | one | partial unique index on `oho_upgrades` |
| Upgrade acknowledgement | 20 s RPC; unanswered upgrade times out after 3 minutes | upgrade service and sweep |
| Upgrade with no progress | `timed_out` after 20 minutes, swept every 5 minutes | `oho_upgrade_timeout` job |
| Post-restart health window | 120 s to reconnect and have capabilities acknowledged | OHO upgrade service |
| Versions kept on the OHO | current plus one previous | OHO layout prune |
| Database copies kept on the OHO | newest two `oho.db.pre-<version>` | OHO upgrade state |
| Minimum-version enforcement | off | platform settings |

## What it emits

* Audit events: `oho.skill_exec_allowed.set`, `execution.olyros_cloud.enabled` and
  `execution.olyros_cloud.disabled`, `backend.byoc.connect_initiated`, `backend.byoc.revoked`,
  `execution.entitlement.granted` and `execution.entitlement.revoked`, and for runtime images
  `environment.secret.created`, `environment.secret.updated`, `environment.secret.deleted` and
  `environment.secret.revealed`. OHO upgrades add `oho.upgrade.requested`, `oho.release_channel.set` and, in the
  admin app, `platform.oho_release_policy.set` and `platform.oho_enforce_minimum_version.set`.
* `oho_upgrades` rows: who asked, from and to version, status, message, log tail and finish time,
  kept as the upgrade history.
* Status changes on OHO instances and backends (`online`, `offline`, `degraded`, `revoked`),
  which the Environments gallery and the placement selector read.
* Month-to-date execution hours per card, from the compute usage meter. A BYO card shows its
  own hours and they are never counted as billable Olyros Cloud time. See
  [Billing and usage](https://user-docs.olyrosstudios.com/billing-and-usage.md).

## Known gaps

* The Connections page says a new OHO "will appear below as a pending request". The pending
  list only shows registrations already bound to the company, and a registration is bound only
  when it is approved, so new registrations never appear there. Approval works only through the
  printed `/oho/approve/<token>` link.
* Approving an OHO, revoking it and connecting or revoking a BYO GCP backend are open to any
  company member. No editor or admin gate exists for them today.
* `assignAgentToOho`, `removeAgentFromOho`, `ohoAgents` and `rotateOhoCredentials` have no UI;
  they are API only.
* Only GCP can be connected as your own cloud. `aws` exists as a provider value but has no
  connect flow.
* Pool entitlements have no tenant-side request flow; a company asks Olyros.

## Customer-safe summary

You choose where your agents' work runs. Connect your own machine by running one command on it
and approving the link it prints, and it shows up next to Olyros Cloud as a place to run work,
with live status, usage and built-in checks. If your company is enabled for it, you can also
connect your own Google Cloud project, verify it, set limits on how many runs it takes and for
how long, and disconnect it whenever you want. You can pick a default for the whole company or
pin individual agents, and an admin can turn Olyros Cloud off entirely. Runtime images describe
what a task starts in: a plain process or a container, with environment variables, secrets that
are only shown on request, and a time limit. Each connected machine shows its version and tells you when a
newer one is available or required, and an admin can upgrade it from the browser with one click:
progress is shown live, and if the new version does not come up cleanly the machine returns to
the previous one by itself.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.