Files
latchd/README.md
Zane Walker 5eae08c7ba
Some checks failed
Integration Check CI / check (push) Has been cancelled
Continuous integration / Check (push) Has been cancelled
Continuous integration / Rustfmt (push) Has been cancelled
Continuous integration / Clippy (push) Has been cancelled
(Feat): Minor Changes
2026-07-18 23:07:56 +05:30

190 lines
6.9 KiB
Markdown

# latchd
a display manager that runs in your terminal. lets you pick a desktop environment and log in — supports tty, x11, and wayland.
## what problem does this solve
Most display managers are graphical. that means you need x11 or wayland running before you can even log in. latchd runs in a plain linux terminal (like tty2), so you can log in first, then start your desktop. it's lightweight, looks decent, and doesn't drag in a full graphics stack just to show a login screen.
## how it works
latchd takes over a virtual terminal (tty2 by default) and draws a login screen using ansi escape codes, powered by [bubbletea](https://github.com/charmbracelet/bubbletea). you type your username and password, pick a session from the switcher, and hit enter.
The actual authentication happens through pam (pluggable authentication modules). Once you're authenticated, latchd forks a child process that opens the pam session, sets up your environment, spawns your desktop or window manager, and does utmp accounting so tools like `who` and `loginctl` can see you're logged in.
For x11 sessions it handles the whole setup — xauthority cookies, sigusr1 handshake with the x server, timing out if xorg fails to start. for wayland it just runs your compositor script. for tty it drops you into your shell.
While the login screen is up, it renders a conway's game of life simulation as the background at 30fps, using unicode half-block characters for a pixelated look.
## what you get
- Session switcher with left/right arrows and dot indicators
- username and password fields
- Status line for errors and info
- power controls (f1 shutdown, f2 reboot by default — configurable)
- caps lock indicator
- shake animation on wrong password
- spring animation on switcher transitions
- faillock integration — shows remaining attempts, detects lockouts
- Admin override (ctrl+u) to unlock a locked-out account
- configurable color theming via toml
- variable substitution in config (`$varname`)
- Preview mode for testing inside an existing session
## Known Issues
This project is a work in progress. here's what you should know:
- **no tests**. at all. no unit tests, no integration tests. if you hit a bug, you'll find it the hard way.
- **Session spawning is a bit rough**. it uses `ForkExec` to re-launch itself as a child process, which means the pam session lifecycle isn't as clean as the original fork-then-exec model. this can cause pam modules that track session leaders to get confused.
- **a handful of open bugs** — edge cases in the switcher, occasional terminal state corruption on abrupt exits, and the automata background can flicker when the terminal resizes rapidly.
- **not all config options are fully wired**. things like `SwitcherConfig.ShowNeighbours`, various color options, and input field styling fields exist in the config struct but may not all be hooked up to the rendering yet.
## installing
### from source
you need go 1.22 or later, `libpam0g-dev` (debian/ubuntu) or `pam-devel` (rhel/fedora) or `pam` (arch), and a c compiler (`build-essential`).
```bash
make deps # install system dependencies
sudo make install # build, install binary + configs + systemd unit
sudo systemctl enable latchd
```
to test without rebooting:
```bash
make run-preview
```
### arch
```bash
pacman -S latchd
systemctl enable latchd
```
## command line
```
latchd [options]
-c, --config <file> config path (default: /etc/latchd/config.toml)
-v, --variables <file> variables path
--tty <n> override the tty number to run on
--preview run inside an existing session for testing
--no-log disable all logging
--show-config print the parsed config and exit
-V, --version print version and exit
--xsessions <dir> override xsessions path
--wlsessions <dir> override wayland-sessions path
--initial-path <path> override initial PATH value
```
## adding sessions
drop executable scripts into the right folder and they show up in the switcher.
**x11** — put your xinitrc scripts in `/etc/latchd/wms/`:
```bash
# /etc/latchd/wms/bspwm
#!/bin/sh
sxhkd &
exec bspwm
```
```bash
chmod +x /etc/latchd/wms/bspwm
```
**wayland** — same thing in `/etc/latchd/wayland/`:
```bash
# /etc/latchd/wayland/sway
#!/bin/sh
exec sway
```
latchd also reads freedesktop `.desktop` files from `/usr/share/xsessions` and `/usr/share/wayland-sessions` automatically.
tty sessions are added automatically if no other environments are found, or you can force one with `include_tty_shell = true` in the config.
## configuring
the config lives at `/etc/latchd/config.toml`. all options are documented inline in the file. you can also use a `variables.toml` file with `$VAR` syntax:
```toml
# /etc/latchd/variables.toml
accent = "orange"
```
```toml
# /etc/latchd/config.toml
[password_field.style]
title_color_focused = "$accent"
border_color_focused = "$accent"
```
## debugging
three log files:
- `/var/log/latchd.log` — main latchd events
- `/var/log/latchd.client.log` — stdout/stderr of your session
- `/var/log/latchd.xorg.log` — x server output (64mb cap)
run `latchd --show-config` to verify your configuration. run `latchd --preview` to test the login screen without leaving your current session.
## keybindings
standard shell-style bindings in text fields:
| key | what it does |
|---|---|
| ctrl+a | start of line |
| ctrl+e | end of line |
| ctrl+l or ctrl+u | clear field |
| ctrl+d | delete forward |
| ctrl+h | backspace |
| ctrl+b/f | left/right |
| ctrl+p/n | up/down (previous/next field) |
| tab, shift+tab | next/prev field |
| left/right | previous/next session (switcher mode) |
| , / . | previous/next session (any mode) |
| f1, f2 | power controls |
| ctrl+u | admin unlock (when account is locked) |
## source layout
```
src/
├── main.go entry point, cli, vt switching, session forking
├── auth/
│ ├── pam.go cgo pam bindings (locks goroutine to os thread)
│ ├── faillock.go faillock tally detection and reset
│ └── utmpx.go user accounting records
├── config/
│ └── config.go toml parsing, variable substitution, defaults
├── session/
│ ├── env.go xdg and environment variable setup
│ ├── exec.go process spawning, privilege dropping, log limits
│ ├── scan.go session discovery and .desktop parsing
│ ├── x11.go xorg setup, xauth, sigusr1 handshake
│ └── wayland.go wayland placeholder
├── login/
│ └── login.go login form ui, state machine, animations, rendering
└── tui/
└── bg/
└── automata.go conway's game of life background
```
## license
MIT or Apache-2.0
## credits
the `extra/` directory structure and the session scanning / pam delegation approach are adapted from [lemurs](https://github.com/coastalwhite/lemurs), a rust display manager.