Distributed nodes
When one machine is not enough, Barry spreads background work across others.
This page explains the protocol, placement, and trust model behind that, for
operators and contributors. To link a worker step by step, follow
Schedule and distribute work,
and for every subcommand, read the
barry workers reference.
One owner machine, many workers
Section titled “One owner machine, many workers”Every workflow run has one owner machine: the installation whose workflow store holds the run’s state and history, and which decides where each activity runs. Every other machine acts as a worker that executes activities for it. The owner machine also works for itself, so an activity that can run locally never leaves it. A worker can serve more than one owner machine, and each owner keeps its own identities and history.
Keep the owner machine distinct from the owner that barry owner shows or
binds. That command concerns the user actor who owns an installation; this page
always means the machine that holds a run.
One route between machines
Section titled “One route between machines”Exactly one wire route connects them. The worker calls POST /api/worker on the
owner machine over HTTPS, carrying its credential as a bearer token. The owner
derives the worker’s identity from that credential, never from the request body,
so a worker cannot claim to be another. Over that route a worker says hello,
advertises what it can run, claims work while it has free capacity, heartbeats,
declines, and reports results. The worker always initiates: inviting a worker
never gives the owner an outgoing connection to it.
Remote executors follow the same start, inspect, and stop contract as local ones, through authenticated, capability-limited operations on that route. A worker credential never becomes an admission credential or a general remote shell.
Credentials
Section titled “Credentials”Linking is one-way. barry workers invite on the owner prints a join token
once, and barry workers join on the worker redeems it. The owner stores only a
SHA-256 hash of the worker’s barry_wk_ credential, beside the worker ID it
assigned, and compares hashes in constant time; the worker stores the owner’s
address and the credential. The owner can verify a worker without being able to
reproduce its secret. The credential opens POST /api/worker and nothing else:
every other route answers 401, and the owner never sends a worker its operator
secret, actor credentials, vault contents, or an identity’s environment.
You manage that trust without disrupting work:
- Scoped invites. An invite can name the versioned jobs the worker may claim. The owner enforces the scope at placement, claim, heartbeat, and completion, and a worker cannot widen it by editing its token or advertisement.
- Invite expiry. An unused scoped invite expires after 24 hours on the owner’s clock. An unscoped invite expires only when you give it an explicit expiry, so revoke unused ones.
- Rotation.
barry workers rotateissues a new credential and keeps the old one working for five minutes, so a running worker keeps going. - Revocation.
barry workers revokerefuses the worker’s next call and stops its running activities. The owner keeps that work’s physical capacity reserved until it observes the execution stopped.
A copied token acts as the same worker: the next successful hello takes over the session, and fencing locks the displaced process out, as Durable workflows explains. The owner keeps audit rows for invites, joins, rotations, revocations, and takeovers.
Capacity and labels
Section titled “Capacity and labels”A worker advertises its capacity, its labels, its executor capabilities, and the
artifacts it holds. Capacity defaults to four concurrent activities and tops out
at 100, set by BARRY_WORKFLOW_CAPACITY. Labels steer work to the machine that
fits it. Every worker advertises its operating system and architecture, and you
add more with BARRY_WORKFLOW_LABELS, a comma-separated KEY=VALUE list such
as model=local,gpu=metal. Set both in the worker’s barry.yaml under
services.workflows.runtime.env, then restart the service with
barry service restart workflows.runtime. Claim only labels the machine can
satisfy: a label does not install model software, and a configured label is not
a health check.
Advertisements expire after 15 seconds and refresh within five, so the owner
stops offering work to a worker that goes quiet. barry workers status lists
what a machine offers and why it withholds anything, and Background work shows
each worker by a human name as Ready, Busy, Offline, or Needs setup.
Placement
Section titled “Placement”The owner places each activity in layers, and a later layer never overrides an earlier one:
- Hard eligibility. The run’s authority, the job’s own node bounds, the grant’s node bounds, the worker’s scope, verified code and resources, and the required executor capability. Every placement records why it excluded each candidate.
- Capacity. Three separate resource layers must all have room: the logical quota that admission reserved, physical slots on the execution host, and shared capacity on the inference endpoint.
- Preference. Locality, an already warm model, and your stated preference break ties among eligible hosts.
The logical layer keeps the compatibility limits for detached agents: four per caller, 16 unscheduled, and a protected four for scheduled work. A long wait for a timer or a decision can hold logical quota while it holds no physical slot. Physical slots stay reserved until the execution host confirms cessation. Endpoint capacity spans owners: an endpoint-owning broker or a worker-local arbiter enforces one aggregate cap, so two owners cannot each spend the same endpoint’s allowance.
Where an agent runs and where its model runs count as separate placements. A run records its execution host and its inference endpoint as separate fields, along with the requested and resolved model, the selection provenance, and limits. Barry never swaps models silently after a failure; a fallback has to exist as an authored step or an authorized attempt policy.
Which work can run remotely
Section titled “Which work can run remotely”Not every task suits every node, and remote execution never silently weakens a task’s contract. A task runs on a worker only when that worker can enforce everything the task requires: its credentials, its workspace, its runtime, and its bounds. Otherwise placement reports a clear eligibility result and the task stays on the owner machine, or stays visibly blocked.
Bag jobs follow fixed rules. A job can run remotely when it carries a version,
addressed as bag:name@1, uses the Node runtime, declares no secrets, and
touches no files. Owner and worker pin it by digest and must have the same bag
version installed. Eligible scripts and agent actions also run remotely under
the same journal, receipt, and identity rules as local runs, using credentials
provisioned for that worker or a narrowly scoped delegated credential. A remote
run declares its workspace: a verified pre-provisioned one, an isolated input
bundle, or none. Remote changes come back as artifacts or a patch for an
authorized publication step, never as a silent overwrite of a shared repository.
Trust runs one way
Section titled “Trust runs one way”A worker you invite holds a credential, not proof of who operates the machine. Scopes narrow what a credential can claim, but they do not verify results or sandbox a malicious operator: a stolen credential can read the inputs of jobs in its scope and report fabricated results. Invite only machines you operate, and publish the owner’s workflow service on a private HTTPS route, because a public route also exposes its console sign-in page.
Linking a worker distributes background work. It does not share an interactive session, copy your stores, or move a running session between machines, and it does not make a worker’s output trustworthy on its own. Treat workers as more hands for work whose definition you already trust. The distributed trust notes and the two-machine walkthrough cover the details.