# ThermalFlow (CLI prototype) This is a working prototype that turns a repeatable CPU benchmark into a persistent trend history: every "run" appends one measurement (single-thread and multi-thread ops/sec, plus a scaling factor) to a local JSON-lines file, and ThermalFlow then compares each new measurement against the machine's own history to flag REGRESSION, IMPROVEMENT, or STABLE. That is the real "why pay more for Team" mechanism over the sibling CorePilot tool: CorePilot runs one benchmark and prints a one-shot report with nothing remembered between runs, while ThermalFlow is built around calling the same benchmark repeatedly over time (from cron / Task Scheduler, or its own built-in --interval polling loop) and answering "how has this machine's performance changed" - the fleet-monitoring question an IT team actually cares about. The regression threshold is 10%: a run's ops/sec more than 10% slower than the comparison baseline is REGRESSION, more than 10% faster is IMPROVEMENT, otherwise STABLE. 10% was chosen as comfortably above the few-percent run-to-run jitter a real benchmark shows on the same machine (see the functional testing evidence gathered while building this tool) while still catching real regressions - a throttling CPU, a background process eating cores, a bad driver update - promptly. Be explicit about scope: this prototype measures CPU throughput only. Real temperatures, fan curves, CPU affinity control, and per-app power profiles all need OS-privileged, vendor-specific hardware APIs that a portable, dependency-free Go CLI cannot reach; they are on the roadmap. See ../plan.md for the full product plan. ## Build from source Requires Go 1.24+, no external dependencies. go build -o thermalflow . Cross-compile for another platform: GOOS=windows GOARCH=amd64 go build -o thermalflow.exe . GOOS=darwin GOARCH=arm64 go build -o thermalflow . ## Usage thermalflow run --history FILE [--duration 500ms] [--json] thermalflow trend --history FILE [--last N] [--json] thermalflow watch --history FILE --interval 1h [--duration 500ms] [--once] [--json] ### run Runs one CPU benchmark round using the same methodology as the sibling CorePilot tool: a trial-division primality workload, run first on a single goroutine and then on runtime.NumCPU() goroutines in parallel, each for --duration. Both phases walk the same odd-number stride pattern over the same base range (worker i in the multi-thread phase checks base+2i, base+2i+2*NumCPU, ...) so the per-operation cost is comparable between phases and the resulting ops/sec numbers are an apples-to-apples comparison - not an artifact of one phase doing cheaper or more expensive checks than the other. The result is APPENDED as one new JSON line to --history (the file is created if it doesn't exist yet), and the run's numbers are printed along with an immediate comparison against the PREVIOUS run in that history (if any): percent change in single-thread and multi-thread ops/sec, each classified REGRESSION / IMPROVEMENT / STABLE using the 10% threshold above. The first run ever recorded has no previous run to compare against; this is reported plainly, not treated as an error. ### trend Read-only. Prints a table of the last --last runs from history (default: 0, meaning show all of them) with their timestamps and key numbers, plus overall trend statistics computed over that shown window: min/max/average single-thread ops/sec and min/max/average multi-thread ops/sec. Separately, trend compares the MOST RECENT run against the AVERAGE of ALL prior runs in the FULL history (not just the shown --last window) - a fuller trend view than run's immediately-previous-run comparison, useful for spotting a slow drift that no single run-to-run comparison would catch. That comparison is classified with the same REGRESSION / IMPROVEMENT / STABLE / 10% logic. If the history file doesn't exist yet (or is empty), trend prints a clean "no history yet" message and exits successfully rather than erroring. ### watch A convenience wrapper that just calls the same logic as run repeatedly, sleeping --interval between rounds - for users who want ThermalFlow to schedule itself instead of being invoked externally by cron / Task Scheduler. --once runs a single round and exits immediately afterward (equivalent to run); it's included for consistency and easy testing with the other polling-style tools in this suite. ### History file format A JSON-lines file (one JSON object per line, append-only). Each line is one benchmark run's result: {"timestamp_utc":"2026-08-10T12:00:00Z","num_cpu":8,"single_thread_ops_per_sec":3200000,"multi_thread_ops_per_sec":24000000,"scaling_factor":7.5} Fields: timestamp_utc RFC 3339 UTC timestamp of the run num_cpu runtime.NumCPU() on the machine that ran it single_thread_ops_per_sec single-goroutine primality checks per second multi_thread_ops_per_sec NumCPU-goroutine primality checks per second (summed across all workers) scaling_factor multi_thread_ops_per_sec / single_thread_ops_per_sec ### Flags --history FILE Path to the JSON-lines history file (required for all three commands). --duration dur How long to run each benchmark phase for "run" and "watch". Go duration syntax, e.g. 500ms, 2s, 1m. (default 500ms). Total wall-clock time per round is roughly 2x --duration, since the single-thread and multi-thread phases run one after another. --interval dur How long "watch" sleeps between rounds. (default 1h) --once "watch" only: run a single round then exit. --last N "trend" only: show only the N most recent runs. 0 (default) or a value >= the number of runs shows all of them. --json Emit structured JSON instead of a text report. -h, --help Show help. ## Prebuilt binaries See ../downloads/ for prebuilt binaries (Windows/macOS/Linux) and CHECKSUMS.txt for their SHA-256 hashes. These are unsigned indie builds - Windows SmartScreen and macOS Gatekeeper will warn on first run, which is expected until a code-signing certificate is in place.