How workers expand iii
Workers add capability to a iii system. Each one contributes functions and triggers the engine can route to. This page covers deploying and wiring workers into a project. Once connected, a worker exposes:- Functions, callable by
function_idfrom anywhere in the system (see Using iii / Functions). - Triggers it advertises, which other workers can bind their functions to (see Using iii / Triggers).
Scaffold a new worker
iii worker init creates a new standalone worker from scratch. The command writes a
language-specific project directory with the iii SDK installed, an iii.worker.yaml manifest, and
example function and trigger registrations you can replace with your own.
iii worker init is a convenience that helps with managing and sandboxing workers but it is not a
requirement. A worker is any code that uses a iii SDK, connects to a iii instance, and calls
registerWorker(). You can write that by hand without scaffolding, run it on bare metal or in
your own virtualization, and deploy it anywhere; iii worker is one way to create and run a
worker, not the only one.typescript (ts), javascript (js), python (py), rust (rs).
Workers will typically store their program’s entrypoint at src/index.ext or src/main.ext though
this may vary slightly by programming language and template.
The positional NAME is used as the target directory; pass --directory to override it.
Worker init will fail by default when targeting a non-empty directory, use --allow-non-empty to
scaffold into any other non-empty directory.
To install an existing worker from the registry instead of scaffolding a new one, use
iii worker add. See Using iii / Workers for the registry surface.Connecting to the engine
A worker connects to the engine over WebSocket. The convention is to set the engine URL via theIII_URL environment variable, but it can also be passed explicitly to register_worker. The
connection string is the only coupling between a worker and the iii instance it joins, so the worker
process can be deployed anywhere reachable on the network.
This connects with full trust, appropriate for workers you run. For an untrusted worker (a browser
client or a third party’s), connect through the
iii-worker-manager RBAC listener and gate it
with an auth function instead. See Untrusted workers and access
control and the iii-worker-manager
worker page.- Node / TypeScript
- Python
- Rust
Worker lifecycle
States
Workers transition through a small set of states after connecting:connecting → connected → available / busy → disconnected. connecting is the WebSocket handshake.
connected means the Worker has joined the Engine’s registry. available and busy describe
whether the Worker is currently handling invocations. disconnected is the terminal state when the
WebSocket closes. The Engine tracks these transitions and surfaces them to other Workers and tooling
through its discovery functions, so the rest of the system can react.
Inspecting the live registry
To see what’s currently connected to the Engine, invoke one of theengine::*::list Functions to
get the current state of the registry. Each returns a list:
Example: list registry contents
Example: list registry contents
- Node / TypeScript
- Python
- Rust
Handling Worker disconnects
When a Worker’s WebSocket closes, the Engine cleans up after it automatically. Its Functions and Triggers leave the live registry, and any in-flight invocations of those Functions are cancelled.In flight requests
In flight requests will get ainvocation_stopped error, catch these errors and treat them like a
cancellation. Retrying will fail until the Worker that owns this function reconnects.
Example: catch `invocation_stopped`
Example: catch `invocation_stopped`
- Node / TypeScript
- Python
- Rust
Subscribe to changes
You can register a Trigger against one of the engine’s discovery events to react to topology changes as they happen. This is particularly useful for continuing work when a Worker comes back online.Example: subscribe to discovery events
Example: subscribe to discovery events
- Node / TypeScript
- Python
- Rust
Worker manifest
iii.worker.yaml is the manifest at the worker’s root that tells iii how to install dependencies,
run the worker, and pass through configuration. This applies to both the iii worker CLI commands
(e.g. start, stop, restart) and to
workers that iii starts automatically when they’re specified in iii’s
config.yaml.
description is an optional one-line, human/LLM-readable summary of what the worker does; the iii
CLI displays it when installing or inspecting the worker.
scripts.install runs once to fetch dependencies and scripts.start launches the worker. Here,
watchfiles reloads it whenever you edit a source file. runtime.base_image selects the OCI image
iii uses as the worker’s rootfs.
The manifest is metadata about starting the Worker. Once the Worker is running iii treats them all
the same. A Worker started by iii via its config.yaml, via iii worker start, or a manually run
process that uses the iii SDK all behave identically with the Engine.
If a worker isn’t starting correctly then make sure to check its manifest and
iii worker logs.Shutting down a worker
Call the SDK’sshutdown to close the WebSocket cleanly. The engine removes the worker’s Functions
and Triggers from the registry, fires engine::workers-available with worker_disconnected, and
cancels in-flight invocations targeting them with invocation_stopped.
Without shutdown, an abrupt process exit reaches the same state once the engine notices the
dropped socket; graceful shutdown makes it deterministic and faster.
- Node / TypeScript
- Python
- Rust
Shutdown is useful for One-shot / ephemeral workers. Kubernetes Jobs, serverless containers,
or scheduled scripts can connect like any other Worker, do their work, and
shutdown()
(shutdown_async().await in Rust).