Executors
How OpenOtters runs agents, and how to pick a backend.
An executor is the thing that turns an agent image into a running agent. It
owns the agent's filesystem layout, its spawn environment, its lifecycle
(start, stop, exec), and the way the runtime reaches back to ottersd for
callbacks like async-job submission.
ottersd ships with two executor backends:
| Backend | Isolation | Storage | Requirements |
|---|---|---|---|
system | host subprocess | embedded registry | none |
docker | OCI container | Docker image store | Docker Engine ≥ 28 + containerd snapshotter |
Both share the same executor.Provider interface, so everything above that
line (chat sessions, async jobs, the tool harness, the dashboard) is
backend-agnostic. You can switch backends without touching your Agentfile,
your tool images, or your code.
Picking one
- Start with
systemwhen you're trying things out, when you don't have Docker installed, or when you just want the agent to be a subprocess you cankillif it hangs. - Move to
dockerwhen you want a kernel-level boundary, when you want image-pinned BIN tools (theghyour agent runs is exactly the bytes ghcr.io served), or when you're running on a box you don't fully trust.
Selecting a backend
The backend is chosen at daemon-start time. Precedence (highest first):
- CLI flag (
--executor docker) - Environment variable (
OTTERSD_EXECUTOR=docker) - YAML config (
serve.executorin~/.otters/ottersd.yaml) - Built-in default (
system)
ottersd serve --executor dockerotters info reports the active backend, so you can confirm which one is
running after a restart.
Background
For the implementation story — why the docker backend was annoying to build,
what the executor.Provider boundary buys, where it heads next — see the
docker executor blog post.