diff --git a/README.md b/README.md
index 68de15a..c2a95fa 100644
--- a/README.md
+++ b/README.md
@@ -6,11 +6,7 @@
An atomic Linux host keeps its base system read-only and replaceable. You still need somewhere to `apt install` a project's dependencies, try a toolchain packaged for another distro, or run a service. nsl gives you persistent Linux machines for that work, as WSL does on Windows. Each machine is a whole distro with its own packages and services. It opens in the directory you were in, works on your files, and stops when you stop using it.
-```sh
-nsl create debian --distro debian:13 # verify and cache the signed images; the first machine is the default
-nsl # a login shell in the machine, in this directory
-nsl run make test # one command, with its exit status
-```
+[Create your first machine](https://frostyard.github.io/nsl/getting-started/first-machine/) walks through creation, a login shell, running a command and stopping the VM.
**Documentation: [frostyard.github.io/nsl](https://frostyard.github.io/nsl/)**
@@ -38,7 +34,7 @@ It is **pre-release**. v0.4.0 was the first release of the current design; v0.3.
## Start
-1. [Install nsl](https://frostyard.github.io/nsl/getting-started/install/) with Homebrew (`brew tap frostyard/tap`, then `brew install --cask frostyard/tap/nsl`) or from the [latest release](https://github.com/frostyard/nsl/releases/latest).
+1. [Install nsl](https://frostyard.github.io/nsl/getting-started/install/) with Homebrew or a release tarball.
2. [Create your first machine](https://frostyard.github.io/nsl/getting-started/first-machine/).
3. Look up [commands](https://frostyard.github.io/nsl/reference/cli/) and [configuration](https://frostyard.github.io/nsl/reference/configuration/) as you need them.
diff --git a/machines.go b/machines.go
index 7455de8..161b9da 100644
--- a/machines.go
+++ b/machines.go
@@ -176,7 +176,7 @@ func (a *app) idleTimeout() (*int, error) {
// create prepares a machine from a verified catalogue selection or a local
// machine image.
func (a *app) create(args []string) error {
- usage := errors.New("usage: create NAME --distro DISTRO:RELEASE [--offline] [--default] [--user NAME] | create NAME --image FILE --digest sha256:HEX [--default] [--user NAME]")
+ usage := errors.New("usage: create NAME --distro DISTRO:RELEASE [--offline] [--isolated] [--default] [--user NAME] | create NAME --image FILE --digest sha256:HEX [--isolated] [--default] [--user NAME]")
if len(args) == 0 || strings.HasPrefix(args[0], "-") {
return usage
}
diff --git a/main.go b/main.go
index 8525c27..2538edb 100644
--- a/main.go
+++ b/main.go
@@ -111,15 +111,15 @@ func usage(w io.Writer) {
[-m NAME] login shell in NAME or the default machine
run [-m NAME] [--root] [--cd PATH] COMMAND [ARGS...]
- create NAME --distro DISTRO:RELEASE [--offline] [--default] [--user NAME]
- create NAME --image FILE --digest sha256:HEX [--default] [--user NAME]
+ create NAME --distro DISTRO:RELEASE [--offline] [--isolated] [--default] [--user NAME]
+ create NAME --image FILE --digest sha256:HEX [--isolated] [--default] [--user NAME]
list [--json]
default NAME
start NAME
stop NAME
remove NAME [--yes]
export NAME FILE
- import NAME FILE
+ import NAME FILE [--isolated]
ports [NAME]
ssh-config NAME
logs [NAME]
diff --git a/site/content/concepts/how-it-works.md b/site/content/concepts/how-it-works.md
index 2aca132..36ccd6c 100644
--- a/site/content/concepts/how-it-works.md
+++ b/site/content/concepts/how-it-works.md
@@ -22,6 +22,12 @@ flowchart LR
Waypipe --> Desktop[Host Wayland desktop]
```
+## Terms
+
+- **Shared VM:** the single virtual machine that runs all ordinary machines. Isolated machines each have their own VM.
+- **Machine image:** a distro root filesystem used to create a machine with its own packages, services and guest home. Updating that image does not change existing machines.
+- **Default machine:** the machine that bare `nsl` and `nsl run` enter when you omit `-m NAME`. The first machine you create or import becomes the default; `nsl default NAME` changes it.
+
## The VM
The shared VM boots the signed nsl VM image with systemd-vmspawn and QEMU/KVM, under a user unit named `nsl-UID-vm-ID.service`. It has two disks:
@@ -43,7 +49,7 @@ Once the images are cached, creation needs no network. The VM imports the image
The CLI reaches the VM over SSH on vsock, where the VM's sshd accepts only nsl's key and only runs the nsl agent. Before doing anything, the CLI checks the VM's identity: its ID, your UID and GID, its role, and the image's protocol and architecture. It checks this even when the VM was already running.
-The agent runs each command as a transient systemd unit in the machine, with a PAM login session. It passes arguments literally, keeps streams separate or uses a terminal, and returns the exit status, with 128+N for a command killed by signal N.
+The agent runs each command as a transient systemd unit in the machine, with a PAM login session for the machine account. Commands run with `--root` have no PAM session. It passes arguments literally, keeps streams separate or uses a terminal, and returns the exit status, with 128+N for a command killed by signal N.
## Host integration
diff --git a/site/content/concepts/trust.md b/site/content/concepts/trust.md
index da8d013..d5b30ad 100644
--- a/site/content/concepts/trust.md
+++ b/site/content/concepts/trust.md
@@ -20,7 +20,7 @@ The VM separates the machine's kernel, packages, services and root from your hos
- Become root on the host. `--root` and `sudo` mean root in the machine. Files it creates through `/mnt/host` belong to you, and it cannot exceed your permissions.
- See host `/usr`, `/etc`, `/tmp`, the rest of `/run`, devices or pseudo-filesystems.
- Reach host sockets: D-Bus, the SSH agent, the GPU and the display are not shared, and Unix sockets do not connect across `/mnt/host`.
-- Run arbitrary commands on the host. The only host action is opening a link or a shared file.
+- Run arbitrary commands through the host-action broker, which only opens links and shared files. A machine can still write shell startup files or other code in your shared home that later runs as you on the host.
- Change host sudoers, device permissions or packages. nsl itself never changes them either.
## Machines share a VM
diff --git a/site/content/contributing/build.md b/site/content/contributing/build.md
index d78ab9e..8e3e934 100644
--- a/site/content/contributing/build.md
+++ b/site/content/contributing/build.md
@@ -51,16 +51,18 @@ source build/poc/env.sh
# The VM image.
scripts/build-image.sh --role vm
-image=build/image/share/nsl-vm-trixie-x86-64-r9.raw
+image=build/image/share/nsl-vm-trixie-x86-64-r10.raw
build/nsl update --image "$image" --digest "sha256:$(sha256sum "$image" | cut -d' ' -f1)"
build/nsl recover
# A machine image, and a machine from it.
scripts/build-image.sh --role machine --distribution debian
-machine=build/image/share/nsl-machine-debian-trixie-x86-64-r4.tar.zst
+machine=build/image/share/nsl-machine-debian-trixie-x86-64-r5.tar.zst
build/nsl create debian --image "$machine" --digest "sha256:$(sha256sum "$machine" | cut -d' ' -f1)"
```
+Each build prints a `Built PATH` line. Use that path for `image` or `machine` if the profile revision differs from these examples.
+
`--distribution` also takes `ubuntu`, `fedora`, `centos`, `arch` and `opensuse`; `--distribution opensuse --release 16.0` builds Leap. The [image build notes ↗](https://github.com/frostyard/nsl/blob/main/image/README.md) describe the layers and the builder.
## Accept images in disposable VMs
diff --git a/site/content/getting-started/first-machine.md b/site/content/getting-started/first-machine.md
index de0e600..0ee8fc4 100644
--- a/site/content/getting-started/first-machine.md
+++ b/site/content/getting-started/first-machine.md
@@ -4,37 +4,53 @@ description: Create a machine from a signed image, enter it, run commands and st
# Your first machine
-Let's create a Debian 13 machine, run a few commands and stop it. The first creation downloads the VM image and the Debian machine image. Once both are cached, creating another machine from them needs no network.
+Let's create a Debian 13 machine, run a few commands and stop it. The first creation downloads the VM image and the Debian [machine image](../concepts/how-it-works.md#terms). Allow several minutes for the first download and setup; the time depends on your connection and host. Download progress is printed in bytes, followed by verification messages. Once both are cached, creating another machine from them needs no network.
1. **Create the machine.**
```sh
- nsl create [name] [flags]
nsl create debian --distro debian:13
```
- nsl downloads the signed image catalogue, checks that both images came from the Frostyard publishing workflow, and caches them. Then it starts the shared VM and creates your Debian machine. Since this is your first machine, it becomes the default.
+ nsl downloads the signed image catalogue, checks that both images came from the Frostyard publishing workflow, and caches them. Then it starts the [shared VM](../concepts/how-it-works.md#terms) and creates your Debian machine. Since this is your first machine, it becomes the [default](../concepts/how-it-works.md#terms). The name and an image selection are required; the [command reference](../reference/cli.md#machines) also covers local images.
+
+ Success ends with a line like this (`BUILD_ID` varies with the published image):
+
+ ```text
+ Created debian from BUILD_ID
+ ```
+
+ If startup stalls or fails, check [`nsl logs`](../guides/storage.md#logs). For a VM that cannot become ready, [`nsl recover`](../guides/storage.md#recover-a-vm) restarts it from a fresh root. See [troubleshooting](../reference/limits.md#troubleshooting).
2. **Open a shell.**
```sh
+ mkdir -p ~/src/project
cd ~/src/project
- nsl # a login shell at /mnt/host/home/src/project
+ nsl
+ ```
+
+ You're now in a login shell in the default machine, working in the same files. Their path starts with `/mnt/host`, followed by the canonical host path. Your username, UID and GID match the host's, and `sudo` needs no password. This works for directories under your home, `/run/media/USER` and `/mnt`. From anywhere else, nsl opens the shell in your guest home and tells you.
+
+ For example, with host username `you` and home `/var/home/you`, a session looks like this (your prompt may differ):
+
+ ```console
+ you@debian:/mnt/host/var/home/you/src/project$ pwd
+ /mnt/host/var/home/you/src/project
+ you@debian:/mnt/host/var/home/you/src/project$ exit
```
- You're now in a login shell in the default machine, working in the same files. Their path starts with `/mnt/host`, followed by the host path. Your username, UID and GID match the host's, and `sudo` needs no password. This works for directories under your home, `/run/media/USER` and `/mnt`. From anywhere else, nsl opens the shell in your guest home and tells you.
+ Type `exit` or press Ctrl-D to return to your host shell. Leaving the shell does not stop the machine immediately; it stays available until you stop it or the idle timeout expires. Run the remaining steps on the host.
-3. **Run one command.**
+3. **Run one command from the host.**
```sh
- nsl run sudo apt-get update
- nsl run sudo apt-get install -y podman
- nsl run podman run --rm docker.io/library/alpine echo hello
+ nsl run cat /etc/os-release
```
- These commands install Podman in the machine and use it to run an Alpine container. `run` passes arguments literally, keeps stdout and stderr separate, and returns the command's exit status.
+ The output identifies Debian 13. `run` passes arguments literally, keeps stdout and stderr separate, and returns the command's exit status. For installing packages and running Podman, see [software in a machine](../guides/machines.md#software-in-a-machine).
4. **Look around.**
diff --git a/site/content/getting-started/install.md b/site/content/getting-started/install.md
index b84d6a3..1709a69 100644
--- a/site/content/getting-started/install.md
+++ b/site/content/getting-started/install.md
@@ -4,7 +4,7 @@ description: Host requirements, installing with Homebrew, downloading and verify
# Install nsl
-nsl is a single binary that runs as your user. You'll need an x86-64 Linux host with KVM to run the x86-64 VM and machine images. The tested setup is Snow Linux 13 with systemd 261.2, QEMU 10.0.13, virtiofsd 1.13.2 and GNOME Wayland.
+nsl is a single binary that runs as your user. You'll need an x86-64 Linux host with KVM to run the x86-64 VM and [machine images](../concepts/how-it-works.md#terms). Releases also include a `linux_arm64` CLI binary, but it cannot run machines: `create` rejects non-x86-64 hosts. The tested setup is Snow Linux 13 with systemd 261.2, QEMU 10.0.13, virtiofsd 1.13.2 and GNOME Wayland.
## Host requirements
@@ -16,7 +16,7 @@ nsl is a single binary that runs as your user. You'll need an x86-64 Linux host
| virtiofsd at `/usr/libexec/virtiofsd` | Sharing your files and the image cache with the VM |
| OpenSSH (`ssh`, `ssh-keygen`) and `/usr/lib/systemd/systemd-ssh-proxy` | Reaching the VM's agent over vsock |
| `sg` or util-linux `newgrp` (on Debian 14, both from `util-linux-extra`), and util-linux `unshare` | Opening the KVM devices through your `kvm` membership |
-| `getent` and `id` | Checking `kvm` membership in the host account database |
+| `getent` and `id` | Checking `kvm` membership in the host account database |
| Membership in `kvm`, with access to `/dev/kvm` and `/dev/vhost-vsock` | Hardware virtualization and vsock |
| Unprivileged user namespaces | Launching the VM without root |
| Waypipe (optional) | Wayland windows from machines |
@@ -37,7 +37,6 @@ nsl doctor
The cask installs only the CLI; the host requirements above still apply.
VM and machine images are downloaded and verified when you create a machine.
-Uninstalling the cask leaves your machines and nsl state intact.
To update the CLI:
@@ -48,7 +47,7 @@ brew upgrade --cask frostyard/tap/nsl
## Download a release
-Each release has a tarball for `linux_amd64`, a `checksums.txt`, and GitHub build provenance for both. The files have the same names in every release, so these steps always fetch the newest one.
+Each release has tarballs for `linux_amd64` and `linux_arm64`, a `checksums.txt`, and GitHub build provenance. The files have the same names in every release, so these steps always fetch the newest one. Use `linux_amd64` on the supported x86-64 hosts, as below.
@@ -72,6 +71,7 @@ Each release has a tarball for `linux_amd64`, a `checksums.txt`, and GitHub buil
```sh
tar -xzf nsl_linux_amd64.tar.gz nsl
+ mkdir -p ~/.local/bin
install -m 0755 nsl ~/.local/bin/nsl
nsl version
```
@@ -94,6 +94,14 @@ make build # writes build/nsl
nsl doctor
```
+A passing check looks like this (one line of the full output):
+
+```text
+OK kvm group membership
+```
+
+For a `MISSING` result, follow [troubleshooting](../reference/limits.md#troubleshooting).
+
`doctor` prints `OK` or `MISSING` for each tool and for the UEFI firmware systemd-vmspawn would use. It checks device access in your current session, looks up your `kvm` membership in the host account database, then tries KVM and vsock access through that group. It also checks user namespaces and the user systemd manager. A missing VM prerequisite makes it exit with an error.
Having firmware installed isn't enough on its own. systemd-vmspawn needs a QEMU firmware descriptor in `/usr/share/qemu/firmware` or `/etc/qemu/firmware`; without one, `doctor` reports the firmware as missing. Waypipe is optional, but you'll need it to display machine windows on the host.
@@ -101,3 +109,9 @@ Having firmware installed isn't enough on its own. systemd-vmspawn needs a QEMU
If you aren't a member of `kvm`, doctor and VM launch report the missing membership with a command such as `sudo usermod -aG kvm 'YOUR_USERNAME'` for an administrator to run. They skip the group switch so it cannot ask for a group password. Once membership is added, retry nsl; no new login is needed. Device permissions must still allow the `kvm` group access.
Next, [create your first machine](first-machine.md).
+
+## Uninstall
+
+Run `nsl shutdown` before removing the CLI. For Homebrew, run `brew uninstall --cask frostyard/tap/nsl`. For the tarball installation above, remove `~/.local/bin/nsl`; if you installed it elsewhere, remove that binary instead. You can also delete the downloaded tarball, checksums and unpacked copy.
+
+Both methods leave your machines and state in `NSL_HOME`, along with your separate `nsl.conf` settings. See [where state lives](../guides/storage.md#where-state-lives). To delete machines too, [remove them](../guides/machines.md#remove-a-machine) with nsl before uninstalling.
diff --git a/site/content/guides/host-files.md b/site/content/guides/host-files.md
index 9cc27e3..a4ebab2 100644
--- a/site/content/guides/host-files.md
+++ b/site/content/guides/host-files.md
@@ -12,7 +12,7 @@ In an ordinary machine, you can read and write files from three places on the ho
| `/run/media/you` | `/mnt/host/run/media/you` |
| `/mnt` | `/mnt/host/mnt` |
-Every ordinary machine sees all three trees. Creating a machine for a project doesn't limit it to that project's directory. Host `/usr`, `/etc`, `/tmp`, the rest of `/run` and pseudo-filesystems are not shared.
+Every ordinary machine sees the trees that exist as directories when the shared VM launches. For example, if `/run/media/USER` is created after launch, restart the VM with `nsl shutdown` and then `nsl` to share it. Creating a machine for a project doesn't limit it to that project's directory. Host `/usr`, `/etc`, `/tmp`, the rest of `/run` and pseudo-filesystems are not shared.
## Paths and aliases
diff --git a/site/content/guides/images.md b/site/content/guides/images.md
index 012ea41..97de99f 100644
--- a/site/content/guides/images.md
+++ b/site/content/guides/images.md
@@ -64,11 +64,6 @@ No flag or environment variable turns these checks off. Images are rebuilt at le
## Local images
-Image developers can select files they built:
+Image developers can select local files with `nsl create NAME --image FILE --digest sha256:HEX` or `nsl update --image FILE --digest sha256:HEX`. The [build walkthrough](../contributing/build.md#the-images) shows how to build both images, select the output paths and calculate their digests.
-```sh
-nsl create test --image nsl-machine-debian-trixie-x86-64-r4.tar.zst --digest sha256:HEX
-nsl update --image nsl-vm-trixie-x86-64-r9.raw --digest sha256:HEX
-```
-
-The digest checks that the file matches the bytes you selected. It can't tell you who built the image. See [build from source](../contributing/build.md).
+The digest checks that the file matches the bytes you selected. It can't tell you who built the image.
diff --git a/site/content/guides/storage.md b/site/content/guides/storage.md
index 52d7827..3aa8a79 100644
--- a/site/content/guides/storage.md
+++ b/site/content/guides/storage.md
@@ -49,8 +49,14 @@ Keep backups of machines you need. `recover` can't rebuild deleted keys or repai
## Logs
```sh
-nsl logs # the VM, its port forwarder and every desktop session
-nsl logs dev # those of one machine
+nsl logs # every VM, its port forwarder and desktop sessions
+nsl logs dev # the desktop session of ordinary machine dev
+```
+
+For an isolated machine, `nsl logs NAME` also includes its own VM and forwarder. With a name, `logs` prints a hint for reading the machine's own journal:
+
+```sh
+nsl run -m dev --root journalctl -n 100
```
A VM that fails to become ready keeps its disks, and the error points to `logs` and `recover`.
diff --git a/site/content/index.md b/site/content/index.md
index 74042b5..f767014 100644
--- a/site/content/index.md
+++ b/site/content/index.md
@@ -18,14 +18,10 @@ hide:
[How it works](concepts/how-it-works.md){ .md-button }
-

+
-```sh
-nsl create debian --distro debian:13 # verify the signed images; the first machine is the default
-nsl # a login shell in the machine, in this directory
-nsl run make test # one command, with its exit status
-```
+[Create your first machine](getting-started/first-machine.md) walks through creation, a login shell, running a command and stopping the VM.
## What a machine gives you
@@ -81,10 +77,18 @@ nsl run make test # one command, with its exit status
How the VM runs your machines and connects them to the host.
-- 03 **[Command reference](reference/cli.md)**
+- 03 **[Guides](guides/machines.md)**
+
+ Work with machines, host files, ports, desktop applications and backups.
+
+- 04 **[Command reference](reference/cli.md)**
Look up commands, settings in `nsl.conf` and published images.
+- 05 **[Limits and troubleshooting](reference/limits.md)**
+
+ Check known limits and find help when a command fails.
+
!!! note "Pre-release"
diff --git a/site/content/reference/cli.md b/site/content/reference/cli.md
index 8c670d9..4db4ecc 100644
--- a/site/content/reference/cli.md
+++ b/site/content/reference/cli.md
@@ -10,40 +10,40 @@ Run `nsl help` for a quick command summary. For commands that take a machine nam
| Command | Behavior |
| --- | --- |
-| `nsl [-m NAME]` | Login shell in NAME or the default machine, in the translated host directory or the guest home. |
-| `nsl run [-m NAME] [--root] [--cd PATH] COMMAND [ARGS...]` | Run a command in the machine. Arguments pass literally; a terminal is used when stdin and stdout are terminals. Flags precede COMMAND; `--` ends them. |
-| `nsl create NAME --distro DISTRO:RELEASE [--offline] [--isolated] [--default] [--user NAME]` | Create a machine from a verified catalogue image. Selects the catalogue's VM image first when none is selected. |
-| `nsl create NAME --image FILE --digest sha256:HEX [--isolated] [--default] [--user NAME]` | Create a machine from a local machine image, offline. |
-| `nsl list [--json]` | Every nsl VM with its state, image, resources and data disk, anything pending until its next start, and every machine with its state, image, trust tier and default marker. |
-| `nsl default NAME` | Make NAME the default machine. |
-| `nsl start NAME` | Start a machine, and its VM if needed, and wait for readiness. |
-| `nsl stop NAME` | Stop one machine and keep all its state. |
-| `nsl shutdown` | Stop every machine and every nsl VM, isolated ones included. |
-| `nsl remove NAME [--yes]` | Preview, then permanently remove a stopped machine. |
+| [`nsl [-m NAME]`](../guides/machines.md#enter-a-machine) | Login shell in NAME or the default machine, in the translated host directory or the guest home. |
+| [`nsl run [-m NAME] [--root] [--cd PATH] COMMAND [ARGS...]`](../guides/machines.md#enter-a-machine) | Run a command in the machine. Arguments pass literally; a terminal is used when stdin and stdout are terminals. Flags precede COMMAND; `--` ends them. |
+| [`nsl create NAME --distro DISTRO:RELEASE [--offline] [--isolated] [--default] [--user NAME]`](../guides/machines.md#create-a-machine) | Create a machine from a verified catalogue image. Selects the catalogue's VM image first when none is selected. |
+| [`nsl create NAME --image FILE --digest sha256:HEX [--isolated] [--default] [--user NAME]`](../guides/images.md#local-images) | Create a machine from a local machine image, offline. |
+| [`nsl list [--json]`](../guides/storage.md#the-data-disk) | Every nsl VM with its state, image, resources and data disk, anything pending until its next start, and every machine with its state, image, trust tier and default marker. |
+| [`nsl default NAME`](../guides/machines.md#the-default-machine) | Make NAME the default machine. |
+| [`nsl start NAME`](../guides/machines.md#start-stop-and-idle) | Start a machine, and its VM if needed, and wait for readiness. |
+| [`nsl stop NAME`](../guides/machines.md#start-stop-and-idle) | Stop one machine and keep all its state. |
+| [`nsl shutdown`](../guides/machines.md#start-stop-and-idle) | Stop every machine and every nsl VM, isolated ones included. |
+| [`nsl remove NAME [--yes]`](../guides/machines.md#remove-a-machine) | Preview, then permanently remove a stopped machine. |
## Archives
| Command | Behavior |
| --- | --- |
-| `nsl export NAME FILE` | Write an archive of a stopped machine. Never overwrites. |
-| `nsl import NAME FILE [--isolated]` | Verify an archive and create a machine from it under an unused name. |
+| [`nsl export NAME FILE`](../guides/export-import.md) | Write an archive of a stopped machine. Never overwrites. |
+| [`nsl import NAME FILE [--isolated]`](../guides/export-import.md) | Verify an archive and create a machine from it under an unused name. |
## Host integration
| Command | Behavior |
| --- | --- |
-| `nsl ports [NAME]` | Forwarded ports and conflicts, for one machine or all. |
-| `nsl ssh-config NAME` | Start the machine if needed and print an SSH host alias, `nsl-NAME`, for remote editors. |
-| `nsl logs [NAME]` | Recent logs of the host units nsl runs: each VM, its forwarder and desktop sessions, or those of one machine. |
+| [`nsl ports [NAME]`](../guides/ports.md) | Forwarded ports and conflicts, for one machine or all. |
+| [`nsl ssh-config NAME`](../guides/editors.md) | Start the machine if needed and print an SSH host alias, `nsl-NAME`, for remote editors. |
+| [`nsl logs [NAME]`](../guides/storage.md#logs) | Without NAME: every VM, its forwarder and desktop sessions. With NAME: that machine's desktop session; isolated machines also include their own VM and forwarder. Prints a hint for the machine's own journal. |
## Images
| Command | Behavior |
| --- | --- |
-| `nsl images [--offline \| --refresh] [--json]` | Authenticated machine-image selections and the VM image in effect. The default reuses a catalogue checked less than one hour ago; `--refresh` checks immediately. |
-| `nsl pull DISTRO:RELEASE [--offline]` | Verify and cache a machine image without creating a machine. |
-| `nsl update [--offline]` | Select the catalogue's current VM image for the next start of each nsl VM. |
-| `nsl update --image FILE --digest sha256:HEX` | Select a local VM image instead. |
+| [`nsl images [--offline \| --refresh] [--json]`](../guides/images.md#browse-and-cache) | Authenticated machine-image selections and the VM image in effect. The default reuses a catalogue checked less than one hour ago; `--refresh` checks immediately. |
+| [`nsl pull DISTRO:RELEASE [--offline]`](../guides/images.md#browse-and-cache) | Verify and cache a machine image without creating a machine. |
+| [`nsl update [--offline]`](../guides/images.md#update-the-vm) | Select the catalogue's current VM image for the next start of each nsl VM. |
+| [`nsl update --image FILE --digest sha256:HEX`](../guides/images.md#local-images) | Select a local VM image instead. |
Add `@sha256:HEX` to a selector to pin an image's OCI manifest. That digest must still be in the current catalogue.
@@ -51,12 +51,12 @@ Add `@sha256:HEX` to a selector to pin an image's OCI manifest. That digest must
| Command | Behavior |
| --- | --- |
-| `nsl config [--json]` | The effective configuration, each value's source, and any change waiting for a VM restart. |
-| `nsl recover [NAME]` | Restart the shared VM, or isolated machine NAME's VM, from a fresh root; check its data disk and resume interrupted work. |
-| `nsl resize [NAME] --disk GiB` | Grow the stopped shared VM's data disk, or isolated machine NAME's, up to 4096 GiB. Never shrinks. |
-| `nsl doctor` | Check the host's prerequisites. |
-| `nsl version` | The build version. |
-| `nsl help` | Usage. |
+| [`nsl config [--json]`](configuration.md) | The effective configuration, each value's source, and any change waiting for a VM restart. |
+| [`nsl recover [NAME]`](../guides/storage.md#recover-a-vm) | Restart the shared VM, or isolated machine NAME's VM, from a fresh root; check its data disk and resume interrupted work. |
+| [`nsl resize [NAME] --disk GiB`](../guides/storage.md#grow-the-data-disk) | Grow the stopped shared VM's data disk, or isolated machine NAME's, up to 4096 GiB. Never shrinks. |
+| [`nsl doctor`](../getting-started/install.md#check-the-host) | Check the host's prerequisites. |
+| [`nsl version`](limits.md#report-a-problem) | The build version. |
+| [`nsl help`](../guides/machines.md) | Usage. |
## Output for scripts
@@ -79,8 +79,8 @@ These commands are installed inside every machine image:
| Command | Behavior |
| --- | --- |
-| `nsl-open TARGET` | Open an `http`/`https` URL or a path under `/mnt/host` with the host's default handler. Also `BROWSER` and the handler for web links. |
-| `nsl-path [--host \| --guest] PATH` | Translate between host and guest paths using the `/mnt/host` prefix. |
+| [`nsl-open TARGET`](../guides/desktop.md) | Open an `http`/`https` URL or a path under `/mnt/host` with the host's default handler. Also `BROWSER` and the handler for web links. |
+| [`nsl-path [--host \| --guest] PATH`](../guides/host-files.md#paths-and-aliases) | Translate between host and guest paths using the `/mnt/host` prefix. |
## Exit status
diff --git a/site/content/reference/machine-images.md b/site/content/reference/machine-images.md
index 365ee27..996b032 100644
--- a/site/content/reference/machine-images.md
+++ b/site/content/reference/machine-images.md
@@ -21,7 +21,7 @@ All images are x86-64. A new distro or release has to pass the same acceptance t
## What every image provides
- **Your account**, added at creation: your username, UID and GID, a home at `/home/USER`, `/bin/bash` and passwordless `sudo`. Root has no usable password.
-- **A login session** for every nsl command: a PAM login with a logind session, `XDG_RUNTIME_DIR`, a user systemd manager and a user D-Bus session.
+- **A login session** for shells and commands run as your machine account: a PAM login with a logind session, `XDG_RUNTIME_DIR`, a user systemd manager and a user D-Bus session. `nsl run --root` does not create a PAM/logind session or provide `XDG_RUNTIME_DIR` or a user manager.
- **Networking from the VM.** The machine's own networkd and resolved are masked; it uses the VM's network and resolver.
- **Nested containers.** A full procfs for nesting and a Podman drop-in, so rootless Podman works.
- **Desktop support.** Time-zone data, a font, a cursor theme and the Wayland client libraries.