Releases: Seqat/tuxctl
Release list
tuxctl v0.3.4
NVIDIA GPU on the proprietary driver, on x86_64? Download tuxctl-x86_64-unknown-linux-gnu.tar.gz (needs glibc 2.28 or newer). The musl binaries cannot load NVML, so they show no NVIDIA temperature or usage.
v0.3.4 makes NVIDIA GPUs work from a release download, frees NVML's memory when it is not in use, and hardens tuxctl and its release process. No new dependencies.
What changed
- New glibc binary for x86_64 (RHEL 8, Debian 10, Ubuntu 20.04 and newer). Unlike the static musl binaries, it can load NVML for NVIDIA GPUs.
- GPU card hint: the static binaries now say "NVML needs a glibc build" on the GPU card instead of showing nothing.
- Less memory off the Overview: NVML is unloaded once the Overview has been hidden for 10 seconds and loaded again when you return. With the glibc build and NVML loaded, memory on the other screens drops from about 31 MiB to 11 MiB.
- Hardening:
- Firmware strings are sanitized in
--check. - Quitting no longer hangs on a stuck worker.
systemctl/journalctlare run from the system directories first.- Command lines are capped at 4 KiB.
- Release archives have build provenance attestations.
- The workflows' actions are pinned to commits.
- Firmware strings are sanitized in
- Elsewhere: documentation at https://seqat.github.io/tuxctl/. The release workflow now publishes to crates.io itself, through Trusted Publishing (no stored token).
CPU and memory of the musl binary are unchanged from v0.3.3. Full details: CHANGELOG.md.
Known limitations
- Hybrid laptops (iGPU + NVIDIA dGPU) can pick the wrong main GPU for the GPU card when the dGPU is asleep at startup (#7).
- NVML unloading on RTD3 GPUs (runtime-suspending dGPUs, common on laptops) is covered by tests but untested on real hardware. If you have one, please report how it behaves in #8.
Verification
base=https://github.com/Seqat/tuxctl/releases/download/v0.3.4
archive=tuxctl-x86_64-unknown-linux-gnu.tar.gz # or tuxctl-$(uname -m)-unknown-linux-musl.tar.gz
curl -LO "$base/$archive" -LO "$base/SHA256SUMS"
sha256sum -c --ignore-missing SHA256SUMS
gh attestation verify "$archive" --repo Seqat/tuxctlgh attestation verify confirms that the archive was built by this repository's release workflow. Installation options: https://seqat.github.io/tuxctl/installation.html.
tuxctl v0.3.3
v0.3.3 redesigns the Overview as a set of cards that uses the whole terminal, and adds what a system monitor is expected to show: component temperatures, GPU usage, CPU power, swap and every local filesystem, colored by load. It also makes risky keys safer: SIGTERM now needs Shift+T, and q asks before quitting. There were no 0.3.1 or 0.3.2 releases.
New
- Overview cards. CPU, GPU, Memory, Network, Storage and Pinned, each with its model, temperature and power in the title and a graph as wide as the card. At 150 columns and more they form a 2×2 grid with Storage below and Pinned on the right; at 100–149 columns Storage and Pinned sit side by side; narrower terminals stack the cards by priority. Hostname, kernel, uptime and process counts moved into the top border. A short terminal gives up the per-CPU grid first, then graph height, then list rows, and only then whole cards.
- Temperatures for CPUs, GPUs, NVMe and SATA disks and network adapters, from the kernel's hwmon drivers and thermal zones. A sleeping GPU is never woken to be read.
- GPU usage. Utilization graph, VRAM, fan and power: through NVML for NVIDIA GPUs on the proprietary driver, through sysfs for
amdgpu, and power and fan fornouveau. - Colors by load. Utilization, graphs, pinned processes' CPU and temperatures go from light blue through green, yellow and orange to red. Temperatures are colored as a share of the component's critical temperature. True color, 256-color and 16-color terminals are supported.
- CPU package power where your user can read it: from
zenpower, or from RAPL energy counters if an administrator makes them readable (see "Optional setup" in the README for a udev rule and its security trade-off). tuxctl asks for no privileges. - Swap and every local filesystem on the Memory and Storage cards.
tuxctl --checklists the sensors tuxctl finds on your machine and what would enable the missing ones (drivetempfor SATA disks, readable RAPL counters, a glibc build for NVIDIA).- Popups grey out the screen behind them.
Changed
- Breaking:
SIGTERMis requested withT/Shift+Tinstead oft. Keys that change the system or persistent state (signals, pins) useShift. qopens the main menu with Exit selected;Enterorqagain quits.Ctrl+Cstill quits immediately.- Graphs keep 240 samples and fill the card; the Network graph uses a logarithmic scale, so one spike no longer flattens everyday traffic.
- Hardware sensors are read only while the Overview is visible.
NVIDIA GPUs
NVIDIA's proprietary driver has no hwmon sensors, so tuxctl loads the driver's own libnvidia-ml.so.1 (NVML) at run time when it finds such a GPU. NVML costs about 20 MiB of memory and a little CPU on the Overview; --no-nvidia-temperature leaves it unloaded. On laptops with runtime power management, NVML is opened only while the GPU is awake, so tuxctl never keeps it powered. The static binaries below cannot load NVML; to see NVIDIA temperatures and usage, build from source with cargo install (see Installation).
Performance
Measured with the static release binary on an AMD Ryzen 5 7500F at the default interval: 0.6% CPU when idle on Overview, 13.4 redraws per second under 240 Hz mouse hover, and about 2.7 MiB of RSS after 15 minutes, with no growth after warm-up. Measured alternately with v0.3.0 on the same machine (3 runs each), CPU is unchanged within run-to-run noise. The binary is about 20% larger (1.74 MB). A glibc build that loads NVML uses about 31 MiB.
Verification
- 505 unit tests and 6 command-line integration tests passing (glibc; 502 + 6 on musl)
cargo fmt --checkPASScargo checkPASScargo clippy --all-targets --all-features -- -D warningsPASS (glibc and musl)cargo testPASScargo build --release --lockedPASS (glibc and musl)scripts/smoke.py38/38 on the glibc and musl release builds- CI green, including MSRV 1.88 and the redraw guards at the default and 250ms intervals
Minimum supported terminal size: 40×15. Minimum supported Rust version: 1.88.
Installation
Linux only
Prebuilt binary (x86_64 or aarch64):
arch=$(uname -m)
base=https://github.com/Seqat/tuxctl/releases/download/v0.3.3
curl -LO "$base/tuxctl-$arch-unknown-linux-musl.tar.gz" -LO "$base/SHA256SUMS"
sha256sum -c --ignore-missing SHA256SUMS
tar xzf "tuxctl-$arch-unknown-linux-musl.tar.gz"
install -Dm755 "tuxctl-$arch-unknown-linux-musl/tuxctl" ~/.local/bin/tuxctlFrom source (Rust 1.88 or newer; needed for NVIDIA temperatures and usage):
cargo install --git https://github.com/Seqat/tuxctl --tag v0.3.3 --lockedtuxctl v0.3.0
v0.3.0 adds ways to track and filter what you are looking at: pin processes, filter views, change the sampling interval while tuxctl runs, and see disk I/O and RAM/network trends on Overview. It also fixes a security issue: text from other users could send escape sequences to your terminal. Upgrading is recommended.
Security
- Terminal escape injection (all earlier versions). Process names, command lines, journal messages and other system data were written to the terminal unfiltered. Any local user could embed escape sequences in them, for example with
loggeror by renaming a process. When you opened the Processes or Logs screen, they could replace your clipboard (OSC 52, which kitty, alacritty, foot and wezterm allow by default) or reset the terminal. tuxctl now removes control characters and bidirectional overrides from everything it draws; affected characters show as�. Upgrade especially if you run tuxctl as root or on a shared machine. - Processes whose name is not valid UTF-8 are now listed and can be signaled; before, any user could hide a process from tuxctl this way.
New
- Pin processes.
Ppins the selected process to the top of the Processes list (up to 8).Shift+↑/Shift+↓(orAlt), or the▲/▼controls, reorder them. Sorting applies below the pins. Pins follow the process identity, so a reused PID never inherits one. A pinned process that exits shows asexitedfor a few seconds and can never be signaled. Pinned processes are also listed with their CPU and memory on the Overview System panel. - View filters (
v). Processes: hide kernel threads. Services: all units, loaded units only, or failed units only. Logs: minimum priority notice, warning or error. Filters combine with search and stay visible in the status line. - Sampling interval at runtime.
+/-, or clicking[-]/[+]in the top-right corner, step through the--intervalpresets (250ms to 60s) without restarting. - Disk I/O. Overview storage rows show read and write throughput for each disk.
- Trends. Overview shows RAM usage and network traffic sparklines next to the CPU history.
- Main menu.
Esc, when there is nothing to close or clear, opens a menu with About and Exit.
Changed
Escwith nothing left to close now opens the main menu instead of doing nothing. The menu starts on About, so an extraEnterdoes not quit.- The Help overlay lists every binding and no longer cuts off its last line.
Fixes
- While typing a search,
↑/↓andPageUp/PageDownnow move through the matches; before,Enteropened whichever row happened to be selected.
Under the hood
- Collectors take their sampling period from their shared control primitive, so it can change while they run; rates use the actual time between samples.
- CI also measures at the 250ms interval, and the idle redraw limit follows the interval. The smoke test covers the menu and the interval keys.
Measured with the release binary on an AMD Ryzen 5 7500F at the default interval: 0.6% CPU when idle on Overview, 13.5 redraws per second under 240 Hz mouse hover, and about 2.3 MiB of RSS after 15 minutes, with no growth after warm-up. Measured alternately with v0.2.7 on the same machine (3 runs each), every difference is within run-to-run noise. The binary is about 4% larger.
Verification
- 401 unit tests and 4 command-line integration tests passing (glibc and musl)
cargo fmt --checkPASScargo checkPASScargo clippy --all-targets --all-features -- -D warningsPASScargo testPASScargo build --releasePASSscripts/smoke.py37/37 on the glibc and musl release builds- CI green, including MSRV 1.88 and the redraw guards at the default and 250ms intervals
Minimum supported terminal size: 40×15. Minimum supported Rust version: 1.88.
Installation
Linux only
Prebuilt binary (x86_64 or aarch64):
arch=$(uname -m)
base=https://github.com/Seqat/tuxctl/releases/download/v0.3.0
curl -LO "$base/tuxctl-$arch-unknown-linux-musl.tar.gz" -LO "$base/SHA256SUMS"
sha256sum -c --ignore-missing SHA256SUMS
tar xzf "tuxctl-$arch-unknown-linux-musl.tar.gz"
install -Dm755 "tuxctl-$arch-unknown-linux-musl/tuxctl" ~/.local/bin/tuxctlFrom source:
cargo install --git https://github.com/Seqat/tuxctl --tag v0.3.0 --lockedThen run:
tuxctl
tuxctl --interval 2stuxctl v0.2.7
v0.2.7 hardens tuxctl before v0.3.0. It ships the first prebuilt binaries, fixes terminal restoration when tuxctl is killed by a signal, and sets up a measured performance baseline that CI now checks on every push. No key bindings or screens changed.
New
- Prebuilt binaries. Statically linked binaries for x86_64 and aarch64 Linux are attached below, with
SHA256SUMS. They do not depend on the system C library, so they run on any distribution. - Release builds are about 35% smaller and use about 200 KiB less memory, with the same CPU usage.
Fixes
kill <pid>, closing the terminal window (SIGHUP), or SIGINT no longer leave your shell in raw mode on the alternate screen with the mouse captured. tuxctl now quits as it does withq: it restores the terminal and stopsjournalctl, then exits. A second signal ends it immediately.
Under the hood
- CI now runs a pseudo-terminal smoke test of the release binary on every push. It also fails the build if redraw rates exceed fixed limits: 31/s for mouse hover, 21/s for background updates, 3.5/s when idle.
- The smoke test now also checks that
journalctlstarts only when the Logs tab is opened, that nothing is left running after exit, and that SIGTERM/SIGHUP restore the terminal. - New command-line integration tests, and machine-readable CPU, memory and redraw measurements (
scripts/). - The README has a quick start, binary installation instructions and a performance section;
docs/performance.mdhas the method and history.
Measured with the release binary on an AMD Ryzen 5 7500F at the default interval: 0.6% CPU when idle on Overview, 13 redraws per second under 240 Hz mouse hover, and about 2.3 MiB of RSS after 15 minutes, with no growth after warm-up. Compared with v0.2.5 (same machine, 3 runs each), CPU and redraw rates are unchanged.
Verification
- 315 unit tests and 4 command-line integration tests passing (glibc and musl)
cargo fmt --checkPASScargo checkPASScargo clippy --all-targets --all-features -- -D warningsPASScargo testPASScargo build --releasePASSscripts/smoke.py32/32 on the glibc and musl release builds- CI green, including MSRV 1.88; release dry run green on x86_64 and aarch64
Minimum supported terminal size: 40×15. Minimum supported Rust version: 1.88.
Installation
Linux only
Prebuilt binary (x86_64 or aarch64):
arch=$(uname -m)
base=https://github.com/Seqat/tuxctl/releases/download/v0.2.7
curl -LO "$base/tuxctl-$arch-unknown-linux-musl.tar.gz" -LO "$base/SHA256SUMS"
sha256sum -c --ignore-missing SHA256SUMS
tar xzf "tuxctl-$arch-unknown-linux-musl.tar.gz"
install -Dm755 "tuxctl-$arch-unknown-linux-musl/tuxctl" ~/.local/bin/tuxctlFrom source:
cargo install --git https://github.com/Seqat/tuxctl --tag v0.2.7 --lockedThen run:
tuxctl
tuxctl --interval 2sFull Changelog: v0.2.5...v0.2.7
tuxctl v0.2.5
v0.2.5 prepares tuxctl for v0.3.0 and adds a few small features early. No key bindings changed.
New
--interval <DURATION>sets how often CPU, memory, and network are sampled. Accepted values are250ms,500ms,1s(the default),2s,5s,10s,30s, and60s. Processes still refresh at most once per second, and services at most every 5 seconds.-h/--helpand-V/--version.- The CPU history on Overview now shows how much time it covers, for example
60sor5m. - The process detail view shows whether a process is a kernel thread or a user process.
- The Logs screen shows journal times in your local time zone. The detail view adds the full date and the UTC offset.
Fixes
- An active search or filter no longer disappears from the status line. Signal results, "Refreshing…", and refresh errors now appear after it.
- A
systemctlcall that timed out after starting helper processes could delay shutdown. Those helpers are now stopped as well.
Under the hood
- Continuous integration: formatting, clippy, tests, and a check against the minimum supported Rust version (1.88).
scripts/contains pty smoke tests and CPU, memory, and redraw measurements.- Internal restructuring prepares for v0.3.0 features: an adjustable interval, disk I/O, filters, and an Esc main menu.
Idle CPU and memory are the same as in v0.2.2: about 0.6% CPU at the default interval and about 5.4 MiB of RSS after 15 minutes. With --interval 5s, idle CPU drops to about 0.2%.
Verification
- 311 automated tests passing
cargo fmt --checkPASScargo checkPASScargo clippy --all-targets --all-features -- -D warningsPASScargo testPASScargo build --releasePASS- CI green, including MSRV 1.88
Minimum supported terminal size: 40×15. Minimum supported Rust version: 1.88.
Installation
Linux only
git clone https://github.com/Seqat/tuxctl.git
cd tuxctl
cargo install --path .Then run:
tuxctl
tuxctl --interval 2sFull Changelog: v0.2.2...v0.2.5
tuxctl v0.2.2
v0.2.2 makes tuxctl lighter while idle and fixes the Overview layout on narrow terminals. No keys or screens changed.
Collector lifecycle
journalctlnow starts the first time you open the Logs tab instead of at startup.- Services are only collected while the Services tab is visible. Each time you open it, the list refreshes once, and no
systemctlruns while the tab is hidden. - A paused Services collector is no longer shown as
stale. - Idle cost drops as a result:
- startup RSS is about 250 kB lower
- after 15 minutes on Overview, RSS is about 5.4 MiB (6.1 MiB in v0.2.1)
- idle CPU is slightly lower
Narrow-layout fixes
- Overview no longer hides logical CPUs without a "… N more" line.
- A taller terminal never shows fewer CPUs than a shorter one.
- RAM, GPU, storage, and network are no longer drawn as headings without content; a section that doesn't fit is left out.
- Dense CPU cells keep a space between the label and the value.
- Tab labels no longer run together at 40 columns. Narrow terminals use short labels (
Ovr Proc Svc Logs Net), and mouse clicks follow them.
Verification
- 278 automated tests passing, including resize sweeps across 40–160 columns and 15–60 rows
cargo fmt --checkPASScargo checkPASScargo clippy --all-targets --all-featuresPASScargo testPASScargo build --releasePASS
Minimum supported terminal size: 40×15. Minimum supported Rust version: 1.88.
Installation
Linux only
git clone https://github.com/Seqat/tuxctl.git
cd tuxctl
cargo install --path .Then run:
tuxctlFull Changelog: v0.2.1...v0.2.2
tuxctl v0.2.1
v0.2.1 is a reliability and efficiency release. tuxctl uses less CPU and is more robust, and no keys or screens changed.
Reliability
- A hung
systemctlcan no longer stall the Services tab or block exit. The listing times out after 10 s and showssystemctl timed out. - If a background collector stops delivering data, the frame title now shows a
stalemarker for the affected screen instead of presenting frozen data as live.
Efficiency
- Snapshots that arrive together are drawn in a single redraw, and background redraws happen at most every 50 ms. Keyboard, mouse and resize still redraw immediately.
- Process command lines are cached per
(PID, start_time)instead of being re-read from/procevery second. - Process sort and search keys are computed once per snapshot, and the process list is only filtered and sorted while the Processes tab is visible.
- Measured idle CPU dropped by about 25–35% (for example, Overview went from 0.85% to 0.60%). RSS stays bounded at about 6.1 MiB after 15 minutes.
Fixes
- The Logs
PRIORITYheader is no longer truncated. - The Overview root filesystem row no longer draws its label over the gauge.
- Interfaces reporting an
unknownstate, such aslo, are shown neutrally as◌ unknown.
Project
- Minimum supported Rust version: 1.88 (
rust-versioninCargo.toml). - Added
CHANGELOG.md.
Verification
- 262 automated tests passing
cargo fmt --checkPASScargo checkPASScargo clippy --all-targets --all-featuresPASScargo testPASScargo build --releasePASS
Minimum supported terminal size: 40×15.
Installation
Linux only
git clone https://github.com/Seqat/tuxctl.git
cd tuxctl
cargo install --path .Then run:
tuxctlFull Changelog: v0.2.0...v0.2.1
tuxctl v0.2.0
v0.2 expands tuxctl's system monitoring capabilities while keeping the
application lightweight, responsive, and keyboard-first.
Highlights
- Redesigned Overview with dedicated System and Hardware dashboards
- Live aggregate and per-logical-CPU utilization
- Bounded CPU utilization history and load averages
- Live RAM usage and filesystem capacity
- GPU, storage, and physical network interface inventory
- Compact live network summary on Overview
- System CPU and RAM summary on the Processes screen
- Improved responsive layouts down to 40×15 terminals
- More consistent screen hierarchy and gauge presentation
Reliability & Safety
- PID-safe SIGTERM/SIGKILL using Linux pidfds
- Fail-closed process signaling when safe pidfd signaling is unavailable
- Bounded newest-wins communication for periodic collector snapshots
- Bounded Journal ingestion with fair terminal/input scheduling
- Reliable Journal failure reporting
- Hardened terminal restoration and resize behavior
- Correct stale-state handling for Process and Network collector failures
- Improved Network counter lifecycle and recovery handling
- Correlated/coalesced Service refresh generations
- Bounded runtime histories, queues, and log storage
UI
- Removed redundant page titles across data screens
- Increased useful table/log viewport space
- Unified CPU/RAM gauge presentation
- Improved narrow-terminal tab layout
- Refined Overview CPU, RAM, storage, and Network presentation
Verification
- 225 automated tests passing
cargo fmt --checkPASScargo checkPASScargo clippy --all-targets --all-featuresPASScargo testPASScargo build --releasePASS
Minimum supported terminal size: 40×15.
Installation
Linux only
git clone https://github.com/Seqat/tuxctl.git
cd tuxctl
cargo install --path .Then run:
tuxctl