docker provider starts sandboxes as sibling
containers on the host daemon. Agent work stays in these isolated containers.
It does not run in the Druks process.
Prerequisites
- Docker with the Compose plugin
- Sufficient local Docker capacity for Postgres, Redis, Druks, Drukbox, and short-lived sandbox containers.
linux/amd64 and linux/arm64.
1. Install the local Druks profile
docker is the default provider. Thus, the bare command selects the local
shape. DRUKS_PROVIDER=docker makes the same selection explicit.
The local shape needs no authored values, so the first run goes all the way:
- The installer writes
~/druks/druks.tomlwith[sandbox].provider = "docker". - It creates
~/druks/.envwithDEFAULT_HOST_PROVIDER=docker. - It generates the database password and the stored-secret key.
- It pulls images and applies migrations.
- It starts Druks, Postgres, Redis, and Drukbox on
127.0.0.1:8780. - It uses
COMPOSE_FILE=compose.yaml:compose.override.yamlwithout Caddy or the janitor profiles.
/var/run/docker.sock. The
installer records the group ID of the socket in .env. This value gives the
non-root service user access to the socket. Drukbox keeps its schema in a
drukbox database in the same Postgres instance. It does not require a separate
data store. If sandbox SSH is unreachable on macOS, enable host networking in
the Docker Desktop settings.
For the bundled software_factory app, connect its GitHub App after startup.
Use Settings → Services in the dashboard. Create the app there, or paste the
credentials of an existing GitHub App. See
the GitHub connection.
If an existing installation runs Drukbox through make dev, finish or cancel
the local runs. Stop the host process. Then run the installer again. The Compose
service starts with a new sandbox registry.
2. Make sure that the first system operates
{"status":"ok"}. The dashboard is at
http://127.0.0.1:8001.
3. Connect agent harnesses
Open Settings → Harnesses in the dashboard and connect Claude and Codex. Druks stores those subscription credentials in Postgres and writes a fresh credential file into each sandbox. It does not use host CLI login files. The local profile uses[identity].mode = "none". It has no browser
authentication and exactly one operator account.
A new installation shows its
setup page until the first harness connection completes. That connection
creates the operator account from the provider-verified email. Protect database
access and backups as credential data. Harness payloads do not use the
[secrets].secrets_key envelope that protects MCP tokens and OAuth grants.
Agent calls refuse before provisioning if their selected harness is not
connected. druks doctor reports the connection and token expiry for every
registered harness.
Run the complete preflight:
4. Log in a browser session
Create the browser session:- Open Settings → Browser sessions.
- Create a stable session name.
- Choose Log in. Druks opens a headed browser in a disposable browser sandbox.
- Authenticate on the site.
- Choose Save. Druks closes the browser and stores its encrypted profile. It marks the session as ready.
profile_dir. This rule also applies to a session
that came from Playwright storage_state.
5. Exercise an app
Druks does not invent a generic domain job. An installed app supplies the workflow and its trigger. In the bundled distribution,software_factory is
the reference app. Register a project in its dashboard. Use its configured
ticket or GitHub trigger.
The run appears on the subject page and in the Events
feed. Agent-call pages stream transcript and artifact data.
If you develop a different app, install that distribution into a
development Druks environment and invoke its documented trigger or
Workflow.start() path. See writing an app.
Sandbox image
[sandbox].image selects the image Drukbox starts. The shipped
ghcr.io/czpython/druks/sandbox:latest image contains the non-root druks
user plus Git, GitHub CLI, Node, Claude, and Codex.
If you change the sandbox, build the image from the repository:
~/druks/druks.toml, then re-run the installer:
Webhook caveat
GitHub, Linear, and Jira cannot connect to a loopback listener. Dashboard-initiated actions work locally, but provider-driven flows need an HTTPS tunnel forwarding to127.0.0.1:8001. Connect tracker credentials under Settings → Services and
keep the exact public paths: