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 ~/.marina/config.yaml.
$ marina [-c ~/.marina/config.yaml] [--debug] [--lima-log-level <level>] <command>
| Flag | Description |
|---|---|
-c, --config <path> | Path to the marina config file (default ~/.marina/config.yaml). |
--debug | Enable marina 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 marina <command> --help — the binary is the
source of truth.
Logging
marina's own output uses Go's log/slog; the embedded
Lima
library logs through logrus. By default marina quiets Lima to
error, so you see marina'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, marina only | (nothing — this is the default) |
marina debug + Lima at info | marina --debug <command> |
| Lima at a specific level | marina --lima-log-level info <command> |
| Full Lima firehose | marina --lima-log-level trace <command> |
| Silence Lima entirely (panic-only) | marina --lima-log-level off <command> |
# See what Lima is doing while the VM comes up
$ marina --lima-log-level info up
# marina debug detail, with Lima surfaced at info
$ marina --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 |
|---|---|
marina up | Create/start the VM, provision Docker, create kind clusters, set up routing (idempotent). Alias start. |
marina migrate | Move a klimax installation (~/.klimax) over: deletes the klimax VM, moves the config and registry cache. --dry-run shows the plan; -y skips the prompt. See Coming from klimax. |
marina down | Stop the VM; every cluster stops with it. Cluster state and registry cache data are preserved (aliases stop, d). |
marina down --remove-route | Also remove the macOS host route (requires sudo). |
marina destroy | Delete kind clusters, delete the VM, and remove the macOS route. |
marina status | Show VM state, host mounts, clusters, route, and iptables rule presence (-o text/json/yaml). |
marina doctor | Diagnose issues and print actionable fix commands (-o text/json/yaml). |
marina doctor --fix | Apply the repairs marina can perform itself: host route, iptables exemption, guest IP forwarding. |
marina shell | Open an interactive SSH session in the marina VM (alias ssh). |
marina shell <cmd> [args…] | Run a command in the VM and exit with its exit code. |
marina copy <src>… <dst> | Copy files between the host and the VM over scp (alias cp). |
marina disk resize <size> | Grow the VM disk — applied on the next VM start. |
marina disk resize-image <size> | Grow the persistent image-cache disk (vm.imageDisk) in place, keeping the cached images. VM must be stopped. |
marina prune | Remove marina's reclaimable cached files. |
marina config edit | Open the marina config file in $EDITOR. |
marina version | Print the marina version. |
# Bring everything up — prompts for sudo once to add the host route
$ marina up
# Stop the VM but keep clusters and cache
$ marina down
# Same pair, under the names Lima and colima use
$ marina start
$ marina stop
# Tear it all down: VM, clusters, and the host route (sudo)
$ marina destroy
marina down keeps the host route in place. Use
--remove-route (or marina destroy) to drop it —
either requires sudo. To stop being prompted at all, install the
sudoers rules.
After upgrading marina, re-create the VM. Provisioning
is baked into the binary, so marina down/up on an
existing VM keeps running the old setup. Run
marina destroy && marina up once after each
brew upgrade --cask marina — the host-backed image cache
survives, so it rebuilds fast.
Running commands in the VM
Bare marina 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). |
$ marina shell # interactive session
$ marina shell docker ps -a # flags after the command are passed through
$ marina shell -- bash -c 'kind get clusters' # -- when a flag could look like marina's
$ cat setup.sh | marina shell bash -s # stdin is piped in
$ marina shell -t htop # force a pseudo-terminal
Flag parsing stops at the first positional argument, so
marina shell docker ps -a works as typed — the
-a goes to docker, not to marina. Use
-- only when the first word could be mistaken for a
marina flag. Because the exit code is the remote command's,
if marina 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. |
$ marina copy ./script.sh vm:/tmp/script.sh # host → VM
$ marina copy vm:/tmp/out.json ./out.json # VM → host
$ marina copy -r ./manifests vm:/tmp/ # directories
$ marina 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 marina 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 marina 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:
$ marina disk resize 80GiB # rewrites vm.disk and the Lima instance config
$ marina down && marina up # Lima expands the image; the guest FS grows on boot
$ marina shell df -h / # confirm the new headroom
The image-cache disk (vm.imageDisk, mounted over
/var/lib/containerd) is a separate disk and grows with its
own command. Images live there rather than on the root disk, so this is
usually the one that fills. It must be stopped first — Lima locks the
backing file while an instance holds it:
$ marina down
$ marina disk resize-image 30GiB # keeps the cached images
$ marina up # guest partition and filesystem grow on boot
Raising vm.imageDisk in the config on its own does
nothing to a disk that already exists — the size applies when the disk
is first created. marina up warns when the two disagree and
quotes the command above.
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
marina up creates the disk at the new size.
Reclaiming space
Removes files marina can re-create: superseded Lima guest agents under
~/.marina/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). |
$ marina prune --dry-run # show what would go
$ marina prune # confirm, then remove
$ marina 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
marina 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 marina build removes
that build's agent; harmless, it re-downloads on its next
marina up.
Host setup
Two commands that configure the Mac rather than the VM: one grants
marina up the single privilege it needs, the other starts the
VM at login.
| Command | Description |
|---|---|
marina sudoers | Print a sudoers snippet so marina up can manage the host route without a password. |
marina sudoers --check | Report whether those rules are in effect. |
marina autostart install | Install and load a per-user launchd agent that runs marina up at login. |
marina autostart status | Show whether the agent is installed and loaded. |
marina autostart uninstall | Unload and remove the agent (alias remove). |
Passwordless host route
marina up needs root for exactly one thing: the macOS route
for the kind bridge CIDR.
marina 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:
$ marina sudoers | sudo tee /etc/sudoers.d/marina >/dev/null
$ sudo chmod 0440 /etc/sudoers.d/marina
$ sudo visudo -c -f /etc/sudoers.d/marina # verify the syntax
$ marina 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.marina.autostart, at
~/Library/LaunchAgents/ that runs marina up when
you log in. Output is appended to
~/.marina/logs/autostart.log.
$ marina autostart install # write the plist and load it
$ marina autostart install --print # emit the plist to stdout instead
$ marina autostart status
$ marina 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.
marina sudoers --check confirms you're set.
The plist records the marina binary by the path you invoked — with the
Homebrew cask that's the stable /opt/homebrew/bin/marina
symlink, so the agent keeps working across
brew upgrade --cask marina. 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 |
|---|---|
marina docker-env | Print the export command to point DOCKER_HOST at the marina VM. |
marina docker-env --unset | Print commands to unset the Docker environment. |
marina docker-context | Create/switch to the marina Docker context. |
marina docker-context --unset | Switch back to the default Docker context. |
# Option A — environment variable, current shell only
$ eval $(marina docker-env)
$ eval $(marina docker-env --unset)
# Option B — Docker context, persistent across shells
$ marina docker-context
$ marina 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 marina cluster —
there is no cluster list in the config file. For declarative,
multi-cluster workflows see Fleet management
and the Fleet resource.
| Command | Description |
|---|---|
marina cluster create <name> | Create a new kind cluster in the running VM. |
marina cluster apply -f <file> | Create a fleet of clusters from a Fleet manifest (additive; honours dependsOn; --adopt relabels listed clusters that already exist). |
marina cluster delete [name] | Delete a kind cluster (interactive picker when no name is given). |
marina cluster delete -f <file> | Delete every cluster listed in a Fleet manifest (reverse-dependency order). |
marina cluster delete -l <selector> | Delete clusters whose nodes match a label selector. |
marina cluster list | List kind clusters running in the VM (filter with -l <selector>). |
marina cluster label <name> | Add, overwrite, or remove node labels on an existing cluster. |
marina cluster e2e-test-nginx | Deploy nginx and curl it via LoadBalancer to verify the cluster end-to-end. |
marina 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=marina. |
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.
$ marina cluster create dev
$ marina cluster create dev --region us-east1 --zone us-east1-a
$ marina 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. |
$ marina cluster apply -f fleet.yaml --dry-run # preview the plan
$ marina cluster apply -f fleet.yaml # create what's missing
$ cat fleet.yaml | marina cluster apply -f - # from stdin
$ marina 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.
$ marina cluster list
$ marina cluster list -o json
$ marina cluster list -l env=dev # filter by label selector
$ marina cluster list -l marina.run/fleet=dev-fleet
Pointing kubectl at a cluster now lives under
marina kubeconfig:
# Use one cluster's isolated kubeconfig in this shell
$ eval $(marina kubeconfig env dev)
# Or merge it into ~/.kube/config and switch to it
$ marina 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.
$ marina cluster label dev -l tier=frontend -l disktype=ssd
$ marina 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).
$ marina cluster delete staging
$ marina cluster delete # interactive picker (Space toggles)
$ marina 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.
$ marina cluster e2e-test-nginx
$ marina cluster e2e-test-nginx --cleanup # delete the nginx pod and service
Kubeconfig
Every cluster keeps an isolated kubeconfig. The marina kubeconfig
family (alias marina kc) prints its path, exports it, or merges
it into your default ~/.kube/config.
| Command | Description |
|---|---|
marina kubeconfig path <name> | Print the path to the cluster's kubeconfig file. |
marina kubeconfig env <name> | Print export KUBECONFIG=<path> — eval it to use the cluster's isolated kubeconfig in the current shell. |
marina kubeconfig merge <name> | Merge the cluster's context into ~/.kube/config. |
marina kubeconfig use <name> | Merge and switch the active kubectl context to it. |
marina kubeconfig remove <name> | Remove the cluster's context, cluster, and user from ~/.kube/config (alias rm). |
$ eval $(marina kubeconfig env dev) # use dev's isolated kubeconfig here
$ marina kubeconfig use dev # merge + switch active context
$ marina kubeconfig path dev
$ marina kubeconfig remove dev # clean it out of ~/.kube/config
marina 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 marina fleet command operates on
live clusters grouped by the
marina.run/fleet=<name> node label (membership is derived
from running clusters, not the manifest). See
Fleet management and the
Fleet resource.
| Command | Description |
|---|---|
marina fleet list | Group clusters by marina.run/fleet (-o text/json/yaml). |
marina fleet describe <name> | Show a fleet's members with their num, ports, nodes, and labels (aliases desc, show). |
marina fleet create -f <file> | Create a manifest's clusters — delegates to cluster apply -f (--dry-run, --max-parallel, --adopt). |
marina fleet adopt <name> <cluster>… | Adopt running clusters into a fleet by setting their marina.run/fleet node label. |
marina fleet export [cluster…] | Write a Fleet manifest describing live clusters — by name, by -l selector, or from an interactive picker. |
marina fleet delete <name> | Delete a fleet's clusters, resolved by label (-y to skip the prompt). |
marina fleet delete -f <file> | Delete a manifest's clusters — same as cluster delete -f. |
marina fleet label <name> -l <k=v> | Apply node labels to every cluster in the fleet (-l key- removes). |
$ marina fleet list
$ marina fleet describe dev-fleet
$ marina fleet create -f fleet.yaml --dry-run
$ marina fleet adopt dev-fleet edge-1 edge-2
$ marina fleet create -f fleet.yaml --adopt # relabel listed clusters that already exist
$ marina fleet label dev-fleet -l tier=frontend
$ marina fleet delete dev-fleet -y
DNS
Inspect the local DNS zone
(network.dns, on by default).
| Command | Description |
|---|---|
marina dns list | List every published name and its IP. -o json|yaml for tooling. |
marina dns attach <cluster>… | Install ExternalDNS and the CoreDNS forward on clusters created before network.dns was on. Restarts their CoreDNS. |
$ marina dns list
$ marina dns attach dev staging
CA
Manage marina's local certificate authority
(network.dns.tls, on by default).
| Command | Description |
|---|---|
marina ca status | Root CA path, expiry and keychain trust, plus each cluster's and fleet's wildcard and its expiry. -o json|yaml for tooling. |
marina ca cert | Print the root CA certificate (PEM) — for a pod's or a tool's trust store. |
marina ca attach <cluster>… | Issue or renew the cluster's *.<cluster>.demo.internal wildcard and install it; adds the marina-ca ClusterIssuer when cert-manager is installed. Restarts the nodes' containerd to trust the root. |
marina ca secret <cluster> -n <ns> [--fleet] | Copy default/marina-wildcard-tls — or, with --fleet, the fleet's marina-fleet-wildcard-tls — into another namespace. |
marina ca trust / untrust | Add or remove the root's trust in the macOS System keychain (sudo). |
$ marina ca status
$ marina ca secret dev -n ingress-nginx
$ marina ca cert | kubectl create configmap marina-root-ca -n my-app --from-file=ca.crt=/dev/stdin
Registry
| Command | Description |
|---|---|
marina registry clean-cache | Remove all registry mirror cache data and their containers. |
$ marina registry clean-cache
$ marina up # restart the mirrors afterwards
With the default cacheStorage: "host", mirror blobs live
at ~/.marina/registry-cache/ and survive
marina destroy. clean-cache is how you wipe
them on purpose. See Registry mirrors.
Skill
Install the marina Agent Skill so AI coding tools like Claude Code know how to drive marina.
| Command | Description |
|---|---|
marina skill install | Install the bundled SKILL.md into an AI tool's skills directory (Claude Code by default). |
marina skill path | Print where the skill is installed for Claude Code. |
Flag (on install) | Description |
|---|---|
--claude | Install into ~/.claude/skills/marina/ (default true). |
--print | Write the skill to stdout instead of installing. |
-f, --force | Overwrite an already-installed skill. |
$ marina skill install # → ~/.claude/skills/marina/SKILL.md
$ marina skill install --print # emit to stdout for other tools
$ marina skill path
Completion
Generate a shell auto-completion script for bash,
zsh, fish, or powershell.
# zsh — add to ~/.zshrc to persist
$ source <(marina completion zsh)
# bash
$ source <(marina completion bash)
# fish
$ marina completion fish > ~/.config/fish/completions/marina.fish
See also
- Fleet management — declarative multi-cluster with
marina fleet. - Fleet resource — the manifest schema in full.
- Getting started — the guided tour from install to a routable cluster.
- Configuration — the
~/.marina/config.yamlschema in full.