CLI reference
One binary, a handful of verbs. VM lifecycle on top, cluster and registry management below. Every command and flag here is taken straight from the binary's own help text.
Global usage
Persistent flags apply to every command. --config
(short -c) points at an alternate config file; it defaults
to ~/.klimax/config.yaml.
$ klimax [-c ~/.klimax/config.yaml] [--debug] [--lima-log-level <level>] <command>
| Flag | Description |
|---|---|
-c, --config <path> | Path to the klimax config file (default ~/.klimax/config.yaml). |
--debug | Enable klimax debug logging — and surface Lima's own logs at info. |
--lima-log-level <level> | Show the embedded Lima VM logs at this level: trace, debug, info, warn, error, or off. Hidden by default. |
This page is a curated summary. For the authoritative, always-current
flag list run klimax <command> --help — the binary is the
source of truth.
Logging
klimax's own output uses Go's log/slog; the embedded
Lima
library logs through logrus. By default klimax quiets Lima to
error, so you see klimax's messages plus any genuine Lima
errors — the noisy INFO[…]/WARN[…] Lima lines are
hidden. Turn them on when you need to debug the VM itself:
| You want… | Run |
|---|---|
| Default — quiet Lima, klimax only | (nothing — this is the default) |
klimax debug + Lima at info | klimax --debug <command> |
| Lima at a specific level | klimax --lima-log-level info <command> |
| Full Lima firehose | klimax --lima-log-level trace <command> |
| Silence Lima entirely (panic-only) | klimax --lima-log-level off <command> |
# See what Lima is doing while the VM comes up
$ klimax --lima-log-level info up
# klimax debug detail, with Lima surfaced at info
$ klimax --debug up
An explicit --lima-log-level wins over --debug.
Levels: trace · debug · info ·
warn · error · off
(none/quiet/silent also work). VM
readiness detection is unaffected — the in-VM hostagent keeps
its own verbose logs regardless.
VM lifecycle
| Command | Description |
|---|---|
klimax up | Create/start the VM, provision Docker, create kind clusters, set up routing (idempotent). |
klimax down | Stop the VM — preserves all clusters and registry cache data. |
klimax down --remove-route | Also remove the macOS host route (requires sudo). |
klimax destroy | Delete kind clusters, delete the VM, and remove the macOS route. |
klimax status | Show VM state, clusters, route, and iptables rule presence. |
klimax doctor | Diagnose issues and print actionable fix commands. |
klimax shell | Open an interactive SSH session in the klimax VM (alias ssh). |
klimax shell <cmd> [args…] | Run a command in the VM and exit with its exit code. |
klimax copy <src>… <dst> | Copy files between the host and the VM over scp (alias cp). |
klimax disk resize <size> | Grow the VM disk — applied on the next VM start. |
klimax prune | Remove klimax's reclaimable cached files. |
klimax config edit | Open the klimax config file in $EDITOR. |
klimax version | Print the klimax version. |
# Bring everything up — prompts for sudo once to add the host route
$ klimax up
# Stop the VM but keep clusters and cache
$ klimax down
# Tear it all down: VM, clusters, and the host route (sudo)
$ klimax destroy
klimax down keeps the host route in place. Use
--remove-route (or klimax destroy) to drop it —
either requires sudo. To stop being prompted at all, install the
sudoers rules.
After upgrading klimax, re-create the VM. Provisioning
is baked into the binary, so klimax down/up on an
existing VM keeps running the old setup. Run
klimax destroy && klimax up once after each
brew upgrade --cask klimax — the host-backed image cache
survives, so it rebuilds fast.
Running commands in the VM
Bare klimax shell opens an interactive session. Give it a
command and it runs that in the VM instead, passing
stdin/stdout/stderr straight
through and exiting with the remote exit code — so it composes in
pipelines and if tests without reaching for
limactl.
| Flag | Description |
|---|---|
-t, --tty | Force pseudo-terminal allocation — for commands that need one (htop, an editor). |
$ klimax shell # interactive session
$ klimax shell docker ps -a # flags after the command are passed through
$ klimax shell -- bash -c 'kind get clusters' # -- when a flag could look like klimax's
$ cat setup.sh | klimax shell bash -s # stdin is piped in
$ klimax shell -t htop # force a pseudo-terminal
Flag parsing stops at the first positional argument, so
klimax shell docker ps -a works as typed — the
-a goes to docker, not to klimax. Use
-- only when the first word could be mistaken for a
klimax flag. Because the exit code is the remote command's,
if klimax shell test -e /run/docker.sock; then … behaves like
a local test.
Copying files
Moves files in either direction over scp. Mark the VM side
with a vm: prefix (the VM's configured name works too);
exactly one side of the copy must carry it.
| Flag | Description |
|---|---|
-r, --recursive | Copy directories recursively. |
$ klimax copy ./script.sh vm:/tmp/script.sh # host → VM
$ klimax copy vm:/tmp/out.json ./out.json # VM → host
$ klimax copy -r ./manifests vm:/tmp/ # directories
$ klimax copy a.yaml b.yaml vm:/tmp/ # many sources → a directory
Multiple sources are allowed when the destination is a directory. To
copy within the VM, use klimax shell cp … — two
vm: sides are rejected.
Growing the disk
Grows the VM disk without recreating the VM. The new size is written to
vm.disk
in the klimax config and to the Lima instance config; Lima
expands the image on the next start and the guest root filesystem grows
during boot. So it lands after a restart:
$ klimax disk resize 80GiB # rewrites vm.disk and the Lima instance config
$ klimax down && klimax up # Lima expands the image; the guest FS grows on boot
$ klimax shell df -h / # confirm the new headroom
Shrinking is refused — neither Lima nor the guest
filesystem supports it. Requesting the current size is a no-op. If the VM
doesn't exist yet, only the config is updated and the next
klimax up creates the disk at the new size.
Reclaiming space
Removes files klimax can re-create: superseded Lima guest agents under
~/.klimax/share/lima, and registry cache directories whose
mirror is no longer in your config (after renaming or removing one). It
lists what it found, grouped and sized, and confirms before deleting.
| Flag | Description |
|---|---|
--dry-run | Show what would be removed, remove nothing. |
--downloads | Also clear Lima's image download cache — shared with every other Lima instance on the host. |
-y, --yes | Skip the confirmation prompt (required to run non-interactively). |
$ klimax prune --dry-run # show what would go
$ klimax prune # confirm, then remove
$ klimax prune --downloads # also Lima's shared image download cache
--downloads clears a cache in the OS cache directory that
Lima shares across tools — limactl, Colima,
Rancher Desktop. Their next start re-downloads its base images too.
Caches of configured mirrors are never touched by
prune — that's
klimax registry clean-cache. And
prune keeps the guest agent matching the Lima version of the
binary you run it with, so pruning with a different klimax build removes
that build's agent; harmless, it re-downloads on its next
klimax up.
Host setup
Two commands that configure the Mac rather than the VM: one grants
klimax up the single privilege it needs, the other starts the
VM at login.
| Command | Description |
|---|---|
klimax sudoers | Print a sudoers snippet so klimax up can manage the host route without a password. |
klimax sudoers --check | Report whether those rules are in effect. |
klimax autostart install | Install and load a per-user launchd agent that runs klimax up at login. |
klimax autostart status | Show whether the agent is installed and loaded. |
klimax autostart uninstall | Unload and remove the agent (alias remove). |
Passwordless host route
klimax up needs root for exactly one thing: the macOS route
for the kind bridge CIDR.
klimax sudoers prints NOPASSWD rules scoped to
those two /sbin/route invocations — the add and the delete,
with the gateway wildcarded, because macOS assigns the VM's
lima0 IP dynamically. Grant that and up stops
prompting:
$ klimax sudoers | sudo tee /etc/sudoers.d/klimax >/dev/null
$ sudo chmod 0440 /etc/sudoers.d/klimax
$ sudo visudo -c -f /etc/sudoers.d/klimax # verify the syntax
$ klimax sudoers --check
✓ Passwordless route rules for 172.30.0.0/16 are in effect.
The rules are scoped to the configured CIDR, so regenerate
them after changing
network.kindBridgeCIDR.
--check reads the sudo policy rather than trying the commands
— a cached sudo credential would let a trial run succeed whether or not
the rules exist.
Starting at login
Installs a per-user launchd agent, dev.klimax.autostart, at
~/Library/LaunchAgents/ that runs klimax up when
you log in. Output is appended to
~/.klimax/logs/autostart.log.
$ klimax autostart install # write the plist and load it
$ klimax autostart install --print # emit the plist to stdout instead
$ klimax autostart status
$ klimax autostart uninstall
Install the sudoers
rules first. launchd cannot answer a password prompt, so
without them the VM comes up at login without the host route and
nothing in 172.30.0.0/16 is reachable from the Mac.
klimax sudoers --check confirms you're set.
The plist records the klimax binary by the path you invoked — with the
Homebrew cask that's the stable /opt/homebrew/bin/klimax
symlink, so the agent keeps working across
brew upgrade --cask klimax. The --config path is
baked in the same way.
Docker access
Point your host's docker CLI at the daemon inside the VM,
either per-shell with an environment variable or persistently with a
Docker context.
| Command | Description |
|---|---|
klimax docker-env | Print the export command to point DOCKER_HOST at the klimax VM. |
klimax docker-env --unset | Print commands to unset the Docker environment. |
klimax docker-context | Create/switch to the klimax Docker context. |
klimax docker-context --unset | Switch back to the default Docker context. |
# Option A — environment variable, current shell only
$ eval $(klimax docker-env)
$ eval $(klimax docker-env --unset)
# Option B — Docker context, persistent across shells
$ klimax docker-context
$ klimax docker-context --unset
If DOCKER_HOST is set it overrides the active Docker
context — use one or the other.
Clusters
Cluster lifecycle lives entirely under klimax cluster —
there is no cluster list in the config file. For declarative,
multi-cluster workflows see Fleet management
and the Fleet resource.
| Command | Description |
|---|---|
klimax cluster create <name> | Create a new kind cluster in the running VM. |
klimax cluster apply -f <file> | Create a fleet of clusters from a Fleet manifest (additive; honours dependsOn). |
klimax cluster delete [name] | Delete a kind cluster (interactive picker when no name is given). |
klimax cluster delete -f <file> | Delete every cluster listed in a Fleet manifest (reverse-dependency order). |
klimax cluster delete -l <selector> | Delete clusters whose nodes match a label selector. |
klimax cluster list | List kind clusters running in the VM (filter with -l <selector>). |
klimax cluster label <name> | Add, overwrite, or remove node labels on an existing cluster. |
klimax cluster e2e-test-nginx | Deploy nginx and curl it via LoadBalancer to verify the cluster end-to-end. |
klimax cluster use / merge | Deprecated — use kubeconfig env / merge (or kubeconfig use to switch context). |
cluster create flags
| Flag | Description |
|---|---|
--region <r> | topology.kubernetes.io/region label (default europe-west<N>). |
--zone <z> | topology.kubernetes.io/zone label (default europe-west<N>-b). |
-l, --label <k=v> | Extra node label; repeatable. All nodes also get managed-by=klimax. |
The cluster num (subnet/port slot)
is always auto-assigned to the lowest free value. To pin one, use a
Fleet manifest's per-cluster
num: field.
$ klimax cluster create dev
$ klimax cluster create dev --region us-east1 --zone us-east1-a
$ klimax cluster create dev -l team=search -l env=dev
Fleets — apply & delete -f
Create or tear down a whole fleet of
clusters from one Fleet manifest.
apply is additive — it creates the clusters that don't exist
yet, in dependsOn order, up to maxParallel at a
time — and never mutates running clusters.
| Flag | Applies to | Description |
|---|---|---|
-f, --filename <path> | apply, delete | Path to a Fleet manifest; - reads stdin. |
--dry-run | apply | Validate and print the resolved plan, then exit without creating anything. |
--max-parallel <N> | apply | Override spec.maxParallel (concurrent cluster creations). |
-y, --yes | delete | Skip the confirmation prompt. |
$ klimax cluster apply -f fleet.yaml --dry-run # preview the plan
$ klimax cluster apply -f fleet.yaml # create what's missing
$ cat fleet.yaml | klimax cluster apply -f - # from stdin
$ klimax cluster delete -f fleet.yaml -y # tear the fleet down
Listing, switching, merging
cluster list takes -o / --output
with text (default), json, or yaml,
and -l / --selector to filter by a kubectl-style
node-label selector.
$ klimax cluster list
$ klimax cluster list -o json
$ klimax cluster list -l env=dev # filter by label selector
$ klimax cluster list -l klimax.dev/fleet=dev-fleet
Pointing kubectl at a cluster now lives under
klimax kubeconfig:
# Use one cluster's isolated kubeconfig in this shell
$ eval $(klimax kubeconfig env dev)
# Or merge it into ~/.kube/config and switch to it
$ klimax kubeconfig use dev
Labeling clusters
Relabel the nodes of a cluster that's already running — no recreate
needed. Repeatable -l key=value sets or overwrites a label
(--overwrite is the default); -l key- removes
one. It runs kubectl label nodes --all under the hood.
$ klimax cluster label dev -l tier=frontend -l disktype=ssd
$ klimax cluster label dev -l disktype- # remove the label
Deleting clusters
Pass a name to delete one cluster, run it bare for an interactive
multi-select picker, or match a set with -l /
--selector (confirms unless -y).
$ klimax cluster delete staging
$ klimax cluster delete # interactive picker (Space toggles)
$ klimax cluster delete -l env=test --yes # delete all matching, no prompt
End-to-end smoke test
Runs against your current kubectl context. --cleanup
removes the test workload instead of deploying it.
$ klimax cluster e2e-test-nginx
$ klimax cluster e2e-test-nginx --cleanup # delete the nginx pod and service
Kubeconfig
Every cluster keeps an isolated kubeconfig. The klimax kubeconfig
family (alias klimax kc) prints its path, exports it, or merges
it into your default ~/.kube/config.
| Command | Description |
|---|---|
klimax kubeconfig path <name> | Print the path to the cluster's kubeconfig file. |
klimax kubeconfig env <name> | Print export KUBECONFIG=<path> — eval it to use the cluster's isolated kubeconfig in the current shell. |
klimax kubeconfig merge <name> | Merge the cluster's context into ~/.kube/config. |
klimax kubeconfig use <name> | Merge and switch the active kubectl context to it. |
klimax kubeconfig remove <name> | Remove the cluster's context, cluster, and user from ~/.kube/config (alias rm). |
$ eval $(klimax kubeconfig env dev) # use dev's isolated kubeconfig here
$ klimax kubeconfig use dev # merge + switch active context
$ klimax kubeconfig path dev
$ klimax kubeconfig remove dev # clean it out of ~/.kube/config
klimax cluster use and cluster merge still work
as deprecated aliases — cluster use maps to
kubeconfig env, cluster merge to
kubeconfig merge. Prefer the kubeconfig forms.
Fleets
The top-level klimax fleet command operates on
live clusters grouped by the
klimax.dev/fleet=<name> node label (membership is derived
from running clusters, not the manifest). See
Fleet management and the
Fleet resource.
| Command | Description |
|---|---|
klimax fleet list | Group clusters by klimax.dev/fleet (-o text/json/yaml). |
klimax fleet describe <name> | Show a fleet's members with their num, ports, nodes, and labels (aliases desc, show). |
klimax fleet create -f <file> | Create a manifest's clusters — delegates to cluster apply -f (--dry-run, --max-parallel). |
klimax fleet delete <name> | Delete a fleet's clusters, resolved by label (-y to skip the prompt). |
klimax fleet delete -f <file> | Delete a manifest's clusters — same as cluster delete -f. |
klimax fleet label <name> -l <k=v> | Apply node labels to every cluster in the fleet (-l key- removes). |
$ klimax fleet list
$ klimax fleet describe dev-fleet
$ klimax fleet create -f fleet.yaml --dry-run
$ klimax fleet label dev-fleet -l tier=frontend
$ klimax fleet delete dev-fleet -y
Registry
| Command | Description |
|---|---|
klimax registry clean-cache | Remove all registry mirror cache data and their containers. |
$ klimax registry clean-cache
$ klimax up # restart the mirrors afterwards
With the default cacheStorage: "host", mirror blobs live
at ~/.klimax/registry-cache/ and survive
klimax destroy. clean-cache is how you wipe
them on purpose. See Registry mirrors.
Skill
Install the klimax Agent Skill so AI coding tools like Claude Code know how to drive klimax.
| Command | Description |
|---|---|
klimax skill install | Install the bundled SKILL.md into an AI tool's skills directory (Claude Code by default). |
klimax skill path | Print where the skill is installed for Claude Code. |
Flag (on install) | Description |
|---|---|
--claude | Install into ~/.claude/skills/klimax/ (default true). |
--print | Write the skill to stdout instead of installing. |
-f, --force | Overwrite an already-installed skill. |
$ klimax skill install # → ~/.claude/skills/klimax/SKILL.md
$ klimax skill install --print # emit to stdout for other tools
$ klimax skill path
Completion
Generate a shell auto-completion script for bash,
zsh, fish, or powershell.
# zsh — add to ~/.zshrc to persist
$ source <(klimax completion zsh)
# bash
$ source <(klimax completion bash)
# fish
$ klimax completion fish > ~/.config/fish/completions/klimax.fish
See also
- Fleet management — declarative multi-cluster with
klimax fleet. - Fleet resource — the manifest schema in full.
- Getting started — the guided tour from install to a routable cluster.
- Configuration — the
~/.klimax/config.yamlschema in full.