Fleet: ship an agent update safely
Fleet connects NexusRun Cloud to local Linux computers. Publish one exact agent version, let a small group try it first, and keep the working version when a candidate fails its acceptance tests. Model inference runs on each computer, not in Cloud.
A host is an enrolled computer. A channel is an update group, such as
production. A canary is a host that tests and activates an update before
the rest of its channel receives permission to activate it.
Before you start
- Use an organization where you are an owner or administrator in NexusRun Cloud. Your plan's host limit applies to enrollment.
- Use Linux x86-64 hosts with a compatible CPU runtime and system libraries. This guide uses CPU inference; a GPU is not required.
- Install the NexusRun binary on the preparation computer and each host. Follow
the first-helper guide for Go, Ollama, the small
qwen2.5:0.5bdownload, and building NexusRun. Only the preparation computer needs Go and Ollama; enrolled hosts use the sealed weights directly. - Prepare a reviewed managed CPU runtime. Follow Build the CPU runtime
and Import it in the offline walkthrough. Copy that
same runtime archive to each host. Match the destination's CPU features and
system libraries, not just its
x86_64architecture. - Keep an internet connection for enrollment, artifact downloads, and updates. An activated release can run while disconnected.
Fleet accepts sealed, single-model chat agents with an included acceptance suite. An agent may use script tools and secrets (see Tools and secrets); MCP servers and model auto-selection are excluded. Test prompts and expected answers in the suite travel inside the published artifact: use synthetic, non-private examples.
Run the commands below from the nexusrun source folder. Replace YOUR_ORG
with your organization slug and PASTE_RUNTIME_ID_HERE with the complete
identifier printed by runtime list. Do not paste a filesystem path there.
1. Package and upload the demo
On your preparation computer:
./bin/nexus build examples/fleet-demo --seal
./bin/nexus inspect fleet-demo:0.1.0
./bin/nexus login
./bin/nexus push fleet-demo:0.1.0 registry.nexusrun.dev/YOUR_ORG/fleet-demo:0.1.0
Keep the full sha256:... artifact digest shown by the build. A digest
identifies exact bytes; a version tag is a human-friendly label. Rollouts use
the digest, so changing a tag does not change an existing release.
The example's nexus.yaml selects the small model, CPU execution, and a Linux
target. Its evals/suite.yaml includes two simple checks: arithmetic and a
short greeting. Both must pass on a host before that host activates it. These
checks demonstrate delivery gates; they are not a general quality or safety
assessment of the model.
2. Enroll the hosts
On the first host, import the runtime archive you prepared:
./bin/nexus runtime import ./llama-demo.runtime.tar.gz
./bin/nexus runtime list
./bin/nexus runtime verify 'PASTE_RUNTIME_ID_HERE'
./bin/nexus login
./bin/nexus fleet join registry.nexusrun.dev/YOUR_ORG/fleet-demo --name host-01 --channel production
Repeat on the other hosts, choosing labels such as host-02 and host-03.
Labels must be unique in the organization. Avoid names containing customer
information. One NexusRun home enrolls for one repository and channel; use a
separate private NEXUSRUN_HOME when intentionally maintaining another
independent installation on the same computer.
Enrollment writes a private, repository-scoped host credential locally. It can check in and pull from its assigned repository; it cannot publish releases. Enrollment also creates the host's own signing key and prints its fingerprint; the private half never leaves the host (see Signed release records). Keep the NexusRun home private and do not copy it between hosts. After enrollment, polling uses this credential rather than your administrator login.
3. Start a one-host canary rollout
On your preparation computer, replace both placeholders:
./bin/nexus fleet release registry.nexusrun.dev/YOUR_ORG/fleet-demo \
--digest 'PASTE_SHA256_DIGEST_HERE' \
--runtime 'PASTE_RUNTIME_ID_HERE' \
--channel production --canaries 1
The first enrolled host in that repository/channel is the canary. With
--canaries 2, the first two enrolled hosts are selected. Selection is fixed
for the release; removing a selected canary pauses its rollout rather than
silently reducing the required approvals.
On each host, run:
./bin/nexus fleet sync
./bin/nexus fleet status
The canary downloads the exact artifact, verifies its bytes and pinned runtime, and runs its tests through the real local CPU backend. It asks Cloud for permission again after testing, then atomically changes its active release. All selected canaries must report activation before other hosts are allowed to activate. Every remaining host also runs the acceptance tests itself.
If a non-canary reports canary, run sync there again after the canary
finishes. A rejected candidate pauses further activation and preserves that
host's previous active release. Hosts that already activated are not
automatically moved backward: use a tested rollback when needed.
4. Ask the active agent a question
On an activated host:
./bin/nexus fleet run -p "What is 2 + 2? Answer with just the digit."
Expect 4 and a CPU backend summary. fleet run uses the activated artifact
and its exact runtime without contacting Cloud. fleet status also reads only
local state. Keep loopback networking enabled for the local model server.
For recurring update checks, leave this running in a separate terminal:
./bin/nexus fleet watch --interval 30s
Interrupt with Ctrl+C. A network outage leaves the local active release in place; the watcher retries on its next interval. Only one Fleet operation uses a given home at a time. A watcher encountering an active invocation retries later, so update evaluation does not compete with it for model memory.
Updates affect subsequent fleet run invocations. Running an ordinary
nexus run reference does not select the Fleet active release.
5. Serve local applications
fleet serve does what watch does and also answers applications on the same
computer through an OpenAI-compatible endpoint:
./bin/nexus fleet serve
./bin/nexus fleet key
serve listens on 127.0.0.1:7720 (change it with --addr; only loopback
addresses are accepted). fleet key prints the API key, which stays the same
across restarts. Point any OpenAI client at http://127.0.0.1:7720/v1 with
that key:
curl -s http://127.0.0.1:7720/v1/chat/completions \
-H "Authorization: Bearer $(./bin/nexus fleet key)" \
-H "Content-Type: application/json" \
-d '{"model":"fleet-demo","messages":[{"role":"user","content":"What is 2 + 2?"}]}'
from openai import OpenAI
client = OpenAI(base_url="http://127.0.0.1:7720/v1", api_key=FLEET_KEY)
client.chat.completions.create(model="fleet-demo", messages=[{"role": "user", "content": "Hello"}])
- Every answer comes from the active release: its system prompt, sampling
settings, model and tools. A request's own system messages are added after
the release's system prompt. The
modelfield is not used to choose anything;GET /v1/modelslists the active unit. - Each response names the release that produced it in the
X-Nexus-ReleaseandX-Nexus-Digestheaders, and the digest insystem_fingerprint, so an application can log exactly which tested version answered. - Requests that try to add their own
toolsare refused. Text content only. stream: truereturns standard server-sent event chunks; the answer arrives once generation finishes, as one content chunk.- The model stays loaded between requests. When an update arrives,
serveunloads the current release, tests the candidate, and answers requests in the meantime with503andRetry-After: 30. The first request after activation loads the new release. serveis the one process using this NexusRun home while it runs;fleet sync,watchandrunreport that another fleet operation is in progress.- The endpoint has the same protections as
nexus serve: requests must carry the key, and web pages in a browser cannot reach it.
Fleet does not supervise your application process or restart in-flight work.
6. See the fleet in Cloud
Open your organization in the Cloud dashboard and select Fleet. It shows host assignments, last check-in, reported hardware, active artifact/runtime, acceptance counts, and release history. Use Refresh status to reload it. Members can view status; owners and administrators can publish, pause, roll back, and remove hosts. Enrollment is done on the host using the CLI.
The CLI view is:
./bin/nexus fleet list registry.nexusrun.dev/YOUR_ORG
Last check-in means the last report received, not continuous application health. A disconnected host continues using its local snapshot and Cloud retains its last reported state.
7. Update, pause, or roll back
Change version in examples/fleet-demo/nexus.yaml to 0.2.0, adjust the
instructions or tests, rebuild with --seal, and push the new version. Create
a new fleet release with its new artifact digest and the runtime ID.
To pause further activation, copy the release UUID from the dashboard or
fleet list:
./bin/nexus fleet pause registry.nexusrun.dev/YOUR_ORG PASTE_RELEASE_ID_HERE
To roll back:
./bin/nexus fleet rollback registry.nexusrun.dev/YOUR_ORG/fleet-demo --channel production --canaries 1
Rollback creates a new canary rollout of the earlier active artifact and runtime. Each host tests it again; rollback is not an unconditional bypass of the gate. Keep the earlier runtime installed. A rejected release requires a new rollout rather than overwriting its failure with a retry.
To revoke a host, use Remove in the dashboard or:
./bin/nexus fleet remove registry.nexusrun.dev/YOUR_ORG PASTE_HOST_ID_HERE
Removal blocks future check-ins and repository access, including already issued host bearer tokens. It does not remotely delete or disable an offline copy. Manage a lost computer through your normal device-security controls.
Tools and secrets
A fleet agent can call script tools shipped in the unit and use secrets stored on each host. examples/fleet-tools is an agent whose tool answers order-status questions and needs an access token. Its acceptance tests ask about orders whose status appears only in the unit's data file, so they pass only when the tool really ran.
Set the agent's secrets on every host before you release it:
./bin/nexus secret set order-desk ORDERS_TOKEN
Secret values stay on the host: they are never part of the artifact, a
check-in, or a release record. A host that lacks a required secret rejects
the release with the code secrets and prints which secret to set. Like any
rejection, this pauses the rollout, so set secrets everywhere first.
Tools run as they do with nexus run: each call in the unit's sandbox, with
only the capabilities the unit and tool declare, from a fresh private copy of
the release's files. A tool may use a program the host provides, such as
/bin/sh or python3. Each host runs the acceptance tests itself, so a host
without that program fails them and keeps its working release.
Signed release records
Each host signs every result it reports with its own key: what it tested (the artifact digest, runtime, and a digest of the acceptance suite), which cases passed, and whether it activated or rejected the release. Cloud keeps those signed statements and refuses a report that is unsigned, signed by a different key, or says something different from what the host claims.
Download a release's record from the dashboard (Signed record on the release) or the CLI, and verify it anywhere, offline:
./bin/nexus fleet record registry.nexusrun.dev/YOUR_ORG PASTE_RELEASE_ID_HERE -o record.json
./bin/nexus fleet verify record.json
verify checks every signature against the host's recorded key and checks
that each signed statement matches the release and the result shown. It
exits non-zero if any report fails. A record contains test case names and
pass or fail, never prompts, answers, secrets, or host paths.
The host keys in a record come from Cloud. To confirm a key is really a
host's own, compare the fingerprint verify prints with the hostKey in
nexus fleet status on that host (also printed by fleet join).
Offline operation and storage
Fleet's control plane uses outbound HTTPS; it adds no inbound listener on a host. An active release, its weights, and its managed runtime remain local. Check-ins contain hardware totals, release IDs, acceptance counts and failure codes, and the host's signed statement of the same with test case names—not inference prompts, generated answers, local paths, or credentials.
Allow space for downloaded model layers, extraction during testing, and retained releases. Each release has an isolated store; shared model weights are not deduplicated across releases. Preserve active and previous stores and their runtimes. Disk budgets increase with the number and size of updates.
For a permanently air-gapped destination, use a complete deployment bundle and physical transfer as described in the offline guide. Fleet polling requires a connection to its control plane; sealing an artifact does not create a transport into a disconnected network.
These instructions also live on GitHub. Runs on your computer. Apache 2.0.