Runners
A Runner is a small native app you install on a real machine (Windows, macOS, or Linux) so agents can act on that machine: capture a genuine full-desktop screenshot, drive a browser you are already logged into, run a command, or read and write files.
It exists for the cases a headless browser cannot cover. When an auditor wants a screenshot with the real desktop, the OS clock, and the signed-in identity - not an AI-generated or headless render - a runner captures the true screen of a real session. The same channel lets an agent operate an authenticated browser or run a check directly on a workstation or server.
Runners are pull-based: the app connects outbound to XTM One and pulls work. The platform never opens a port on your machine, and there is nothing inbound to firewall.
Install a runner
You download and enroll runners from Profile > Runners. On a personal machine
the graphical installer needs no command line; for servers and fleets there is a
fully headless command-line path (see the next section).
- Open
Profile > Runnersand download the installer for your operating system. The main button is the x86_64 (Intel/AMD) build; ARM machines take thearm64link next to it. Macs need no choice at all - one universal bundle covers both Intel and Apple Silicon. - Run the installer (
next, next, finishon Windows; drag toApplicationson macOS; an AppImage or a.deb/.rpmon Linux). - Launch XTM One Runner. On the
Connectscreen, paste this instance's URL and an enrollment key, then connect.
If the OS blocks the first launch
A build that is not code-signed for your operating system trips the first-open gate: Windows SmartScreen shows "unrecognized app" (click More info > Run anyway), and macOS reports it "could not verify ... is free of malware" - click Done (not Move to Trash), then open System Settings > Privacy & Security, click Open Anyway, and launch again. This only ever concerns the first manual install: self-updates are signature-verified and never re-prompt, and the headless install path is not affected.
Create an enrollment key from the same Profile > Runners screen. A key is
single-use for the first machine but can be configured for reuse across a fleet,
and it can carry defaults (labels, capabilities, permission mode) so an
unattended roll-out lands already configured. After enrollment the app stores a
durable credential in the machine's OS keychain and stays connected across
reboots - you never paste the key again.
One record per machine
Each enrolled machine is one runner. Installing on ten machines gives you ten runners you can name, label, and target individually - not ten integrations. Re-enrolling a machine that is already in the list (a reinstall, a re-run of the install script) updates its existing record - new credential, refreshed host facts, your name/permissions/labels kept - instead of creating a duplicate. Revoked runners stay revoked: enrolling that machine again deliberately creates a fresh record.
Install headless (command line)
Servers, VMs, and MDM-managed fleets rarely have someone sitting at a desktop.
For those machines, Profile > Runners also shows a one-line install command
per operating system under Headless install (command line): copy it, replace
the key placeholder with an enrollment key, and run it on the target machine -
no graphical session is ever needed.
The command downloads the runner build matched to your instance's version,
verifies its integrity, installs the binary, enrolls the machine, and registers
it to start automatically (a LaunchAgent on macOS, a systemd user service on
Linux, a logon task on Windows). The same binary is also a CLI afterwards:
xtm-one-runner status, xtm-one-runner run, and xtm-one-runner reset manage
it without any UI.
The headless build (Linux servers)
On Linux the installer picks between two builds of the same runner:
| Build | Ships | Capabilities |
|---|---|---|
| Desktop (default) | Everywhere else, and any Linux with a graphical session | Screenshots, mouse/keyboard, shell, files, browser |
| Headless | Linux hosts with no graphical session | Shell, files, browser |
This is not a matter of taste. The desktop build links the desktop libraries (GTK, X11) at load time, so on a server without them it fails before it runs - no flag or setting can work around that. The headless build links none of them.
The installer decides from the environment: no DISPLAY and no
WAYLAND_DISPLAY, and no graphical session on the machine, means headless — so
SSH-ing into your own Linux desktop to run the installer still gets you the
desktop build. Force either one with --headless or --desktop (or
XTM_RUNNER_FLAVOR=headless for cloud-init and MDM). The choice sticks: a
headless runner is only ever offered headless updates.
Two things a server does differently:
- Credential storage. Servers usually run no keyring daemon. When there is no OS keychain, the runner stores its credential in a file readable only by its own user, next to its config, and says so in the log.
- Staying up after logout. The service runs under your user account, so
enable lingering or it stops when your SSH session ends. The installer does it
for you when it can:
sudo loginctl enable-linger <user>.
Desktop capabilities need a desktop
Screenshots and mouse/keyboard control require a logged-in graphical session. Shell commands, file operations, and browser control work on fully headless servers. A headless runner asked for a screenshot answers with a clear error rather than a black frame - assign that work to a runner on a real desktop.
The runner app
Once enrolled, the app lives in the system tray (or menu bar) behind the XTM One icon. From there you can:
- see live status -
Connected,Connecting, orOffline - open an overview panel with the runner name, the enrolled instance URL, the app version, and the host facts reported to the platform (OS build, available shells, installed browsers, monitors, timezone and locale)
- change a few settings - automatic updates, launch-at-login, and the browser CDP URL
- unenroll the machine locally
Closing the window hides the app to the tray; the runner keeps serving. The app updates itself from signed bundles matched to your instance, so a fleet stays current without anyone touching each machine.
Uninstall and re-enroll
Uninstalling the app removes the local enrollment with it - the stored
credential, the configuration, and the launch-at-login entry - so the next
install always starts fresh at the Connect form. The runner's record on the
platform is deliberately left alone (an uninstall can happen offline): revoke
it in Profile > Runners when you retire a machine for good.
If a running runner's record is revoked on the platform, the app shows a fatal error with a Re-enroll this machine button: one click drops the dead local credential and reopens the Connect form, prefilled with your instance URL and ready for a fresh enrollment key.
Permissions the first time
- macOS asks for Screen Recording and Accessibility permission the
first time an agent captures the screen or controls input. Grant them in
System Settings > Privacy & Security; the app links you straight there and shows whether each one is granted. - Linux capture and input need a graphical session. On Wayland, capture goes through the desktop portal; the app warns when the current session cannot be captured.
What an agent can do on a runner
When an agent has the computer_use built-in tool and at least one of your
runners is online, it can:
- take a full-desktop screenshot (the audit-evidence case)
- perform mouse and keyboard actions
- run a shell command
- read, write, and list files
Flows can drive runners too: the Runner command node dispatches the same
command kinds through the same transport — the runner's permission mode,
allow-lists, and approval gating apply unchanged — and can wait for the
result. Flows can also react to runner lifecycle through the built-in
Runner online, Runner offline, and Runner command completed event
types with the On event and Wait for event nodes.
- control a browser you already authenticated
Screenshots and file reads come back into the conversation as inline images or downloadable files, exactly like other tool results, so they can flow straight into an evidence workflow. The PNG is also forwarded to the model as a native vision block (high-detail, PNG preserved) so the agent can read the URL bar, labels, errors, and OS clock itself - it should never ask you to describe or verify the capture.
Control what a runner allows
Each runner carries its own permission model, set in Profile > Runners:
- Restricted (default) - least privilege. Only the capabilities you enable
are allowed (screenshot, mouse/keyboard, shell, file operations, browser
control). Enabling a capability is the consent: once it is on, it runs
without further prompts. Shell commands are the exception and get finer
control:
- Allow-list (standing approvals) - a matching command runs immediately and never asks for approval. With approval off, only allow-listed commands can run at all.
- Block-list (standing refusals) - a command containing a blocked word or phrase is always refused. It never runs and never reaches the approval queue, and the block-list wins over the allow-list.
- Require approval - any shell command not covered by the lists waits
for a human decision in
Profile > Runners. When approving or rejecting, Approve & always allow / Reject & always block persists the decision into the corresponding list, so the same command never asks again. Approval applies to shell commands only - screenshots, input, file operations and browser control never queue. - File operations can additionally be narrowed with a path allow-list.
- Full control - a deliberate opt-in that allows every capability and every command with no lists and no approval. It is clearly flagged in the UI, and every command is still audited.
Whatever the mode, every command is recorded server-side with its result, and revoking a runner invalidates its credential immediately - the next command fails and the app stops.
Choose which machines an agent can reach
Runners are targeted, not global:
- Give runners labels (for example
audit,eu-west,workstation). - On an agent, set a runner selector - specific runners or a set of labels - so the agent can only reach the machines you intend.
- An assignment can refine that selection further, never widen it, so an
agent-driven automation can never reach a machine its agent could not. A
flow's
Runner commandnode targets one explicit runner instead — gated by the runner's own permission mode, allow-lists, and visibility (a flow can only use runners visible to the person who runs it: their own, group-shared, or company-managed).
When more than one eligible machine is online, mutating actions require the agent
to name the target runner explicitly, so a command can never land on the wrong
machine by accident. The list_runners tool lets an agent see which machines are
online before acting.
Availability and limits
The whole subsystem is governed by platform configuration: an administrator enables it, sets where installers are downloaded from, and can cap how many runners a user may enroll and how many commands may run on one machine at once. If downloads are not configured on your deployment, the page explains it and you can still enroll a runner you obtained separately. See the runner variables in Configuration for the full list.
Good habits
- Name each machine so you can tell an agent exactly where to work.
- Start in
Restrictedmode and enable only the capabilities you need; reserveFull controlfor machines you fully trust. - Use labels for fleets and set agent selectors so each agent reaches only its own machines.
- Turn on shell-command approval when a person should stay in the loop, and build up the allow/block lists from real decisions with "Approve & always allow" / "Reject & always block".
- Revoke a runner as soon as a machine is decommissioned.
Related
- My profile - where you download runners and manage enrollment keys.
- Agents - bind the
computer_usetool and set the runner selector. - Configuration - the
RUNNERS_ENABLEDandRUNNER_*deployment variables.