Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 9 additions & 10 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# and the `mon` binary name are the only additions to upstream's manifest header -- keeping
# `[package] name = "bottom"` intact is deliberate so rebases onto upstream stay clean.
[workspace]
members = ["crates/claude-metrics"]
members = ["crates/harness-metrics"]
# `scripts/schema_gen` is a standalone tool with its own `Cargo.lock`. Adding the
# workspace above swept it in and broke `scripts/schema/nightly.sh`; it stays out.
exclude = ["scripts/schema_gen"]
Expand Down Expand Up @@ -75,7 +75,7 @@ logging = ["fern", "log"]
generate_schema = ["schemars", "strum"]

[dependencies]
claude-metrics = { path = "crates/claude-metrics" }
harness-metrics = { path = "crates/harness-metrics" }
# `default-features = false` is mandatory, not tidiness: the default `chafa-dyn` feature
# runs a `build.rs` that `.expect()`s a pkg-config probe for libchafa and panics the whole
# build when it is absent.
Expand Down
98 changes: 73 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,57 @@
> additions, described below. Everything past that section is upstream's documentation and
> still applies -- the binary is just named `mon` instead of `btm`. See `NOTICE`.

## Quickstart

One `cargo run` example per addition, run from a source checkout rather than assuming an
installed `mon`. Drop `--release` for a faster compile / slower runtime while iterating.

```bash
# Apple Silicon power widget -- macOS + Apple Silicon only.
cargo run --release -- --pixel_graphs kitty

# Agent token metrics for one harness.
cargo run --release -- -C sample_configs/claude_config.toml --pixel_graphs kitty
cargo run --release -- -C sample_configs/codex_config.toml --pixel_graphs kitty
cargo run --release -- -C sample_configs/pi_config.toml --pixel_graphs kitty

# Track every harness's token usage in one view -- the flagship example.
cargo run --release -- -C sample_configs/all_harnesses_config.toml --pixel_graphs kitty

# Custom graph marker.
cargo run --release -- --marker sextant
```

### Kitty pixel-graph rendering

Requires a terminal that speaks the [Kitty graphics protocol](https://sw.kovidgoyal.net/kitty/graphics-protocol/) --
Ghostty, Kitty, or WezTerm. `auto` detects it in most of them; force it explicitly with
`--pixel_graphs kitty` wherever detection is unreliable (notably tmux -- see below), or just
to always get it.

```bash
# Works with any layout/config -- every graph widget in it renders as real pixels instead
# of cell markers. The default layout already has plenty of graphs to look at:
cargo run --release -- --pixel_graphs kitty

# The demo config packs more graphs on screen at once, which is where the resolution jump
# reads the most "slick" -- worth roughly an order of magnitude more vertical resolution on
# a short graph than the cell-marker path:
cargo run --release -- -C sample_configs/demo_config.toml --pixel_graphs kitty

# Combine it with any agent config for the token graphs specifically:
cargo run --release -- -C sample_configs/all_harnesses_config.toml --pixel_graphs kitty

# `auto` instead of `kitty` tries to detect support and falls back to cell markers cleanly
# when it can't:
cargo run --release -- --pixel_graphs auto
```

Under tmux, pass `--pixel_graphs kitty` explicitly rather than `auto` -- tmux's passthrough
eats the capability query `auto` relies on to detect Kitty support, even though the image
transport itself works fine through it. `auto` can never select Kitty there, only an explicit
`kitty` can.

## What this fork adds

Nothing here changes the default layout or default behaviour. Every addition is opt-in.
Expand All @@ -43,37 +94,34 @@ drawing flat lines that read as "idle".
Cluster labels come from `SocInfo` rather than being hardcoded: they are `E`/`P` on M1-M4
but `P`/`S` on M5+.

### Claude Code metrics
### Agent token metrics

Three widgets reading live [Claude Code](https://claude.com/claude-code) activity off
`~/.claude`:
Two widgets, `agent_graph` and `agent_stats`, tracking live token usage for a coding-agent
harness off its own local transcript files. Harness-agnostic: which harness (or harnesses) a
given instance reads is set per-instance with `source = "claude" | "codex" | "pi" | "all"`.

- `claude` -- a sortable table of live sessions: name, directory, model family, state,
tokens, cost, context-window occupancy, subagent count
- `claude_graph` -- token throughput by model family over time, on a log axis by default
- `claude_stats` -- the equivalent of Claude Code's own `/status` stats screen, as stacked
rounded-staircase bands of token spend by model family. That screen bars by day; this buckets by minute over
the last hour, so the shape of a working session is visible rather than collapsed into a
single bar. Built by walking `~/.claude/projects` and attributing each record to a bucket
from its own timestamp, so the window is complete the moment the widget appears rather
than having to be accumulated live -- and it keeps the tokens of sessions that have since
exited, which the live-session view cannot
- `agent_graph` -- token throughput by series over time, on a log axis by default
- `agent_stats` -- the equivalent of Claude Code's own `/status` stats screen, as stacked
rounded-staircase bands of token spend by series. That screen bars by day; this buckets by
minute over the last hour, so the shape of a working session is visible rather than
collapsed into a single bar

Backed by the `claude-metrics` workspace crate, which has no dependency on bottom. Counting
is the fiddly part and the rules are documented in that crate: dedupe on
`requestId` + `message.id`, take `cache_creation_input_tokens` without the ephemeral buckets
it already sums, ignore `usage.iterations[]`, and treat `output_tokens` as a running total
across a message's per-content-block records.
A series is a model family for a single-harness `source` (e.g. Claude: Opus/Sonnet/Haiku/
Fable/Other), or a harness (Claude/Codex/Pi) for `source = "all"`.

Cost, context, and rate limits need a small tee in your statusline -- see
[the docs](https://github.com/nredd/mon/blob/main/docs/content/usage/widgets/claude.md).
Without it those columns read `N/A` and everything else still works.
There is no live-session table. Codex and pi write no PID registry the way Claude Code does,
so rather than give one harness a live view the others can't have, every harness -- Claude
included -- is read the same lagging way: tailing whatever transcripts it has written to
disk, a refresh tick behind the actual model call.

`sample_configs/claude_config.toml` is a ready-made layout with all three and nothing else:
Backed by the `harness-metrics` workspace crate, which has no dependency on bottom and knows
nothing about the other two. Counting is the fiddly part and the rules -- and each harness's
transcript format -- are documented in that crate and in
[the docs](https://github.com/nredd/mon/blob/main/docs/content/usage/widgets/agent.md).

```console
$ mon -C sample_configs/claude_config.toml --pixel_graphs kitty
```
Four ready-made layouts, each drawing a stats graph and a rate graph and nothing else:
`sample_configs/claude_config.toml`, `codex_config.toml`, `pi_config.toml`, and
`all_harnesses_config.toml` (every harness combined -- see the Quickstart above).

### Configurable graph markers

Expand Down
151 changes: 0 additions & 151 deletions crates/claude-metrics/examples/claude_dump.rs

This file was deleted.

Loading
Loading