These docs are under active development.
On this page
reference 9 min read

CLI

Provium's CLI surface is the single binary provium. By default it discovers *.test.lua files under the given paths and runs them; subcommands cover REPL, fixture management, and listing.

Synopsis

provium [PATHS]... [FLAGS]
provium prepare [PROFILE]
provium repl <PROFILE> [--name <NAME>] [--fixture <PATH>]
provium console <PROFILE> [--mem <BYTES>] [--cpus <N>] [--cmdline <TEXT>] [--agent] [--qemu <PATH>] [--print-command] [-- QEMU_ARG...]
provium fixture list
provium fixture build <PATH>
provium fixture rebuild <PATH>
provium fixture clean
provium fixture stale
provium list [--fixtures]
provium lsp-setup [DIR] [--force]

If no paths are given, the current directory is scanned recursively.

Top-level flags

Discovery and selection

Flag Type Default Description
--config <PATH> path provium.toml Config file location.
--filter <STR> string none Only run files whose test-root-relative path contains this substring.
--include-slow flag off Include meta.slow tests (default skips them).
--tag <TAG> string, repeatable none Run only tests with one of these tags. OR'd.
--no-tag <TAG> string, repeatable none Skip tests with any of these tags. Wins over --tag.
--tag-meta <KEY=VALUE> string, repeatable none Run only tests where meta[KEY] contains VALUE. Multi-flag same KEY = OR within key; different KEYs = AND across keys. Useful for filtering on arbitrary fields like subsystems.
--no-tag-meta <KEY=VALUE> string, repeatable none Skip tests where meta[KEY] contains VALUE. Same key/value semantics as --tag-meta. Wins over --tag-meta.
--rerun-failed flag off Run only files that failed in the last run. Reads from ~/.cache/provium/rerun.json.
--since <PATH> path none Run only files whose mtime is newer than this reference file.
--watch flag off Re-run on file change (poll every 500 ms).

VMM and resources

Flag Type Default Description
--vmm <CHOICE> qemu / local qemu VMM backend. local is for dev runs without KVM — does not actually boot a kernel.
--mem <BYTES> size string "4G" 80 % of host RAM Pool memory budget.
--cpus <N> int host online CPUs Pool vCPU budget.
--cpu-overcommit <F> float 1.0 Multiplier on --cpus. Clamped to [0.5, 8.0].
--no-preflight flag off Skip the startup /dev/kvm / iproute2 / nft / qemu / CAP_NET_ADMIN checks.
--no-ksm flag off Skip Kernel Same-page Merging tuning at startup.
--no-build flag off Skip every dynamic profile's build command for this run. Use when you know the artifacts are already current. Does not affect provium prepare, whose whole purpose is to build.

Lifecycle

Flag Type Default Description
--timeout <DUR> seconds-int or duration string 300 (5 min) Per-file wall-clock timeout. 0 disables. Accepts "500ms", "30s", "10m", "2h".
--fail-fast flag off Stop after the first failed file.

Output

Flag Type Default Description
-v, --verbose flag off Show passing tests too. Mutually exclusive with --quiet.
-q, --quiet flag off Show only failures. Mutually exclusive with --verbose.
--json flag off Line-delimited JSON output, one object per file. Mutually exclusive with --events-stdout.

Observability

Flag Type Description
--save-events <PATH> path Persist the event stream to PATH as length-prefixed msgpack frames. Compatible with provium-coverage --from PATH.
--events-stdout flag Emit msgpack event frames on stdout; the human/JSON renderer redirects to stderr. Mutually exclusive with --json.
--events-socket <PATH> path Multiplex the event stream over a Unix socket. The binary listens, accepts connections, fans out frames. Reused across --watch iterations.
--coverage flag Pipe the buffered event stream into provium-coverage (must be on PATH) after the run.

Subcommands

When a subcommand is given, the test-runner mode is suppressed.

provium prepare [PROFILE]

Run dynamic profiles' build commands without booting anything. With a PROFILE argument, builds just that profile (and errors with provium prepare: profile \` not found in provium.tomlif it isn't declared); with no argument, builds every profile that declares abuild` command, in name order, stopping at the first failure.

Use it to pre-warm artifacts — provium prepare && provium --no-build builds once, then runs the suite without rebuilding — or to drive an image build from a machine that isn't a test host: prepare skips the pre-flight checks (/dev/kvm, iproute2, CAP_NET_ADMIN), so it runs anywhere sh and the builder do.

A profile with no build command is a silent no-op. A build that exits non-zero aborts with the profile name and exit status, and Provium never falls through to using whatever stale artifacts are on disk.

provium repl <PROFILE> [--name <NAME>] [--fixture <PATH>]

Boot a VM and drop into an interactive Lua REPL against it.

Arg / flag Description
<PROFILE> Profile name from provium.toml. Optional when --fixture is given.
--name <NAME> VM name. Defaults to repl.
--fixture <PATH> Resume from a fixture instead of cold-booting.

If --fixture is set without a profile arg, the first profile in provium.toml (sorted by name) is used.

provium console <PROFILE> [flags] [-- QEMU_ARG...]

Boot a profile's VM and attach your terminal to its serial console — no agent, no Lua. Ctrl-A X quits QEMU; Ctrl-A C toggles the QEMU monitor.

Flag Description
--mem <BYTES> Override the per-VM memory default.
--cpus <N> Override the per-VM vCPU default.
--cmdline <TEXT> Override the profile's kernel command line.
--agent Inject the agent overlay (off by default for console sessions).
--qemu <PATH> Pick the QEMU binary.
--print-command Print the assembled QEMU command line and exit.

Anything after -- is passed verbatim to QEMU.

provium fixture list

Show every cached entry with size and key.

provium fixture build <PATH>

Force a build for the named fixture (test-root-relative path, no .fixture.lua suffix). If the fixture is already cached, prints already built: <path> and exits.

provium fixture rebuild <PATH>

Evict the existing cache entry and rebuild. Both single-VM (.snap) and lab (.lab/) layouts are evicted.

provium fixture clean

Wipe the entire cache directory.

provium fixture stale

List .fixture.lua files whose source hash (folded with kernel + initrd identifiers and any external host-file deps declared via vm:push_file / lab:depends_on_file) doesn't correspond to any cached entry. Useful for "what would provium rebuild on the next run?"

provium list [--fixtures]

List discovered tests (default) or fixtures (--fixtures) without running anything. Useful for piping into xargs or for CI dry-runs.

provium lsp-setup [DIR] [--force]

Drop Lua Language Server definitions into a test directory so test, provium, wait_until, json, and the rest of the harness globals stop showing up as undefined in your editor.

Writes:

  • <DIR>/.provium-meta/types.lua---@meta stubs covering the test framework, the TestContext (t:assert_eq, t:fail, …), the root Lab, and the json global. Less-trafficked methods are typed as any — the goal is silencing diagnostics, not full IDE intellisense.
  • <DIR>/.luarc.json — config pointing the LSP at .provium-meta/.

DIR defaults to the current directory. If .luarc.json already exists, the command refuses to overwrite and prints the snippet to merge in by hand; pass --force to replace it.

Skips pre-flight checks (/dev/kvm, iproute2, nft) so it runs cleanly on machines without test prerequisites — useful from a dev laptop separate from the test host.

After running, reload your editor's Lua server. To extend the types further (e.g. richer completion on a specific userdata you use a lot), edit .provium-meta/types.lua directly.

Exit codes

Code Meaning
0 Every file passed (or skipped).
1 At least one file did not finish cleanly (failed test, panicked runner, timed-out file). With --coverage, also reflects the coverage post-run's exit code if it failed.
2 Internal error — config load failure, pre-flight failure, a dynamic profile's build command failing, or a panic in the dispatcher.

The exit code is intentionally clamped to 0/1/2 rather than reflecting the number of failed files, so shell scripts don't have to worry about overflow at the 256-file mark or accidentally interpret failed_count == 2 as the internal-error sentinel.

Environment variables

Variable Effect
PROVIUM_TEST_FILTER JSON object set by the binary at startup carrying --include-slow / --tag / --no-tag / --tag-meta / --no-tag-meta so the runner picks them up. Test code does not set this directly.
PROVIUM_OVERLAY Path to the agent-overlay cpio. Overrides the binary-relative path-walk; lower priority than the per-profile agent_overlay_path config field. Useful for distribution-installed Provium where the overlay isn't co-located with the binary.
PROVIUM_RERUN_STATE Override the path of the rerun-state file (default: ~/.cache/provium/rerun.json, or /tmp/provium-rerun.json if $HOME is unset).
PROVIUM_COVERAGE_TMP Set by --coverage to point at the temp event file the post-run hook will read. Cleared after the hook completes.
PROVIUM_COVERAGE_USER_FILE Set when --coverage reuses an explicit --save-events path so the post-run hook does NOT delete it.
PROVIUM_COVERAGE_MARKER Marker file --coverage uses to recognise its own temp file (vs an externally-set PROVIUM_COVERAGE_TMP pointing at user data).
HOME Used to compute the default rerun-state path.
PATH Searched for qemu-system-x86_64, ip, tc, nft, tcpdump, and (on --coverage) provium-coverage.

Output shape

Plain text (default)

PASS tests/smoke.test.lua (3 passed, 0 failed, 0 skipped)
FAIL tests/networking/partition.test.lua (2 passed, 1 failed, 0 skipped)
    FAIL split-brain
        client A could not reach client B after partition
TIME tests/long.test.lua (1 passed, 0 failed, 0 skipped)

3 file(s); 6 passed, 1 failed, 0 skipped; 12.34s

-v adds PASS <name> / SKIP <name> lines for each test. -q suppresses everything except the file-status line for files with failures and the summary.

JSON (--json)

One object per file, line-delimited. Schema:

{
  "path": "tests/smoke.test.lua",
  "timeout": "in_time",
  "passed": true,
  "chunk_error": null,
  "tests": [
    {"name": "boots", "status": "passed", "message": null, "log": []},
    {"name": "fails", "status": "failed", "message": "1 ~= 2", "log": []}
  ]
}

status is one of "passed", "failed", "skipped". timeout is "in_time" or "timed_out".

Msgpack events (--events-stdout)

Length-prefixed msgpack frames, one per EventFrame (see events). When --events-stdout is set, the human-readable / JSON renderer redirects to stderr so consumers piping provium --events-stdout | provium-coverage don't see human text interleaved into their msgpack parser.

Filter precedence

Multiple selection flags compose:

  1. Discovery: walk <paths> for *.test.lua files.
  2. --filter substring match against test-root-relative path.
  3. --rerun-failed intersect with the prior failed set (zero-result clean exit if no prior state).
  4. --since mtime newer than the reference path.
  5. Per-test (within each file): meta.skip → instant skip.
  6. Per-test: meta.slow and --include-slow.
  7. Per-test: --no-tag (skip if any match).
  8. Per-test: --tag (run if any match).
  9. Per-test: --no-tag-meta KEY=VALUE (skip if meta[KEY] contains VALUE).
  10. Per-test: --tag-meta KEY=VALUE (run if all KEYs have at least one matching VALUE).

--watch mode rediscovers from scratch every iteration; --rerun-failed is automatically dropped under --watch so file-edit detection works as expected.

See also