Concepts
Workers
A worker is a process you run that holds an outbound connection to Mobius and executes work. The agent loop and the runtime live in Mobius Cloud; the worker runs your code, your network calls, and (optionally) your local LLM generations.
The connection is outbound-only. Mobius never connects to you.
When do I need one?
You need a worker when a step has to:
- call something behind your firewall,
- use a secret that shouldn't live in Mobius,
- run a custom model (Ollama, an internal serving stack),
- scale separately from the Mobius backend,
- run inside a managed environment (a Sprite) pinned to a worker instance.
If a step only calls a provider Mobius already integrates with (Slack, GitHub, Linear, email, ...), use a server action instead. No worker required.
The stock worker
The CLI ships a "stock" worker that registers a small set of built-in
actions (print, fail, json, time, random). It's the fastest
way to see a worker on the wire:
mobius worker --queues defaultThat's enough to run the quickstart's sample automation. For real work
you'll register your own actions and run a worker with a custom handler
(see the SDK examples in the mobius repo).
Concurrency: one process or many?
The CLI gives you two knobs. Pick one.
--concurrency N runs a single worker process that holds up to N
jobs in flight. This is the default and what you want for raw
throughput. The workers page in the app shows a single saturation bar.
mobius worker --queues default --concurrency 5--workers N spawns N independent worker instances inside one CLI
process. Use this when each child needs to drain or be observed
independently (separate presence rows). It's the advanced mode.
mobius worker --queues default --workers 5If you can't decide, use --concurrency. It's simpler and saturates the
same way under most workloads.
Queues and selectivity
--queues selects which queues this worker claims from. By default,
workers claim from default. You'll want to split queues when:
- Some actions are slow and shouldn't starve fast ones.
- A subset of actions needs special hardware (a GPU worker, an on-premise box).
- You want a separate worker pool per environment (
prodvs.staging).
You can also restrict workers to specific actions or models. Useful
when one worker process is your image.resize pool and another is your
summarize-document pool. The SDK exposes those filters; the stock
worker accepts them as flags.
Instance identity
Every worker advertises a stable worker_instance_id. The CLI
auto-detects one from the runtime platform (Cloud Run revision,
Kubernetes pod, Fly machine, Railway replica, Render instance) and
falls back to a per-boot UUID. Override only when you genuinely need a
fixed identifier across restarts:
mobius worker --queues default --instance-id "deploy-worker-prod-01"The instance ID is used for display and for queries; the per-boot session token (handled by the SDK) is what fences zombie processes.
Managed environments
Mobius can launch a worker for you inside a managed environment (a
Sprite, typically). That worker's session reports an environment_id
and gets jobs that were pinned to that environment. This is how you give
an agent a real filesystem, a git clone, and an isolated network without
running the infrastructure yourself.
You don't need to do anything special on the worker side to use this:
the automation declares an environment for the agent or run, Mobius
spins up an environment with a worker inside, and the runtime routes
jobs to that worker by environment_id.
Operating workers
# Who's online right now?
mobius worker-sessions list
# What's pending and which worker has each job?
mobius automations list-runs --status suspendedIf a worker dies mid-job, Mobius reclaims the job after the heartbeat-miss window and another compatible worker picks it up. The lease mechanism stops a zombie from completing a job a fresh worker already took.
SDKs and the wire protocol
The wire protocol is a WebSocket plus typed JSON frames. The SDKs (Go, TypeScript, Python) speak it for you, including reconnects, backpressure, lease management, and streaming. You should use an SDK in production. The raw protocol is documented in the interactive API reference for cases where you need to implement a worker in a language without an SDK.