Configuration Reference
Vaibify projects are configured through three files: vaibify.yml and
container.conf in the project root directory, and project.json at
.vaibify/projects/project.json. This page documents every field and
option.
vaibify.yml
The primary configuration file. All fields use camelCase keys in the YAML file; the Python dataclass uses Hungarian notation internally.
Top-Level Fields
YAML Key |
Type |
Default |
Description |
|---|---|---|---|
|
string |
(required) |
Docker container and image name |
|
string |
|
Non-root user inside the container |
|
string |
|
Python version to install |
|
string |
|
Base Docker image. Left out, or set to |
|
string |
|
Mount point for the workspace volume |
|
string |
|
Package manager: |
|
boolean |
|
Disable outbound network access |
|
boolean |
|
Forward the host X display so graphical programs in the container can open windows. Opt-in because a connected client can read the screen and inject input (see Security). Refused together with |
|
string |
|
Extra flags passed to |
|
boolean |
|
Keep the host awake ( |
|
integer |
|
The project’s dashboard port. |
|
integer |
|
Cap on container CPU cores. |
|
float |
|
Container memory cap in GB. |
List Fields
YAML Key |
Element Type |
Description |
|---|---|---|
|
dict |
Repository definitions (see below) |
|
string |
APT packages to install |
|
string |
pip packages to install |
|
string |
Refused at validation — see below |
|
dict |
Pre-built binaries to download |
|
dict |
Ports to expose from the container |
|
dict |
Host directories to mount |
|
dict |
Secret references (see Security below) |
Note
A bindMounts host path must be absolute. It is handed to Docker
exactly as written, and Docker does not expand ~, so ~/data is
refused with a request for the full path. Vaibify compares each host
path with its protected locations (credential directories, the Docker
endpoint and ~/.vaibify/tmp) as filesystem objects, so a different
spelling of a protected directory, such as ~/.SSH on a case-insensitive
volume, is refused as well.
Note
A user-supplied systemPackages list replaces the default set — it
does not extend it. The defaults are gcc, make, git, curl,
ca-certificates, gnupg, gosu, and time. If you set
systemPackages in vaibify.yml, include any of those you still
need alongside your additions.
Note
condaPackages is refused, not installed. A non-empty value fails
validation. The image installs Miniforge, but there is no
conda install step and no build argument carries the list, so
accepting the field would produce a container without the requested
packages and say nothing. Refusing is the honest interim until the
install step is wired; install what you need with pythonPackages (every
name is checked against pypi.org before the build starts, so a misspelling
is refused in seconds rather than after the toolchain has installed), or
add a conda install line to container.conf.
Features Block
Nested under the features key:
YAML Key |
Type |
Default |
Description |
|---|---|---|---|
|
boolean |
|
Install JupyterLab |
|
boolean |
|
Install R and IRkernel |
|
boolean |
|
Install Julia |
|
boolean |
|
Install PostgreSQL client |
|
boolean |
|
Install DVC for data versioning |
|
boolean |
|
Install MultiNest, pymultinest and ultranest (adds a Fortran/LAPACK toolchain and a from-source build) |
|
boolean |
|
Install TeX Live |
|
boolean |
|
Install Claude Code CLI |
|
boolean |
|
Allow Claude Code to update itself |
|
boolean |
|
Install OpenAI Codex CLI |
|
boolean |
|
Update Codex when the container starts |
|
boolean |
|
Install Google Gemini CLI |
|
boolean |
|
Allow Gemini CLI to update itself |
|
boolean |
|
Install Google Antigravity CLI ( |
|
boolean |
|
Update Antigravity when the container starts |
|
boolean |
|
Install OpenCode CLI |
|
boolean |
|
Update OpenCode when the container starts |
|
boolean |
|
Install Cline CLI |
|
boolean |
|
Update Cline when the container starts |
|
boolean |
|
Install OpenHands CLI |
|
boolean |
|
Update OpenHands when the container starts |
|
boolean |
|
Install Pi coding agent |
|
boolean |
|
Update Pi when the container starts |
|
boolean |
|
Enable NVIDIA GPU passthrough. Builds with |
All enabled CLIs receive the same Vaibify context, skills, persistent
configuration directory, and vaibify-do dashboard bridge. Auto-updates
need network access; when networkIsolation is enabled, Vaibify records a
startup warning that the update was deferred.
Reproducibility Block
Nested under the reproducibility key:
YAML Key |
Type |
Default |
Description |
|---|---|---|---|
|
string |
|
|
|
string |
|
Path to LaTeX source files |
|
string |
|
Path to generated figures |
Overleaf Sub-Block
Nested under reproducibility.overleaf:
YAML Key |
Type |
Default |
Description |
|---|---|---|---|
|
string |
|
Overleaf project identifier |
|
string |
|
Target directory in Overleaf |
|
list |
|
Paths to sync from Overleaf |
Example
projectName: earth-water-study
containerUser: researcher
pythonVersion: "3.12"
baseImage: ubuntu:24.04
workspaceRoot: /workspace
packageManager: pip
networkIsolation: false
systemPackages:
- gcc
- make
- git
- curl
pythonPackages:
- numpy
- matplotlib
- h5py
features:
jupyter: true
latex: true
reproducibility:
zenodoService: sandbox
latexRoot: src/tex
figuresRoot: src/tex/figures
container.conf
A line-oriented file listing repositories to clone and install. Each non-comment line has four pipe-separated fields:
name|url|branch|install_method
Install Methods
Method |
Action |
|---|---|
|
|
|
|
|
|
|
Add to |
|
Clone for reference, do not install |
What is checked before a build starts
A build takes an hour, and every failure below used to be discovered
somewhere inside it. Both vaibify build and the dashboard’s Build now
ask the same questions first, of the authority that actually answers
them:
Field |
Asked of |
A failure means |
|---|---|---|
|
their own format |
the image recipe cannot use the value ( |
|
the image’s own toolchain |
the name says another Ubuntu release than the 24.04 the toolchain is pinned to, or the GPU feature is on; the build would stop at the pinned |
|
Launchpad, for the series |
Ubuntu publishes no such package |
|
pypi.org’s simple index |
the index serves no such project |
|
|
the remote has no such branch; the refusal names its default |
Three answers are deliberately not refusals, because none of them
is evidence about the value: an index, archive or remote that cannot be
reached, a pipInstallFlags naming an index other than pypi.org, and a
baseImage outside the Ubuntu releases vaibify knows. Each reports
“not checked” and the build goes ahead and asks for itself. The
baseImage refusal judges only what the image’s name says: a
digest-only reference or a registry mirror carries no release in its
spelling, so it is not refused, and the Dockerfile’s own guard still
stops a base that is not Ubuntu.
Both setup wizards apply the same field rules when they SAVE, so a
value the build would refuse is refused at the form. They also write
each repository’s branch by asking the remote for its default rather
than assuming main, and write reference for a GitHub repository
they can see has no Python project file.
Example
mycode|git@github.com:user/mycode.git|main|pip_editable
data-utils|git@github.com:user/data-utils.git|develop|pip_no_deps
project.json
Defines the execution pipeline. It lives at
.vaibify/projects/project.json inside the project repository — not
at the repository root — which is where the dashboard and vaibify run discover it. See Pipelines for full
documentation.
Environment variables
VAIBIFY_HUB_IDLE_TIMEOUT_SECONDS
How long a hub or viewer server may sit idle before it self-retires. This is the highest-precedence override — it wins over the stored Settings preference and the launch default — so scripts and CI can pin a deterministic value.
Accepts a non-negative number of seconds, or the string never (also
off, none, disabled) to disable self-shutdown entirely. 0
retains its historical meaning — retire as soon as the server is idle.
A malformed or negative value is ignored, and resolution falls through
to the next tier.
VAIBIFY_HUB_IDLE_TIMEOUT_SECONDS=60 vaibify # 60-second reaper
VAIBIFY_HUB_IDLE_TIMEOUT_SECONDS=never vaibify # never self-retire
When this variable is unset, the effective timeout is resolved in this
order: the stored host-global Settings preference (set from the gear
menu’s Idle shutdown control and applied live, without relaunching
the hub), then the launch default. The launch default is never for
a browser launch — a researcher sitting at the dashboard should never
have the connection reaped out from under them — and 1800 (30
minutes) for a headless/remote launch (browser suppressed via
VAIBIFY_SUPPRESS_BROWSER), so an abandoned server still retires.
Self-shutdown only fires when no browser tab is connected and no pipeline is running in any container the server holds; an open dashboard keeps the server alive indefinitely. See the Session & container-lock lifecycle section for the full rationale.
This is not what disconnects a dashboard you are using. An open tab
vetoes this timeout entirely, so setting it to never changes nothing
about how long your browser session lasts. That is the absolute session
cap below — a different timer, with its own control.
VAIBIFY_ABSOLUTE_SESSION_CAP_SECONDS
How long one browser session’s credential lives, counted from when the
tab was minted and regardless of whether anyone is using it. When
it is reached the tab’s session ends; the container and any running
step are untouched, and vaibify open gives you a fresh tab.
It accepts the same vocabulary as the idle timeout — a non-negative
number of seconds, or never (also off, none, disabled) — and
resolves across the same three tiers: this variable, then the stored
host-global Settings preference (the toolbar gear’s Session
lifetime control), then the built-in default of 604800 (7 days).
Resolution happens on every evaluation, so a change applies without
relaunching the hub, and raising the cap rescues a session that has
not expired yet.
The default was twelve hours until 2026-09-21. What twelve hours actually bounded was a researcher’s working week: reaching the cap ends the browser session, and with it the agent conversations that session was holding, which is a loss measured in days of context paid to retire a credential on your own machine.
VAIBIFY_ABSOLUTE_SESSION_CAP_SECONDS=never vaibify # never sign out
VAIBIFY_ABSOLUTE_SESSION_CAP_SECONDS=2592000 vaibify # 30 days
You are warned as the cap approaches, at three quarters, nine tenths and nineteen twentieths of the way through it — fractions rather than a fixed lead, so the notice stays proportional to a cap you set. Each warning offers to renew the session: clicking it restarts the clock in place, keeping the open panels and agent conversations a fresh tab would lose. Renewal is only ever a click; nothing renews on a timer, because an automatic renewal would delete the cap while this control went on claiming one existed.
Unlike the idle timeout, a live WebSocket does not veto this window. That asymmetry is deliberate — the case the cap exists to bound is a forgotten-open tab, which holds a live socket by definition — and is explained in Session lifetime.
Security
Secrets are never stored in configuration files. The secrets field in
vaibify.yml lists secret references (names), not values. At
build time, Vaibify delegates to the host’s credential manager
(e.g., gh auth, OS keychain) to resolve secrets. See the
Reproducibility page for details on how secrets
interact with published projects.