Project overlays¶
A project can extend the agent image it runs in — extra apt packages, language
toolchains, CLIs — by committing a FROM-less Dockerfile fragment:
.vibepod/overlay/
├── Dockerfile # shared: applies to every agent in this project
└── claude/
└── Dockerfile # per-agent: wins over the shared one for claude
On vp run (and vp task create), VibePod appends the fragment to the agent's
base image and builds a workspace-local image tagged
localhost/vibepod/overlay-<agent>-<project>:<hash> (the explicit localhost/
registry keeps Podman from resolving the name against docker.io). <project>
is the workspace directory name, lowercased and reduced to characters a
repository name allows; the hash covers the base image, the fragment, every
file in the overlay directory, and the workspace identity, so:
- every project gets its own image — running ten projects through the same
agent gives ten readable rows in
docker images, not ten identical names - unchanged overlays never rebuild — the cached image is reused instantly
- switching branches with different overlays just switches images
- pulling a newer base image rebuilds the overlay on top of it
$ docker images | grep vibepod/overlay
localhost/vibepod/overlay-claude-vibepod-cli f1e2d3c4b5a6
localhost/vibepod/overlay-claude-my-app 9a8b7c6d5e4f
localhost/vibepod/overlay-qwen-my-app 4c5d6e7f8a9b
Two projects that happen to share a directory name share the repository name but never the tag: the workspace path is part of the hash.
The overlay directory is the docker build context, so the fragment can COPY
files committed next to it:
# .vibepod/overlay/Dockerfile — no FROM line
RUN apt-get update && apt-get install -y --no-install-recommends jq \
&& rm -rf /var/lib/apt/lists/*
COPY requirements.txt /tmp/requirements.txt
RUN pip install -r /tmp/requirements.txt
Because the directory is committable, the whole team shares the environment.
Symlinks anywhere in the overlay directory — including a symlinked
Dockerfile — are ignored: their targets may not exist on a teammate's
machine or may point outside the committed project.
Compared to init and custom images¶
agents.<agent>.initre-runs shell commands on every start — good for tiny setup, slow for package installs.- A custom image (
agents.<agent>.image, see Customizing agent images) is fully manual: write a complete Dockerfile, build, tag, configure. - An overlay sits in between: persistent like a custom image, zero-ceremony
like
init.
Controls¶
vp list— shows a Project Overlays table for the current project: the overlay image each agent resolves to, and whether it isbuilt,not built,disabled, or still waiting on its base image (base not pulled— the hash follows the base image id, so until that image is local only the repository name is known)vp run <agent> --no-overlay— skip the overlay for one runvp run <agent> --rebuild-overlay— force a rebuild, bypassing docker's layer cache so every instruction re-runsagents.<agent>.overlay: falsein.vibepod/config.yamlor the global config — disable overlays for that agent
Superseded overlay images for the same project and agent are removed automatically after each successful build.
Recipes¶
Ready-to-copy fragments for common needs — apt packages, Python requirements, the pixi package manager, a PDF/OCR toolchain — live on the recipes page.