{"id":51002101,"url":"https://github.com/yeet-src/heatsink","last_synced_at":"2026-06-20T15:33:12.887Z","repository":{"id":363619875,"uuid":"1264147824","full_name":"yeet-src/heatsink","owner":"yeet-src","description":"Live hwmon temperatures, throttle headroom, GPU draw and per-core clocks in one terminal dashboard. htop for thermals.","archived":false,"fork":false,"pushed_at":"2026-06-09T16:46:02.000Z","size":12,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-09T18:09:25.781Z","etag":null,"topics":["cpufreq","dashboard","gpu","hwmon","linux","monitoring","observability","sensors","temperature","terminal","thermal","tui","yeet"],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/yeet-src.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-09T15:51:57.000Z","updated_at":"2026-06-09T16:50:52.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/yeet-src/heatsink","commit_stats":null,"previous_names":["yeet-src/heatsink"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/yeet-src/heatsink","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yeet-src%2Fheatsink","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yeet-src%2Fheatsink/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yeet-src%2Fheatsink/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yeet-src%2Fheatsink/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/yeet-src","download_url":"https://codeload.github.com/yeet-src/heatsink/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yeet-src%2Fheatsink/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34576043,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-20T02:00:06.407Z","response_time":98,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cpufreq","dashboard","gpu","hwmon","linux","monitoring","observability","sensors","temperature","terminal","thermal","tui","yeet"],"created_at":"2026-06-20T15:33:09.672Z","updated_at":"2026-06-20T15:33:12.880Z","avatar_url":"https://github.com/yeet-src.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# heatsink\n\n\u003e **htop for your thermals.** Six columns, four colors, the number that actually predicts a throttle.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://img.shields.io/badge/platform-Linux-1793D1\" alt=\"Linux\"\u003e\n  \u003cimg src=\"https://img.shields.io/badge/built%20with-yeet-8A2BE2\" alt=\"yeet\"\u003e\n  \u003ca href=\"https://discord.gg/dYZu9PjKB\"\u003e\u003cimg src=\"https://img.shields.io/badge/chat-Discord-5865F2\" alt=\"Discord\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n![heatsink demo](assets/heatsink.gif)\n\n**heatsink is a live terminal dashboard that reads every hwmon sensor on a Linux box and shows each one's temperature, throttle limit, and headroom in a color-coded table, with GPU draw and per-core clock speeds below.**\n\n\u003e [!TIP]\n\u003e No kernel modules, no BPF. heatsink queries the kernel's hwmon sysfs tree directly through yeet's graph API, so the same one-liner runs on any Linux box that exposes `/sys/class/hwmon`.\n\n## Quick start\n\n```sh\ncurl -fsSL https://yeet.cx | sh\nyeet run github:yeet-src/heatsink\n```\n[Manual install guide](https://yeet.cx/docs/installation) · Linux only\n\nSort by who's closest to throttling, or grab a single pipe-safe snapshot:\n\n```sh\nyeet run github:yeet-src/heatsink -- --sort head\nyeet run github:yeet-src/heatsink -- --once | less -R\n```\n\n### Flags\n\n**Live dashboard (`main.js`)**\n\n- `--sort \u003ctemp|head|chip|name\u003e` (default `temp`) — `temp`: hottest first; `head`: least throttle headroom first; `chip`: by chip then sensor; `name`: by sensor name.\n- `--interval \u003cms\u003e` (default `1000`, floored at `100`) — live refresh period.\n- `--secs \u003cn\u003e` — exit after n seconds (default: run until Ctrl-C).\n- `--once` — render a single snapshot and exit (automatic when output is piped).\n\n**JSON stream (`dump.js`)**\n\n```sh\nyeet run github:yeet-src/heatsink/dump.js\n```\n\n- `--interval \u003cms\u003e` — stream a record set every interval (default: emit one snapshot, then exit).\n\n## A 60-second primer on hwmon and throttle headroom\n\nThe Linux kernel exposes hardware sensors through the `hwmon` subsystem. Each sensor chip (a CPU temperature controller, an NVMe drive, a voltage regulator) registers under `/sys/class/hwmon/hwmonN/` and publishes temperature readings in millidegrees Celsius, along with optional `_max` and `_crit` thresholds the chip's firmware considers dangerous.\n\n**Throttle headroom** is the gap between the current reading and that threshold. A CPU package 8°C under its `crit` limit is about to throttle; the same chip at 40°C under is fine. The raw temperature tells you where you are; the headroom tells you how much margin you have. heatsink surfaces both, and colors the row to match.\n\n**Per-core clock speed** comes from `cpufreq` (`scaling_cur_freq`). When a core is running flat-out, it boosts to its maximum clock; when the chip is power- or thermally-limited, the clocks back off. The CLOCKS grid shows that spread core-by-core.\n\n**GPU data** (temperature, power draw, utilization) comes from NVIDIA's management layer, not hwmon. It appears in a separate panel below the thermal table when a device is present.\n\n## Common use cases\n\nMostly sysadmins and developers who want to know why a box is slow or loud, without ssh-ing into a stats stack.\n\n- Fan is screaming. What's actually hot right now?\n- Compile job is slower than expected. Are the cores throttling?\n- New server arrived. What sensors does this board actually expose?\n- GPU training run. Is the card power-limited or thermally-limited?\n\n## What you're looking at\n\n**Header line:** box uptime, 1/5/15-minute load average, core count, and the single hottest sensor highlighted in its severity color. The current time sits at the right edge.\n\n**THERMAL table:** one row per hwmon sensor that reports a reading. Columns, left to right:\n\n- `CHIP`: the hwmon chip label (e.g. `k10temp`, `nvme`, `gigabyte_wmi`). This is the hardware source.\n- `SENSOR`: the specific input within that chip (e.g. `Tctl`, `Composite`, `cpu_fan`).\n- `TEMP`: current reading in °C. Color reflects severity: green (ok), yellow (warm), orange (hot), red (crit).\n- Gauge: a filled bar from a 30°C floor to the chip's limit (or 90°C when none is published). Width adapts to terminal width.\n- `LIMIT`: the crit or max threshold the chip published, in °C. A dash means the driver exposes no threshold for this sensor.\n- `HEAD`: degrees of headroom to that limit. This is the number to watch. A dash means no threshold.\n- `STATE`: the severity word. `crit` fires when the driver raises an alarm bit or headroom drops to 5°C or below; `hot` at 15°C; `warm` at 30°C. Sensors with no threshold fall back to absolute temperature bands.\n\nWhen the terminal is too narrow to hold all columns, lower-priority columns drop first. The gauge is flexible and takes whatever space remains, down to its minimum width.\n\n**GPU panel:** appears when an NVIDIA device is detected. Shows the device name, temperature, power draw in watts, and a utilization gauge.\n\n**CLOCKS grid:** one cell per CPU core: label, a block character scaled to current-vs-max ratio, and the current frequency in GHz. A core running at full boost fills the block and turns yellow-green; a throttled or parked core shows a shorter block in blue.\n\n## How it works\n\n**JS side (the whole thing).** heatsink is pure JavaScript with no compiled components.\n\n- `main.js` (entrypoint): terminal management, the render loop, and screen layout. Detects whether stdout is a PTY; if not, it falls back to a single snapshot automatically. Handles column dropping when the terminal is too narrow and clips colored lines to the visible width without breaking ANSI escape sequences. Flags: `--sort`, `--interval`, `--secs`, `--once`.\n- `data.js`: one `yeet.graph.query()` call per refresh, covering `hwmons`, `cpu.cores.cpufreq`, `nvidia`, `load_average`, and `host.uptime`. Converts millidegrees to °C, milliwatts to W, and kHz to GHz. Computes headroom and sensor severity (`ok` / `warm` / `hot` / `crit`). Shared by both `main.js` and `dump.js`.\n- `dump.js`: alternate entrypoint. Emits the same sample as newline-delimited JSON, one record per line, tagged by `kind` (`zone`, `gpu`, `clock`). Pipe to `jq` to filter or stream into other tools. Accepts `--interval` to stream continuously.\n- `demo.sh`: spins up one CPU busy-loop per core to force clock boost and temperature climb, then launches the dashboard. Override the worker count with `LOAD=N`.\n\n**Data flow.** Each refresh: `data.js` queries yeet's graph layer, which reads the relevant sysfs paths and NVIDIA management interfaces. The result is a plain JS object (zones, clocks, GPU, load, uptime). `main.js` sorts and renders it to the terminal in one write per frame, using the alternate screen buffer and cursor positioning to avoid flicker.\n\n## Requirements\n\n\u003e [!IMPORTANT]\n\u003e yeet itself is the only hard requirement. The hwmon subsystem is present on all mainstream Linux distributions by default; no special kernel config is needed. NVIDIA GPU data requires the NVIDIA driver to be loaded. Per-core clock data requires the `cpufreq` subsystem, which is enabled by default on most x86 and ARM systems.\n\n- The yeet daemon, which handles process sandboxing and the graph API. `curl -fsSL https://yeet.cx | sh` installs it.\n\n## Honest caveats\n\n\u003e [!NOTE]\n\u003e What heatsink doesn't do, and where it gets things wrong.\n\n- Every reading is an instantaneous snapshot. There are no counters, no rate calculations, no min/max history. A brief throttle event between refreshes is invisible.\n- hwmon coverage depends entirely on what drivers are loaded on the box. A board probe that the kernel driver never fills shows no input and is silently dropped. What you see is what the kernel exposes; sensors the driver doesn't publish are absent with no indication.\n- Sensor names (`Tctl`, `Tdie`, `Composite`) are driver-defined and vary by hardware. The `CHIP` and `SENSOR` columns show raw driver strings; there is no normalization or aliasing across machines.\n- GPU support covers NVIDIA only, via the device's management interface. AMD and Intel GPUs may surface a temperature through hwmon (when their driver publishes one) but do not appear in the dedicated GPU panel with power and utilization data.\n- The severity thresholds (`crit` ≤ 5°C headroom, `hot` ≤ 15°C, `warm` ≤ 30°C) are fixed in code. They are not configurable. Sensors that publish no `crit` or `max` value use absolute temperature bands (85°C / 70°C / 55°C) that may not match the actual hardware limit.\n- Headroom calculations use whichever of `crit` or `max` the driver publishes. Some drivers publish both with different meanings; heatsink prefers `crit` when present.\n\n## Community questions\n\n**1. Why are some sensors missing a HEAD / LIMIT value?**\nNot all hwmon drivers publish a `crit` or `max` threshold. When the driver exposes no threshold for a sensor, heatsink has no limit to measure against, so HEAD and LIMIT both show a dash. Severity for those rows falls back to absolute temperature bands.\n\n**2. Will this affect my system's performance or thermals?**\nOne sysfs round-trip per second at default settings. The read load is negligible. `demo.sh` does spin up CPU workers intentionally to generate heat for demonstration; that's opt-in and stops when you Ctrl-C.\n\n**3. Why don't I see my GPU / some sensors?**\nhwmon reports only what the loaded kernel drivers publish. If a sensor chip has no driver, or the driver doesn't populate a given input, the reading is absent. NVIDIA GPU data specifically requires the proprietary NVIDIA driver. On AMD systems, GPU temperature may appear as an hwmon zone (`amdgpu`) but the dedicated GPU panel (with power and utilization) will be empty.\n\n**4. Is this safe to run on shared or production infrastructure?**\nheatsink reads sensor data only; it writes nothing to the system. It does not attach to other processes, does not trace network traffic, and does not modify kernel state. Running it on a production box is equivalent to running `cat /sys/class/hwmon/hwmon0/temp1_input` in a loop.\n\n**5. How is this different from `sensors` (lm-sensors) or `psensor`?**\n`sensors` (the lm-sensors CLI) also reads hwmon, but it prints a one-shot human-readable dump with no headroom calculation, no sort order, no GPU panel, and no clock spread. `psensor` is a GUI application. heatsink is a live terminal dashboard that adds the headroom column (the number that predicts throttling), per-core clock visualization, and pipe-friendly JSON output via `dump.js`, all in a single `yeet run` without installation.\n\n## License\n\nheatsink is pure JavaScript and currently ships without a dedicated license file in this repository.\n\n---\n\nBuilt with [yeet](https://yeet.cx/docs/?utm_source=github\u0026utm_medium=readme\u0026utm_campaign=heatsink), a JS runtime for writing eBPF programs on Linux machines. Join us on [discord](https://discord.gg/dYZu9PjKB?utm_source=github\u0026utm_medium=readme\u0026utm_campaign=heatsink).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyeet-src%2Fheatsink","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyeet-src%2Fheatsink","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyeet-src%2Fheatsink/lists"}