Workers
A Toki network worker is a process that connects outward over TLS to a coordinator and runs the commands it is assigned. It has no listening port, so the machine needs no SSH server, no inbound firewall rule and no CI runner.
You can run a worker in two ways:
- Standalone: start
toki-workeryourself with a JSON configuration. - Managed: let Tama download, configure and supervise it.
Both use the same protocol, durable queue, identities and receipts.
Standalone worker
sh
toki-worker --config toki-worker.jsonWithout --config, toki-worker reads toki-worker.json from the current directory. The combined binary has the same command as toki worker --config FILE.
Configuration
json
{
"coordinatorUrl": "https://toki.example:7443",
"serverName": "toki.example",
"caPem": "-----BEGIN CERTIFICATE-----\nYOUR CA CERTIFICATE\n-----END CERTIFICATE-----",
"token": "YOUR_64_HEX_WORKER_TOKEN",
"workDir": "./workspace",
"stateDir": "./worker-state",
"reconnectDelayMs": 1000
}| Field | Meaning |
|---|---|
coordinatorUrl | The coordinator's advertised HTTPS endpoint. |
serverName | The TLS name (or IP) the coordinator's certificate must match. |
caPem | The coordinator's CA certificate. |
token | A worker credential issued with toki daemon issue --role worker. |
workDir | Workspace root. Commands outside it are refused. |
stateDir | Launch journal and results; keep it across restarts. |
reconnectDelayMs | Delay before reconnecting, 50–60000 ms (default 1000). |
builds | Optional. Enables committed-source builds; see below. |
Relative directories resolve against the config file. The file holds a credential: keep it private to the user that runs the worker.
The worker requires HTTPS with the supplied CA and server name. Authentication, role and protocol refusals stop it. Temporary network failures reconnect automatically, including after a laptop sleeps.
Build settings
To accept committed-source builds, add a builds object:
json
"builds": {
"targetDir": "D:/toki/targets",
"jobs": 8,
"memoryBytes": 34359738368,
"cpuRate": 2500,
"labels": ["build-host"],
"repositories": ["https://github.com/your-org/your-repo.git"]
}| Field | Meaning |
|---|---|
targetDir | Absolute directory for the worker's leased Cargo target slots. |
jobs | Cargo parallelism, 1–256. |
memoryBytes | Optional memory limit per command (Windows and Linux only). |
cpuRate | Optional CPU limit in hundredths of a percent of the machine, 1–10000 (Windows and Linux only). |
labels | Labels clients can select as class:<label>. |
repositories | HTTPS allowlist of repositories the worker may fetch. Must not be empty. |
toolchainRoot | Optional absolute directory of toolchain manifests; see provisioned execution. |
gin | Optional Gin snapshot providers; see Gin sources. |
Each build gets a disposable checkout and one leased target slot. Git fetches only the requested commit. Clients cannot supply local paths or mirrors.
Trust the coordinator
The worker runs the commands its coordinator sends. This is process ownership, not a security sandbox: only connect to a coordinator you trust.
Stopping and signals
Ctrl+C cancels the active command and stops the worker. On Unix, SIGTERM and terminal hang-up take the same path. The cancelled command's process tree is stopped and reaped.
Restart-safe execution
Each assignment is one attempt. Before launching, the worker flushes a record to stateDir/launched.jsonl, and it refuses to launch the same assignment twice.
A durable build keeps running when the connection drops or the coordinator restarts. Its outcome is journalled in stateDir/results when it ends. After the worker reconnects, the coordinator queries that journal and publishes the result once, without a second launch. While such an attempt is still running, the reconnected worker answers outcome queries but takes no new builds.
If the worker crashes after launching a command but before saving its result, the attempt is reported as indeterminate. Toki does not re-run it automatically, because it cannot prove the first run had no side effects.
Keep the state directory
Keep the journal and result files together and retain them across upgrades. Deleting either removes the evidence Toki needs to recover.
Output
Output is returned when the command ends, including after cancellation or a deadline. Failed attempts keep their own stdout and stderr; retries never concatenate logs. More than 4 MiB of combined output is reported as a transport failure. Status lines on stderr contain only the component and its connection state.
Configuration reload
The running worker watches its configuration file, including atomic replacement. You can change the coordinator connection (endpoint, CA, server name, credential) without a restart:
- the new connection is validated over TLS and protocol negotiation before switching;
- an in-flight command finishes on its existing connection first, and the worker reports
update-pendingmeanwhile; - a malformed file or unreachable endpoint keeps the working connection and reports
configuration-rejectedorupdate-unavailable; updates are retried.
The last working connection is kept in <config-name>.working.json beside the configuration, and is used for recovery after a restart. It also contains a credential.
Changing workDir, stateDir or builds needs a supervised restart.
Coordinator address changes
On the coordinator side, change addresses with one settings file:
json
{
"coordinatorUrl": "https://builds.example:7444",
"serverName": "builds.example",
"listen": "0.0.0.0:7444"
}sh
toki build configure --config /var/lib/toki/coordinator/server.json --settings address.jsonlisten is the local binding; coordinatorUrl is the advertised endpoint, and they may differ (for example behind a port forward). The running coordinator applies the change, renewing its certificate when the TLS name changes. The command prints a public {version, connection} publication with coordinatorUrl, serverName and caPem. Copy those fields into your client and worker files; their credentials stay the same.
Managed workers
Tama can manage the worker for you. In Tama's worker settings, enable Toki, choose the native release and enter the coordinator connection. Tama downloads the pinned executable, verifies its size and SHA-256, starts it and reports its connection state.
Disabling Toki or changing the settings cancels and reaps the current command before the worker is stopped or replaced. If Tama exits, including when it crashes, its managed worker stops too.
Daemon updates
The coordinator can be updated in place by a supervising owner:
sh
toki daemon-update manage --config update.json
toki daemon-update select --config update.json --desired desired.jsonmanage runs the coordinator as its child. select delivers a desired release: an uploaded executable pinned by its BLAKE3 digest, size, OS and architecture, under a monotonically increasing generation.
An update drains rather than kills. The running child stops dispatching new builds, keeps serving active workers until their results are durable, then exits; queued work stays in the database. The new executable starts with dispatch paused until it is healthy. A failed start restores the last healthy executable. To roll back, select the older release under a new generation.
WARNING
Run only one manager per coordinator configuration. In Tama-managed setups, Tama owns release publication and rollout policy; the production launcher is still being delivered.
Containment
Each command runs inside the strongest native boundary the platform offers.
Windows uses a Job Object. Commands start suspended until they are in the job, so all descendants inherit it. cpuRate is a hard CPU cap. memoryBytes is a committed-memory threshold: crossing it kills the whole job at the next poll. Accounting covers the entire job, including exited children.
Linux uses cgroup v2 when the worker's environment sets TOKI_CGROUP_ROOT to a private, operator-delegated subtree:
- Create a subtree for this worker installation only.
- Enable the
cpu,memoryandpidscontrollers in itscgroup.subtree_control. - Start the worker with
TOKI_CGROUP_ROOTpointing at it.
Toki creates one owned toki-action-* child per command. Memory uses memory.max with group OOM termination; task count uses pids.max. Cancellation writes cgroup.kill, which also catches processes that left the process group. After a crash, the next launch cleans up unlocked children. Toki never enables host controllers or changes privileges.
Without TOKI_CGROUP_ROOT, Linux uses process-group containment, which is explicitly incomplete, and any requested limit is refused before launch.
macOS tracks descendants by polling, kills them even after they leave the process group, and reports escapes. Polling can miss very fast fork sequences, so results always say trackingComplete: false. CPU and memory limits are refused, and a worker configured with memoryBytes or cpuRate fails at startup.
Not a security sandbox
None of these backends isolate the filesystem, network or secrets. Same-user code can escape resource containment. Use Toki for cooperative, trusted workloads.