pipx install 'syswatch-linux[tui]'
A local Linux system diagnostics and monitoring tool with an interactive
terminal UI and scriptable CLI. syswatch reads /proc and /sys
directly (plus a few well-known OS interfaces) and degrades gracefully when
information cannot be collected.
| Live TUI | CPU, memory, disks, network graphs updating every second |
| Process explorer | Sortable, filterable table with per-process details pane |
| Health checks | CPU, RAM, swap, disk, load, zombies, systemd, gateway — all thresholded |
| Zero deps CLI | info, monitor, ps, health, report all run on stdlib alone |
| Hermetic tests | Injectable /proc roots — no live system required |
$ syswatch info
Hostname debian
OS Debian GNU/Linux 12 (bookworm)
Kernel 6.1.0-34-amd64
CPU Intel(R) Core(TM) i7-10750H @ 2.60GHz
RAM 3.8 GiB total · 1.1 GiB available
$ syswatch health
OVERALL HEALTH: HEALTHY — 8/8 checks normal
$ syswatch ps -s cpu -n 5
PID Name S CPU% MEM% RSS
4806 opencode R 99.0 24.7% 1.2 GiB
17343 python S 42.9 1.6% 82 MiB
1886 gnome-shell S 33.0 9.4% 470 MiB
2500 gnome-terminal S 13.2 1.5% 76 MiB
1 systemd S 0.0 0.3% 12 MiB- Linux (kernel 4.x+ tested) — the application is designed for Linux; on other platforms it exits with a clear message.
- Python 3.11+ (Debian 12+, Ubuntu 23.04+, Fedora 38+, Arch, RHEL 9+)
- For the interactive TUI only:
textual(installed automatically with the[tui]extra). All non-interactive commands run on the standard library alone.
pipx installs CLI tools in isolated environments
and puts the command on your PATH. It handles Debian/Ubuntu's
externally managed Python restriction transparently.
# Debian / Ubuntu
sudo apt install pipx && pipx ensurepath
# Fedora
sudo dnf install pipx && pipx ensurepath
# Arch
sudo pacman -S python-pipx && pipx ensurepath
# Install syswatch (restart your shell after the first ensurepath)
pipx install 'syswatch-linux[tui]' # CLI + interactive TUI
pipx install syswatch-linux # CLI only, no TUI dependenciesIf pipx isn't available:
python3 -m pip install --user 'syswatch-linux[tui]'
# then make sure ~/.local/bin is on your PATHOn distros that mark system Python as externally managed (PEP 668), add
--break-system-packages. It's safe here since --user writes only to
~/.local/, not to system directories.
The CLI runs straight from the source tree on the standard library alone:
git clone https://github.com/S0mthingIDK/syswatch
cd syswatch
chmod +x bin/syswatch # only needed if you did not clone via git
./bin/syswatch info
./bin/syswatch healthOr invoke the module directly:
python3 -m syswatch info # from the checkout rootOnly the TUI needs the extra packages. To install them into the checkout:
python3 -m venv .venv
.venv/bin/pip install -e '.[tui]'
.venv/bin/syswatchNote for tarball / ZIP users: after copying the tree onto Linux, run
chmod +x bin/syswatchonce. The executable bit is preserved bygit clonebut not by zip,scp, or shared folders from Windows.
syswatch --version
syswatch info
syswatch healthRun syswatch with no arguments (or syswatch tui) in a terminal:
syswatch # pipx install
.venv/bin/syswatch # from a checkoutCPU, memory, disks, and network graphs with a live health strip.
Live process table with filtering, sorting, and a detailed side pane.
Host identity, CPU, memory, filesystem, and network cards.
Every check with its live value, threshold, status, and notes — passing included.
| Key | Action |
|---|---|
1..5 |
switch view |
r |
force an immediate refresh |
/ |
focus process filter (Esc clears, works globally) |
s |
cycle process sort: cpu → mem → pid → name |
Enter |
popup with full details of selected process |
d |
toggle the process details side pane |
q |
quit |
Everything is live: CPU/memory/network graphs update every refresh interval, the process table rescans in a background thread, and health checks re-run periodically without blocking the UI. A failed collector shows "unavailable" in its panel instead of crashing the app.
Troubleshooting the TUI:
ModuleNotFoundError: textual— reinstall with the extra:pipx install --force 'syswatch-linux[tui]'(orpip install 'syswatch-linux[tui]').- Broken/garbled colors over SSH — ensure
TERMis set correctly (e.g.xterm-256color). - Below ~100 columns views stack into a single column; below ~26 rows the
System view becomes a scrollable column so no panel is crushed.
The process details pane appears from ~100 columns (
dtoggles it). - On very wide terminals (>160 columns) panels regroup into balanced multi-column grids instead of stretching; content stays centered.
| Command | Purpose |
|---|---|
info |
Static system facts: hostname, OS, kernel, CPU, RAM, disks, NICs (--json supported) |
monitor |
Live view: CPU %, memory, worst disk, network RX/TX rates, process count, load average. Options: -i/--interval, -n/--count, --json, --no-clear |
ps |
Process viewer with PID, name, state, CPU %, MEM %, RSS. Options: -s/--sort {cpu,mem,pid,name}, -f/--filter NAME, -n/--rows 0=all, --json |
health |
Health checks (see below). Exit status reflects findings (--json supported) |
report |
Machine-readable JSON diagnostic report to stdout or -o FILE; --pretty for indented output |
config |
Show effective configuration, its source file and search order |
tui |
Launch the interactive terminal UI (also the default when no command is given) |
syswatch info
syswatch ps -s cpu -f chrome -n 20
syswatch monitor -i 2
syswatch health --json | jq '.findings'
syswatch report -o /var/tmp/report.json --prettyAll commands work without the TUI dependency, making them safe for cron jobs, scripts and CI.
Every check is always visible in the TUI Health view with its live value, configured threshold and status (normal / warning / critical / unavailable) — even when it passes:
- CPU usage – sampled over
sample_delayseconds; warning abovecpu_warning, critical abovecpu_warning + critical_offset - memory usage – same pattern with
ram_warning - swap usage – same pattern with
swap_warning; reported normal when no swap is configured - filesystem almost full – per mounted filesystem, warning above
disk_warning, critical abovedisk_warning + critical_offset - abnormal load average – 1-minute load above
load_per_core_warning x cores - zombie processes – any process in state
Z - failed systemd services – only where systemd is detectable; shown as unavailable otherwise
- default gateway reachability – ICMP ping when available, TCP probes as fallback; unavailable when no default route exists
CLI exit status: 0 healthy, 1 warnings found, 2 any critical finding.
Three surfaces, all fed by the same evaluate_health() call:
| Surface | Shows |
|---|---|
syswatch health (CLI) |
Only findings — problems above their thresholds. Silence means healthy. |
| TUI Dashboard strip | One-line summary: healthy · no issues detected, N warnings, or N critical. Links to view [4]. |
TUI Health view [4] |
Every check, with live value, threshold, status and note — passing ones included. |
TOML file. Search order: $SYSWATCH_CONFIG, ~/.config/syswatch/config.toml,
/etc/syswatch/config.toml. A path passed via --config overrides all and
must exist.
[thresholds]
cpu_warning = 85.0 # percent, 0-100
ram_warning = 85.0 # percent, 0-100
swap_warning = 85.0 # percent, 0-100
disk_warning = 85.0 # percent, 0-100
critical_offset = 10.0 # added to warning thresholds for critical level
load_per_core_warning = 3.0
[monitor]
interval = 1.0 # seconds between refreshes
[processes]
rows = 15 # default rows shown by `ps`
[tui]
interval = 2.0 # dashboard refresh seconds (>= 0.25)
history = 120 # graph history samples
theme = "" # Textual theme name e.g. "nord", "dracula"
[general]
health_timeout = 3.0 # timeout for systemctl/ping probesTUI thresholds reuse the same [thresholds] values as syswatch health;
every panel — CPU, memory, swap, filesystems — switches to warning/critical
colors using warning_threshold and critical_offset from this table.
Unknown options produce a warning; values outside valid ranges are rejected with a clear error and exit status 1.
Logs go to stderr only (stdout stays clean for output and JSON):
- default: warnings and errors
-v/--verbose: debug logging including per-source collection failures-q/--quiet: suppress log output
Every collector tolerates missing files, malformed /proc content,
permission problems, disappearing interfaces/mountpoints, and unavailable
external commands (systemctl, ping). Partial results are rendered, and
collection failures are reported:
infoprints a "could not be collected" sectionreportincludes acollection_errorsarray- running on a non-Linux platform exits with status 1 and an explanatory message
git clone https://github.com/S0mthingIDK/syswatch
cd syswatch
python3 -m venv .venv
.venv/bin/pip install --upgrade pip
.venv/bin/pip install -e '.[dev]'.venv/bin/python -m pytest -qThe suite is hermetic — collectors accept injectable proc_root / sysfs_root
/ etc_root paths, so tests run against synthetic /proc and /sys trees
in tmp_path rather than the live system. tests/test_tui.py drives the
Textual app headlessly via App.run_test(); it is skipped automatically
(pytest.importorskip("textual")) if the TUI extra is not installed, so
pip install -e '.[dev]' — which includes textual — is required to run
the complete suite.
python -m build # produces dist/*.whl and dist/*.tar.gz
python -m twine check dist/* # metadata sanity check
python -m twine upload --repository testpypi dist/* # test
python -m twine upload dist/* # real PyPIReleases are published automatically by GitHub Actions when a GitHub Release
is created — see .github/workflows/publish.yml. Uses PyPI Trusted
Publishing, no API tokens required.
bin/syswatch checkout launcher (auto-selects the project .venv)
docs/screenshots/ rendered TUI captures (SVG)
tests/ pytest suite incl. headless Textual pilot tests
syswatch/
├── cli.py argument parsing, command handlers
├── config.py TOML loading/validation
├── tui/ interactive terminal UI (Textual)
│ ├── app.py navigation, timers, background workers
│ ├── state.py UI-independent collector hub (no Textual imports)
│ ├── widgets.py dashboard/system/health/about panels
│ └── processes.py process table, filtering, details pane & popup
├── collectors/
│ ├── cpu.py /proc/stat deltas, load average
│ ├── memory.py /proc/meminfo
│ ├── network.py /proc/net/dev counters, /proc/net/route gateways
│ ├── processes.py /proc/[pid] scanning, zombies, CPU deltas
│ └── system.py host identity, statvfs disks, interfaces
├── health.py checks and severity model (findings + per-check statuses)
├── report.py JSON report assembly
├── output.py terminal tables/colors
├── logging_setup.py stderr logging configuration
├── paths.py /proc, /sys, /etc roots (injectable for tests)
├── util.py formatting and safe-read helpers
└── exceptions.py
Non-interactive syswatch is standard-library only. The optional TUI adds
textual; because Textual (as of
8.x) relies on Rich APIs removed in Rich 15, the project pins
rich >=13,<15 alongside it — pipx install 'syswatch-linux[tui]' resolves a
compatible pair automatically.
- CPU/memory percentages are sampled over short windows (
sample_delay), so they are estimates, not long-run averages. - Failed-service detection requires systemd; other init systems are skipped.
- Gateway reachability relies on ping or open TCP ports; firewalled gateways may be reported unreachable when merely filtered.
- IPv4 interface addresses come from SIOCGIFADDR, which reports the primary address only; aliases are not listed.
- Per-process CPU percentages need two refreshes to warm up (they are deltas), so the first sample after launch reads 0.
- CPU frequency is shown only when the kernel exposes it via
cpuinfoor cpufreq; on some VMs neither is available.
Issues and pull requests are welcome. Before opening a PR:
.venv/bin/python -m pytest -q # expect all tests to passKeep new collectors proc_root/sysfs_root-injectable so tests stay
hermetic, and prefer extending evaluate_health() over ad-hoc checks in
the CLI or TUI.
MIT — see LICENSE for the full text.