Skip to content

About

TermSaver: an ultra-lightweight terminal dashboard and screensaver with live system telemetry and Lua plugins (Windows + Linux)

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

telemetrix

TermSaver: a very light terminal screensaver and live system dashboard for Windows 11 and Linux, written in Rust.

It shows CPU, memory, swap, disks and CPU temperature (where the computer reports it), plus cards from small Lua plugins: exchange rates, crypto prices, weather, an internet speed test, internet latency, a clock, uptime, or anything you write yourself. It uses about 8 MB of memory without plugins and about 12 MB with the seven default plugins, and almost no CPU on the static theme. Settings live in a commented telemetrix.toml that a wrong value can never break.

What it looks like

telemetrix with the Matrix theme: CPU, RAM, swap, two GPUs, disks, crypto and currency graphs, internet latency, speed test and weather over digital rain

The Matrix theme in Windows Terminal: system cards on the left and in the middle, plugin cards on the right, digital rain behind them. Press t to switch to the quiet minimalist theme or to one of the other themes (see Themes).

Install

Download a release. Open the Releases page and take the file for your system:

  • Windows: telemetrix-<version>-windows-x86_64.zip. Unpack it and start telemetrix.exe from Windows Terminal. Windows may warn that the program is from an unknown publisher, because it is not signed; choose "More info", then "Run anyway".
  • Linux: telemetrix-<version>-linux-x86_64.tar.gz. Unpack it with tar -xzf and run ./telemetrix in a terminal.

The program is one file. Copy it to any folder on your PATH.

Or build it with Rust (1.95 or newer; see Build from source for the C compiler it needs):

cargo install --git https://github.com/OliverD25/telemetrix

Quick start

telemetrix                        # open the dashboard
telemetrix --exit-on-any-key      # screensaver mode: any key closes it
telemetrix snapshot               # print the numbers once, no dashboard
telemetrix screensaver install    # open it full screen when the PC is idle (Windows)

In the dashboard: t picks a theme, s opens the settings, l shows the log, ? lists all keys, q quits. Every change you make is saved at once.

Where things live

What Windows Linux
Settings file %APPDATA%\telemetrix\telemetrix.toml ~/.config/telemetrix/telemetrix.toml
Plugins (.lua files) %APPDATA%\telemetrix\plugins ~/.config/telemetrix/plugins
Plugin data (stored rates, results) %LOCALAPPDATA%\telemetrix\plugins ~/.local/share/telemetrix/plugins
Screensaver watcher's copy of the program, and its log watch.log %LOCALAPPDATA%\telemetrix\screensaver (none)

The settings file appears the first time you change something in the dashboard; telemetrix config init writes it now, with a comment on every key. telemetrix config path prints the path in use. The default plugins are built into the program and are copied into the plugins folder on the first start. See Settings and Where plugins live for the details.

Build from source

You need Rust 1.95 or newer. On Windows you also need the Visual Studio C++ build tools, because the Lua interpreter is compiled from C source.

cargo build --release

The program is target/release/telemetrix (telemetrix.exe on Windows), about 3.3 MB. It is all you need: the eight built-in plugins are part of it, and it installs them on its first start (see Where plugins live). It works the same from any folder.

telemetrix                        # the dashboard
telemetrix --theme minimalist     # start with the quiet theme
telemetrix --exit-on-any-key      # screensaver mode: any key quits

Keys

Key What it does
q, Esc, Ctrl+C quit (Esc closes an open box first)
t open the theme box: Up/Down (or t/T) preview each theme live, Enter saves it, Esc goes back; q does not quit while the box is open. Right or o opens the options of the highlighted theme (see Options per theme)
v the next CPU view of the current theme: bar, chart, both (saved at once)
s settings: pages on the left, their settings on the right; / searches them all. Every change is saved at once (see The settings box)
+ / - more / fewer frames per second (saved)
space pause the animation
l log, with the program's own memory use at the top
r look for new, changed and removed plugins now
u when the status bar says update ready · u restart: install the new version if needed and restart into it (see Updates)
g run the speed test now (a plugin's own key)
? help

The settings box

s opens the settings. The categories are on the left, the settings of the chosen one on the right:

╭ Settings ─────────────────────────────────────────────────╮
│ > Appearance │   theme                 matrix             │
│   Cards      │   fps                   15                 │
│   Plugins    │ [options of matrix]                        │
│   Updates    │   cpu_view              bar                │
│   System     │   ram_view              bar                │
│              │   chart_height          medium             │
│              │   color                 green              │
│              │ [cards of matrix]                          │
│              │   cpu                   on                 │
│↑↓ choose · → open · / search · Esc close                  │
│changes apply live and are saved at once                   │
╰───────────────────────────────────────────────────────────╯
Page What is on it
Appearance theme and fps; the options of the current theme (CPU and RAM view, chart height, accent) and its cards on or off; units; the keys of one theme only (matrix density, speed and colour, minimalist sparklines)
Cards the warning thresholds, the disk and network drive options, the GPU card, the history length
Plugins the switch for all plugins, then every plugin file with on, off or error. Right opens a plugin's own page: enabled, interval and its own settings, like the weather city or the main bank
Updates the version, the latest release, check now, install now, and the automatic update settings (see From the settings box)
System screensaver mode (exit_on_any_key), the log file and its length, the plugin folder, the memory budgets, the plugin limits and the metrics intervals

Keys:

  • On the category list: Up/Down choose a page, Right or Enter opens it, Esc closes the box. The box always opens at Appearance.
  • On a page: Up/Down move, Right or Enter picks the next value, Left the previous one, Shift with Left/Right moves ten steps. On a plugin, Right or Enter opens its page. Esc or Backspace goes back one level: from a plugin's page to the plugin list, from a page to the category list.
  • Left on a row without a value to step also goes back one level: on a plugin in the list, on check now, on a text setting and on the paths, which are shown but can only be changed in the file. So Left never does nothing, and it never changes a value by surprise on a row that has no values.
  • / searches every setting on every page, including each plugin's page, by its name and its key in the file, in any letter case. The results show where each one is: Cards › gpu › enabled, Plugins › weather › city. Up/Down choose, Enter opens that page with the setting chosen, Esc goes back to where you were.
  • Text: on the weather city, Enter opens a search list: type a few letters, pick the place with Up/Down and Enter. On a text setting, Enter opens an input line: type the text, Enter saves it and the plugin runs at once, Esc cancels. While you type in any of these, and in the / search, every key goes to the text; only Ctrl+C quits.

A page longer than the box scrolls. On a terminal narrower than 60 columns or shorter than 11 rows (down to 40×10), the category list becomes one line of letters on top, A C P U S, followed by the name of the open page:

╭ Settings ──────────────────────────╮
│  A  C  P  U  S  Appearance         │
│  theme             matrix          │
│  fps               15              │
│[options of matrix]                 │
│↑↓ · → open · / · Esc close         │
│changes apply live and are saved at │
╰────────────────────────────────────╯

Flags

Flag Meaning
--config <path> use this settings file
--theme <name> minimalist, matrix, tokyo-night, crt-amber, cyberpunk, nasa, pip-boy, synthwave, kernel-log or ascii-dashboard
--fps <n> frames per second for animated themes, 1..60
--plugins-dir <dir> folder with .lua plugins
--no-plugins run no plugins
--exit-on-any-key screensaver mode: any key quits
--log <path> also write the log to this file
-h, --help / -V, --version help / version

Flags never write to the settings file. If you change a value in the dashboard that a flag set, your choice wins from then on.

Commands without the dashboard

These need no terminal window, so scripts and agents can use them.

Command What it does
telemetrix snapshot [--json] [--plugins] read the metrics once (and run every plugin once) and print them
telemetrix config init [--force] write the default settings file with comments
telemetrix config path print where the settings file is and whether it exists
telemetrix config check [--json] list every problem in the settings file, with line numbers; exit 1 if there is one
telemetrix config show print every setting, its value and where it came from (default, file or flag)
telemetrix config reference print the settings table below
telemetrix plugin check <file> [--json] [--run] run a plugin once and print its card, its settings and any error; exit 1 on error. --run acts like the plugin's key, so the speed test really runs
telemetrix plugin check <file> --search <text> [--json] run the plugin's search(text) once and print the list the s box would show, for example the weather places for lvov
telemetrix plugin list list the plugins that would run, the plugin home, and whether each one is built-in, built-in-edited or yours
telemetrix plugin install [--force] [name...] install or update the built-in plugins now; --force also replaces your edits and restores deleted ones (all, or only the named ones)
telemetrix themes list the theme names
telemetrix update [--check] [--dry-run] [--force] install the latest release from GitHub; --check only says whether it is newer. See Updates
telemetrix screensaver install [--idle-minutes N] [--dry-run] open the dashboard full screen after N minutes without input (Windows); on Linux print the idle-daemon line. See As a screensaver
telemetrix screensaver uninstall [--dry-run] / status remove it / show whether it is installed and running
telemetrix screensaver update [--dry-run] after cargo install: copy the new program to the watcher and restart it. See Updating telemetrix
telemetrix selftest --memory [--seconds N] [--json] measure memory against the budgets; exit 1 if over (see below)

Themes

  • matrix (the default): digital rain behind the cards, 15 frames per second. Density, speed and colour are in [theme.matrix]. On very large terminals (over 20 000 cells) it limits itself to 10 frames per second.
  • minimalist: grey cards, colour only where a value is above its threshold.
  • tokyo-night: the Tokyo Night colours: a dark slate background with quiet blues, purples and soft accents.
  • crt-amber: an old amber monitor: amber on near-black, heavy card frames, and every second row a little darker, like scanlines.
  • cyberpunk: a neon HUD: magenta titles in [ brackets ], cyan frames and yellow values on a near-black background.
  • nasa: a mission control console in white and amber on black. Every value is a table row with a short code (CPU-LD, MEM-US, DSK-C), the value, its unit and a status: NOMINAL, CAUTION (above 85 % of the warning threshold) or WARNING. The top line shows the time since the computer started (MET) and the UTC day and time (GMT). Static.
  • pip-boy: a green wrist-computer screen in one hue at several brightness levels. Plain ASCII frames (+--+), bracketed tabs ([STAT] [DATA] [RADIO]) and [▮▮▮▯▯] gauges. A warning is the brightest shade. No rain. Static.
  • synthwave: an 80s neon sunset. The sky goes from deep purple to magenta, a striped sun sits on the horizon, and a wireframe grid floor moves slowly toward you. Card frames fade from purple at the top to orange at the bottom. Animated: it follows general.fps and the space pause, and like matrix it limits itself to 10 frames per second above 20 000 cells. Only the floor lines change between frames.
  • kernel-log: a Linux boot log. Every change of a value adds a record like [ 1234.567890] [ OK ] cpu0: load 23% temp 52.0C or [ WARN ] disk C: 91% used, and the view scrolls. The time is seconds since the computer started, as dmesg counts it. A pinned status block (on the right, or on top on narrow screens) always shows the current values and every plugin row. The log keeps the last 500 records. Static: it redraws only when new data arrives.
  • ascii-dashboard: large bar charts of the CPU and RAM history in block characters (▂▄▆█), green at the bottom, yellow and red near the top, with a 0..100 scale. They show as many samples as fit, up to metrics.history_len, and grow taller when the screen has room. Disks, GPUs and swap get horizontal block bars that fill in eighths of a cell. Plugin cards look as usual, with their trend rows. Static.

Every theme except matrix and synthwave is static: it redraws only when data changes, so it uses almost no CPU. Press t to try them with a live preview.

All themes show the same values. Below 40 by 10 cells the screen only says "terminal too small". Most themes show the same cards and rows, and only the colours, frames and background differ. nasa shows the values as table rows, kernel-log as log records next to a status block, and ascii-dashboard draws the CPU and RAM history as large charts. The card themes lay the cards out in three columns on wide terminals, two on medium ones and one on narrow ones. The status bar and the boxes (s, l, t, ?) look the same in every theme.

Options per theme

Every theme has its own options in its own table, [theme.<name>]. A change in one theme never changes another.

[theme.synthwave]
cpu_view = "chart"          # bar | chart | both
ram_view = "bar"            # bar | chart | both
chart_height = "tall"       # small | medium | tall
hide = ["swap", "clock"]    # cards not shown
order = ["crypto", "cpu"]   # these cards first, in this order
accent = "cyan"             # default, a colour name or #rrggbb
  • cpu_view, ram_view: bar is the one-line gauge. chart is the tall history chart of ascii-dashboard: a scale from 0 to 100, the columns coloured by height, and a line with the average and the peak. both shows the chart and the gauge. ascii-dashboard uses chart by default, every other theme bar. The chart shows the last metrics.history_len samples that fit the card.
  • chart_height: the most rows one chart takes: 4, 10 or 20. A chart never takes more than the space its column has left, and never fewer than 2 rows.
  • hide: card ids that are not shown. The ids are cpu, ram, swap, gpu, disks, network and the plugin ids (the file names, like clock, crypto, currency, hosts, weather, speedtest, network_ping, uptime). An id that names no card gets one warning in the log and in telemetrix config check, and is ignored.
  • order: the listed cards come first, in that order; the others follow in their usual order. The cards then fill the columns one after another. With an empty order the system cards stay on the left and the plugins on the right.
  • accent: the main colour of the theme: the card titles and gauges, the phosphor colour of crt-amber and pip-boy, the codes of nasa and the titles of kernel-log. matrix keeps its color key for this.

nasa draws its tables either way; a chart view adds the chart under its rows. kernel-log shows no bars or charts, so the views and the chart height do nothing there, and the options boxes say "(not used by this theme)". hide, order and accent work in every theme.

Three ways to change them:

  • The t box: highlight a theme and press Right or o. The options box shows CPU view, RAM view, chart height, accent and every card with [x] (shown) or [ ] (hidden). Up/Down move, Left/Right or Enter change a value, Space switches a card on or off, [ and ] (or Shift with Up/Down) move a card in the order. Every change shows at once behind the box. s or the Save row writes all changes of that theme to the file in one step; Esc puts them back.
  • The s box: the Appearance page has the groups "options of " and "cards of " with the same rows (without the order) and saves every change at once.
  • v cycles the CPU view of the current theme and saves it.

GPU card

Set gpu.enabled = true, or turn it on in the s box, to show one card per GPU: the GPU's name, its load, the video memory used and total, and the temperature. The temperature follows units.temperature and turns red above thresholds.temp_warn_c. gpu.interval_ms sets how often the card is read (every 2 seconds by default). With three columns the cards sit under Swap; with two or one column they come after Disks. With two GPUs, the one with more video memory is GPU 1.

gpu.source says where the numbers come from:

  • auto (the default). On Windows, the counters Task Manager uses: the adapter statistics of the Windows display kernel (D3DKMT). Every GPU with a current driver answers, NVIDIA, AMD and Intel alike. The load is the busiest engine's share of the time, as in Task Manager's GPU column. The memory is the dedicated video memory. The temperature shows when the driver reports it. There is no power reading: Windows gives power only as a share of the card's limit, not in watts. On Linux, auto reads the files the amdgpu driver writes in /sys/class/drm (load, video memory, and the temperature of the card's sensor). NVIDIA's own driver does not write these files, so use nvml for an NVIDIA card on Linux.
  • nvml: NVIDIA's NVML library, which comes with the NVIDIA driver (nvml.dll on Windows, libnvidia-ml.so.1 on Linux). It also gives the power draw in watts, but it shows NVIDIA GPUs only.

The card needs no extra program. Without any readable GPU it stays hidden, and the log (l) says why.

Memory. On the test PC (an RTX 4090 and an AMD Radeon iGPU) the auto source adds about 1.3 MB of working set and 0.3 MB of private memory (selftest --memory: 7.9 → 9.1 MB without plugins, 11.9 → 13.1 MB with the 7 default plugins). Almost all of it is Windows' gdi32.dll, which telemetrix loads only while the card is on; the readings themselves cost next to nothing. That leaves little room under the 14 MB total budget, so the card is still off by default. NVML is much larger: the working set grows by about 24 MB when it starts, and it stays at that size until the program ends. telemetrix snapshot always lists the GPUs from gpu.source, because it ends right after.

Readings of both sources on the test PC, at rest, compared with Windows' own performance counters (the ones Task Manager shows):

RTX 4090 auto (D3DKMT) nvml Windows counters
load 0.0 – 0.2 % 0 – 2 % 0.08 %
video memory used 7.60 GiB 8.0 GiB 7.50 GiB
video memory total 23.6 GiB 24.0 GiB
temperature 54.2 °C 54 °C
power (none) 49.3 W

NVML counts the memory the driver keeps for itself as used and as part of the total; Windows leaves it out of both. The AMD iGPU (only auto shows it) read 0 % load, 0.22 GiB of 0.47 GiB video memory and 39 – 40 °C.

Disks and network drives

The Disks card shows each local drive with its label, as Explorer does: "System Disk (C:)". Long names are cut with "…" so the numbers stay visible.

Mapped network drives get their own Network card under Disks. On Windows they are asked on a separate thread every disks.network_interval_s seconds; a drive that does not answer within disks.network_timeout_s is shown as offline in red, and a stuck drive never slows the rest of the dashboard. Drives on the same server with the same size and free space (several shares of one NAS volume) share one row, for example nas M: P: R: W: X:; set disks.group_network = false to list them one by one. Explorer "network locations" without a drive letter are not shown. disks.hide hides letters or mount points in both cards.

On Linux, mounts of type nfs, nfs4, cifs, smb3, smbfs, fuse.sshfs and 9p go to the Network card. A hung network mount can still delay the disk readings there; protecting against that is planned after v0.1.

All eight extra themes from the original brief are here: tokyo-night, crt-amber, cyberpunk, nasa, pip-boy, synthwave, kernel-log and ascii-dashboard.

Where plugins live

Plugins are .lua files in one folder, the plugin home: the plugins folder next to the settings file.

  • Windows: %APPDATA%\telemetrix\plugins
  • Linux: ~/.config/telemetrix/plugins (or $XDG_CONFIG_HOME/telemetrix/plugins)
  • Portable mode (a telemetrix.toml next to the program): the plugins folder next to that file.

telemetrix looks in this order: --plugins-dir <dir> (relative to the current folder), then general.plugins_dir in the settings file (relative to the settings file's folder; empty means the home), then the home. The old default plugins_dir = "plugins" from v0.1 settings files means the home too. The folder in use is written to the log (l) on every rescan, and an empty Plugins card shows it.

Built-in plugins. The eight built-in plugins are part of the program (seven run by default; Hosts is off until you set it up). On every start, telemetrix copies them into the home and remembers what it wrote in .bundled.json there:

  • a built-in plugin that was never installed is installed;
  • one you have not changed is updated when a new telemetrix brings a new version;
  • one you changed is never touched; the log says so once per start and names the command that would replace it;
  • one you deleted stays deleted.

Files that are not built in are never touched.

To change a built-in plugin, edit its file in the home. telemetrix keeps your version from then on. To go back to the built-in version, run telemetrix plugin install --force weather. To restore a plugin you deleted, run the same command with its name. To add your own plugin, put a new .lua file into the home and press r; see PLUGINS.md.

For development, start telemetrix from the repository with --plugins-dir plugins. It then reads the plugins from the repository folder, so a change to plugins/weather.lua shows after r.

Plugins and where their data comes from

telemetrix comes with eight plugins. None needs an account or a key. The network plugins stay far below the free limits of their services. When a service does not answer, a card keeps its last values and marks them stale. Rates, prices, the weather place and speed results are kept in a small file per plugin (%LOCALAPPDATA%\telemetrix\plugins on Windows, ~/.local/share/telemetrix/plugins on Linux, or --data-dir <dir>), so cards are not empty after a restart.

Plugin Shows Data source Free limit How often telemetrix asks
Currency USD, EUR, GBP to hryvnia from one bank (the other as backup), 7-day, 30-day and 1-year graphs Monobank api.monobank.ua/bank/currency; PrivatBank card rate api.privatbank.ua/p24api/pubinfo; NBU official rate bank.gov.ua/NBU_Exchange Monobank: 1 request per 5 minutes; the answer is cached on their side. PrivatBank and NBU publish no limit. Monobank and PrivatBank every 5 minutes (Monobank never sooner, even after a restart). NBU history once a day, one request per currency for the whole year (about 75 KB).
Crypto BTC, ETH, SOL in USDT, 7- and 30-day graphs Binance api.binance.com/api/v3/ticker/price and /klines A request weight of 6000 per minute per IP address (Binance's exchangeInfo, checked 2026-09-26). An address that keeps asking after HTTP 429 is banned for 2 minutes up to 3 days (HTTP 418). After a 429 the plugin stops asking until the next interval. After a 418 it waits as long as Binance's Retry-After header says, or else 10 minutes, doubled for every 418 in a row up to 24 hours; the card keeps its stored prices and shows a red line paused by Binance until 14:32. Prices every minute (one request). Daily history once an hour, one request per coin.
Weather now, tomorrow and the day after Open-Meteo api.open-meteo.com and its geocoding service Free for non-commercial use: 600 requests a minute, 5,000 an hour, 10,000 a day (open-meteo.com/en/terms, checked 2026-09-26). The data is licensed CC BY 4.0, which requires attribution. Every 10 minutes. A search in the s box sends at most 6 requests and keeps answers for 10 minutes; a city typed in the file is looked up once per change.
Speed test download, upload, ping, server the nearest Ookla speed-test server; Cloudflare speed.cloudflare.com as the backup No published limit. Every 30 minutes, and when you press g. Never at start. The server list once a day.
Internet latency time to connect to 1.1.1.1:443 a TCP connection, no service none every 30 seconds
Clock, Uptime time and date; computer name and uptime this computer none every second; every 30 seconds
Hosts (off by default) health, load, memory, disk, uptime and UPS of your own servers commands you list in [commands], for example ssh none every 5 minutes, and when you press h

Weather data by Open-Meteo.com (CC BY 4.0). The weather card says so in its last line, data: Open-Meteo.com.

The speed test uses a lot of data. It runs for a fixed time, not a fixed size: 3 seconds per direction over 2 connections. So each test moves about (download speed + upload speed) × 3 seconds. On a 935/933 Mbps line that is about 700 MB per test, and at the 30-minute interval about 34 GB a day, or about 1 TB a month. On a metered connection, raise the interval, lower streams or seconds in the s box, or set enabled = false under [plugin.speedtest].

Where the speed test measures. It asks Ookla's public server list (www.speedtest.net/api/js/servers) for the five nearest servers, pings each and uses the fastest one for 24 hours. This is the same list the open-source speedtest-cli uses. It is not an official API, so it may change without notice; that is why Cloudflare is the automatic backup. When the backup is used, the card says Cloudflare (backup) and the log says why. Cloudflare's servers can be farther away, so its numbers are often lower.

Settings you can change in the s box:

  • Currency: the primary bank, mono or privat, and show_year (default on). The card shows that bank's buy and sell rates next to each currency code. On the right, a grey column shows the 7-day graph of the official NBU rate on the currency's line, the 30-day graph under it and, with show_year, the 1-year graph under that; each change is green when the rate rose and red when it fell. The other bank is only a backup: the card switches to it when the primary bank fails and has no rates from the last hour, and the title then says (backup). Rates from a failed bank that are less than an hour old stay on the card with a red stale since 14:32 (HTTP 429) line. Monobank has no buy/sell rate for GBP, so the card shows its cross rate; PrivatBank has no GBP at all, so the card shows the NBU rate. On a card narrower than 37 characters all graphs are left out (they are all the same width) and only the rates stay. The list of currencies (currencies = ["USD", "EUR", "GBP"]) is set in the file. The v0.2 keys compact and show_month are no longer used.

  • Crypto: the quote currency (default USDT). The coins (coins = ["BTC", "ETH", "SOL"]) are set in the file.

  • Weather: the city and the preferred country. Enter on the city row opens a search list: type a few letters, even misspelled, an old Russian name like kiev or lvov, or Cyrillic; pick the place with Up/Down and Enter. That saves city, lat, lon and place, so the card shows exactly that place. Places in country (default UA; empty = any country) come first in the list, then the biggest. A city typed by hand in the file still works. The coordinates alone (with label as the card title) are used only when no city is set: settings files from v0.1 have lat, lon and label but no city, so they keep showing the same place. Without a city and without coordinates the card shows Kyiv. The log says which one is used, and config check warns when a file has a city and coordinates but no picked place. Temperatures follow units.temperature (°C or °F); changing it redraws the card at once.

  • Speed test: server (empty = the nearest Ookla server, host:port forces one, cloudflare uses Cloudflare only), streams (parallel connections, 1..8) and seconds per direction (2..10). The old keys download_mb, upload_mb and max_seconds are ignored.

  • Hosts: set in the file only. List your servers under [plugin.hosts] and the commands that read them under [commands], then set enabled = true. telemetrix runs only the commands you list there, by name, never through a shell. See the hosts notes in PLUGINS.md and the commented example in telemetrix.example.toml.

To write your own plugin, see PLUGINS.md.

Settings

The settings file is found in this order:

  1. --config <path>
  2. the environment variable TELEMETRIX_CONFIG
  3. telemetrix.toml next to the program
  4. Windows: %APPDATA%\telemetrix\telemetrix.toml; Linux: $XDG_CONFIG_HOME/telemetrix/telemetrix.toml or ~/.config/telemetrix/telemetrix.toml

Without a file the defaults are used. The first change you make in the dashboard creates the file, with a comment on every key. telemetrix.example.toml in this repository is the same file.

A bad settings file never stops the program:

  • A missing key uses its default.
  • An unknown key is ignored, with a warning in the log.
  • A wrong value (wrong type or out of range) uses the default for that key only, with a warning.
  • A syntax error keeps the last good settings and shows a red line at the top of the screen with the line number.
  • The running dashboard picks up a saved change within 2 seconds.

Each plugin can have its own [plugin.<name>] section; see PLUGINS.md.

Settings reference

This table is printed by telemetrix config reference. A test fails when it no longer matches the program.

Key Default Allowed values In the s overlay Meaning
schema 1 1..1 no, edit the file format version of this file, do not change
general.theme "matrix" minimalist | matrix | tokyo-night | crt-amber | cyberpunk | nasa | pip-boy | synthwave | kernel-log | ascii-dashboard yes minimalist | matrix | tokyo-night | crt-amber | cyberpunk | nasa | pip-boy | synthwave | kernel-log | ascii-dashboard
general.fps 15 1..60 yes frames per second for animated themes, 1..60
general.exit_on_any_key false true | false yes true = screensaver mode: any key quits
general.plugins_dir "" a file or folder path no, edit the file empty = the plugins folder next to this file; relative paths start there
general.log_file "" a file or folder path no, edit the file "" = off, otherwise a file path
general.log_lines 200 50..2000 yes lines kept for the l overlay, 50..2000
units.temperature "celsius" celsius | fahrenheit yes celsius | fahrenheit
units.bytes "binary" binary | decimal yes binary = GiB, decimal = GB
metrics.cpu_interval_ms 1000 200..60000 yes 200..60000
metrics.memory_interval_ms 1000 200..60000 yes 200..60000
metrics.temps_interval_ms 5000 1000..60000 yes 1000..60000
metrics.disks_interval_ms 30000 1000..600000 yes 1000..600000
metrics.history_len 240 10..3600 yes samples kept for sparklines, 10..3600
thresholds.cpu_warn_pct 80 1..100 yes highlight CPU above this, 1..100
thresholds.temp_warn_c 75 1..150 yes highlight temperature above this
thresholds.disk_warn_pct 90 1..100 yes highlight disks fuller than this
gpu.enabled false true | false yes GPU card: load, video memory, temperature; about 1.3 MB more memory, so off by default
gpu.interval_ms 2000 500..60000 yes 500..60000
gpu.source "auto" auto | nvml yes auto = the system's counters (Windows: as Task Manager; Linux: amdgpu files); nvml = NVIDIA's library, about 24 MB more
disks.show_network true true | false yes show mapped network drives in their own card
disks.network_interval_s 60 10..3600 yes how often network drives are asked, 10..3600
disks.network_timeout_s 5 1..30 yes a drive that takes longer is shown offline, 1..30
disks.group_network true true | false yes one row for drives on the same server and volume
disks.hide [] list of texts no, edit the file letters or mount points to hide, like ["X:", "/boot"]
plugins.enabled true true | false yes false = run no plugins at all
plugins.default_interval_s 60 5..86400 yes used when a plugin sets no interval, 5..86400
plugins.http_timeout_s 10 1..60 yes per request, 1..60
plugins.call_timeout_s 5 1..60 yes Lua time limit per update(), 1..60
plugins.memory_limit_mb 8 1..64 yes per plugin, 1..64
plugins.rescan_interval_s 60 0..86400 yes 0 = rescan only on the r key
plugins.max_plugins 16 1..64 yes at most this many plugins run, 1..64
memory.budget_mb 14 5..1024 yes whole program, above it the status bar turns amber
memory.plugin_budget_mb 1 1..64 yes Lua memory per plugin, above it one log warning
update.auto true true | false yes the screensaver watcher installs new releases by itself
update.check_interval_h 24 1..168 yes hours between two checks, 1..168
theme.matrix.density 0.5 0.0..1.0 yes 0.0..1.0
theme.matrix.speed 1.0 0.1..5.0 yes 0.1..5.0
theme.matrix.color "green" green | amber | cyan | white | #rrggbb yes green | amber | cyan | white | #rrggbb
theme.minimalist.show_sparklines true true | false yes history graphs under CPU and RAM
theme.<name>.cpu_view "bar"; ascii-dashboard "chart" bar | chart | both yes; also in the t options panel bar | chart | both
theme.<name>.ram_view "bar"; ascii-dashboard "chart" bar | chart | both yes; also in the t options panel bar | chart | both
theme.<name>.chart_height "medium" small | medium | tall yes; also in the t options panel small | medium | tall: the most rows a chart takes
theme.<name>.hide [] list of card ids cards on/off; also in the t options panel cards not shown: cpu, ram, swap, gpu, disks, network or a plugin id
theme.<name>.order [] list of card ids no; in the t options panel cards shown first, in this order; empty = system cards left, plugins right
theme.<name>.accent "default" default | red | orange | amber | yellow | green | cyan | blue | purple | magenta | pink | white | #rrggbb yes; also in the t options panel the theme's main colour: default, a colour name or #rrggbb

Memory and CPU

Keeping telemetrix small is a main goal. There are two budgets:

  • Core (the dashboard without plugins): under 10 MB working set. This limit is fixed.
  • Total (the default setup, Matrix and the seven plugins): under memory.budget_mb, 14 MB by default. Each plugin gets an allowance of about 1 MB (memory.plugin_budget_mb for its Lua memory).

The dashboard reads its own memory every 5 seconds. The status bar shows it ("self 7.4 MB") and turns amber above the budget. The log (l) shows the peak, the private bytes and each plugin's Lua memory. Going over a budget only writes a warning to the log; nothing is stopped. The warning and the amber colour pause while a speed test runs and for 10 seconds after it, because a test briefly needs a few MB for its connections; the status bar then shows (speed test) next to the number. The separate Lua limit (plugins.memory_limit_mb) still stops a runaway plugin.

Measured numbers

Windows 11, release build, 32-core PC, legacy console, 20 seconds after the start. Working set is what Task Manager shows as memory; private bytes is the memory that belongs to this program alone.

Setup Working set Private bytes
no plugins, minimalist 7.3 MB 1.9 MB
no plugins, matrix 7.3 MB 2.0 MB
2 offline plugins (clock, uptime) 7.9 MB 2.4 MB
1 network plugin (weather) 10.0 MB 2.5 MB
5 plugins, minimalist 11.0 MB 3.4 MB
5 plugins, matrix (v0.1 default) 11.0 MB 3.3 MB
7 plugins, matrix (v0.2 default, selftest --memory, 30 s) 12.5 MB 4.5 MB
no plugins, GPU card on (auto, RTX 4090 + iGPU, selftest --memory, 30 s) 9.1 MB 2.4 MB
7 plugins, GPU card on (auto, RTX 4090 + iGPU, selftest --memory, 30 s) 13.0 MB 4.0 MB
no plugins, GPU card on (NVML, RTX 4090, selftest --memory, 30 s) 31.1 MB 21.9 MB
7 plugins, GPU card on (NVML, RTX 4090, selftest --memory, 30 s) 35.5 MB 23.6 MB

For comparison, a Rust program that does nothing but sleep uses 4.9 MB working set on the same PC. Much of that comes from Windows itself and from other software that loads into every process (for example an antivirus).

CPU, measured over 60 seconds, as a share of one core:

Setup CPU
minimalist, no plugins 0.18 %
matrix at 15 fps, 5 plugins 1.45 %

The first network request loads the TLS code, about 2 MB. That is why one network plugin costs more than two offline ones.

What keeps it small on Windows:

  • CPU usage comes from GetSystemTimes, not from Windows performance counters (PDH), which cost about 4 MB.
  • Temperature sensors are read through WMI, which costs about 3.7 MB, and most Windows PCs report none. A short helper process asks first, and the dashboard loads WMI only if it will get a value.
  • DLLs that are rarely needed are loaded on first use, not at start.
  • All plugins share one HTTP client, which is dropped after a minute without requests.
  • The program uses the Windows segment heap, chosen in its embedded manifest (telemetrix.manifest). With the default heap, private memory crept up by about 1 MB an hour with the default plugins, although the memory in use stayed flat: the heap kept freed space committed and never gave it back. The segment heap gives it back, so private memory stays flat over hours, and the total is about 0.5 MB lower. The dashboard without plugins measures the same with either heap.

Before every release: selftest --memory

telemetrix selftest --memory

It starts the real dashboard twice in a hidden console: once with the default settings and all plugins, then once with --no-plugins. After 30 seconds (--seconds N to change) each run reports its peak and final working set. The command prints both against their budgets and exits with code 1 if either is over. Network plugins run for real; if the network is down they fail, which is fine for this test.

memory selftest: 30 s per run, one run after the other, hidden consoles
            final      peak   private  budget  result
total     11.7 MB   12.2 MB    3.7 MB   14 MB  ok  (7 plugins)
core       7.8 MB    7.8 MB    2.1 MB   10 MB  ok  (0 plugins)

Run it before every release. Agents should run it after any change to the code or the plugins.

Memory growth over time: selftest --memory --soak <minutes>

telemetrix selftest --memory --soak 60

A short run cannot show a slow leak. The soak runs one hidden dashboard with the default plugins (without the speed test, whose test would hide everything else) for 10 minutes of warm-up plus the given minutes. The dashboard notes its private bytes (memory that belongs to this program alone) once a minute. After the warm-up, the command takes the median of the slopes between all pairs of those numbers, which ignores the single jumps of about 0.2 MB when a plugin fetches something, and fails with exit code 1 when private memory grows faster than 0.2 MB per hour. It also fails when the peak is over the budget. --json prints every minute's number.

For a deeper look, build with cargo build --release --features alloc-stats. That build counts the bytes the program holds on its heap, Lua included, and writes a heap: line to the log every minute. Heap bytes that climb mean a leak in the program; flat heap bytes under rising private bytes mean the memory is held outside the program's own allocations.

Linux

telemetrix builds and runs the same way on Linux. You need Rust 1.95 or newer and a C compiler (gcc or clang) for the Lua interpreter.

cargo install --path .

This puts telemetrix in ~/.cargo/bin. Nothing else needs copying: the default plugins are built in and go to ~/.config/telemetrix/plugins on the first start.

  • Settings file: ~/.config/telemetrix/telemetrix.toml, or $XDG_CONFIG_HOME/telemetrix/telemetrix.toml when that variable is set.
  • Start it automatically: see the swayidle and xautolock recipes under "Starting it automatically".
  • Disks: system and package mounts are not shown: snap images (/snap), and on WSL its own mounts (/usr/lib/wsl, /usr/lib/modules, /mnt/wslg, /mnt/wsl, /init). On WSL, the Windows drives at /mnt/c, /mnt/d and so on are local disks of the host and appear as "C: (/mnt/c)".
  • Network drives: nfs, nfs4, cifs, smb3, smbfs, fuse.sshfs and 9p mounts go to the Network card. A hung network mount can still delay the disk readings in v0.1.
  • CPU temperature: read from hwmon. telemetrix prefers the Intel package sensor (coretemp, "Package id 0"), then the AMD control temperature (k10temp, "Tctl"), then any other CPU sensor. WSL and most virtual machines have no sensors; the line is then hidden.
  • Containers: sysinfo takes cgroup limits into account, so inside a container the total RAM can be the container's limit, not the machine's.
  • Signals: SIGTERM, SIGHUP (the terminal was closed) and SIGINT end the dashboard cleanly and restore the terminal. If the terminal is already gone, the program still exits within about a second.
  • selftest --memory needs the script command from util-linux (part of every common distribution); it gives each run a pseudo-terminal.

Measured in WSL 2 with selftest --memory (Ubuntu 24.04, release build, 30 seconds after the start, peak resident memory; Linux has no cheap "private bytes" figure):

Setup Resident memory
no plugins 4.4 MB
7 plugins, matrix (default) 6.6 MB

These are WSL numbers: Linux shares library pages differently from Windows, so they are not comparable with the Windows table above.

Guide for agents

  • Change the settings file safely. Write the new content to a temporary file next to it, then rename it over telemetrix.toml. The dashboard reads the file at any moment and must never see half of it.
  • Check the settings after every change: telemetrix config check. Exit code 0 means no problems; otherwise it lists each one with its line. --json gives the same list for a program.
  • Check a plugin after every change: telemetrix plugin check <file>. Exit code 0 means the card works. See PLUGINS.md.
  • Read the numbers without a terminal: telemetrix snapshot --json --plugins.
  • Keep memory in budget: run telemetrix selftest --memory after a change. Exit code 1 means a budget is broken.

Starting it automatically

Windows Terminal profile

Add a profile to Windows Terminal's settings.json (Settings, then "Open JSON file"), in the profiles.list array:

{
    "name": "telemetrix",
    "commandline": "%USERPROFILE%\\.cargo\\bin\\telemetrix.exe",
    "closeOnExit": "always"
}

The path assumes you installed it with cargo install --path .. Start it full screen with:

wt.exe -F -p telemetrix

A keyboard shortcut on the desktop

  1. Right-click the desktop, then New, then Shortcut.
  2. As the location, enter wt.exe -F -p telemetrix.
  3. Open the shortcut's Properties and click into "Shortcut key".
  4. Press the keys you want, for example Ctrl+Alt+T.

Windows only honours such keys for shortcuts on the desktop or in the Start menu.

As a screensaver when the PC is idle (Windows)

telemetrix screensaver install --idle-minutes 10

After 10 minutes without a key press or mouse move, the dashboard opens full screen in Windows Terminal, in screensaver mode: any key closes it. It uses the Windows Terminal profile telemetrix when you have one (see above) and the default profile otherwise. Without Windows Terminal it opens in a normal console window.

  • telemetrix screensaver install --dry-run prints exactly what would be created and changes nothing.
  • telemetrix screensaver status shows whether it is installed, whether the watcher and a screensaver dashboard run, the last lines of the watcher's log, and how long the PC has been idle.
  • install and update start the watcher and check 5 seconds later that it still runs. If it does not, they say so, show the last lines of its log (watch.log next to the copy) and end with exit code 1. They also refuse to go on while another watcher runs that does not end when asked. Only one watcher can run at a time: a second one ends at once and writes another screensaver watcher is already running; this one ends to the log.
  • Run install and update from a normal terminal. A packaged app (the Claude desktop app, for example) and the programs it starts see %LOCALAPPDATA% through a redirection, so the copy really lands in the app's own folder under %LOCALAPPDATA%\Packages. telemetrix then registers that real folder, because Task Scheduler cannot see the redirected path; install says so with a note: line. It works, but the copy disappears if that app is removed or reset, and status then says copy: missing. Running update from a normal terminal moves it back.
  • telemetrix screensaver uninstall removes it, ends the watcher and deletes the watcher's copy of the program (--dry-run works here too).
  • telemetrix screensaver update copies a new telemetrix to the watcher after an update. See Updating telemetrix.

How it works. install creates a Task Scheduler task named "telemetrix screensaver" that starts a small watcher, telemetrix screensaver watch, at every logon, and starts it once right away. The task runs as you, only while you are logged on, and needs no administrator rights. The watcher has no window. Every 5 seconds it asks Windows how long ago the last input came (GetLastInputInfo). When that passes the limit, it opens the dashboard once; it opens it again only after you have used the PC in between. It does not open a second dashboard while one it started still runs, and it waits while a program (a video player, for example) asks Windows to keep the display on. The watcher uses about 0.7 MB of working set and 1.4 MB of private memory (measured on Windows 11 after 60 seconds) and almost no CPU.

Why not Task Scheduler's own idle trigger? Windows counts the PC as idle only when the CPU and disks are quiet too, and checks that only every few minutes, so the start comes late or never. The logon trigger that starts the watcher is reliable.

The watcher runs from a copy of the program, %LOCALAPPDATA%\telemetrix\screensaver\telemetrix-watch.exe. Windows cannot replace a program file while it runs. If the watcher ran your telemetrix.exe itself, cargo install could not update that file. The copy still opens the dashboard from the telemetrix.exe you ran install with; install writes down its path. If you move telemetrix somewhere else, run install again. If you ran install with --config <file>, the dashboard uses that file.

Updating telemetrix

telemetrix update does all of this by itself, and the screensaver watcher runs it once a day (see Updates). By hand, with cargo install:

  1. Close every telemetrix dashboard. A running dashboard locks telemetrix.exe, so the update would fail with "Access is denied".
  2. Install the new version, for example cargo install --git https://github.com/OliverD25/telemetrix.
  3. If you use the screensaver, run telemetrix screensaver update. It ends the watcher, copies the new program to it and starts it again. telemetrix screensaver status says copy: older than ... when you forgot this step.

A screensaver installed by a build without screensaver update runs telemetrix.exe itself and blocks step 2. Run telemetrix screensaver uninstall with that build first, then update, then run telemetrix screensaver install again. A newer build's telemetrix screensaver update also changes such an older task to use the copy, with the same settings.

An older version of this README suggested a task with /SC ONIDLE and the same name. install replaces it, and uninstall removes it.

On Linux, telemetrix screensaver install writes nothing; it prints the swayidle and xautolock lines below with the right path.

Linux: swayidle (Sway, Wayland)

In your Sway config, start it after 5 minutes without input:

exec swayidle -w timeout 300 'foot telemetrix --exit-on-any-key'

Use your own terminal instead of foot if you like.

Linux: xautolock (X11)

xautolock -time 5 -locker "xterm -fullscreen -e telemetrix --exit-on-any-key" &

Updates

telemetrix updates itself from the GitHub Releases of OliverD25/telemetrix, and from nowhere else.

telemetrix update --check      # only say whether a newer release exists
telemetrix update --dry-run    # show what an update would do
telemetrix update              # download, check and install it

What telemetrix update does:

  1. It asks the GitHub API for the latest release. The request has no login. GitHub allows 60 such requests per hour for one address; when it refuses (HTTP 403 or 429), the command says so and stops.
  2. It compares the release version with its own. An older or equal release changes nothing. --force installs the release anyway.
  3. It downloads SHA256SUMS and the bare program for this platform (telemetrix-<tag>-windows-x86_64.exe or telemetrix-<tag>-linux-x86_64) into the folder of the installed program, as telemetrix.exe.download. Only https is used.
  4. It checks the SHA-256 of the download against the line in SHA256SUMS. When they differ, it deletes the download and stops; nothing else changes.
  5. It replaces the program. On Windows a running program cannot be overwritten, but it can be renamed: the current file becomes telemetrix.exe.old and the download takes its name. The .old file is deleted at the next start. On Linux one rename replaces the file.
  6. If the screensaver is installed, it runs the new program with screensaver update, so the watcher copy follows.

Nothing from the download runs except the checked new program.

What the checksum proves: the program matches the list that the same release publishes, so the download is complete and unchanged on the way. It does not prove who built the release: someone who could change the release could change both files. The trust is in the GitHub account and its release workflow.

Automatic updates

With the screensaver installed (Windows), the watcher looks every hour whether update.check_interval_h (24 by default) has passed since its last check, and then asks GitHub. It keeps the time of the last check in update-check.txt next to its copy, and writes every step to watch.log.

  • No dashboard is open: it downloads, checks and installs the new version, then runs screensaver update, which restarts the watcher from a fresh copy.
  • A dashboard is open: it only downloads and checks, and keeps the file as telemetrix.exe.ready with its checksum in telemetrix.exe.ready.json. It installs it when no dashboard is open any more.

Turn this off with update.auto = false (also in the s box). On Linux there is no watcher; run telemetrix update yourself or from a timer.

In an open dashboard

The dashboard looks once an hour for a ready download or a newer program file. Then the status bar shows update ready · u restart. Press u: the dashboard installs a ready download if needed, gives the terminal back and starts the new version in the same window with the same arguments.

  • On Linux the new version replaces the old process (exec).
  • On Windows a program cannot replace itself. In Windows Terminal the shell (for example powershell -NoExit -Command & telemetrix.exe) waits for the dashboard; if the dashboard ended at once, the shell would show its prompt and read keys while the new dashboard draws. So the old process starts the new one in the same console, gives back its memory and waits for it. It then ends with the new one's exit code. While it waits it uses almost no memory and no CPU.

From the settings box

The Updates page of the s box has these rows:

Row What it shows or does
version this program's version
latest the latest release and when it was checked (UTC), not checked yet, or a short error like check failed: no network (the log has the whole message)
check now Enter asks GitHub, in the background, as telemetrix update --check does. The row shows checking…; the answer comes as a short message: up to date, v0.3.2 available, or this build is newer than v0.3.0
install now only when a newer release is known. Enter downloads it in the background (downloading 42%), checks its SHA-256 (verifying) and installs it the same way telemetrix update does, including screensaver update when the screensaver is installed. Then the status bar shows update ready · u restart. A failure or a checksum mismatch changes nothing and shows the reason
auto, check_interval_h the settings of the automatic updates above

Only one check or install runs at a time; Enter while one runs says already running. Right does nothing on these rows, and Left goes back to the category list.

Questions and bugs

Please open an issue: https://github.com/OliverD25/telemetrix/issues. Say which system you use (Windows or Linux), the telemetrix version (telemetrix --version), and what you saw. For a plugin problem, add the output of telemetrix plugin check <file> --run.

License

Either MIT or Apache-2.0, at your option.

About

TermSaver: an ultra-lightweight terminal dashboard and screensaver with live system telemetry and Lua plugins (Windows + Linux)

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages