CLI reference
Overview
Install, global flags, and a map of every labctl command.
docs/reference/cli/index.mdOn this page
labctl is the command-line interface for SnowOps Labs. It builds the lab,
runs scenarios, injects faults and grades your fix.
Install
git clone --branch stable https://github.com/sagar2395/snowopslabs.git
cd snowopslabs && ./install.shinstall.sh puts the labctl release named by the clone's LAB_VERSION in
~/.local/bin, with no sudo, and records the clone in ~/.snowops/lab-dir.
Re-run it after upgrading the clone (git merge origin/stable). The per-OS
guides are under Getting started.
labctl finds the lab in this order: --project-dir; the clone around the
working directory; SNOWOPS_LAB_DIR; the recorded clone
(details). Lab state (active
scenarios and faults, history, progress, snapshots, users) is kept per cluster
in ~/.snowops/state/<cluster>/ (SNOWOPS_HOME moves ~/.snowops). State an
older labctl kept in the clone's .labctl/ is moved there on first use.
Build from source (contributors) - needs Go 1.25+ and Node 22+; see CONTRIBUTING:
make cli-build # builds bin/labctl with the UI embeddedGlobal flags
| Flag | Default | Description |
|---|---|---|
--project-dir |
auto-detected | The lab (a snowopslabs clone) to use; see Install for how it is found otherwise |
-v, --verbose |
false |
Debug logging: config load, script exec, API calls |
--app |
APP_NAME |
The application scenarios and faults act on for this command. Challenges and learning paths refuse it: they are graded against the default app |
--version |
- | Print the build version |
Configuration
labctl reads its settings each time a command starts. This section says
where they come from and which one wins; config/.env.example describes every
key. labctl -v <command> logs a config loaded line with the lab, profile
and cluster it resolved.
Which lab labctl uses
Without --project-dir, the first of these:
- The nearest clone at or above the working directory: a directory with
scenarios/andruntimes/. SNOWOPS_LAB_DIR.- The clone
install.shrecorded in~/.snowops/lab-dir.
--project-dir overrides all three, and is used as given, without checking
that it is a clone: a wrong directory fails later, typically with
runtime profile "k3d" not found in runtimes/. A SNOWOPS_LAB_DIR that is not
a clone is an error, not a reason to try the recorded clone. Inside a clone,
that clone is used whatever SNOWOPS_LAB_DIR says.
Which value wins
For every key, the first value that is not empty:
- The environment variable.
.envin the lab.runtimes/<PROFILE>/runtime.env.- The built-in default.
PROFILE comes from the environment or .env (default k3d), since it picks
the runtime.env. Some defaults follow another key: CLUSTER_NAME is
snowops (kind's runtime.env makes it snowops-kind), DOMAIN_SUFFIX is
<CLUSTER_NAME>.localhost and INGRESS_CLASS takes the value of
INGRESS_PROVIDER.
An empty value counts as unset wherever it appears. An empty environment
variable is skipped, and an empty line in .env, such as STORAGE_CLASS=,
leaves the key to the profile, so kind still gets standard.
The scripts and Make targets labctl runs receive every key from .env and
runtime.env, resolved the same way.
Values the cluster recorded
A local runtime records the ingress ports it bound and the domain suffix in
~/.snowops/clusters/<CLUSTER_NAME>.env
(runtime profiles).
For HTTP_PORT, HTTPS_PORT and DOMAIN_SUFFIX, the record wins over .env
and runtime.env; only an environment variable wins over the record. A new
value in .env therefore does not move a cluster that already exists. The
record lasts as long as the cluster: the profile's down.sh removes it.
SNOWOPS_HOME moves ~/.snowops, and with it lab-dir, clusters/ and
state/.
Examples
Use kind for one command, without editing .env:
PROFILE=kind labctl -v statusThe cluster is snowops-kind and the URLs end in snowops-kind.localhost,
unless .env sets CLUSTER_NAME, which wins over kind's runtime.env.
Use a clone from another directory:
cd ~
labctl --project-dir ~/src/snowopslabs scenario list
SNOWOPS_LAB_DIR=~/src/snowopslabs labctl scenario listBoth use that clone. From inside another clone, only --project-dir does.
Find out why a value in .env is ignored, for example HTTP_PORT=80 while
URLs end in :8080: an environment variable of the same name, or the
cluster's record, wins over .env.
env | grep '^HTTP_PORT='
cat ~/.snowops/clusters/snowops.env # the record of the default clusterExit status and errors
A command exits 0 when it did what it was asked and 1 otherwise, so it is
safe in scripts and CI. A failing check is a failure: scenario verify exits
1 while any check fails.
- A mistake in how the command was typed (a missing argument, an unknown flag) prints the error and that command's usage.
- A command that was typed correctly and then failed prints only the error, with what to run next where there is something to run.
- A name that does not exist is answered with the command that lists the names
that do, such as
see 'labctl scenario list'.
Command map
| Page | Commands |
|---|---|
| Lifecycle | init teardown reset status doctor setup-tools check hosts runtime lab runs |
| Applications & services | app service |
| Platform | platform |
| Scenarios | scenario validate |
| Incidents | incident |
| Traffic | traffic |
| Comparing stacks | compare |
| Learning & challenges | learn challenge |
| Server, metrics & auth | ui users |
CLI or Make
Both work. Make targets are more granular; the CLI adds scenarios, the web UI and a unified status view.
| Operation | CLI | Make |
|---|---|---|
| Full setup | labctl init |
make init |
| Build an app | labctl app build go-api |
make build APP_NAME=go-api |
| Deploy an app | labctl app deploy go-api |
make deploy APP_NAME=go-api |
| Platform status | labctl platform status |
make platform-status |
| Activate a scenario | labctl scenario up observability-sre |
CLI only |
| Web dashboard | labctl ui |
CLI only |
| Deploy every app | - | make deploy-all |