|
| 1 | +# Base Image Auto-Resolution for All Drivers |
| 2 | + |
| 3 | +**Date:** 2026-03-21 |
| 4 | +**Status:** Approved |
| 5 | + |
| 6 | +## Problem |
| 7 | + |
| 8 | +Most Clawfiles in-tree use repo-local driver tags such as `openclaw:latest`, `hermes:latest`, `microclaw:latest`, and `nullclaw:latest`, but not all of them. Current exceptions include: |
| 9 | + |
| 10 | +- `examples/picoclaw/Clawfile` using `FROM docker.io/sipeed/picoclaw:latest` |
| 11 | +- nanoclaw examples using `FROM nanoclaw-orchestrator:latest` |
| 12 | + |
| 13 | +Today, only the openclaw driver implements `BaseImageProvider`, so only it auto-builds when the local base image is missing. Users of the other six drivers must manually build or pull base images before `claw build` works. |
| 14 | + |
| 15 | +Maintaining Clawdapus-owned pre-built images for every runtime is the wrong burden. Some upstreams already publish official images, some publish installers or packages, and nanoclaw currently needs a Clawdapus-compatible orchestrator wrapper. The implementation needs to follow the packaging reality of each driver instead of forcing one recipe style onto all of them. |
| 16 | + |
| 17 | +## Solution |
| 18 | + |
| 19 | +Each driver ships a `baseimage.go` file implementing `BaseImageProvider`. When `claw build` encounters a missing `FROM` image, the existing `ensureBaseImage()` in `internal/build/build.go` already handles resolution — no changes needed to the build pipeline. We just need to fill in the missing implementations. |
| 20 | + |
| 21 | +Each `baseimage.go` produces a self-contained Dockerfile string. The rule is: |
| 22 | + |
| 23 | +- prefer the real upstream packaging path |
| 24 | +- use a local compatibility alias over an official upstream image when that is the upstream distribution model |
| 25 | +- use a source-build wrapper only when no stable published base fits the current Clawdapus runtime contract |
| 26 | + |
| 27 | +That keeps the images real, but avoids rebuilding tooling that upstream already ships. |
| 28 | + |
| 29 | +## Per-Driver Dockerfile Recipes |
| 30 | + |
| 31 | +### openclaw (already exists — no changes) |
| 32 | + |
| 33 | +- Base: `node:22-slim` |
| 34 | +- Install: `curl -fsSL https://openclaw.ai/install.sh | bash -s -- --no-prompt --no-onboard --method npm` |
| 35 | +- Entrypoint: `openclaw gateway --port 18789 --bind loopback` |
| 36 | +- Extras: build-essential, python3, cmake (native deps for npm packages) |
| 37 | + |
| 38 | +### hermes |
| 39 | + |
| 40 | +- Tag: `hermes:latest` |
| 41 | +- Base: `ghcr.io/astral-sh/uv:python3.11-bookworm-slim` |
| 42 | +- Install: clone `https://github.com/NousResearch/hermes-agent` and `uv pip install --system "/opt/hermes-agent[messaging,cron]"` |
| 43 | +- Entrypoint: `hermes gateway start` |
| 44 | +- Extras: `bash`, `ca-certificates`, `curl`, `git`, `jq`, `procps`, `tini` |
| 45 | +- Notes: use the real Hermes repo and install the packaged CLI entrypoint instead of a stub shell script |
| 46 | + |
| 47 | +### nanobot |
| 48 | + |
| 49 | +- Tag: `nanobot:latest` |
| 50 | +- Base: `ghcr.io/astral-sh/uv:python3.12-bookworm-slim` |
| 51 | +- Install: `uv pip install --system --no-cache nanobot-ai` |
| 52 | +- Entrypoint: `nanobot gateway` |
| 53 | +- Extras: `ca-certificates`, `curl`, `git`, `jq`, `procps`, `tini` |
| 54 | + |
| 55 | +### picoclaw |
| 56 | + |
| 57 | +- Tag: `picoclaw:latest` |
| 58 | +- Base: `docker.io/sipeed/picoclaw:latest` |
| 59 | +- Install: none; local base image is a compatibility alias over the upstream image |
| 60 | +- Entrypoint: `picoclaw gateway` |
| 61 | +- Extras: inherit upstream runtime as-is |
| 62 | +- Notes: this keeps the local `picoclaw:latest` tag usable for auto-resolution without forking the upstream container recipe |
| 63 | + |
| 64 | +### nullclaw |
| 65 | + |
| 66 | +- Tag: `nullclaw:latest` |
| 67 | +- Base: `ghcr.io/nullclaw/nullclaw:latest` |
| 68 | +- Install: none; local base image is a compatibility alias over the upstream image |
| 69 | +- Entrypoint: inherited upstream `nullclaw gateway --port 3000 --host ::` |
| 70 | +- Extras: inherit upstream runtime as-is |
| 71 | +- Notes: this avoids reimplementing the upstream Zig build and preserves the current HOME/config behavior the driver already targets |
| 72 | + |
| 73 | +### microclaw |
| 74 | + |
| 75 | +- Tag: `microclaw:latest` |
| 76 | +- Base: `ghcr.io/microclaw/microclaw:latest` |
| 77 | +- Install: add `procps` and create `/app/config` for the file mount used by the driver |
| 78 | +- Entrypoint: `microclaw start` |
| 79 | +- Extras: inherit upstream runtime plus `procps` |
| 80 | +- Notes: the upstream image is the real runtime; the only local change is making the image satisfy Clawdapus healthcheck and mount assumptions |
| 81 | + |
| 82 | +### nanoclaw |
| 83 | + |
| 84 | +- Tag: `nanoclaw-orchestrator:latest` |
| 85 | +- Builder: `node:22-bookworm-slim` + clone `https://github.com/qwibitai/nanoclaw.git` + `npm ci && npm run build` |
| 86 | +- Runtime: `node:22-bookworm-slim` + Docker CLI copied from `docker:27-cli` |
| 87 | +- Entrypoint: `node /workspace/dist/index.js` |
| 88 | +- Extras: `ca-certificates`, `git`, `procps`, `python3`, `make`, `g++`, `tini`, global `@anthropic-ai/claude-code` |
| 89 | +- Notes: nanoclaw is the one driver that still needs a source-build compatibility image because Clawdapus expects an orchestrator container with Docker CLI access and Claude Code SDK wiring |
| 90 | + |
| 91 | +## File Layout |
| 92 | + |
| 93 | +### New files (one per driver) |
| 94 | + |
| 95 | +- `internal/driver/hermes/baseimage.go` |
| 96 | +- `internal/driver/nanobot/baseimage.go` |
| 97 | +- `internal/driver/nanoclaw/baseimage.go` |
| 98 | +- `internal/driver/nullclaw/baseimage.go` |
| 99 | +- `internal/driver/microclaw/baseimage.go` |
| 100 | +- `internal/driver/picoclaw/baseimage.go` |
| 101 | + |
| 102 | +### New test files (one per driver) |
| 103 | + |
| 104 | +- `internal/driver/<name>/baseimage_test.go` — same pattern as openclaw: assert interface satisfaction, non-empty tag/dockerfile |
| 105 | + |
| 106 | +### No changes needed |
| 107 | + |
| 108 | +- `internal/build/build.go` — `ensureBaseImage()` already handles the resolution |
| 109 | +- `internal/driver/types.go` — `BaseImageProvider` interface already exists |
| 110 | +- `internal/driver/openclaw/baseimage.go` — already correct |
| 111 | +- Rollcall `Dockerfile.*-base` files — stay as spike test fixtures |
| 112 | + |
| 113 | +### Adjacent doc cleanup |
| 114 | + |
| 115 | +- fix stale Hermes upstream references to point at `https://github.com/NousResearch/hermes-agent` |
| 116 | + |
| 117 | +## Follow-up |
| 118 | + |
| 119 | +- optional cleanup: decide later whether to standardize `examples/picoclaw/Clawfile` on local `picoclaw:latest`; the current fully qualified upstream image still works via Docker's normal pull path |
0 commit comments