@agents-fleet/worker
v0.8.2
Published
A worker bridges an agent backend to the manager over a single WebSocket connection. There is one worker process per conversation, spun up by the manager's Docker orchestration inside a network-restricted sandbox.
Readme
@agents-fleet/worker
A worker bridges an agent backend to the manager over a single WebSocket connection. There is one worker process per conversation, spun up by the manager's Docker orchestration inside a network-restricted sandbox.
This package only provides the Worker class — the WebSocket plumbing, worker-owned tools (send_message, update_memory, upload_artifact, expose_port), and the manager wire protocol. It is agent-agnostic: it doesn't know how to run an agent, it only drives whatever IAgentRunner (from @agents-fleet/worker-runner) you give it.
To actually run a worker, you must bring your own:
- An agent runner — an
IAgentRunnerimplementation. Use one of the provided runners, or write your own:@agents-fleet/worker-claude-runner— Claude Agent SDK@agents-fleet/worker-pi-runner— pi.dev
- An app — a small entrypoint that constructs the runner and the
Worker, then starts it. - A Docker image — see
Dockerfile.examplefor a starting point using the Claude runner.
Usage
import { Worker } from "@agents-fleet/worker";
import { createClaudeAgent } from "@agents-fleet/worker-claude-runner";
new Worker({
runner: createClaudeAgent(),
}).start();Configuration
The process reads these environment variables:
MANAGER_URL— WebSocket URL of the manager to connect to.MANAGER_API_KEY— bearer token identifying this worker to the manager.
Runner packages may require their own environment variables — see their READMEs.
What the manager sets up when starting a worker container
The manager's Docker orchestration (packages/manager/docker/docker.ts) does not just run the image — it wires the container into a per-worker sandbox. If you're building a custom worker image, expect the following:
- Env —
MANAGER_URLandMANAGER_API_KEY(above), plus whatever else the caller passes in (system prompt/settings/etc. arrive later over WS viastart-worker, not as env vars). - Network — the worker container joins the firewall sidecar's network namespace (
NetworkMode: container:<sidecar>), so it has no network stack of its own; all egress is governed by the sidecar's iptables rules. The worker is never grantedNET_ADMINand cannot alter them. - Egress firewall / MITM CA cert — the sidecar transparently redirects outbound 80/443 through a per-worker mitmproxy enforcing an allow-list. Its ephemeral public CA cert is relayed into the worker container at
/mitm-ca-ro(viaputArchive, before the container starts) — a custom image's entrypoint must install/trust that cert (seeDockerfile.exampleand the rootdocker/README.md) or outbound HTTPS requests will fail TLS verification. - Persisted volume — a named Docker volume is bind-mounted at
/mnt/persisted, keyed by(clientId, originId)so it survives container recreation across restarts. Use this path for anything that needs to persist across a conversation's lifetime (e.g. the attachment files saved bywebsocket/handler.ts). - Security constraints — the container is started with
CapDrop: ["ALL"]andSecurityOpt: ["no-new-privileges"]. Don't rely on any Linux capability or on being able tosetuid/escalate privileges. - Lifecycle —
AutoRemove: trueis set, and the manager force-removes/recreates the worker's container (rather than reusing it) on everyWorker.start(), since a stale container would carry an env-baked auth token from a previous manager process.
See the root docker/README.md for the full firewall/sidecar design.
