CLI Reference

Vaibify provides two equivalent entry points: vaibify and the shorthand vaib. All commands accept a --config flag to specify an alternate vaibify.yml path.

Global Options

Flag

Description

--config PATH

Path to vaibify.yml (default: ./vaibify.yml)

--port N

Port for the hub server. Defaults to the port the last hub used, so a bookmarked tab keeps working; an explicit port is used verbatim and fails loudly if taken

--no-browser

Serve without opening a browser. The process still runs in the foreground until you stop it – this does not make it a daemon

--version

Print the installed version and exit

--help

Show the help message and exit

When invoked with no subcommand, Vaibify starts in hub mode – a browser-based dashboard for managing multiple projects.

Driving a hub on another machine

vaibify remote compute-machine
vaibify remote researcher@compute-machine
vaibify remote compute-machine --port 18050

Opens one SSH connection, forwards a loopback port, starts or adopts a hub beside your projects on that machine, and opens a signed-in browser tab locally. The remote hub keeps running if your tunnel drops, and a session is held for fifteen minutes so you can come back to it.

Two things to check before the first attempt: both machines need the same vaibify version, and ssh <host> vaibify --version must print one – a pip --user install, a virtualenv, or a conda environment activated by your shell profile is invisible to a non-interactive SSH command. SSH options themselves belong in ~/.ssh/config.

There is no --project flag: a project name may contain a space, and the remote command reaches a login shell, so the project is chosen in the dashboard once the tunnel is up.

See Working on a remote machine for what a dropped connection does to a run and to an open terminal, how the three file actions differ once the backend is elsewhere, and troubleshooting.

vaibify remote-helper is the far-end counterpart. It is invoked by vaibify remote over SSH and is not meant to be run by hand.

Troubleshooting log

Every CLI invocation attaches a rotating log at ~/.vaibify/vaibify.log (10 MB per file, five backups kept). Warnings and errors from the hub, the pipeline runner, and the Docker layer land there, each tagged with the container id it concerns ([cid:<container-id>]), so when something misbehaves the log is the first place to look. vaibify doctor (below) is the other first stop.

Project Targeting

Note: When you are in a directory containing vaibify.yml, the --project flag defaults to that project. When only one project is registered globally, the flag can be omitted entirely. When multiple projects exist, --project is required unless you are in a project directory. Projects are registered automatically when you run vaibify init.

Project Setup

Host installer agent defaults

The host installer can select which in-container agent CLIs a later vaibify init enables by default:

sh vaibify/install/installVaibify.sh --agent=OpenCode --install-pi

Accepted provider names are claude, codex, gemini, antigravity, opencode, cline, openhands, and pi; each also has a matching --install-<provider> flag. These choices are defaults only: each new project’s vaibify.yml remains the authority, and can enable or disable any provider independently.

vaibify init

Create a new project, from a template or from nothing.

vaibify init [--template NAME] [--name NAME] [--minimal] [--force]

Option

Description

--template

Template name: sandbox, toolkit, or workflow

--name

Project name; scaffolds without a template when given alone

--minimal

Smallest config that still builds: no optional features, no extra packages

--force

Overwrite existing configuration files

With --template, this copies the template’s files and creates vaibify.yml in the current directory. With --name alone it writes only vaibify.yml, which is what a script wants:

mkdir myProject && cd myProject
vaibify init --name myProject --minimal

Run with neither option, it lists the available templates and exits.

vaibify register

Register an existing project directory in the global registry so it can be targeted with --project/-p from any directory. Unlike vaibify init, this does not create or overwrite any files.

vaibify register [DIRECTORY]

Argument

Description

DIRECTORY

Path to the project directory (default: .)

The directory must contain a vaibify.yml file.

vaibify setup

Launch the interactive setup wizard in a browser (port 8051). The wizard walks through configuration fields and writes the result to vaibify.yml.

vaibify setup

vaibify config

Edit, export, or import configuration.

vaibify config edit                         # Open vaibify.yml in $EDITOR
vaibify config export [-p NAME] <file>      # Write current config to a file
vaibify config import <file>                # Load config from a file

Container Lifecycle

vaibify doctor

The command to run when something is wrong. It DIAGNOSES and changes nothing — no container is started, stopped, removed or restarted by any check it performs. When a finding has a fix vaibify itself can apply, the finding names the command (see vaibify repair below).

Three scopes:

Scope

What it examines

host

This machine: Docker context and endpoint, daemon reachability, the runtime (Docker Desktop / Colima / rootful or rootless Engine), architecture, daemon storage and memory, what vaibify will request against what the daemon has, and room for an environment deposit

container

Inside the running container: network attachments and default route, the resolver configuration, name resolution compared against this host’s, the effective proxy path, and (with --online) transport

project

Vaibify’s own record of the project: journal quarantine, whether the environment envelope pins the image the container runs, workspace ownership, and what the entrypoint observed at the last start

Four states, and not checked is one of them:

State

Meaning

ok

Assessed and correct

warn

Assessed, and something is worth acting on

fail

Assessed, and something is broken

not checked

Could not be assessed, with the reason. Never counted as ok, and printed in its own group

Every warn and fail names a next step, and the command it names is correct for the runtime this host is actually using — colima start --profile <yours>, systemctl --user start docker for a rootless daemon, open -a Docker for Docker Desktop. When the runtime cannot be identified, doctor says so and names the diagnostic step rather than guessing at a command that does not apply to your machine.

vaibify doctor [--quiet] [--build] [--start] [--container] [--online]
               [--json] [--explain CHECK] [--project/-p NAME]

Option

Description

--quiet

Suppress ok lines; show only warns, fails and unassessed

--build

Run only the build-relevant subset

--start

Run only the start-relevant subset

--container

Run only the checks inside the running container and against this project’s records

--online

Permit connection attempts to the host this project already depends on

--json

Emit the results as JSON instead of a report

--explain CHECK

Print how one named check decides its answer, and nothing else

--project, -p

Target project name (optional if only one exists)

With no scope flag, every scope runs. The report ends with an N ok / M warn / K fail / J not checked summary line.

Exit codes.

Code

Meaning

0

Everything applicable in the requested scope was assessed, and nothing failed

1

At least one check failed

2

A scope you asked for by name contains a check that could not be assessed

Code 2 fires for any unassessed applicable check inside an explicitly requested scope — not only when the whole scope was unassessable. Without a scope flag nothing is explicitly requested, so a laptop with no container running does not turn an ordinary vaibify doctor run non-zero.

What doctor does over the network. By default it resolves exactly one name, and it is a name your project already depends on: your first configured repository’s host, or the API host of the agent provider you enabled. It introduces no third party of its own, and with neither configured it falls back to inspecting the resolver configuration and says so.

Connection attempts happen only with --online, and they follow the path your project actually uses rather than a fixed one: the port its remote is reached on (443 for https://, 22 for ssh:// and for the git@host:path form, 9418 for git://, or whatever the URL names), TLS only where the transport carries it, and through the container’s own proxy with a CONNECT when HTTPS_PROXY / HTTP_PROXY is set and NO_PROXY does not exempt the host. Nothing vaibify probes is ever authenticated to: no request bytes are sent to the destination and no Proxy-Authorization is sent to the proxy — a proxy that answers 407 is reported as exactly that, which is the diagnosis rather than a thing to work around.

vaibify repair

The acted-on half of vaibify doctor. One subject exists today.

vaibify repair dns [--recreate] [--yes] [--project/-p NAME]

vaibify repair dns clears a container’s stale resolver state. It reads the resolver configuration first and branches on it, because the three configurations do not have the same remedy:

  • a default bridge or Docker’s embedded resolver clears on a restart, so the repair restarts the container;

  • an explicit HostConfig.Dns is baked into the container and no restart can change it. Vaibify never sets that field, so finding one means the container’s specification drifted from its vaibify configuration — introduced from outside vaibify. The repair refuses to restart (which would succeed and change nothing, and read as the fix failing) and points at --recreate, which recreates the container from the vaibify configuration.

A repair tells you what it is about to do before it does it: a restart re-runs the entrypoint and kills every shell, agent and pipeline step inside the container. It refuses over live work, naming what is busy; it routes a restart through the live hub when one owns the container; it is journaled, so a crash mid-repair reconciles like any other interrupted operation; and a recreation pins the image identity the container is running rather than the project’s latest tag, which may have moved.

A recreation is refused while a vaibify hub holds the container, on both sides. Recreating gives the container a new id, and the hub’s session, workflow cache and file paths are all bound to the old one — so the session would stay authorized and cached against a container that no longer exists. Close the dashboard session for that project and run the command again; it then takes the direct lane.

Afterwards it re-probes and reports the state it actually found.

Code

Meaning

0

The repair ran and the re-probe confirmed the container resolves names again

1

The repair was refused, failed, or ran and the container still does not resolve

2

The repair ran and nothing was verified — this project names no host vaibify may resolve, or the container could not answer a lookup

Exit 2 is not a success. It is the command saying it changed something and cannot tell you whether that helped.

vaibify build

Build the Docker image from vaibify.yml and container.conf.

vaibify build [--no-cache] [--project/-p NAME]

Option

Description

--no-cache

Force a clean rebuild of all layers

--project, -p

Target project name (optional if only one exists)

vaibify start

Start the container. By default it attaches a terminal and holds the shell; --detach leaves it running in the background instead, which is what a script or a CI job needs.

vaibify start [--detach/-d] [--gui] [--jupyter] [--project/-p NAME]

Option

Description

--detach, -d

Start in the background and return

--gui

Launch the pipeline viewer after starting

--jupyter

Start JupyterLab inside the container

--project, -p

Target project name (optional if only one exists)

A detached container runs idle so you can vaibify connect into it; a COMMAND argument is refused with --detach rather than silently dropped.

vaibify stop

Stop the running container. The workspace volume persists.

vaibify stop [--project/-p NAME]

vaibify destroy

Delete the project’s workspace volume, after confirming, and then offer to remove the image as well.

Warning

This deletes the workspace volume — every file the container holds that is not committed and pushed. The volume is the only copy: /workspace is Docker-managed storage, not a directory on your machine. There is no --volumes flag to opt in; deleting the volume is what the command does, and the prompt is the only guard.

vaibify destroy [--project/-p NAME]

Option

Description

--project, -p

Target project name (optional if only one exists)

Two things it does not remove: the container itself (stop it with vaibify stop), and the credential volume, which persists until you remove it with docker volume rm.

vaibify status

Report the state of the container, image, and workspace volume — and, on request, the project’s PROOF level and everything blocking the next one.

vaibify status [--proof] [--json] [--project/-p NAME]

Option

Description

--proof

Also print the PROOF level and its blockers

--json

Emit environment and PROOF status as one JSON object

The level and the blockers come from the same gates the dashboard renders, read straight from the container, so no browser and no running hub is needed:

vaibify status --json | python -c \
  "import json,sys; print(json.load(sys.stdin)['dictProof']['iProofLevel'])"

One criterion is honestly absent. The dashboard polls file modification times and therefore also evaluates script-stale; a single read of the container has no mtime history, so that criterion is not evaluated here. The payload says which criteria were skipped in listUnevaluatedCriteria rather than letting the silence read as a pass.

Working with the Container

These commands work from any directory on the host. If you have multiple projects, specify which one with --project/-p. If only one project is registered, the flag can be omitted.

vaibify connect

Open an interactive shell inside the running container.

vaibify connect [--project/-p NAME]

Option

Description

--project, -p

Target project name (optional if only one exists)

vaibify push

Copy files from the host into the container workspace.

vaibify push [--project/-p NAME] <source> <destination>

Option

Description

--project, -p

Target project name (optional if only one exists)

vaibify pull

Copy files from the container workspace to the host.

vaibify pull [--project/-p NAME] <source> <destination>

Option

Description

--project, -p

Target project name (optional if only one exists)

vaibify verify

Run the isolation security audit inside the container. The audit checks for Docker socket access, privilege escalation paths, exposed ports, and mounted secrets.

vaibify verify [--project/-p NAME]

vaibify ls

List files in the container workspace. The path defaults to /workspace; relative paths are resolved against /workspace/.

vaibify ls [--project/-p NAME] [--json] [PATH]

Option

Description

--project, -p

Target project name (optional if only one exists)

--json

Emit a JSON array instead of one filename per line

PATH

Directory to list (default: /workspace)

vaibify cat

Print the contents of a file inside the container. Relative paths are resolved against /workspace/.

vaibify cat [--project/-p NAME] PATH

vaibify run

Execute pipeline steps inside the container. Without options, runs every step from the beginning. Use --step to run one step in isolation, or --from to resume from a specific step. The two are mutually exclusive.

vaibify run [--project/-p NAME] [--step N | --from N]

Option

Description

--step N

Run only step N (1-based)

--from N

Run step N and every step after it

--project, -p

Target project name (optional if only one exists)

Step progress, per-step pass/fail, and pipeline outcome are printed to stdout as the run progresses.

vaibify workflow

Print a summary of the current project, or details for a single step. Without --step, emits a table of all steps with their last verification status and run timestamp. With --step N, emits the step’s name, directory, run flags, and verification block.

vaibify workflow [--project/-p NAME] [--step N] [--json]

Option

Description

--step N

Show details for step N (1-based) only

--json

Emit JSON instead of a human-readable table

--project, -p

Target project name (optional if only one exists)

vaibify test

Run the test commands attached to one or all pipeline steps. Without --step, every step’s tests run in order. The exit code is non-zero if any step’s tests fail.

vaibify test [--project/-p NAME] [--step N] [--json]

Option

Description

--step N

Run tests for step N only (1-based)

--json

Emit JSON results instead of a summary table

--project, -p

Target project name (optional if only one exists)

vaibify verify-step

Set the user-verification status for a single pipeline step. This is the CLI counterpart to clicking your sign-off row in a step’s Verification section in the GUI: a researcher records their judgment that a step’s outputs look correct (or don’t).

vaibify verify-step --step N --status STATUS [--project/-p NAME]

Option

Description

--step N

Step number (1-based, required)

--status STATUS

One of passed, failed, untested (required)

--project, -p

Target project name (optional if only one exists)

vaibify generate-standards

Refresh or generate a step’s tests/quantitative_standards.json from live data files. If a curated standards file already exists, only each entry’s value is recomputed and the schema is preserved; otherwise a fresh file is generated from the data files found under the step directory.

vaibify generate-standards --step-dir PATH [--rtol X] [--detect-stochastic]
vaibify generate-standards --workflow JSON --step-label A09

Option

Description

--step-dir PATH

Path to a step directory containing tests/ and data files

--workflow JSON

Path to a workflow JSON (alternative to --step-dir)

--step-label LABEL

Step label like A09 or I01 (use with --workflow)

--rtol X

Default relative tolerance when generating a fresh standards file (default: 1e-6)

--detect-stochastic

Scan the step’s data*.py scripts for unseeded RNG before generating

Reproducibility

vaibify reproduce

Verify a project’s PROOF L3 reproducibility envelope: manifest integrity, hash-pinned dependency install, pinned container image, the seven L3 artifact-coherence checks, and — with --rerun — a full re-run of the workflow with a post-run hash compare and an L3 attestation written to .vaibify/l3_attestation.json.

vaibify reproduce [--repo PATH] [--rerun] [--workflow NAME] [--skip-tier N]
vaibify reproduce --from SOURCE [--workflow NAME] [--prepare | --rerun] [--allow-emulation]

Option

Description

--repo PATH

Path to the project repo (default: current directory)

--rerun / --no-rerun

Also re-run the workflow (tier 5), re-hash its outputs, and write an attestation (default: off)

--workflow NAME

Name (or container path) of the workflow to re-run; required when the container hosts more than one

--skip-tier N

Skip tier 1, 2, 3, or 4; may be repeated

--from SOURCE

Reproduce a published project: stage an exact snapshot of one commit from a clone URL or a clean local clone and validate it as reproduction-ready (six staging rules, not the author’s Level 3 gate). Alone it describes and discards the snapshot. Takes --workflow; refuses --repo and --skip-tier. Exit 1 names the first rule the snapshot failed. See Reproducing somebody else’s project

--prepare

With --from: obtain the pinned image through the published chain (registry, archived deposit, local copy) and stop

--rerun with --from

Obtain the image, re-run the snapshot in a shadow container, compare the bytes there, and write a reproduction report under ~/.vaibify/reproductions/reports/. Exit 0 only when the verdict is reproduced

--allow-emulation

With --from: accept a pinned build of another architecture than this daemon’s; the verdict then reads “reproduced under emulation”. Refused by name otherwise

Exit codes: 0 when every selected tier passed, 1 when any tier failed, 2 on a usage error (missing required file, malformed environment.json). The five tiers, the printed output, and the attestation files are documented in Reproducibility.

Credentials

vaibify revoke

Remove a stored credential from the local keyring and best-effort revoke it upstream. Supports the three services vaibify pushes to. Prints what was and was not revoked; exits non-zero when the local keyring slot could not be cleared.

vaibify revoke {github|overleaf|zenodo} [--keyring-slot SLOT] [--instance {sandbox|production}]

Option

Description

SERVICE

One of github, overleaf, zenodo (required)

--keyring-slot SLOT

GitHub only: per-repo keyring slot to clear (e.g. github_token:owner/repo)

--instance NAME

Zenodo only: target the sandbox (default) or production keyring slot

GUI and Pipeline

vaibify gui

Launch the pipeline viewer in a browser. The port is fixed at 8050 — there is no --port flag on this subcommand (hub mode, vaibify [--port N], is the invocation that accepts a port). When run without a project, the landing page opens and displays all registered containers. Use the + button to add an existing project or create a new one. See The Dashboard for details.

vaibify gui [--project/-p NAME]

Multiple sessions

Several vaibify instances can run on the same host. Typing vaibify twice in two terminals does not collide — the second invocation auto-shifts to the next free port (8051, 8052, …) and announces the fallback on stderr. Pass --port N to pin an explicit port. Any given container may be accessed by only one browser session at a time: the hub landing page greys out containers already held by another session, a second tab that tries to open a held container is refused “In use in another browser session”, and a second vaibify start -p X on the same project refuses to attach. The exclusivity mechanism — the per-claim lease, the owner-of-record map, the one-live-connection invariant, and the release triggers — is specified once in the architecture reference; that section is the normative source of truth, including the holder-payload field table. The New vaibify window button on the container hub, project picker, and Admin menu spawns a detached hub on a free port and opens it in a new browser tab.

Session management

Vaibify hub and viewer servers run in the foreground of the terminal that launched them. Closing a browser tab does not stop them, and closing the terminal orphans the server, which keeps holding its session slot and per-container locks until it is reaped. These commands let you see and stop live sessions. They are the host-side analog of jupyter server list and jupyter server stop, and like those, they run on the host only – they are not invokable from inside a container.

vaibify sessions

List every live hub and viewer session on the host, with its PID, role, port, start time, and the container(s) it holds.

vaibify sessions

Each line reports pid, role (hub or viewer), port, started (the ISO start time), and containers (the names locked on that port). When nothing is running it prints No live Vaibify sessions.

vaibify sessions stop

Gracefully stop a session by PID, or every session with --all.

vaibify sessions stop <PID>
vaibify sessions stop --all

Option

Description

PID

The session PID to stop (from vaibify sessions)

--all

Stop every live session except the current one

Stopping sends SIGTERM, which lets the server run its graceful shutdown – releasing its session slot and any container locks it holds. stop refuses any PID that is not a known live Vaibify session, so it can never signal an unrelated process, and --all excludes the current session so a session never stops itself.

Dashboard actions from the host: vaibify do

Everything a researcher can do from the dashboard has a name in the agent-action catalog (vaibify/gui/actionCatalog.py), and every one of those names is a vaibify do subcommand, generated from the catalog itself. The CLI therefore cannot drift from the dashboard: a new dashboard action is a new CLI command, and an action the CLI could not dispatch fails CI (testArchitecturalInvariants.py::testEveryCatalogActionHasCliCommand).

vaibify do                       # list every action, grouped by category
vaibify do <action> --help       # one action's arguments
vaibify do run-step A09          # run one step through the dashboard's own path
vaibify do push-to-github \
    listFilePaths='["Step/out.csv"]'
vaibify do check-l2-readiness --json

Option

Description

--project, -p

Target project name (optional if only one exists)

--port

Port of the vaibify session to drive (required when several are live)

--workflow

Container path of the project.json to connect

--json

Emit one JSON object per line

--dry-run

Print the call that would be made; send nothing

--timeout

Seconds to wait on the hub (0 disables the limit)

Path parameters become positional arguments (vaibify do run-test-category A09 sCategory=integrity); request-body fields are key=value pairs, coerced to numbers, booleans, and JSON by shape. A whole JSON object also works: vaibify do declare-ai-model '{"sVendor": "...", "sModelId": "..."}'.

A hub must be running. These commands drive the same backend the browser drives, so the dashboard sees every one of them; they are not a second, parallel way to change a project. Start one with vaibify in another terminal.

One session per container still holds. The CLI claims the container’s lease for the duration of one command and releases it afterwards — including when the action fails, so a failed command never strands the claim. A container currently open in a dashboard tab is therefore refused rather than taken over:

Error: Container 'myProject' is held by another vaibify session: In use
in another browser session. Vaibify allows one session per container, so
this command cannot take it from a live dashboard. Either close the
dashboard tab holding it (or release the container from the picker) and
run this again, or run the same action from inside the container with
'vaibify-do', the in-container agent lane, which acts within the session
that is already open.

That is the deliberate answer, not a limitation to work around: taking the container would mean revoking a session someone is working in.

The CLI is the researcher lane. It authenticates exactly as the browser does — with a per-browser credential — obtaining it headlessly: it mints a one-time launch capability over the hub’s host control socket (a 0700 Unix socket, peer-authenticated to the user who started the hub, unreachable from any container or remote peer) and redeems it at /api/bootstrap. The bAgentSafe flag in the catalog governs what a compromised in-container agent may invoke; it does not restrict the person at their own terminal, so user-only actions like clean-outputs are available here and are marked in --help.

Publishing

The vaibify publish subcommands are not implemented, and the publish group is not registered on the CLI at all — vaibify publish is an unknown command, not a command that reports its own absence. The sections below describe intended behaviour only.

There is no Settings → Publish pane. This section previously said the publishing machinery was “already available” through one; it never existed, and vaibify/reproducibility/githubWorkflow.py — the GitHub Actions generator behind that claim — has no caller anywhere in the product. Zenodo archiving is real and reachable, but through the PROOF Level 2 workflow in the dashboard, not a publish pane.

vaibify publish workflow (coming soon)

Generate a GitHub Actions workflow from project.json and vaibify.yml. The output will be written to .github/workflows/vaibify.yml.

vaibify publish workflow

vaibify publish archive (coming soon)

Package pipeline outputs and upload them to Zenodo (or the Zenodo sandbox). Will return a DOI on success.

vaibify publish archive