tachometer
Shared repo and resource profiling helpers for the portfolio.
tachometer extracts the reusable profiling contract that first lived in the
portfolio's original per-repo profiler: resource snapshots, persisted sample
history, command profiling, and portable JSON summaries. Downstream repos keep
their own workload logic.
tachometer owns the common profiling model, CLI, and repo-local manifest
convention.
Scope
tachometer currently provides:
- host resource snapshots: CPU, load average, memory, disk, and optional GPU
- canonical host profile and summary artifacts for the dashboard banner
- local AI-provider utilization snapshots for Claude, Codex, and Copilot when their local CLI caches expose usage
- optional Fedora-specific sidecar signals exported by
fedora-debugg - repo snapshots: repo size, file and directory counts, and git tracked/dirty or untracked counts when git is available
- profiled command runs with pre and post samples plus runtime metadata
- manifest-driven profile and summary paths so every repo can use the same local output convention
tachometer does not yet try to own:
- repo-specific stoplight policies or adaptive controller logic
- portfolio-wide dashboards or central metric shipping
- long-running daemon collection
That split is intentional. The origin profiler keeps its controller and system
monitor; tachometer owns the lower-level profiling primitive those features
depend on.
Platform support
The package installs and the CLI runs on Linux, macOS and Windows, verified by CI on every push. How much it can actually measure differs sharply, because most signals come from interfaces only Linux provides.
| Signal source | Linux | macOS | Windows |
|---|---|---|---|
| Repo metrics (size, file counts, git) | yes | yes | yes |
| Disk usage | yes | yes | yes |
Child CPU time, peak RSS, page faults (resource) |
yes | yes | no |
Per-process CPU, memory, I/O (psutil, optional) |
yes | yes | yes |
Load average, memory detail, uptime, process count (/proc) |
yes | no | no |
CPU temperature, fan RPM (/sys/class) |
yes | no | no |
| Energy in joules (Intel RAPL) | yes | no | no |
GPU (nvidia-smi) |
if present | if present | if present |
What this means in practice
Linux is the reference platform. Everything above works.
macOS loses the /proc and /sys signals — no load average detail, memory
breakdown, uptime, process count, temperature, fan or energy. Child-process CPU
and memory still work, because resource is a Unix module.
Windows additionally loses resource, which does not exist there at all.
Without psutil installed, a profiled command reports None for CPU percent,
peak RSS and fault counts.
psutil is not a declared dependency, so on Windows it is worth installing
explicitly for anything beyond timing:
pip install psutil
Fields that cannot be measured are reported as None rather than 0, so a
missing signal is distinguishable from a genuine zero. Widening native Windows
coverage is tracked in BACKLOG.md.
Install
python3 -m venv .venv
. .venv/bin/activate
pip install -e .[dev]
CLI
Capture a repo snapshot from a tracked manifest:
tachometer snapshot --manifest examples/example-repo/repo-profile.toml
Capture the canonical host snapshot used by the portfolio dashboard banner:
tachometer host-snapshot --manifest config/tachometer/profile.toml
Profile a command and append pre/post samples plus a run record:
tachometer run --manifest examples/example-repo/repo-profile.toml -- python3 -m pytest -q
Print the current JSON summary:
tachometer summarize --manifest examples/example-repo/repo-profile.toml
Print the current canonical host summary:
tachometer host-summarize --manifest config/tachometer/profile.toml
Capture the local AI-provider utilization snapshot used by the dashboard:
tachometer agent-utilization --manifest config/tachometer/profile.toml
Record one host temperature and load sample for the thermal history (meant
to run every five minutes; see config/clockwork/host-sampler.toml.template):
bash scripts/sample_host.sh
The dashboard charts the history at /thermal.
To add SMART drive temperatures and a Drive health light, set
TACHOMETER_SMART_DIR for the sampler to a directory that a separate
root-run collector fills with one <drive>.jsonl per drive. Each line is one
snapshot with taken_at (ISO 8601), kind, health_passed,
temperature_c and counters; the sampler reads the last two lines and
ignores snapshots older than three hours. Unset or empty, the sampler reads
no SMART data. Set it in the rendered, gitignored manifest
config/clockwork/host-sampler.toml so the path stays out of the tracked
template:
[jobs.environment]
TACHOMETER_SMART_DIR = "/path/to/smart/history"
The rendered manifest is per machine. On macOS, install it with
--target launchd-user (clockwork 2026-10-15 or newer renders the
five-minute calendar there) and leave TACHOMETER_SMART_DIR empty. The
sampler then reads what macOS exposes without root: each physical disk's
SMART verdict from diskutil, which drives the Drive health light, and the
battery temperature from ioreg where the battery reports one, charted as the
board reading. Recent Apple Silicon laptops publish no battery temperature to
ioreg at all (checked on a MacBook Air, 2026-10-15), so there the board
reading stays empty. diskutil reports no temperatures or counters, and CPU
temperature on macOS needs root, so those stay empty too. The launchd job puts Homebrew's bin first on PATH
because tachometer needs Python 3.10 or newer.
For what macOS reserves for root, install the root-run collector once:
sudo bash scripts/macos/install_powermetrics_collector.sh
It installs a root-owned copy of scripts/macos/powermetrics_collector.py
under /usr/local/libexec/tachometer (the daemon never runs the editable
checkout) and a LaunchDaemon that appends one powermetrics reading every five
minutes to /var/db/tachometer/powermetrics.jsonl. Set
TACHOMETER_MACOS_POWERMETRICS to that file in the rendered manifest's
[jobs.launchd.environment] and reinstall the sampler. Every Mac then gets a
Thermal pressure light (Nominal, Fair, Serious, Critical); Intel Macs also get
CPU and GPU die temperature and fan speed. Apple Silicon powermetrics reports
no temperatures, only pressure and power. --uninstall removes the daemon.
Serve the dashboard on loopback only:
tachometer serve --manifest config/tachometer/profile.toml --host 127.0.0.1 --port 5100
Non-loopback binds are blocked unless you pass --allow-remote explicitly.
Dashboard-triggered Run All Snapshots writes the active run to
.tachometer/run-all.log; before a new run starts, the previous non-empty log
is archived under .tachometer/logs/run-all-<timestamp>.log. The 10 newest
archives stay loose for quick inspection; older archives are compressed into
date-based bundles under .tachometer/logs/bundles/run-all-YYYYMMDD.zip.
If fedora-debugg has exported artifacts/latest/tachometer-signals.json,
the dashboard also renders a separate Fedora Debug strip with snapshot age plus
bucketed Collection, Display, Coredumps, GPU, Storage, Packages, Python, Node,
and Go signals.
If .tachometer/agent-utilization.json exists, the dashboard also renders an
AI Utilization strip sourced from local CLI state:
- Claude:
~/.claude/stats-cache.jsonplusclaude auth status --json - Codex: the latest
.codexsessiontoken_countevent with rate-limit data - Copilot: the latest
.copilot/session-state/*/events.jsonlshutdown record
Copilot usage only appears after at least one session has started, and the current session totals land when that session shuts down.
Disk Pressure Response
When disk utilization crosses the red threshold, tachometer writes an open
system.disk or host.disk item to the local .tachometer/backlog.json /
.tachometer/host-backlog.json file. The shared remediation path lives in
./util-repos/traction-control: its tachometer disk-pressure agentic job scans
those backlog and summary files, selects clean pressure candidates, and launches
an agent to add reversible repo-local archive automation.
The standard fix pattern is intentionally conservative: compress/decompress local-only caches, generated artefacts, temporary downloads, and debug snapshots with an audit trail; never delete source data or raw private inputs as the default pressure response.
Manifest Shape
[repo]
name = "example-repo"
category = "health-repos"
kind = "python"
[paths]
disk_path = "."
profile_path = ".tachometer/profile.json"
summary_path = ".tachometer/summary.json"
host_profile_path = ".tachometer/host-profile.json"
host_summary_path = ".tachometer/host-summary.json"
[defaults]
label = "repo-snapshot"
Manifest rules:
- manifests live at
config/tachometer/profile.tomlin downstream repos - the repo root is inferred from the manifest location
.tachometer/is the standard local-only output directorydisk_pathis resolved relative to the repo roothost_profile_pathandhost_summary_pathdefault to canonical dashboard artifacts and are primarily used by thetachometerrepo itself
Portfolio Rollout
The shared utility repo is paired with a lightweight downstream convention:
config/tachometer/profile.tomlscripts/run_tachometer_profile.sh.gitignoreentry for.tachometer/
That gives every repo one stable local profiling entrypoint while keeping the actual profiler implementation centralized here.
Development
ruff check .
ruff format --check .
black --check --diff .
pytest -q
Contributing
See CONTRIBUTING.md.
License
MIT. See LICENSE.
Metadata
Release files for tachometer 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| tachometer-0.1.0.tar.gz | 77.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| tachometer-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 141.6 kB
Release files / tachometer-0.1.0.tar.gz
| Download URL | tachometer-0.1.0.tar.gz |
|---|---|
| Size | 77.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a51803501d9f62f38ce9cb9673907c30d7550e73ea7a9dd800309f9676ce4c73
|
|
BLAKE2b-256 checksum How to use checksums |
734ade2de2f81ec71e8369ab7362d89b20eb89b7e851e873b09661ac828d965b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 18, 2026.
Transparency logRelease files / tachometer-0.1.0-py3-none-any.whl
| Download URL | tachometer-0.1.0-py3-none-any.whl |
|---|---|
| Size | 63.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
7139a116ea0e10051ec4b2bac7994c95830634e1fc82fb8b184fd8c20e06f55b
|
|
BLAKE2b-256 checksum How to use checksums |
cad4961245a68ed66db6ba768c61405352c1b14aea3f0598089cb4b4aa3b6e55
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 18, 2026.
Transparency log