Commit graph

12 commits

Author SHA1 Message Date
e5fc0a1d35 icons: ship the leather mark, with a simplified version for tab size
Christian's leather patch art is the app icon at 180px and up. It cannot be
the favicon: leather grain and stitching turn to mud below 48px, and the
pulse is black on brown, which is not enough contrast in a tab bar.

So the set is two-tier. Sizes 180 and above come from the leather art;
16, 32, 48 and the .ico come from a flat source whose spike geometry was
measured off the original (left tail at 52% height, peak at 42% width,
trough at 54%, right tail at 84%). Same colours sampled from the leather
body, so the small mark reads as the same object rather than a different
logo.

make_icons.py gained --small-from for this: one command builds both tiers.

Signed-off-by: Christian Sass <csass@binaryranch.com>
2026-10-21 22:24:01 -05:00
2af4a877ec design: three icon candidates, a brief, and the Imagine prompt
The icon cannot carry the product's sentence, so it carries the shortest
true part: something is beating and you can see it.

Three candidates as plain SVG geometry, all rendered through make_icons.py
and judged at 32px rather than at full size. A rows (workload table),
B tab carrying a pulse, C pulse alone. B is the most specific idea and
needs simplifying; A is the clearest and the least distinctive; C wins at
16px but says health monitor, not browser.

Signed-off-by: Christian Sass <csass@binaryranch.com>
2026-10-21 22:12:15 -05:00
bb9471442a docs: the repo now lives in Bunkhouse
Binary Ranch Labs was a placeholder name for a public roof. It is now
Bunkhouse: open tools from Binary Ranch, built with the community.

Forge is canonical, GitHub remains the public mirror. The clone command
and the forge link in the README both point at the new home.

Signed-off-by: Christian Sass <csass@binaryranch.com>
2026-10-21 22:02:34 -05:00
6cddabc633 frontend: a status-bar widget, and evidence the data plane is the product
Omarchy 4 runs one long-running Quickshell process and its bar accepts
command modules that print {"text", "tooltip", "class"}. That is the
cheapest native frontend Vitals can have: no QML, no websocket, no plugin
manifest, just a command the bar runs on an interval.

bar_widget.py prints that shape from the existing JSON API, with a
workload selector and a tooltip that carries the verdict line. It also
fails soft, because a status bar should never make a session look broken
when the monitor is down.

This is the point of splitting sampling from presentation: a native UI on
another distro is a new frontend, not a rewrite.

Signed-off-by: Christian Sass <csass@binaryranch.com>
2026-10-21 13:54:07 -05:00
aeb8065807 docs: contribution terms, and a check that enforces them
Vitals takes contributions under MIT, inbound equal to outbound, with a
Developer Certificate of Origin instead of a CLA. That is the same shape
Nextcloud uses on the project this tool was written to watch, so nobody
contributing here is being asked for paperwork they would not sign
upstream.

tools/check-dco.sh verifies both presence and identity of the sign-off,
and fails the pull request if either is wrong. Tested against three
cases: unsigned, correctly signed, and signed by someone other than the
author.

Signed-off-by: Christian Sass <csass@binaryranch.com>
2026-10-21 13:46:29 -05:00
52885cad78 icons: one mark in, every size out, and a place to serve them
Three surfaces were showing generated identicons: the forge org avatar
(which is what Discord unfurls), the GitHub org avatar, and the browser
tab, because the app shipped no favicon at all.

make_icons.py turns one SVG or PNG into the seven sizes plus a
multi-resolution favicon.ico. The server now serves /favicon.ico and
/icons/*.png from icons/ when they exist, and index.html asks for them,
so dropping the real mark into icons/ is the whole integration.

Co-developed-with: CLU <clu@binaryranch.com>
2026-10-21 13:35:45 -05:00
CLU
9cdbb43394 Answer the question the process list asks: what IS that, and whose is it
Eight identical 'call (WebRTC)' rows with no owner is the least useful thing
a monitor can print. Three changes:

- detail panes group processes by role with a plain-English gloss, a pid list,
  and a judgement when a group looks abandoned ('11 of 14 idle for over 30
  min, oldest 201.7h'). The hint states evidence and never says safe to delete,
  because a muted call and a dead call both sit at zero.
- the tab list is one row per URL, duplicates summed with a count badge, each
  row carrying the site's own favicon fetched through the local server and
  cached on disk. Sites with no icon get a letter tile, never a third-party
  icon service.
- Vitals' own cost is in the header, and its own tab is badged 'this screen'.

Tests caught a real bug while writing this: merge_tabs compared each tab to the
group running total, so the busiest tab could never name the row.

Co-developed-with: CLU
2026-10-20 13:56:26 -05:00
CLU
95c1c1d3eb Live UI: stop the page from jumping, and put Vitals in the bookmark bar
The page rebuilt its whole header, bar and row list twice a second, so
numbers snapped, columns resized as digits changed, and rows swapped places
over a hundredth of a core.

- header values are tabular-width and tweened toward the newest sample
- machine-bar segments are keyed and reordered by flex order, so widths
  animate instead of being recreated mid-transition
- rows are keyed DOM nodes updated in place, sorted on a 0.1-core grid with
  the previous order as tiebreak, with hysteresis at the idle threshold
- tabs, banner and detail panes only re-render when their data changes
- poll every 700ms and drop repeat frames from the 2s sampler

bookmark.py puts a Vitals bookmark and a popup bookmarklet in the browser's
bookmark bar. It recomputes Chromium's bookmark checksum (MD5 over the
canonical node serialisation) and verifies it after writing, because a file
that fails that check leaves the browser showing an empty bar while the file
on disk still looks perfect. Refuses while the browser holds the profile,
keeps a timestamped backup, idempotent. install.sh runs it.

Co-developed-with: CLU
2026-10-20 13:52:49 -05:00
f086afc030 docs: point clone and documentation links at the real homes
The quickstart still told people to clone sastian/vitals on the forge,
which stopped existing when the repo moved to binaryranch-labs. A broken
clone command in the first code block is the worst place to have one.

Co-developed-with: CLU <clu@binaryranch.com>
2026-10-19 17:03:52 -05:00
cd6e76c830 docs: record authorship and how to credit it
Credit is not a courtesy here, it is a factual claim about who decided
what. Christian supplied the question, the framing (the browser is the top
layer of the OS), and the field evidence; the code and its failures are
mine. AUTHORS.md states that split so a future reader does not have to
guess.

Co-developed-with: CLU <clu@binaryranch.com>
2026-10-19 16:50:18 -05:00
b66c6619d8 docs: synthetic demo mode and a screenshot with no customer data
The first screenshot was captured on a real workstation: it carried a
machine name, a live call with a named participant, and a staging URL.
None of that belongs in a public repo.

--demo now loads demo/demo-snapshot.json and serves it through the same
API, so documentation screenshots are reproducible, reviewable, and free
of anyone's actual desktop. The canned snapshot is shaped to tell the
story: a leaked automation run at 6.10 cores with idle pages, and a video
call tab carrying 221% page work beside its idle siblings.
2026-10-19 16:49:07 -05:00
9d065153b0 Vitals 0.1.0: workload map with browser tab accounting
Process monitors stop at the browser boundary, so the thing that usually
pegs a machine is invisible: forty identical processes, no age, no tab
names, no idea which page is the offender.

Vitals resolves every process to a human identity (container, flatpak,
systemd unit, tree root, or script), then joins the OS view to the
browser's own DevTools counters so each tab carries its own page-work
number beside the cores its browser instance is burning. The gap between
those two numbers is the diagnosis: idle page, burning compositor.

- dependency-free sampler over /proc, 2s cadence, 5 min in-memory history
- minimal CDP client (WebSocket + JSON) with no third-party packages
- both unit systems side by side: percent of machine and fractional cores
- flags for leaked automation instances and live WebRTC calls
- user service with CPUQuota so the monitor can never be the problem
- identity tests that need no root, server, or browser

MIT licensed. Runs on Linux, reads /proc, asks for no privilege.
2026-10-19 16:42:54 -05:00