Repository navigation
How It Works
retch gathers system information from many independent, often-slow sources (GPU
drivers, package managers, network interfaces, sensors, display EDID blocks, audio
servers, Bluetooth, etc.) and renders it as a themed report next to a distro logo.
The two design problems that shape the codebase are: don't block on slow queries
sequentially, and don't run slow queries at all unless the requested output mode
needs them.
Slow queries (GPU, package counts, IP resolution, active network interface detection,
motherboard/BIOS, displays, audio, Wi-Fi, Bluetooth, UI theme/fonts, camera, gamepad,
weather, hardware temperatures, window manager) start on their own threads before
sys-init when they borrow nothing from sys, then join after the concurrent scope.
This is the difference between retch's tens-of-milliseconds standard-mode runtime and
multi-second runtimes if each probe ran one after another. The fetch orchestration
lives in crates/sysinfo/src/fetch.rs. temp and wm used to run serially after the
scope waited for weather (~24 ms on Linux); since v0.20.27 they start with weather and
overlap it.
retch has four output modes with increasing verbosity and acceptable runtime. Each
mode is a strict superset of the one above it — nothing is hidden or replaced when you
escalate, except the temperature view (see below).
| Mode | Flag | Runtime (Linux laptop, v0.20.10) | Purpose |
|---|---|---|---|
| Short | --short |
~3 ms | Hardware snapshot — fastest, scriptable |
| Standard | (none) | ~4 ms | Daily-use system overview |
| Long | --long |
~220 ms | Diagnostics — consolidated thermals, network detail, firmware |
| Full | --full |
~430 ms | Everything, including slow and cosmetic fields |
--long cannot go much below ~200 ms on Linux and macOS: cpu-usage needs two samples at
least that far apart. --full is set by the network (weather, then public-ip), so it
depends on your connection. macOS and Windows are slower in some modes; see
the benchmarks.
Fast hardware-only snapshot. No network calls, no sensors, no cosmetic fields.
Fields: host, os, kernel, cpu, gpu, memory, disk, net.
Full system overview suitable for daily use. No slow fields, no sensors, no cosmetic
fields. BIOS moves to --long (firmware detail, not needed at a glance); gamepad
moves to --full (cosmetic/slow). CPU usage moves to --long (v0.19.0): on Linux and
macOS it needs two samples at least 200 ms apart, which was ~80% of this mode's runtime. In
--long the first sample is taken before the concurrent probes, so the interval overlaps them
rather than adding to them (v0.19.2), and retch subtracts its own CPU time from the figure.
Standard plus diagnostics — aimed at understanding system health and network configuration. Adds:
- system:
domain,chassis,init,locale,arch,bootmgr,bios,tpm,procs,users,packages - CPU and thermals:
cpu-freq,cpu-usage, consolidatedtemp - storage and network:
disk-io,btrfs,zpool,net-io,public-ip,wifi,dns,bluetooth - power and input:
battery,power-adapter,brightness,keyboard,mouse - session:
shell,editor,terminal,terminal-font,terminal-size,desktop,wm,login-manager,font - media:
player,media
Temperature consolidation: --long shows one representative reading per physical
unit (CPU, GPU, SSD/NVMe, WiFi adapter, System/Motherboard) — sensors are classified
by name pattern (k10temp/coretemp → CPU, amdgpu/nvidia → GPU, nvme → SSD,
ath/iwl → WiFi, acpitz/thinkpad → System) and the highest reading in each
category is reported, since that's the worst-case thermal indicator you actually care
about at a glance.
Long plus everything slow, verbose, or cosmetic. Suitable for reporting, screenshots, or deep diagnostics. Adds:
-
temp(all sensors) — replaces the consolidated--longview with every reading -
domain-search— per-interface DNS search domains (viaresolvectl statusor equivalent) -
vulkan,opengl,opencl— graphics/compute API versions, on Linux, macOS and Windows. Each loads its library at runtime rather than linking it (dlopenon Linux and macOS,LoadLibraryAon Windows), so a machine without the library simply omits the field.vulkanandopencluse the same probe code everywhere, since only the loader's filename differs.openglneeds a context to read a version from, and each platform gets one differently: Linux uses a headless EGL context (no display server needed); stock Windows ships no EGL, so there retch creates a 1×1 WGL window that is never shown and tears it down afterwards; macOS uses CGL, which needs no window. They sit in--fullbecause the three cost ~80 ms of CPU combined, though that overlaps the other probes - Cosmetic fields:
theme,icons,cursor,wm-theme,wallpaper,terminal-theme(font/terminal-fontstay in--long; theme detection involves sqlite/gsettings queries and is purely cosmetic, not diagnostic) gamepad-
weather— current conditions via wttr.in, one plain-HTTP request, as fastfetch does (~4s network timeout) - FUSE mounts — disk detection re-enables
statvfsforfuse.*entries, skipped in every other mode to avoid 600ms+ hangs from cryfs/EncFS vaults
retch is a Cargo workspace split into a library and a CLI binary:
| Crate | Path | Description |
|---|---|---|
retch-sysinfo |
crates/sysinfo |
System info library — all detect_* logic, SystemInfo, CollectOptions, GPU, battery. No dependency on clap or the CLI. |
retch-cli |
. |
CLI binary — display logic, configuration, logo rendering |
retch-sysinfo can be used independently as a cross-platform system-information
library outside of retch itself.
Distro logos render through a fallback chain: full-color graphical protocols (Kitty,
iTerm2, Sixel) first, then Chafa-based Unicode symbol art, then plain ASCII art
(adapted from Fastfetch). Logo output is automatically suppressed whenever stdout is
not a terminal (e.g. retch | bat or retch > file), so piping never produces
garbled escape sequences in a file.
When the terminal is wide enough, the field list renders on the left and the logo is anchored to the right margin — its right edge sits on the terminal's last column, whatever the width. Two independent numbers drive this, and keeping them separate is what makes it correct:
| what it controls | |
|---|---|
| text column | whether the layout goes side-by-side at all, and the minimum room reserved for text (45–65 columns) |
| logo column | where the logo is drawn: terminal width − logo width
|
Field lines wrap to the space actually available: beside the logo that is
logo column − 2, and below it (where nothing overlaps) the full terminal width.
Before v0.9.3 the beside-logo case wrapped at the text column instead, so on a wide
terminal a long value could break at ~55 columns with the rest of the gap to the logo
left unused.
Before v0.9.2 these were the same value, so the logo was drawn wherever the text column happened to end — capped at column 65, which stranded everything to its right on any terminal wider than about 110 columns.
Below 95 columns, or when the text column and logo cannot both fit, the layout falls
back to stacked: the logo prints above the field list at column 0. Long lines that
sit below the logo (Wi-Fi, Net, Battery in --long/--full) never influence
the decision, since nothing overlaps them — only the field lines actually beside the
logo do.
Placement is logo-type agnostic. ASCII and Chafa are measured from their rendered text; the image protocols get their cell footprint from a single sizing function whose result feeds both the protocol escape and the layout, so the space reserved and the space drawn cannot disagree.
A field line too long for the space beside the logo wraps onto continuation lines indented to the value column. Two properties are preserved across a break, both fixed in v0.9.3:
-
The separator is kept. Breaking a comma-separated value leaves the comma on the
preceding line, so
American Megatrends International, LLC.cannot be misread as two separate values. - The colour continues. Lines are colourised before they are wrapped, so a split value's opening escape sits on the first line and its closing reset on the last. Continuation lines re-open the active colour and close it at each line end, which also stops a colour bleeding into the logo column.
Alignment is computed in terminal columns, not characters. A CJK ideograph or
Hangul syllable occupies two columns, a combining mark none, and an emoji with a
variation selector two. This matters for ordinary output, not just exotic input: the
media and player fields surface arbitrary track metadata, so a Japanese or Korean
song title is a normal value. Widths come from the unicode-width crate after ANSI
escape sequences are stripped.