Docker
Supported
Run Operator from an official multi-arch container image. The image bundles the Operator binary (with the embedded web dashboard and REST API) and the opr8r client on a slim Debian base, plus the git and tmux substrate Operator needs to launch agents. Mount your projects root into the container and Operator treats it as the workspace.
Image: untra/operator - linux/amd64 and linux/arm64.
Usage
Run the TUI dashboard from your projects root:
docker run --rm -v $(pwd):/op:rw -it untra/operator
The image sets WORKDIR /op, so the mounted directory becomes Operator’s working
directory. If it contains .tickets/operator/config.toml, Operator loads it as implied
startup; otherwise it falls back to built-in defaults.
Subcommands are appended after the image name. Run as a background REST API service:
docker run --rm -v $(pwd):/op:rw \
-e OPERATOR_REST_API__HOST=0.0.0.0 \
-e OPERATOR_BOOTSTRAP_PASSWORD_FILE=/run/secrets/bootstrap \
-p 127.0.0.1:7008:7008 untra/operator api
OPERATOR_REST_API__HOST=0.0.0.0 is required to publish the port at all.
Operator binds 127.0.0.1 by default, which inside a container means the container’s loopback - unreachable from the host no matter how you publish it.
Setting the bind address to 0.0.0.0 makes it reachable from the container network; -p 127.0.0.1:7008:7008 then restricts which host interface it appears on. Both halves are needed, and they do different jobs.
Outside a container the default is unchanged: Operator binds loopback, and you do not need to set this.
-p 127.0.0.1:7008:7008 binds the published port to host loopback only. A
bare -p 7008:7008 publishes on every host interface.
Authentication. The REST API is authenticated. On first start Operator has no admin account and only the bootstrap, login, and probe endpoints respond; visit
/setupto set the admin password, or mount a bootstrap password so the account cannot be claimed by whoever reaches the port first. CORS defaults to same-origin; set[rest_api].cors_originsto allow specific origins. See Authentication.
Any Operator subcommand works the same way:
docker run --rm -v $(pwd):/op:rw untra/operator queue # show queue
docker run --rm -v $(pwd):/op:rw untra/operator setup # initialize workspace
Pin a specific version instead of latest:
docker run --rm -v $(pwd):/op:rw -it untra/operator:0.2.16
What’s in the image
| Included | Purpose |
|---|---|
operator binary |
The CLI/TUI/REST API, with the web dashboard embedded |
opr8r binary |
Client agent sessions call to report step completion for multi-step workflows |
git |
Branch and commit operations for ticket work |
tmux |
Default session wrapper Operator uses to spawn agent sessions |
ca-certificates |
TLS for LLM, kanban, and git provider APIs |
Not included: the LLM CLI and its auth. Operator launches agents via an LLM tool
(claude, codex, or gemini) that you supply. Two ways to provide it:
-
Derived image - extend the official image with your tool of choice:
FROM untra/operator # The base image defaults to the non-root `operator` user; switch to root to # install, then drop back. USER root RUN apt-get update && apt-get install -y --no-install-recommends nodejs npm \ && npm install -g @anthropic-ai/claude-code \ && rm -rf /var/lib/apt/lists/* USER 10001 -
Mount + env vars - mount an already-installed, authenticated CLI from the host and pass credentials. The container runs as uid/gid 10001 with
$HOME=/home/operator:docker run --rm -v $(pwd):/op:rw \ -v $HOME/.claude:/home/operator/.claude \ -e ANTHROPIC_API_KEY \ -it untra/operator
Implied startup
Operator reads .tickets/operator/config.toml relative to its working directory. Because
the image uses WORKDIR /op and you mount your projects root at /op, an existing config
is picked up automatically - no flags required. Run from a directory without one and
Operator uses its built-in defaults.
A global override at ~/.config/operator/config.toml (i.e.
/home/operator/.config/operator/config.toml in the container) also works if you mount it.
Prerequisites
- Docker (with
buildxfor multi-arch hosts, which is the default on modern Docker). - The host directory you mount at
/opshould be your projects root - the directory containing your code repositories and.tickets/- so Operator can start work in the right place. - Use
-itfor the interactive TUI; omit it for one-shot subcommands andapi.
Troubleshooting
Permission denied writing to the mounted directory
The container runs as the unprivileged operator user (uid/gid 10001), so it can only write
into /op (state, prompts, logs) if the mounted host directory is writable by uid 10001.
Either make the directory writable (e.g. chown -R 10001:10001, or chmod -R g+w with a
matching group) or run the container as your own uid:
docker run --rm -v $(pwd):/op:rw --user $(id -u):$(id -g) -it untra/operator
When overriding --user, the chosen uid has no entry in the image, so point $HOME at a
writable location for any tool config (e.g. add -e HOME=/op).
The dashboard renders as garbled output
The TUI needs an interactive TTY. Include -it in the docker run invocation.
Agents fail to launch
The base image intentionally omits the LLM CLI. Confirm your derived image or mount
provides an authenticated claude / codex / gemini on PATH inside the container
(docker run --rm --entrypoint sh untra/operator -c 'command -v claude').