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

projectName

string

(required)

Docker container and image name

containerUser

string

researcher

Non-root user inside the container

pythonVersion

string

3.12

Python version to install

baseImage

string

ubuntu:24.04

Base Docker image. Left out, or set to ubuntu:24.04, the build uses the digest-pinned image named in the Dockerfile, not whatever the tag points at that day. Any other value is used as written; a different Ubuntu release is refused (see below)

workspaceRoot

string

/workspace

Mount point for the workspace volume

packageManager

string

pip

Package manager: pip, conda, or mamba

networkIsolation

boolean

false

Disable outbound network access

x11Forwarding

boolean

false

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 networkIsolation: true. Takes effect when the container is created, so stop and start it after changing this. Also a checkbox in the creation wizard and in the project’s Settings dialog

pipInstallFlags

string

--prefer-binary

Extra flags passed to pip install during the image build

neverSleep

boolean

false

Keep the host awake (caffeinate) while the container runs; macOS only, ignored elsewhere

dashboardPort

integer

0

The project’s dashboard port. 0 means “not yet assigned”: the first launch picks a free port and writes it back here so the same port is reused on every restart. A non-zero value must be 1024–65535

cpuLimit

integer

0

Cap on container CPU cores. 0 means no explicit limit (all host cores minus one); a positive value is clamped to the host’s core count

memoryLimitGigabytes

float

0.0

Container memory cap in GB. 0 means unlimited; a non-zero value must be at least 0.25

List Fields

YAML Key

Element Type

Description

repositories

dict

Repository definitions (see below)

systemPackages

string

APT packages to install

pythonPackages

string

pip packages to install

condaPackages

string

Refused at validation — see below

binaries

dict

Pre-built binaries to download

ports

dict

Ports to expose from the container

bindMounts

dict

Host directories to mount

secrets

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

jupyter

boolean

false

Install JupyterLab

rLanguage

boolean

false

Install R and IRkernel

julia

boolean

false

Install Julia

database

boolean

false

Install PostgreSQL client

dvc

boolean

false

Install DVC for data versioning

nestedSampling

boolean

false

Install MultiNest, pymultinest and ultranest (adds a Fortran/LAPACK toolchain and a from-source build)

latex

boolean

true

Install TeX Live

claude

boolean

false

Install Claude Code CLI

claudeAutoUpdate

boolean

true

Allow Claude Code to update itself

codex

boolean

false

Install OpenAI Codex CLI

codexAutoUpdate

boolean

true

Update Codex when the container starts

gemini

boolean

false

Install Google Gemini CLI

geminiAutoUpdate

boolean

true

Allow Gemini CLI to update itself

antigravity

boolean

false

Install Google Antigravity CLI (agy)

antigravityAutoUpdate

boolean

true

Update Antigravity when the container starts

opencode

boolean

false

Install OpenCode CLI

opencodeAutoUpdate

boolean

true

Update OpenCode when the container starts

cline

boolean

false

Install Cline CLI

clineAutoUpdate

boolean

true

Update Cline when the container starts

openhands

boolean

false

Install OpenHands CLI

openhandsAutoUpdate

boolean

true

Update OpenHands when the container starts

pi

boolean

false

Install Pi coding agent

piAutoUpdate

boolean

true

Update Pi when the container starts

gpu

boolean

false

Enable NVIDIA GPU passthrough. Builds with gpu: true are refused for now: the GPU image sits on Ubuntu 22.04 while the toolchain is pinned to Ubuntu 24.04, and NVIDIA publishes no CUDA 12.2 image for 24.04

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

zenodoService

string

sandbox

sandbox or production

latexRoot

string

src/tex

Path to LaTeX source files

figuresRoot

string

src/tex/figures

Path to generated figures

Overleaf Sub-Block

Nested under reproducibility.overleaf:

YAML Key

Type

Default

Description

projectId

string

""

Overleaf project identifier

figureDirectory

string

figures

Target directory in Overleaf

pullPaths

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

c_and_pip

make opt then pip install -e . --no-deps

pip_no_deps

pip install -e . --no-deps

pip_editable

pip install -e . (needs a setup.py or pyproject.toml; a repository without one is cloned only, with a warning naming this table)

scripts_only

Add to PYTHONPATH and PATH only

reference

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

containerUser, pythonVersion, workspaceRoot

their own format

the image recipe cannot use the value (pythonVersion becomes the apt package python3.12, so 3.12.1 is refused)

baseImage, features.gpu

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 apt-get step after the base image had been fetched

systemPackages

Launchpad, for the series baseImage names

Ubuntu publishes no such package

pythonPackages

pypi.org’s simple index

the index serves no such project

repositories[].branch

git ls-remote against the remote

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.