Remote runhosts¶
A remote runhost is a Linux server you own that runs your QuickAgents for you. The CLI (or the desktop app) sets it up over SSH and then drives it over SSH: a run on it is the same run the Runner reference describes, with your consent and your keys, executed on the server instead of this computer. Nothing about it goes through Agentry: the registry is not in the path, no credits pay for its compute, and a run there is never a hosted run.
This page describes CLI v0.7.14. A runhost runs the same CLI version as the computer that drives it (see Updates).
What it is for¶
- Runs that need a machine that stays on: schedules that run with nobody present, and persistent agents that keep running when your laptop is shut.
- More capacity than your own computer, on hardware you choose.
- Your secrets stay yours: they reach your own server, never Agentry.
Servers¶
Debian 12 and 13, Ubuntu 22.04 and 24.04, Fedora 43 and 44, and RHEL, AlmaLinux and Rocky Linux 9 and 10, on amd64 or arm64, with systemd 249 or newer. Schedules need systemd 256 or newer (see The store): setup's checks say so on an older server, and it runs everything else.
The server needs at least 20 GB of free disk, 2 GB of free memory, and
outbound HTTPS to ghcr.io and your registry. An existing Docker Engine is
kept. Another container engine running containers stops setup; podman that is
installed but runs no container, as Fedora and the RHEL family install it, is
left beside Docker Engine and never used.
Setting one up¶
add signs in with an admin sign-in: root, or an account that can
sudo, by a key file, the SSH agent or a password, each named by a file, an
environment variable or a prompt, never by a value on the command line. The
admin sign-in is used for this one call and kept nowhere, on either machine.
The server's host key is checked as a target host's is: a key in
your known_hosts is accepted, an unknown one is asked about at a terminal,
and a changed one is refused.
Setup first checks the server without changing anything and shows every finding: the system, its architecture and systemd, a TPM2, free disk and memory, the container engines and gVisor runtimes already there, the ports already open, and whether the registries are reachable. An unsupported server stops there. Then it installs, each step one that can run again:
- an
agentryaccount with no password and no shell of its own: its login shell is the CLI, which runs the runhost's relay and nothing else, and the account has linger, so its service runs with nobody signed in; - Docker Engine from Docker's own repository, when the server has none.
The
agentryaccount joins thedockergroup, which makes it root-equivalent on the server. Your run key can reach only the runhost's service (below), never a shell; - gVisor (
runsc), pinned by version and SHA-512 and registered with the Docker daemon asrunscandrunsc-uds. Every container a run starts runs under it, the gateway underrunsc-uds; - this CLI's own signed release for the server's architecture: its
signature is checked on this computer and again on the server, in the
agentryaccount's own directory; - under SELinux, a module that labels the CLI's directories as commands; on a
RHEL-family kernel that lacks Docker's netfilter module, that kernel's own
kernel-modules-extra; - the images runs need, checked by their signatures;
- the runhost's service, a systemd user service of the
agentryaccount.
Then it pairs this computer: a run key (ed25519) and a sealing key (X25519)
are made here and kept in this computer's keychain. The run key's public half
goes into the account's authorized_keys with
restrict,command="agentry runhost serve --device <id>", and the sealing
key's into the service's list of devices. Finally it checks, over the run key
alone, that the service answers and its doctor is green, that the run key is
refused a shell, a terminal, any other command and every forwarding, and that
no network listener was added.
The owner of a runhost is the Agentry account this computer is signed in
to at setup, or, set up signed out, its paired devices alone, bound to an
account at the next pair made signed in.
How it is reached¶
The service listens on an owner-only Unix socket in the agentry account's
runtime directory, and on nothing else: setup opens no network port. SSH is
the only way in, and only your run key's forced command reaches the service.
Each request is one of its verbs (a job, attaching to one, cancelling,
collecting, status, doctor, version, update, the store, schedules, sign-ins,
agents, unpairing). Setup, pairing, Unsafe Mode and removal are not verbs of
the run key: they take the admin sign-in.
Setup adds no firewall. The service needs nothing open but SSH, so you may firewall everything else; the runs' own egress is bounded by the egress proxy and gVisor, exactly as on your computer.
A run on a runhost¶
The release is resolved and verified on this computer as for a local run, your consent is asked here, and the run's secrets, model key, files and intake are read here. One SSH session carries the job to the service, followed by the release when the runhost does not already keep it. The service verifies the release again with its own CLI's keys, keeps it in its store, and runs it under gVisor in a job directory of its own:
- Secrets and files are on the server while the run runs. Secrets are in a file only the account can read, deleted when the run ends, on every path; a run's files are deleted with its job directory. Neither ever reaches the agent's container but as the runner gives it there, as on your computer.
- The output is sealed to every paired device's sealing key before it is
kept, and the plaintext is deleted. It waits, sealed, until a device collects
it, and at most 7 days. This computer opens it into
./agentry-out/as a local run's. - The receipt says the run happened on the runhost and names its host key.
A run that loses its connection goes on on the runhost: agentry runhost attach
lab <job> follows it again, agentry runhost jobs lab lists the runhost's
jobs, and collect and cancel act on one. An interactive session runs there
too (--mode interactive --on lab), driven from this terminal.
Claude Code, Codex and Copilot run on a runhost only as their images, under
gVisor: agentry runhost model lab --sign-in claude|chatgpt|copilot signs the
runhost in to your plan from this computer's browser, and the sign-in is the
runhost's own. agentry runhost model lab --provider agentry gives it a token
that can only pay for model use with your Agentry credits, revoked by unpair
and remove.
A target host a release reaches is resolved and reached from the runhost, with this computer's sign-in for it.
The store¶
The runhost keeps what it must hold between runs in its store: the releases it
has run, its model sign-ins and credits token, the model key its persistent
agents run on, what each schedule needs to run with nobody present, and its
persistent agents' stored secrets and accounts. Nothing is written to it
without a consent that names it and the server, and agentry runhost store
lab lists it, never a value.
Every entry is encrypted under the store's key. On systemd 256 and newer that
key is sealed by systemd-creds to the server (to its TPM2 where it has one,
to its own credential key otherwise) and to the agentry account, and opened
into memory only. This protects a copied disk or a backup, not a running
server's root, which can open what the account can. Below systemd 256 the
key is a file the account owns, and the runhost takes no schedule.
Schedules¶
The schedule is prepared here as a run is, then handed to the runhost with
what its occurrences need: the release, its secrets and model key, its files,
its destinations and target hosts, each named in the consent. The runhost fires
its occurrences itself, with nobody present, and each one's output waits sealed
for the next collection. An OAuth connection the release signs in to is the
runhost's own: you sign the runhost in from this computer's browser, and it
keeps and refreshes that grant itself; this computer's connection is never
handed over. agentry runhost schedules lab lists them, and agentry runhost
store lab --remove schedule:<id> takes one off with everything it kept. Needs
CLI v0.7.11 or later.
Persistent agents¶
agentry runhost model lab --provider anthropic --model claude-sonnet-5-5
agentry agent start assistant --on lab
agentry agent chat assistant --on lab
The persistent agents run on the runhost under its service, on the model the
runhost keeps (agentry runhost model … --provider <provider> keeps that
provider's key in its store). agentry agent list|show|start|stop|chat|attach|
enable|disable|reset|grant|configure|tasks|secret --on lab drive them; what an
agent would be given for the first time is agreed to on this computer. A stored
secret, a git host account's token, the Fastmail token and a calendar feed's
address are read here and kept in the runhost's store once you agree; Microsoft
365 signs in by its device code. The service starts again every agent it was
running after it restarts. Agentry Helper runs only in the desktop app. Needs
CLI v0.7.14 or later.
On a runhost the Coding agent's programs run under gVisor as an unprivileged user that owns only the agent's workspace and home: gVisor has no Landlock, which holds those writes on a computer. A step that needs root, such as a system package install, fails there.
Unsafe Mode¶
agentry runhost set lab --unsafe-mode on --user admin makes every run on the
runhost, from every paired device, an Unsafe Mode run, still under
gVisor and behind the egress proxy. The setting is kept on the server in a file
only root writes, so only the admin sign-in changes it; runs say it is on.
Devices¶
agentry runhost pair lab ssh://admin@lab.example.net pairs another of your
computers with the admin sign-in: its own run key and sealing key, and
nothing else. agentry runhost unpair lab, over the run key, takes this
computer off and revokes the credits token it made; the last device cannot
leave that way, remove is the way out.
Updates¶
A runhost runs this computer's exact CLI version, and a run on one of another
version is refused, naming both. After this CLI changes version, its first
runhost command updates every paired runhost over the run key, and agentry
runhost update does it on demand. The runhost installs only a CLI release
whose signature verifies against the keys its own CLI carries, for its own
architecture, and no older than the one it runs. It readies the new release's
images first, and restarts its service once its running jobs finish. gVisor
follows the version the CLI pins. What only the admin sign-in can change is
reported as needing attention.
Removing one¶
agentry runhost remove lab --user admin stops the service, removes the
agentry account with everything in its home, takes gVisor's runtimes out of
the Docker daemon, revokes the credits token and ends the sign-ins. Docker
Engine and the images stay unless you pass --remove-docker (only when setup
installed it) and --remove-images.
Command reference¶
| Command | What it does |
|---|---|
agentry runhost add <name> ssh://[user@]host[:port] |
Sets the server up and pairs this computer, with the admin sign-in (--key, --agent, --password-env, --password-file, --sudo-password-env, --sudo-password-file, --yes). |
agentry runhost list |
This computer's runhosts: name, address, host key, owner, CLI version. |
agentry runhost status <name> |
The runhost's state over the run key. |
agentry runhost doctor <name> |
Its engine, gVisor for every container, its images and its service. |
agentry runhost update [<name>…] |
Brings runhosts to this CLI's version. |
agentry runhost pair <name> ssh://… / unpair <name> |
Pairs another computer / takes this one off. |
agentry runhost model <name> |
--sign-in claude\|chatgpt\|copilot, --provider agentry, or --provider <api provider> [--model] [--api-key-env] for its persistent agents. |
agentry runhost set <name> --unsafe-mode on\|off |
Unsafe Mode, with the admin sign-in. |
agentry runhost store <name> [--remove …] |
What its store keeps; removes the credits token, a sign-in or a schedule. |
agentry runhost schedules <name> [--run <id>] |
Its schedules and their runs. |
agentry runhost jobs <name>, attach, collect, cancel |
Its jobs and their sealed outputs. |
agentry runhost remove <name> |
Takes Agentry off the server, with the admin sign-in. |
agentry run … --on <name> |
A run, or an interactive session, on the runhost. |
agentry schedule add … --on <name> |
A schedule the runhost runs with nobody present (--check says what it would keep). |
agentry agent … --on <name> |
The persistent agents on the runhost. |