Help us shape the future of Go! Take the 2026 Go Developer Survey

tui-snapper

module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 30, 2026 License: MIT

README

tui-snapper

tui-snapper

btrfs snapshots, managed by snapper, from the terminal. Part of the tui-tools family.

Your machine has been taking snapshots before every package upgrade for months. snapper list prints them; answering "what did that upgrade actually change, and can I put back just this one file" from there is a different matter. That is what this is for.

The snapshot history

What changed between two snapshots

make demo     # the whole UI, on sample data, with no btrfs and no root

Install

Any distribution, static binary
curl -fsSL https://github.com/tui-tools/tui-snapper/releases/download/v{version}/tui-snapper_{version}_linux_amd64.tar.gz | tar -xz tui-snapper
sudo install -m0755 tui-snapper /usr/local/bin/tui-snapper

Static, no runtime dependencies beyond the snapper binary it drives.

From source
git clone https://github.com/tui-tools/tui-snapper
cd tui-snapper && make demo

make demo needs no btrfs filesystem and no root.

The distribution packages are not published yet. The commands below are here so you know what they will be; a package repository at pkgs.tui.tools is what turns them on.

Arch Linux — coming soon

Needs the tui-tools repository, which is a one-time setup.

sudo pacman -S tui-snapper

Needs the snapper package, which Arch already has.

Debian and Ubuntu — coming soon

Needs the tui-tools repository, which is a one-time setup.

sudo apt install tui-snapper

Needs the snapper package.

Fedora and RHEL — coming soon

Needs the tui-tools repository, which is a one-time setup.

sudo dnf install tui-snapper

Needs the snapper package.

openSUSE — coming soon

Needs the tui-tools repository, which is a one-time setup.

sudo zypper install tui-snapper

openSUSE ships snapper by default, and is the layout snapper rollback was written for.

Verify a download

Every release of tui-snapper ships a checksums.txt. Check an archive against it before installing:

sha256sum -c checksums.txt --ignore-missing

What it does

The history. Every config's snapshots, newest first: the hourly timeline ones, the pre/post pairs your package manager left behind — a post snapshot shows the pre it belongs to, 47←46 — and the ones you took by hand. A snapshot no cleanup algorithm will ever remove is colored as kept, because that is the difference between a state you can rely on and one a timer will quietly take away. The header carries the config, its subvolume, how far back the history goes, and the space the snapshots hold when btrfs quotas make that figure real.

What changed. d compares two snapshots. A post snapshot pairs with its own pre without being asked, which is the comparison anyone opening a package upgrade wants; mark two snapshots with space to compare any other pair. enter on a path opens its unified diff, read-only and scrollable.

One file's diff

Putting things back. u in the diff view runs undochange for the selected paths, or for every path you marked. One configuration file goes back without the rest of the filesystem moving.

Managing the history. Create a snapshot with a description, a type and a cleanup algorithm; delete one, or every snapshot you marked; change a description; pin a snapshot by clearing its cleanup algorithm; run number, timeline or empty-pre-post cleanup. Every one of them is shown as the exact snapper command line first.

The confirm dialog

Rollback, honestly. This is the one thing that genuinely differs between machines, so the tool works out which mechanism is in front of you instead of assuming:

  • where snapper rollback is the real mechanism — the config is the root filesystem and snapper carries the rollback flag — it is offered, with the warning it deserves;
  • on an Omarchy or limine-snapper-sync layout, the snapshots are in the boot menu and booting one is the rollback. tui-snapper reads /boot/limine.conf and shows those entries read-only. It never edits that file, and it never swaps subvolumes itself.

The rollback screen

The timers, read-only. T shows whether snapper-timeline.timer and snapper-cleanup.timer are running and enabled, which is the answer to "why did nothing get cleaned up". Turning them on and off is systemd's job, and tui-systemd already does it.

It needs root, including to read

Most tools in this family read as an ordinary user and escalate only to change something. snapper does not work that way: it opens its subvolumes directly, so even snapper list fails for a non-root user with

IO error (open failed path:/ errno:1 (Operation not permitted)).

So either run the whole thing with sudo tui-snapper, or leave sudo = "sudo -n" configured and keep a sudo timestamp warm — every snapper call is then escalated individually. The tool says which of the two it is doing in its header, and explains this failure rather than showing you an empty list. --demo needs neither.

Keys

Key What it does
↑ ↓ j k move the selection; g / G first and last, pgup / pgdn a page
space mark a snapshot: two marks are a range, many are one delete
d / enter compare two snapshots; a post snapshot pairs with its own pre
enter in the diff: that file's changes, read-only
u in the diff: put the selected or marked files back
c create a snapshot: description, type, cleanup algorithm
D delete the selected snapshot, or every marked one
e / a change the description / the cleanup algorithm
C run a cleanup: number, timeline or empty-pre-post
R rollback, or how this machine actually rolls back
s / T switch config / snapper's timers, read-only
/ filter the list
r re-read the current view
? / q help / quit

The help screen

Configuration

/etc/tui-snapper/config.toml, then ~/.config/tui-snapper/config.toml, then TUI_SNAPPER_* in the environment, then the flags. See examples/config.toml.

config = "root"                    # the snapper config to open on
sudo = "sudo -n"                   # "" runs snapper directly
boot-config = "/boot/limine.conf"  # where the rollback screen reads the boot menu
no-dbus = false                    # true where no snapperd is running
theme = ""                         # empty follows the active Omarchy theme

no-dbus is worth knowing about. snapper normally talks to snapperd over D-Bus; in a container, a chroot or a rescue shell there is no snapperd, and every command comes back as Failure (org.freedesktop.DBus.Error.FileNotFound). --no-dbus makes snapper do the work itself. The flag becomes part of the previewed command line, so the dialog still shows exactly what will run.

The rules it keeps

These are the family's, and they are what the tests are about:

  • Preview, then confirm. Nothing changes without the exact snapper command line being shown first. The dialog is the only path to a mutation, and internal/snapper/command.go is the only place a command line is built.
  • Read-only by default. Starting the tool only reads.
  • No daemon, no state of its own. The filesystem is the source of truth, and it is re-read after every change.
  • --demo always works. It builds and previews every command for real and touches nothing.
  • Backend behind an interface. The UI never names a binary.
  • Responsive. It works in a 40-column pane and on a full screen.

Development

make check         # gofmt, go vet, tests
make demo          # the UI on sample data
make screenshots   # re-render the README frames from --demo
make manifest      # validate tool.json against the family schema

The parsers are table-tested against output captured from a real snapper 0.13.1 on a real btrfs filesystem — internal/snapper/testdata holds those captures verbatim. The limine fixtures in limine_test.go are reconstructions rather than captures, and say so: there is no public dump of a generated limine.conf to paste in, so they were rebuilt from the writer that produces them and from limine's own CONFIG.md.

Two things worth knowing if you extend a parser:

  • snapper status is plain text even under --jsonout in 0.13.1, so it is parsed line by line while list and list-configs are read as JSON;
  • snapper --jsonout list keys its array by the config's own name, not by a fixed field, so {"root": [...]} is what comes back.

License

MIT — see LICENSE. Part of the tui-tools family.

Directories

Path Synopsis
cmd
tui-snapper command
Command tui-snapper is a terminal UI for btrfs snapshots managed by snapper.
Command tui-snapper is a terminal UI for btrfs snapshots managed by snapper.
internal
snapper
Package snapper holds the model tui-snapper renders, the actions it can perform, and the interface every backend satisfies.
Package snapper holds the model tui-snapper renders, the actions it can perform, and the interface every backend satisfies.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL