Skip to content

lmx command ​

lmx is the command inside every LimaNix VM. It shows the state of the guest and what to do about a problem, and it carries out the updates that limanix starts on the Mac. The work that must outlive your terminal, such as a build or a Nix store cleanup, runs in lmxd, a root daemon under systemd. The lmx command shows how to use it day to day.

Usage ​

sh
lmx [COMMAND]

lmx without a command, lmx --help and lmx -h print the guest help page: the VM, your account, the selected modules, and the commands inside the VM and on the Mac. lmx COMMAND --help prints the options of one command.

OptionDescription
-h, --helpPrint the guest help page, or the help of the command it follows.
-V, --versionPrint the version of lmx.

--json, on the commands that take it, answers with the JSON host contract instead of text: one line with contract, ok, and data or error. limanix on the Mac reads these answers.

Colors follow [theme] in limanix.toml. Output that does not go to a terminal, NO_COLOR and TERM=dumb turn them off.

Privileges ​

CommandNeeds
lmx store reserve, lmx apply, lmx apply cancelRoot, with sudo, and a running lmxd.
lmx status --waitA running lmxd.
lmx logsRoot, or membership in the wheel or systemd-journal group, which may read the journal of lmxd.
lmx dotfiles linkThe development account. It refuses any other user, root included.
lmx status, lmx doctor, lmx net checkNothing. With sudo they read more: the generation the Mac mounted, and the processes of other users.
Every other commandNothing.

Exit status ​

StatusMeaning
0Success.
1The command failed, or a check of lmx doctor or lmx net check failed.
2Usage error.
3lmxd is unavailable. Only store reserve, apply, apply cancel and status --wait need it.
127lmx session or limanix-session found no session provider.
130The apply was cancelled.

lmx help ​

Show the workspace and its commands, or what a module gives you.

sh
lmx help [TOPIC]
ArgumentTypeDefaultDescription
TOPICstringnoneModule to explain, such as python, python-3.12 or lmx:python-3.12.

Without a topic, lmx help prints the guest help page, whose lmx help TOPIC line lists the topics. With a topic, it prints the module's help card: what the module installed in this VM, its commands, common tasks and a link to its guide. A topic without a card fails and lists the topics that have one. Your own modules can add a card with the NixOS option limanix.help.<topic>.

lmx info ​

Show the kernel, guest disk, shared folders and failed units.

sh
lmx info

lmx info prints the VM and its architecture, your account, home and selected modules, then the kernel, the guest disk usage, the shared folders with their type and mode, and the failed systemd units. When a part cannot be read, it says so and exits with status 1 after printing the rest.

lmx welcome ​

Show the workspace welcome again.

sh
lmx welcome

The welcome appears once per session when the development account opens an interactive shell in a terminal. It shows the state of the guest with what to do next, the VM, its system and resources, the guest disk, the addresses and open ports, the shared folders and the selected modules.

lmx status ​

Show generations, disk usage, network interfaces and failed units.

sh
lmx status [--json]
lmx status --short
lmx status --wait converged --generation GENERATION [--timeout DURATION] [--json]
OptionTypeDefaultDescription
--shortbooleanfalsePrint only what needs attention, such as restart, for tmux and the prompt. Cannot be combined with --wait or --json.
--waitconvergednoneWait until the guest reaches this state, then answer. converged means the generation is booted, healthy and finalized. Requires --generation.
-g, --generationstringnoneGeneration the wait is for. Requires --wait.
--timeoutduration10mLongest wait, such as 90s, 10m or 1h. A number alone is seconds. Requires --wait.
--jsonbooleanfalseAnswer with the JSON host contract instead of text.
LineShows
GenerationThe generation the Mac mounted (desired), the one built for the next boot (built) and the one running now (booted).
DiskFree space on the disk that holds the Nix store. On a file system with an inode table, free inodes too.
NetworkThe guest's interfaces and addresses.
Failed unitssystemd units that failed.
OwnerThe version of lmxd and what it is doing.
ConditionWhat needs attention and why, when something does.
ProblemWhy a fact could not be read. That fact shows unknown; the other lines still show.

Without sudo, the generation the Mac mounted may show as unknown: that mount is readable only by root.

--short prints one word per thing that needs attention, and nothing while all is well. It never waits more than 200 ms for lmxd and exits with status 0.

WordMeaning
degradedThe running generation failed its health check.
finalizeThe update works, but removing older generations failed.
disk-lowLess than 10% of the store disk is free.
restartA new generation is built and waits for a restart.
applyingAn update is being built now.
applyThe Mac mounted a generation that is not built yet.
lmxd?lmxd did not answer within 200 ms.

--wait asks lmxd every two seconds until the generation is converged, then answers as lmx status does. A failed finalize of that generation ends the wait at once. At the timeout, the command fails. limanix update runs it after it restarts the VM.

lmx doctor ​

Diagnose the configuration, lmxd and the generations, with what to do next.

sh
lmx doctor [--json]
OptionTypeDefaultDescription
--jsonbooleanfalseAnswer with the JSON host contract instead of text.

Each line is one check: its status, its name and a message, with what to do on an indented line below.

CheckChecks
config/etc/lmx/config.json is readable and valid.
ownerlmxd answers, with the same version as lmx.
generationsThe state of the generations, from lmxd or, without it, from the generation markers.
diskShown when lmxd reports that the disk is low.
dotfilesShown when limanix.toml names dotfiles: their entries are linked into the home. A warning names the paths in the way; failed means the directory is not mounted or cannot be read.
StatusMeaning
okFine.
warningWorth knowing; nothing is broken.
failedBroken. The command exits with status 1.
unknownYour account cannot read what the check needs. Run sudo lmx doctor.

lmx doctor works without lmxd. On the Mac, limanix doctor NAME runs the same checks and adds the VM and its address.

lmx net check ​

Check why a port of this VM may be unreachable from the Mac: firewall, listener and process.

sh
lmx net check PORT [--udp] [--json]
Argument or optionTypeDefaultDescription
PORTintegerrequiredPort to check, from 1 to 65535.
--udpbooleanfalseCheck a UDP port instead of a TCP one.
--jsonbooleanfalseAnswer with the JSON host contract instead of text.
CheckChecks
firewallThe guest firewall opens the port for its protocol. TCP port 22 is always open for SSH.
listenerSomething listens on the port, and not only on a loopback address.
processWhich process holds the socket, and which user created it. Only when something listens. Docker's proxy is a warning: network.ports does not control the ports Docker publishes.

The command exits with status 1 when a check failed. Run it with sudo to see the processes of other users. On the Mac, limanix network check NAME PORT runs the same checks, then connects from the Mac.

lmx logs ​

Show the output of the latest lmxd task of a kind, from the journal.

sh
sudo lmx logs KIND [--previous]
Argument or optionTypeDefaultDescription
KINDstringrequiredKind of lmxd task: apply, health, finalize, collect or roots.
--previousbooleanfalseRead the boot before the running one, such as the one that built the running generation.
KindTasks
applyBuilds of a mounted generation.
healthHealth checks of the booted generation.
finalizeRemovals of older generations after a healthy boot.
collectCollections of unreferenced store paths.
rootsReports of the garbage-collector roots.

lmx logs prints the task, its generation and its start time in UTC, then its lines. It fails when no task of that kind ran in the boot. An update builds in one boot and restarts into the next: its build output is in sudo lmx logs apply --previous.

lmx version ​

Show the lmx version and the host contract it speaks.

sh
lmx version [--json]
OptionTypeDefaultDescription
--jsonbooleanfalseAnswer with the JSON host contract instead of text.

It prints lmx VERSION (host contract N).

lmx store reserve ​

Collect unreferenced Nix store paths when free space is low. The work runs in lmxd.

sh
sudo lmx store reserve [--json]
OptionTypeDefaultDescription
--jsonbooleanfalseAnswer with the JSON host contract instead of text.

When less than 20% of the store disk is free, lmxd collects the store paths that nothing uses, and the command waits for the collection. It then prints how much it freed, or Nothing was collected., and the free space of the guest disk. A collection that already runs is shared, and interrupting the command does not stop it. The command fails when less than 10% is still free afterwards. limanix update runs it before it stops the VM.

lmx apply ​

Build the generation the Mac mounted for the next boot. The work runs in lmxd.

sh
sudo lmx apply --generation GENERATION [--follow] [--json]
OptionTypeDefaultDescription
-g, --generationstringrequiredGeneration to apply. It must be the one the Mac mounted at /mnt/limanix.
--followbooleanfalseFollow the apply until it ends, with the build's output.
--jsonbooleanfalseAnswer with the JSON host contract instead of text. With --follow, one JSON line per event, and the answer last.

limanix update runs it for you. lmxd installs the environment files of the generation into /etc/limanix, makes room in the store as lmx store reserve does, and builds the generation with nixos-rebuild boot. Interrupting the command does not stop the apply, and running it again attaches to the running apply. An apply of another generation is cancelled and replaced. After a successful apply, the generation waits for a restart. A cancelled apply exits with status 130.

lmx apply cancel ​

Cancel the apply of a generation and wait until it stops.

sh
sudo lmx apply cancel --generation GENERATION [--json]
OptionTypeDefaultDescription
-g, --generationstringrequiredGeneration whose apply to cancel.
--jsonbooleanfalseAnswer with the JSON host contract instead of text.

limanix update runs it when you press Ctrl-C. The build is killed; a boot loader update that nixos-rebuild already started finishes in its own unit.

lmx clipboard copy ​

Copy standard input to the Mac clipboard. Also installed as pbcopy.

sh
lmx clipboard copy < FILE

The input travels through your terminal as an OSC 52 sequence, or through tmux inside a tmux session. The terminal on the Mac must allow it.

Guide: Clipboard.

lmx clipboard paste ​

Print the Mac clipboard, if the terminal allows reads. Also installed as pbpaste.

sh
lmx clipboard paste

paste asks the terminal for the clipboard and waits up to 10 seconds for the answer. Reading the clipboard usually needs one more permission in the terminal than writing it. When the terminal does not share the clipboard, the command says so on standard error and exits with status 1.

Guide: Clipboard.

lmx session ​

Open a named session with the selected provider. Also installed as limanix-session.

sh
lmx session NAME
ArgumentTypeDefaultDescription
NAMEstringrequiredSession name, passed to the provider unchanged. Put -- before a name that starts with -.

The command creates the session or attaches to it with the provider the VM's configuration selects, such as tmux; the provider then owns the terminal and the exit status. Without a provider, it says which setting of limanix.toml adds one and exits with status 127. limanix shell NAME --session SESSION on the Mac runs limanix-session SESSION.

Guide: Shell and sessions.

lmx dotfiles ​

Show which of your dotfiles from the Mac are linked into your home, without changing anything.

sh
lmx dotfiles [status]

lmx dotfiles and lmx dotfiles status print the dotfiles directory and the home, then one line per entry: linked, missing, or conflict for a path of your own that is in the way. Without dotfiles in limanix.toml, it says that none are configured.

Guide: Dotfiles.

Link the dotfiles into your home. Every shell of the development account does it as it starts.

sh
lmx dotfiles link [--quiet]
OptionTypeDefaultDescription
--quietbooleanfalsePrint nothing but errors, as a starting shell runs it.
  • It links each top-level entry of the dotfiles that starts with . into the home, and each entry of their .config into ~/.config, and prints each change. .git, .github, .gitignore, .gitmodules and .DS_Store are never linked.
  • It changes only links that point into the dotfiles. A file, a directory or a link to anywhere else stays and is a conflict; a conflict does not fail the command.
  • A link to an entry that is gone from the dotfiles is removed.
  • While the dotfiles directory is not mounted, it links and removes nothing.
  • It runs only as the development account: with sudo, the links in the home would belong to root.

Guide: Dotfiles.

Other names ​

The lmx binary is also installed under these names. Each keeps the arguments, messages and exit statuses of the command it replaces.

NameRunsArguments
pbcopylmx clipboard copyNone; input comes from standard input, as in pbcopy < FILE.
pbpastelmx clipboard pasteNone.
limanix-session NAMElmx session NAMEExactly one nonempty name.

Free and open source under the Apache License 2.0.