latchd
Want a TUI-based login manager because you are tired of GDM or Plasma Login? Latchd gives you a small keyboard-first login screen on a Linux virtual terminal, then starts a TTY shell, an X11 desktop, or a Wayland desktop for the account you choose.
Latchd is written in Rust and runs as a systemd service. It finds login accounts through NSS, reads desktop entries from the configured directories, The old Go prototype is still in legacy/go/, but it is not part of the build.
This screen comes from the Docker preview capture; the UI guide has the keyboard map and the help screen.
What latchd does
- account discovery — reads normal login accounts through NSS; filters low UIDs, excluded names, no-login shells, and unsafe home directories
- account status — reads shadow aging fields and the configured faillock helper; shows expiry, lock, inactivity, and failure counts in the screen
- session discovery — reads X11 and Wayland
.desktopfiles plus administrator scripts; keeps the program and its arguments separate instead of passing them to a shell - login handoff — builds the user environment, opens the configured login session, starts the selected program with the account UID and groups, and closes the session when it exits
- X11 startup — creates a private Xauthority file, waits for the X server readiness signal, and removes the file after the desktop exits
- Wayland startup — starts the selected desktop with the session values it needs; it does not start a compositor
- TTY startup — attaches the selected shell to the virtual terminal and records the user process when UTMPX is available
- user interface — provides account switching, last-session preferences, filtering, refresh, notifications, wallpapers, reduced motion, and confirmed power actions
Preview mode draws the same screen and reads the same TOML structure, but it does not authenticate or start a user program, which makes it useful for layout work and config checks.
Quick start
Install the build requirements on Debian or Ubuntu:
sudo apt-get install build-essential pkg-config libpam0g-dev libpam-modules
Build the release binary and run the checks:
make check
make build
The binary is build/latchd. Open the preview screen with:
./build/latchd --preview --no-log
The repository pins Rust 1.88 in rust-toolchain.toml.
Configuration
The service reads /etc/latchd/config.toml. Preview mode first checks $XDG_CONFIG_HOME/latchd/config.toml, then ~/.config/latchd/config.toml, and finally the system file. --config PATH selects one file directly.
Create a user file from the example with:
make install-user
That command creates ~/.config/latchd/ with mode 700, writes config.toml with mode 600, and leaves an existing file alone. The full field reference, variable substitution, command-line overrides, desktop entry rules, and permission checks are in docs/configuration.md.
Install on a test machine
Use a disposable machine and keep another login path available while you change the display manager:
sudo make install
sudo systemctl enable latchd.service
sudo systemctl start latchd.service
The install target writes the binary, /etc/latchd/config.toml, /etc/pam.d/latchd, the session-script directories, and the systemd unit. The supplied unit uses /dev/tty2, so change both tty in the TOML file and TTYPath in the unit if you use another virtual terminal. The install target does not disable the current display manager for you.
Keyboard controls
| Key | Action |
|---|---|
| Tab / Shift-Tab | Move focus |
| Up / Down | Move focus or move in a filtered list |
| Left / Right | Change the selected session |
/ |
Filter sessions or accounts |
| Ctrl-R | Refresh accounts and sessions |
| Ctrl-N / Ctrl-P | Select the next or previous account |
| Ctrl-B | Toggle the background |
| Ctrl-M | Toggle reduced motion |
| Enter | Authenticate or submit a password change |
| Esc | Clear the password or close a popup |
? |
Show the key reference |
| Ctrl-C | Restore the terminal and quit |
| F1–F12 | Confirm a configured power action |
Lowercase filters ignore case, while a filter with an uppercase character is case-sensitive. The preview screen and the capture command are documented in docs/ui.md.
Checks and releases
Use make check for formatting, unit tests, Clippy, and rustdoc; use make integration-test for the CLI paths and make docker-test for the pinned container build. make pam-fixture-test needs root because it installs temporary test policies, while make system-e2e checks the services and devices available on the current host.
Run make system-e2e-strict only in a disposable VM that has a test policy, a real virtual terminal, systemd-logind, and the X11 or Wayland stack you want to test. docs/e2e-testing.md explains what each check can and cannot cover.
Create a local release archive with:
make package
GitLab CI runs the same Rust, CLI, container, and capability checks, then creates an archive and SHA-256 file for a SemVer tag. The release process is described in docs/development.md.
Read next
docs/guide.mdexplains the service from startup to session cleanup.docs/configuration.mdexplains each configuration field.docs/architecture.mdexplains the workspace and the process boundaries.docs/development.mdexplains builds, tests, Docker, and packages.docs/ui.mdshows the screen and its controls.docs/e2e-testing.mdexplains the VM and container checks.
Project layout
crates/latchd-core/ account discovery, configuration, sessions, and UTMPX
crates/latchd-auth/ authentication worker and session handoff
crates/latchd-tui/ terminal state, rendering, input, and effects
rust/main.rs command-line entry point and service loop
extra/ example configuration, login policy, and systemd unit
scripts/ CLI, Docker, fixture, and host checks
legacy/go/ reference implementation from the early prototype
License
Apache-2.0. See LICENSE.
