PCHealth 1.0.0 Hardware Health Hub - Team variant ================================================================== PCHealth is the FLEET tool of the Hardware Health Hub. Every other tool in the line looks at one computer; PCHealth looks at all of them at once and tells you which one is the problem. You run "pchealth collect" on each machine, which writes that machine's health report as a JSON file. You then run "pchealth rollup" over every report you have gathered. Rollup merges them into a single fleet view: a per-machine table sorted by disk usage, fleet-wide totals, and the mean, median and standard deviation of usage across the fleet - with any machine that sits further than --stddev-threshold standard deviations from the fleet mean automatically flagged as an OUTLIER. If you are looking after forty workstations, you do not have to read forty numbers; you read the flagged line. How PCHealth differs from its siblings: HardwareLens is a browser web app. It reads live browser APIs for the one machine you happen to be sitting at, and keeps nothing. DevicePulse is a per-machine snapshot history. It appends snapshots of ONE machine to a log over time and warns when that machine's own usage grows. Its axis is TIME, and its scope is one box. PCHealth's axis is the FLEET. It compares many machines to EACH OTHER at a point in time and uses statistics - mean, median, standard deviation, z-score - to decide which machines are abnormal RELATIVE TO THEIR PEERS. Neither sibling ever compares one machine against another. ------------------------------------------------------------------ WHAT IS ACTUALLY IMPLEMENTED ------------------------------------------------------------------ Everything below is real, working code in this binary. Nothing here is simulated or stubbed. * collect: writes one machine's report as JSON containing - the machine label you pass with --machine - the OS hostname (os.Hostname) - a UTC RFC3339 timestamp - GOOS, GOARCH and the Go runtime version - the logical CPU count (runtime.NumCPU) - Go runtime memory statistics for the collecting process (runtime.ReadMemStats: alloc, total alloc, sys, heap alloc, heap sys, NumGC) - for every --watch path, a genuine recursive walk of the directory tree recording total bytes, file count, subdirectory count and the number of entries that could not be read * rollup: ingests N report files (named on the command line, or every *.json in a directory via --dir, or both) and produces - a per-machine table: machine, hostname, CPUs, watched-path count, disk usage in human and exact byte form, share of the fleet total, and z-score - fleet totals: machine count, summed logical CPUs, summed disk usage - usage statistics across machines: mean, median, standard deviation, plus the min and max machine - OUTLIERS: every machine whose |z-score| is strictly greater than --stddev-threshold (default 2.0), labelled high or low * Fault isolation: a report that is missing, empty, unreadable, not valid JSON, or not a PCHealth report at all is SKIPPED with a printed reason. The remaining reports still roll up, and the statistics are computed from the good reports only. One corrupt file never takes the run down. * Duplicate handling: if two reports carry the same machine name, the one with the newer timestamp wins and the other is listed under SUPERSEDED, so a machine cannot be counted twice in the fleet statistics. * --json: the entire rollup - machines, fleet statistics, outliers, skipped files and superseded files - as one JSON document, for piping into other tooling. * Flags may be written before or after positional arguments, so "pchealth rollup reports/*.json --json" works as expected. ------------------------------------------------------------------ WHICH STANDARD DEVIATION, EXACTLY ------------------------------------------------------------------ PCHealth computes the POPULATION standard deviation: stddev = sqrt( sum((x - mean)^2) / n ) It divides by n, NOT by n-1. This is deliberate. The reports you hand to rollup are the whole fleet you care about, not a random sample drawn from a larger unseen population, so the population form is the correct one. It also behaves sanely at the edges: one machine gives 0 rather than an undefined value, and two identical machines give exactly 0. The JSON output records this as "stddev_kind": "population", and the human output prints "std dev (population)", so there is never any doubt about which formula produced a number. Consequences worth knowing before you set a threshold: * When the standard deviation is 0 - a single machine, or every machine identical - every z-score is 0 and NOTHING is flagged. There is no division by zero. * With population standard deviation, no single machine in a fleet of n can ever have |z| greater than sqrt(n-1), no matter how extreme it is. A fleet of 5 therefore tops out at |z| = 2.0, so the default threshold of 2.0 cannot flag anything until you have at least 6 machines. For very small fleets, lower --stddev-threshold (1.0 to 1.5 is reasonable) or just read the table, which is sorted worst-first anyway. ------------------------------------------------------------------ WHAT IS NOT IMPLEMENTED (ROADMAP) ------------------------------------------------------------------ PCHealth is honest about its limits. The following are NOT in this release and are NOT faked anywhere in the output: * Real hardware sensors. CPU and drive temperature, fan RPM, voltages, and S.M.A.R.T. drive attributes (reallocated sectors, power-on hours, pending sectors) are not read. Getting them requires OS-privileged APIs and vendor interfaces - WMI/MSAcpi on Windows, IOKit and SMC on macOS, sysfs/hwmon and smartctl on Linux - none of which the Go standard library exposes portably. A future release would ship a privileged helper per platform. * Network push. Today the agent writes a report file and you gather those files yourself (shared folder, scp, sync tool, whatever you already use). Agents pushing reports to a collector over HTTP, with authentication and retry, is a roadmap item. * Historical fleet trending. Rollup describes the fleet at ONE point in time. It does not keep a fleet history or show how the fleet moved week over week. Per-machine history over time is what the sibling tool DevicePulse does. * Alerting and webhooks. Outliers are printed and exposed in --json; they are not emailed, posted to a webhook, or raised as a ticket. Wiring the --json output into your own alerting is currently a one-liner you write. * OS-level disk capacity. PCHealth measures the size of the directory trees you point it at. It does not report free or total space on a volume, which again needs platform-specific syscalls. * Per-process, per-user or per-file-type breakdowns within a machine, and any form of remediation or cleanup. PCHealth reports; it never deletes. ------------------------------------------------------------------ BUILDING ------------------------------------------------------------------ Requires Go 1.24 or newer. Go standard library only - there are no third party dependencies, no module downloads, and no network access needed. go build -o pchealth . Cross compiling: GOOS=windows GOARCH=amd64 go build -ldflags="-s -w" -o dist/pchealth-windows-amd64.exe . GOOS=darwin GOARCH=arm64 go build -ldflags="-s -w" -o dist/pchealth-darwin-arm64 . GOOS=darwin GOARCH=amd64 go build -ldflags="-s -w" -o dist/pchealth-darwin-amd64 . GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" -o dist/pchealth-linux-amd64 . Prebuilt binaries for those four targets are in dist/. ------------------------------------------------------------------ USAGE ------------------------------------------------------------------ pchealth collect --machine --watch [--watch ...] --out pchealth rollup [report2.json ...] [--stddev-threshold N] [--json] pchealth rollup --dir [--stddev-threshold N] [--json] pchealth help collect flags --machine Machine label recorded in the report. Required. --watch Directory or file to measure. Repeat for several. At least one is required. --out Where to write the report. Parent directories are created if needed. Use "-" to write JSON to stdout. rollup flags --dir Ingest every *.json in this directory. May be repeated, and may be combined with report files named directly. Duplicate paths are ignored. --stddev-threshold N Outlier cutoff in standard deviations. Default 2.0. Must be zero or positive. A machine is flagged when |z-score| is strictly greater than N. --json Print the whole rollup as JSON instead of a table. Exit codes 0 Success. This includes a rollup where some reports were skipped, as long as at least one valid report was ingested; skipped files are listed with their reason. 1 Bad invocation (unknown command, missing required flag, bad threshold value), no reports given at all, an unreadable --dir, or no valid report among the files given. Explicit help (-h, --help, or the "help" subcommand) prints usage to stdout and exits 0. A bad invocation prints the error and usage to stderr and exits 1. ------------------------------------------------------------------ TYPICAL SESSION ------------------------------------------------------------------ On each machine, once (from a login script, scheduled task or cron job): pchealth collect --machine ws-014 --watch C:\Users --out \\share\reports\ws-014.json On the admin's machine, whenever you want the fleet picture: pchealth rollup --dir \\share\reports pchealth fleet rollup (2026-08-10T03:45:21Z) files seen 10, reports ingested 10, skipped 0, machines 10 MACHINE HOSTNAME CPUS PATHS DISK USAGE ... Z-SCORE FLAG ws-666-BADBOX ws-666-badbox.lan 8 1 500.0 MiB ... +3.00 ** OUTLIER (high) ws-109 ws-109.lan 8 1 1.0 MiB ... -0.33 ... OUTLIERS (further than 2.00 population standard deviation(s) from the fleet mean) ** ws-666-BADBOX 500.0 MiB z=+3.00 (above the mean by 449.1 MiB) To feed the result into something else: pchealth rollup --dir \\share\reports --json > fleet.json To tighten or loosen the flagging: pchealth rollup --dir \\share\reports --stddev-threshold 1.5 ------------------------------------------------------------------ REPORT FORMAT ------------------------------------------------------------------ Reports are plain JSON and can be written by hand or by other tooling. Only two things are required for rollup to accept a file: a non-empty "machine" field, and a usage figure. Usage may be given as a "paths" array, as a "total_bytes" number, or both - when "paths" is present its byte counts are summed and that sum is authoritative, so a stale hand-edited total can never skew the fleet statistics. { "schema": "pchealth.report.v1", "machine": "ws-014", "hostname": "ws-014.lan", "timestamp": "2026-08-10T09:00:00Z", "os": "windows", "arch": "amd64", "num_cpu": 8, "memory": { "heap_alloc_bytes": 421312, "sys_bytes": 7602448 }, "paths": [ { "path": "C:\\Users", "bytes": 3145728, "files": 812, "dirs": 40, "errors": 0 } ], "total_bytes": 3145728 }