Files
2026-06-28 20:35:59 +01:00

7.6 KiB

Choosing a Kandev Image

Kandev publishes two container image flavors to GitHub Container Registry. Both are functionally identical kandev - same backend, same web UI, same persistence model. They differ only in what else is preinstalled in the image.

Tag Size (compressed) Contents Pick when…
ghcr.io/kdlbs/kandev:X.Y.Z ~600 MB kandev + Node 24 + npm + git + gh + python3 + pipx You only need npm-installable agent CLIs (claude-code, codex, …) and want the smallest possible footprint.
ghcr.io/kdlbs/kandev:X.Y.Z-universal ~1.4 GB vanilla + language toolchains, build tools, Playwright Chromium deps Your agents work on Go / Rust / Python projects, run native test suites, or drive headless browsers.

:latest aliases the vanilla image; :universal aliases the latest universal. Tag pinning is strongly recommended in production - :latest moves and we don't promise it stays the same forever.

What's in :universal (and what's not)

Language toolchains: Go (latest stable), Rust (rustup, stable default toolchain), pnpm (preinstalled through npm into /usr/local so pnpm is on $PATH for everyone).

Build essentials: build-essential (gcc, g++, make, libc-dev), pkg-config, python3-dev, libssl-dev. These cover CGO compilation, native Python pip wheels, and native Node modules.

Linters and developer CLIs: golangci-lint, ripgrep, fd, jq, yq.

Playwright Chromium system libraries (browsers themselves are not preinstalled - see below).

Not included:

  • JDKs / .NET / Mono - out of scope in v1; if these matter to your workflow, derive your own image (see Customizing your image below).
  • Playwright browsers (chromium, firefox, webkit). Run pnpm exec playwright install chromium (or whichever browsers you need) once after the container starts. Downloads land at ~/.cache/ms-playwright, which lives on the PV under HOME=/data/home and survives pod restarts. This keeps universal under 1.5 GB; it adds a one-time setup command per agent that wants browsers.
  • Database servers (Postgres, MySQL, Redis). Use a sidecar or external service.
  • Kandev's own test dependencies beyond what's listed above. Universal is enough to run kandev's backend Go tests, but the Playwright e2e suite needs the user to pnpm install and run playwright install first, same as on a fresh dev machine.

Inclusion policy

We add a tool to universal when all four of these hold:

  1. It's commonly needed by agent-driven dev workflows (Go/Rust/Python/Node project work).
  2. It's reasonably available in apt or a well-maintained prebuilt binary.
  3. It adds less than 200 MB to the installed image.
  4. It doesn't carry a license that conflicts with redistributing the image.

We decline additions that fail any of these. The escape hatch is always derive your own image - see below.

Switching between flavors

There is no migration. Both images mount /data the same way and use the same database schema. To switch a running deployment:

Docker:

docker pull ghcr.io/kdlbs/kandev:X.Y.Z-universal
docker stop kandev && docker rm kandev
docker run -p 38429:38429 -v kandev-data:/data ghcr.io/kdlbs/kandev:X.Y.Z-universal

Kubernetes:

kubectl set image deployment/kandev kandev=ghcr.io/kdlbs/kandev:X.Y.Z-universal

All your data (database, worktrees, npm globals, agent auth state) carries over because it lives on the PV, not in the image.

Customizing your image

Universal is opinionated. If you need something it doesn't include - a JDK, a private apt repository, a specific Node version, your company's CA cert - derive your own image from whichever base fits.

The pattern: a tiny Dockerfile that does FROM ghcr.io/kdlbs/kandev:X.Y.Z (or …:X.Y.Z-universal), drops back to root, installs what you need, drops back to kandev. Build it, push it to a registry you control, point your deployment at it.

Recipe: add a JDK on top of universal

FROM ghcr.io/kdlbs/kandev:0.45.0-universal

USER root
RUN apt-get update && apt-get install -y --no-install-recommends \
        openjdk-21-jdk-headless \
    && rm -rf /var/lib/apt/lists/*
USER kandev
docker build -t my-registry.example.com/kandev:0.45.0-jdk .
docker push my-registry.example.com/kandev:0.45.0-jdk
kubectl set image deployment/kandev kandev=my-registry.example.com/kandev:0.45.0-jdk

Recipe: lightweight extras on top of vanilla

If universal is too big for you but you need a couple of specific tools:

FROM ghcr.io/kdlbs/kandev:0.45.0

USER root
RUN apt-get update && apt-get install -y --no-install-recommends \
        make \
        rsync \
    && rm -rf /var/lib/apt/lists/*
USER kandev

Recipe: bake a corporate CA cert

FROM ghcr.io/kdlbs/kandev:0.45.0-universal

USER root
COPY corporate-ca.crt /usr/local/share/ca-certificates/
RUN update-ca-certificates
USER kandev

Recipe: preinstall a specific agent CLI version

The Settings → Agents Install button calls npm install -g at runtime. If you want a fixed version baked into the image (so every container starts with it), do it at build time - and install outside /data, otherwise the named volume mounted at /data will shadow your install on every container after the first one is created:

FROM ghcr.io/kdlbs/kandev:0.45.0

USER root
# Install to /usr/local (NOT /data/.npm-global, which is on the named volume
# and only seeded on first volume creation). /usr/local/bin is already on
# PATH after /data/.npm-global/bin, so a user-installed runtime version
# would still win if anyone adds one later.
RUN npm install -g --prefix /usr/local @anthropic-ai/claude-code@1.2.3
USER kandev

Note: kandev users will see the agent as already installed on the agents page. Baking it in means the version is tied to your image rather than to user choice - if a user runtime-installs a different version, that one wins (because the runtime path /data/.npm-global/bin precedes /usr/local/bin on $PATH).

What if I need something that doesn't fit any of these patterns?

Two reasonable paths:

  1. Open an issue suggesting an addition to universal. Cite (a) the workflow that needs it, (b) the installed size, (c) whether it's apt-available or needs a prebuilt binary. We'll evaluate against the inclusion policy.
  2. Just maintain your own derived image. This is what most teams end up doing for org-specific needs (corporate CAs, internal tools, JDK pinning). It's a 10-line Dockerfile and a 2-line CI step.

A note on building locally

The repository also contains the source Dockerfiles (Dockerfile and Dockerfile.universal). You can build either locally:

# Vanilla
docker build -t kandev:dev .

# Universal (depends on a vanilla base - build vanilla first if you want a
# fully-from-source universal, or let BASE_IMAGE default to the published one)
docker build -f Dockerfile.universal --build-arg BASE_IMAGE=kandev:dev -t kandev:dev-universal .

In CI we always build vanilla first and pass its tag as BASE_IMAGE to the universal build, so a single release run produces a matched vX.Y.Z + vX.Y.Z-universal pair.