Workers
Operating a worker
wb worker status [--json]
wb worker logs [-f]
wb worker stop [--now]
wb worker remove [--now]
wb connect --worker <slug> <runner>Status#
wb worker status
wb worker status --jsonShows whether the worker is online or offline and since when, its organization, how many slots are busy, and one line per active run with its Workbench, run ID, runtime, and age. --json prints the same fields.
Worker mini is online for acme since 14:02:11 (15m 37s). 1 of 1 slot busy, runtimes docker.
threejs-game wb_d8m99qyw2e4qqhitfff63f1n docker 12m 8sOn workbenches.dev, the worker's page and GET /v1/workers/:id show its owner, whether it is shared, its machine (OS, architecture, CPUs, memory, GPUs, Docker version, runner versions), runtimes, whether it is online, busy and total slots, and how many of its runs have not ended.
Logs#
wb worker logs # print the lifecycle log
wb worker logs -f # keep following it[mini] 14:02:11 online, 1 slot, docker 27.3.1, runtimes docker
[mini] 14:05:40 threejs-game started wb_d8m99qyw2e4qqhitfff63f1n by matty "Build a pirate game..."
[mini] 14:09:02 threejs-game needs input permission: bash "npm install"
[mini] 14:17:48 threejs-game completed in 12m 8s PR #12
[mini] 14:30:00 reconnected after 4s offline, 0 events resentA run is named by its workbenches.dev run ID. by names the member who started it when they have connected a runner on this worker. Log lines carry names, IDs, states, and a short task excerpt, never credentials, environment values, or task output.
The worker also sends its log to workbenches.dev. Every member can read the latest 300 lines on the worker's page or with GET /v1/workers/:id/logs. A worker sends at most 600 lines a minute; a line says how many were dropped.
The local log is rotated at 5 MiB, keeping one previous file as worker.log.1. The service output daemon.out is emptied at 5 MiB.
Member sign-ins#
Each member who runs on a worker has a directory there, $WORKBENCH_HOME/worker/members/<member id>/. It is the home of their local runs and holds their runner connections. A member connects a runner from any machine where they are signed in with wb login, their laptop or the worker itself. The runner does not need to be installed on that machine.
wb connect --worker mini claude-code
wb connect --worker mini opencode --provider openai --method chatgpt
wb connect --worker mini pi --provider google --method api-keywb connect --worker asks the same provider and method questions wb connect --runtime local asks for that runner, or takes them from --provider and --method. It sends only the choice to workbenches.dev, which asks the worker to carry it out for that member. The worker refuses a method the runner does not offer. A connection not finished within 10 minutes expires. The member must be allowed to run on the worker: it is shared, or theirs. When the worker is offline the request fails with worker_offline.
Subscription sign-in#
A subscription method runs the runner's own command-line sign-in on the worker, in a terminal at your terminal's size, with your member directory as its home:
| Runner | Sign-in |
|---|---|
| Claude Code | claude auth login --claudeai |
| OpenCode | opencode auth login with the provider and method |
| Pi | None. A Pi subscription cannot be connected on a worker yet; an API key can. |
Its terminal is your terminal: what it draws reaches you through workbenches.dev as it is, and your keys go back raw, so links, codes, prompts, menus, and Ctrl-C work as on your own machine. Closing wb connect cancels it on the worker.
Your browser is on another machine, so Claude Code shows a code after you sign in, which you paste at its Paste code here if prompted prompt. OpenCode's ChatGPT subscription signs in with its device code.
The runner keeps the login in your sign-ins, the data home .local/share in your directory: OpenCode in opencode/auth.json, Claude Code in claude/.credentials.json on Linux. On macOS, Claude Code keeps it in the account's keychain instead, in an entry named for your sign-ins, apart from the account's own Claude Code login.
API key#
An API key method asks for the key, which wb connect reads with input hidden and relays once through workbenches.dev, which keeps nothing. Whitespace in what you paste, such as the line break a long key wraps at, is dropped. The worker saves it in your directory (connections.json, mode 0600) for the provider's standard variable, such as OPENROUTER_API_KEY. It is never logged, written to an event, or sent to workbenches.dev.
Which credential a run uses#
Your most recent connection for a runner is your default on that worker. A run you start uses it unless the run asks for another connection, or the Workbench's model routes leave out its provider: a Workbench routed only through OpenRouter never uses your ChatGPT subscription. Only a run that uses your connection gets its saved key, ahead of an organization key of the same name. A docker run mounts your sign-ins read-write as the runner's credential root, so it uses and renews the same login your local runs do. One member's docker runs never see another's sign-ins or runner state.
A run uses only the connections of the member who started it:
- Without a connection for its runner, or with one whose provider the Workbench's routes leave out, it uses the provider keys workbenches.dev sends with the run, as a hosted run does.
- With one the Workbench allows that is not signed in on the worker, it fails and says to connect again.
- A run that asks for a connection the Workbench's routes leave out fails with
<Workbench> does not allow connection <provider>, naming the providers it does allow. - A run started with an organization API key has no member and uses only the keys workbenches.dev sends.
- With neither, the run fails before any model call with the preflight reason and
Run wb connect --worker mini claude-code.
A run started with a connection other than openrouter is never sent the organization's OpenRouter key, only the secrets its Workbench declares. The account's own runner sign-ins and credential variables never reach a run.
How runs flow#
- Runs survive a daemon restart or a dropped connection. On reconnect the worker lists its runs and sends every event after the sequence the server has stored, so delivery is at least once and the server dedupes by run and sequence.
- Commands from workbenches.dev go through the same session controls as
wb send(send, steer, queue),wb answer, andwb kill. - A run's time limit cancels it when reached. A run the worker never ends fails at its deadline plus 15 minutes, and the worker is told to cancel it.
- A repository workspace is cloned with the run's token like a hosted run. The agent pushes and opens pull requests itself when the task asks.
- When a run ends, its outcome is uploaded as a gzip tar of the
wb outcome --exporttree, at most 50 MB decompressed.
Cleanup#
The worker cleans up after itself at start and then hourly. Seven days after a run finishes, its workspace, its saved package, and its engine sessions, runs, events, and outcomes are removed.
Stop#
wb worker stop # wait for active runs, take no new ones
wb worker stop --now # cancel active runs firststop waits for active runs to finish and takes no new ones meanwhile, printing how many it is waiting on. --now cancels them first. Once no run is active, the worker waits up to 5 seconds for workbenches.dev to store its last events, and sends anything not stored again after the next start. The service is stopped and does not start again at boot until the next start.
Remove#
wb worker remove
wb worker remove --nowremove stops the worker the same way, removes the service, revokes its key with workbenches.dev, and deletes the key locally. When the API cannot be reached the key is kept, so remove can be run again.
Removing a worker from workbenches.dev (DELETE /v1/workers/:id, by its owner or an organization owner or admin) makes its key stop working, closes its connection, and fails the runs it held. A removed worker frees its slug.