-
Notifications
You must be signed in to change notification settings - Fork 0
Docker
conductor publishes a multi-arch (linux/amd64, linux/arm64) image to
ghcr.io/nodespy/conductor. The image runs the same static binary as the
released binaries — no database, no web UI — wired up for a container: config
and state are volumes, and agent dispatch links out to a runtime box over SSH
instead of baking a runtime CLI into the image.
docker run -d --name conductor \
-v ~/.config/conductor:/config \
-v conductor-data:/data \
-p 8080:8080 \
ghcr.io/nodespy/conductor:latest-
/config— mount yourconfig.yaml,conductor.env, and anyconf.d/fragments. This is the same directory the installer seeds at~/.config/conductor/— see Installation. -
/data— a named volume for state ($HOMEinside the container is/data): run history, blob storage, dedup index, the secrets vault. Use a real volume, not a bind mount to a throwaway directory — this is the daemon's durable state. -
-p 8080:8080— only needed if you're running awebhook/sentryconnector with an inboundlisten:address, or the Callable-Service HTTP surface. Match it to whatever port your config actually listens on; omit it entirely for a cron/poll-only setup.
The entrypoint is conductor; the default command is
run --config /config/config.yaml. Override the command to run one-off
verbs against the same volumes, e.g.:
docker run --rm -v ~/.config/conductor:/config ghcr.io/nodespy/conductor:latest \
validate --config /config/config.yaml-
:latest— the most recent tagged release. -
:vX.Y.Z— a pinned release, matching GitHub releases.
services:
conductor:
image: ghcr.io/nodespy/conductor:latest
container_name: conductor
restart: unless-stopped
ports:
- "8080:8080"
volumes:
- ~/.config/conductor:/config
- conductor-data:/data
- ~/.ssh/id_ed25519:/data/.ssh/id_ed25519:ro # only if linking a runtime over SSH
volumes:
conductor-data:The image does not embed a runtime (paseo/cli/acp/agent-deck) or any
agent CLI. Agent dispatch is a transport concern, not a packaging one: define
your runtime box under hosts: and point a runtime's host: at it, and
conductor drives the agent CLI there over SSH — see Hosts and
Runtimes for the full model.
-
Generate (or reuse) an SSH key that can reach your runtime box, and mount it read-only into the container:
docker run -d --name conductor \ -v ~/.config/conductor:/config \ -v conductor-data:/data \ -v ~/.ssh/conductor_ed25519:/data/.ssh/id_ed25519:ro \ -p 8080:8080 \ ghcr.io/nodespy/conductor:latest
(
$HOMEinside the container is/data, so~/.sshresolves to/data/.ssh— mount the key there, or pointhosts.<name>.keyat wherever you mounted it.) -
Point a host entry at the runtime box and reference it from a runtime:
hosts: runtime-box: host: runtime.internal user: conductor key: /data/.ssh/id_ed25519 known_hosts: /data/.ssh/known_hosts # optional pin runtimes: paseo: { use: paseo, bin: paseo, host: runtime-box, default: true }
The runtime box needs the actual runtime binary (
paseo, or whatevercli/acp/agent-decktool you're driving) and its own agent CLI installed and authenticated — the container never runs it locally. See Hosts for what executes remotely under each runtime type.
Auto-update (update.auto: true) is meant for a long-lived host process that
can restart itself into a freshly-downloaded binary — that model doesn't fit
a container, where the binary comes from the image, not a self-download.
Leave update.auto off (the default) in a containerized deployment; update
by pulling a new image tag instead:
docker pull ghcr.io/nodespy/conductor:latest
docker stop conductor && docker rm conductor
docker run -d --name conductor ... # same flags as beforeOr, with compose: docker compose pull && docker compose up -d.
isolation: sandboxing (see Isolation) has two modes that need
privileges the container itself may not have:
-
mode: containerlaunches agent work in a further nested container (docker rununder the hood) — it needs the Docker socket mounted in (-v /var/run/docker.sock:/var/run/docker.sock) and a matching-architecture agent image. Mounting the host's Docker socket into a container is a meaningful privilege escalation; do it only if you understand that trade-off. -
mode: namespaceneeds Linux user/mount namespaces and cgroups, which requires the container to run with the rightuserns/capabilities — not available in a default, unprivileged container runtime.
If neither is workable in your deployment, isolate on a linked host
instead: give the runtime box its own isolation: block (hosts.<name>.isolation)
and let the SSH-linked runtime enforce sandboxing there, where you control the
privileges directly.
Related: Installation · Hosts · Runtimes · Isolation · Configuration
Setup
The model
- Connectors
- Workflows
- Reuse
- Settings-and-Templating
- Packs
- Verbs
- Code-Steps
- Stores
- Runtimes
- Model-Selection
- Model-Discovery
- Steps
- Decide-Steps
- Grouping
- Memory
- Binary-Data
- Agent-Skill
- Policy
- Gates
- Teams
- Outcomes
- Cost-Accounting
- Secrets
- Hosts
- Isolation
- Trust-and-Isolation
Connectors
Operations
- One-Shot
- Callable-Service
- Runs
- Hand-offs
- Notifications
- Migration
- Controllers (legacy name → Runtimes)