Sync the self-hosting stack

This commit is contained in:
2026-10-01 08:14:29 +02:00
parent ef1b961d2d
commit b8cf169331
2 changed files with 371 additions and 11 deletions
+72 -11
View File
@@ -73,6 +73,13 @@ and different accounts on the far end. The choice is made before the shell opens
the session and in the audit trail, and every route is held to the same limits: the same idle and
duration ceilings, the same recording, the same retention policy.
**And, on Windows, a screen.** Where the terminal gives you a shell on an enrolled machine, remote
desktop gives you what the person sitting at it is looking at. It reuses the terminal's permission
model and adds one thing the terminal has no equivalent of: **the person at the machine is always
told.** Each organisation chooses a standing banner or a request they must answer, there is no third
choice and no way to switch the notice off, and the session ends if the notice cannot be kept in
front of them. Nothing of the screen is recorded — see [The agent](#the-agent).
**Documents.** A conversation accumulates what the assistant writes: reports and runbooks in
Markdown, diagrams in Mermaid, tabular data as a workbook. What it writes is always a *source*, and
Jarvis renders the file on download — PDF and Word from prose, Excel and CSV from a workbook, HTML
@@ -290,14 +297,23 @@ marked installed by a backfill — so you will never see the install screen. Not
All three are the kind that produce confusing symptoms rather than clean errors.
- **Forward the WebSocket upgrade.** Two separate sockets ride `JARVIS_PORT`: the chat, on
`/socket.io/`, and enrolled agents, on `/api/agents/ws`. Neither falls back to plain HTTP. Without
- **Forward the WebSocket upgrade.** Three separate sockets ride `JARVIS_PORT`: the chat, on
`/socket.io/`; enrolled agents, on `/api/agents/ws`; and, for remote desktop only, one media
connection per live session on `/api/agents/ws/desktop`. None falls back to plain HTTP. Without
the upgrade the chat does not lose streaming — it never connects at all, and since the prompt
itself travels over that socket, nothing sends. Presence and in-chat approvals go with it, and no
agent can connect.
itself travels over that socket, nothing sends. Presence and in-chat approvals go with it, no
agent can connect, and no screen can be watched. A proxy that forwards `/api/agents/ws` by exact
path rather than by prefix will pass the first two and silently fail the third, which reads as
"remote terminal works and remote desktop does not".
- **Give it a long read timeout** — 300s or so. A reasoning model can go 90+ seconds without emitting
a byte, and a 60s default cuts the response mid-stream. The client sees a connection reset rather
than a timeout, which reads like a bug in Jarvis.
than a timeout, which reads like a bug in Jarvis. The desktop media socket is legitimately silent
for far longer than that — a viewer whose tab is hidden pauses the stream, and nothing is sent
until the tab comes back — but it does not need a longer timeout, because the api pings it on a
beat of its own and a WebSocket ping is traffic as far as your proxy's read timer is concerned.
A proxy that drops idle **upgraded** connections on a separate, shorter clock is the one
configuration that breaks this; on nginx that is `proxy_read_timeout` and the ping already
covers it.
- **Let uploads through.** Attaching or uploading a file posts it to `/api/uploads/`, up to 10 MB
each, and an image uploaded to a workspace travels with a copy of up to 3 MB prepared for the
model. Your proxy must accept request bodies of at least **13,376 KiB** on that path (nginx:
@@ -416,16 +432,42 @@ Four things worth knowing about it:
recorded by default, encrypted under `VAULT_MASTER_KEY` and deleted on a retention policy you set
under **Settings → Organization → Terminal sessions**. Turning recording off stops the transcript,
never the audit entry.
- **It carries a remote desktop, on Windows.** The same permission model, one level up: a person
with the right watches the signed-in session's screen from the browser. **Nobody is ever watched
invisibly.** Each organization picks one of two policies under **Settings → Organization → Remote
desktop** — a banner that stands on the screen for the whole session, or a prompt the person must
answer before anything is captured, which auto-accepts only when nobody is signed in. There is no
third option and no way to turn the notice off, which is the one decision in this feature that is
not configurable. The session ends the moment the banner cannot be kept visible. Nothing of the
screen is stored: there is no recording, no thumbnail and no still, so the audit entry is the
whole of the trail. Linux and macOS are not supported yet, and a session opened against one is
refused rather than silently downgraded.
**What an enrolled agent can do.** Inventory the machine, run commands, read, write and fetch files,
list and control services, list processes, update itself, and carry that shell. It runs as root on
Linux and macOS and as LocalSystem on Windows, deliberately — its purpose is to administer the
machine.
list and control services, list processes, update itself, carry that shell, and — on Windows — show
its screen. It runs as root on Linux and macOS and as LocalSystem on Windows, deliberately: its
purpose is to administer the machine. Watching a screen is the one thing it cannot do from there,
because a Windows service has no access to the window station a person is signed in to; capture runs
in a short-lived helper the service launches into that session, and that helper is also what draws
the notice.
What the **assistant** does with that reach is bounded by the autonomy policy and the approval gates
above. **The interactive shell is not.** There is no command to inspect before a shell opens, so the
risk ceiling has nothing to weigh; it is gated instead by a permission and a per-machine switch on
the grant. Decide who holds those before enrolling anything you care about.
above. **The interactive shell and the remote desktop are not.** There is no command to inspect
before a shell opens and no command at all behind a screen, so the risk ceiling has nothing to
weigh; both are gated instead by a permission and a per-machine switch on the grant, and neither is
ever opened by the assistant — a person opens them. Decide who holds those before enrolling anything
you care about. The desktop has one protection the shell does not, and it is not a permission: the
person sitting at the machine is told, every time, for as long as it lasts.
**Being told is not the same as being able to stop it, and the difference matters.** The notice is
click-through on purpose — it takes no click, it has no menu and it has no keyboard — so that it can
never sit between somebody and the work they are doing, and so that it cannot be closed by accident
or by a script. The cost of that choice is that the person at the keyboard cannot dismiss the viewer
from the notice itself. Their ways out are elsewhere: refusing the prompt under the ask policy,
before anything is captured; signing out, which ends the session with it; or an administrator
turning the feature off for the instance. What the banner guarantees is that watching is never
secret. It does not guarantee consent once it has started, and under the banner policy it is not
asking for any.
## Things worth knowing before you trust it with production
@@ -468,6 +510,23 @@ These are deliberate and documented rather than surprises waiting to be found.
something to watch rather than something to assume. Two API processes have been run together
against one database and one Redis, and the manifests are published, but that is not the same
thing as your machines depending on it.
- **Remote desktop is the newest thing here, and its way out is a switch rather than a rollback.**
The api and the web roll back by pinning a digest, but an agent has already replaced its own binary
on every machine it runs on by the time you want it back — so the control that matters is
**Settings → Platform → Agents → Remote desktop**. Turning it off refuses new sessions and ends
every live one within 15 seconds, fleet-wide, without touching the interactive shell or anything
else the agent does. Know where it is before you need it. Two consequences worth holding onto: no
part of a screen is ever written anywhere, so if an incident needs a record of what was *seen*,
this feature cannot produce one after the fact. What the session record does hold is more than a
timestamp — who watched, which machine, which Windows session and account, which monitor, which
consent policy applied, whether consent was agreed and when, whether it was auto-accepted because
nobody was signed in to be asked, whether control was allowed, how many input events were accepted
and how many were dropped, and how it ended — so write a staff disclosure from that list rather
than from "no recording". Note what is *not* on it: there is deliberately no column saying the
banner was drawn. The banner is drawn by the agent on the far side of a websocket and the server
never learns whether it went up, so a field answering "was it shown" could only ever hold a guess;
what the row holds instead is which policy the session ran under. And it is Windows-only; a session opened against Linux or macOS is
refused outright rather than quietly degraded into something weaker.
- **There is no rate limiting on sign-in.** No throttler, no account lockout, and authentication
events are not audited. Credential stuffing is bounded only by the reverse proxy you put in front,
which this repository does not ship. If your proxy can rate-limit one route, make it that one.
@@ -544,6 +603,8 @@ wrong on the screen that asks for it.
| An answer dies part-way through, every time | The proxy's read timeout is too short. |
| Everything works but one kind of thing cannot be created | A limit is full — the community edition's, or your licence's. The message names which. See below. |
| An agent installer answers 503 | No agent build is published — the overlay is off. That is a supported state. |
| The remote terminal works and remote desktop never connects | The proxy forwards `/api/agents/ws` but not the paths under it. The media socket is `/api/agents/ws/desktop` and needs the upgrade too. |
| A remote desktop session opens and ends immediately | Almost always the notice. It ends by design if the banner cannot be kept on top, if the person refuses, or if nobody answers the request within the minute. The end reason on the session says which. |
The api takes about a minute on first boot, syncing the schema before it listens. `docker compose ps`
showing `health: starting` for that long is expected, not a fault.