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
12 changes: 7 additions & 5 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,14 @@ request.
Token Meter has no Python package installation step. Its Python server uses only
the standard library.

For the full macOS experience, run the installer from your checkout:
For the full macOS or Linux desktop experience, run the installer from your
checkout:

```bash
./scripts/install
```

This starts the local server and menu bar companion. Open
This starts the local server and menu bar or desktop tray companion. Open
[http://localhost:8722](http://localhost:8722) and check its health with:

```bash
Expand All @@ -60,7 +61,8 @@ runtime. For dashboard-only development, when port 8722 is free, run:
python3 meter.py
```

The menu bar companion requires the Swift toolchain. Token Meter works best
The macOS menu bar companion requires the Swift toolchain. The Linux tray requires
GTK 3, PyGObject, and Ayatana AppIndicator. Token Meter works best
when the machine already has Claude, Codex, or Cursor session logs. If it does
not, the app should still start; create a normal agent session and reload the
dashboard to see live data.
Expand Down Expand Up @@ -97,9 +99,9 @@ See [SECURITY.md](SECURITY.md) for the full security and privacy model.
Run these checks from the repository root before opening a pull request:

```bash
PYTHONPYCACHEPREFIX=/private/tmp/token-meter-pycache python3 -m py_compile meter.py token_meter_mcp.py
PYTHONPYCACHEPREFIX=/tmp/token-meter-pycache python3 -m py_compile meter.py token_meter_mcp.py menubar/token_meter_tray.py
python3 -m unittest discover -s tests -v
bash -n scripts/install scripts/install-launch-agent scripts/run-menubar scripts/run-token-meter-mcp scripts/start-token-meter scripts/uninstall-launch-agent scripts/update
bash -n scripts/install scripts/install-linux scripts/install-launch-agent scripts/install-systemd-user scripts/run-menubar scripts/run-token-meter-mcp scripts/start-token-meter scripts/uninstall-launch-agent scripts/uninstall-systemd-user scripts/update
node -e "const fs=require('fs'); const html=fs.readFileSync('page.html','utf8'); const m=html.match(/<script>([\\s\\S]*)<\\/script>/); new Function(m[1]); console.log('js ok')"
git diff --check
```
Expand Down
121 changes: 82 additions & 39 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ turns them into one live dashboard.
| **Install updates explicitly** | Check the configured Git upstream every 10 minutes by default. Token Meter shows a bottom-right update button when a clean fast-forward update exists and does not change the checkout until you click it. |
| **Ask your agent** | Let Codex or Claude check the current run, summarize usage, and point you to the relevant dashboard view through a local MCP. |
| **Move around quickly** | Open common views with the command palette and keyboard shortcuts. Definitions appear as tooltips on the metrics they explain. |
| **Keep data private** | Run analysis stays on your Mac and Token Meter sends no telemetry. Limit checks use your existing account only to read usage from the matching provider. |
| **Keep data private** | Run analysis stays on your computer and Token Meter sends no telemetry. Limit checks use your existing account only to read usage from the matching provider. |

Token Meter supports Claude Code, Claude Desktop Agent/Cowork, Codex CLI, the
Codex desktop app, and Cursor Agent/Composer. It follows local agent logs as they are written and
Expand All @@ -32,24 +32,26 @@ machine.

### Install From Terminal

On macOS, clone the repository and run its installer:
On macOS or Linux, clone the repository and run its installer:

```bash
git clone https://github.com/splunk/token-meter.git
./token-meter/scripts/install
```

The installer checks the required tools, installs the server and menu bar login
items,
waits for the local server, verifies both endpoints, prints
The public installer selects the current operating system; on Linux it delegates
to `scripts/install-linux`. The installer checks the required tools, installs the
server and desktop tray
startup items, waits for the local server, verifies both endpoints, prints
`Token Meter installation complete`, and returns control to your terminal.
It starts the server first and lets the initial local-history index finish before
starting the menu bar, so large coding histories may take longer on the first run
without requiring a retry.
It copies the runtime into `~/Library/Application Support/Token Meter/runtime`,
so the cloned folder is not used for automatic startup.
starting the menu bar or desktop tray, so large coding histories may take longer
on the first run without requiring a retry.
It copies a stable runtime outside the clone: the macOS default is
`~/Library/Application Support/Token Meter/runtime`; the Linux default is
`~/.local/share/token-meter/runtime`. The clone is not used for automatic startup.

Token Meter starts its local server and menu bar widget automatically after
Token Meter starts its local server and menu bar or desktop tray widget automatically after
installation and after future logins. Open the dashboard at:

```text
Expand Down Expand Up @@ -187,18 +189,18 @@ observation establishes a baseline and never sends a catch-up notification.

## Requirements

- Python 3.8 or newer. The macOS package first tries `/usr/bin/python3`, then
Homebrew and user `python3` installs.
- Python 3.8 or newer.
- Claude Code CLI, Codex CLI, Claude Desktop Agent/Cowork, and/or the Codex
desktop app if you want live log data.
- macOS with the Swift toolchain, usually from Xcode Command Line Tools, when
running from source. The macOS package includes a prebuilt menu bar binary.
- macOS: the Swift toolchain, usually from Xcode Command Line Tools.
- Linux: systemd user services, GTK 3, PyGObject, and Ayatana AppIndicator. KDE exposes AppIndicator items
natively; GNOME requires an AppIndicator/KStatusNotifierItem shell extension (Ubuntu enables one by default).
- `curl`, used by the helper scripts.

The web dashboard has no third-party Python packages. `meter.py` uses only the
Python standard library. Dashboard-only mode is available for development,
troubleshooting, and non-macOS use, but the normal experience includes the menu
bar companion.
Python standard library. Dashboard-only mode is available for development and
troubleshooting, but the normal experience includes the macOS menu bar or Linux
desktop tray companion.

## Ask From Codex Or Claude

Expand Down Expand Up @@ -231,7 +233,7 @@ When a tool is called, its derived result enters the connected agent's context
and may be processed by that client's model provider under the client's own
terms. Token Meter does not send trace content or derived analytics itself;
menu-bar quota sync separately makes read-only usage requests to the provider
accounts already signed in on this Mac.
accounts already signed in on this computer.

For source installs, the equivalent manual commands are:

Expand Down Expand Up @@ -272,45 +274,62 @@ not modified by the background checker or update button.

## Automatic Startup And Uninstall

The installer creates separate user LaunchAgents for the local server and menu
bar companion. Both start after login and use `KeepAlive`, so macOS restarts
either process independently if it exits. Remove both login items with:
On macOS, the installer creates separate user LaunchAgents for the local server
and menu bar companion. Both start after login and use `KeepAlive`. Remove them with:

```bash
"$HOME/Library/Application Support/Token Meter/runtime/scripts/uninstall-launch-agent"
```

On Linux, separate `token-meter-server.service` and `token-meter-tray.service`
user units provide the same supervision. Remove them with:

```bash
"${XDG_DATA_HOME:-$HOME/.local/share}/token-meter/runtime/scripts/uninstall-systemd-user"
```

Inspect either service with:

```bash
systemctl --user status token-meter-server token-meter-tray
```

## Dashboard-Only Mode

For development, troubleshooting, or non-macOS use, run only the local web
For development, troubleshooting, or headless use, run only the local web
dashboard:

```bash
python3 meter.py
```

The menu bar companion polls the local `/menubar` endpoint. Clicking its status
item opens the **Run Slip** popover: the selected local run leads with a measured
context trace, cost confidence, output pace, and latest-execution spend.
The menu bar companion polls the local `/menubar` endpoint. On macOS, clicking its
status item opens the **Run Slip** popover: the selected local run leads with a
measured context trace, cost confidence, output pace, and latest-execution spend.
The popover stays 360px wide across every scope, while sparse provider scopes
shorten vertically; each whole scope cell is clickable, not only its label.
Provider tabs show only cached provider-reported quota snapshots; unavailable
or stale data is never shown as zero. Recent sessions are labeled Claude, Codex,
or Cursor and can be pinned; choose **Follow latest** to resume automatic tracking. The
companion does not parse logs or read provider credentials directly.
or Cursor and can be pinned; choose **Follow latest** to resume automatic tracking.
On Linux, the AppIndicator tray exposes equivalent run, provider-limit, and
settings flows. The companion does not parse logs or read provider credentials
directly.

## How It Finds Logs

Token Meter reads local log stores:

```text
Claude Code CLI: ~/.claude/projects/*/*.jsonl
Claude Desktop metadata: ~/Library/Application Support/{Claude,Claude-3p}/{claude-code-sessions,local-agent-mode-sessions}/**/local_*.json
Claude Desktop Agent: ~/Library/Application Support/{Claude,Claude-3p}/local-agent-mode-sessions/**/.claude/projects/*/*.jsonl
Claude Desktop metadata (macOS): ~/Library/Application Support/{Claude,Claude-3p}/{claude-code-sessions,local-agent-mode-sessions}/**/local_*.json
Claude Desktop Agent (macOS): ~/Library/Application Support/{Claude,Claude-3p}/local-agent-mode-sessions/**/.claude/projects/*/*.jsonl
Codex CLI + desktop app: ~/.codex/sessions/YYYY/MM/DD/rollout-*.jsonl
Cursor transcript anchor: ~/.cursor/projects/*/agent-transcripts/<composer-id>/<composer-id>.jsonl
Cursor conversation data: ~/Library/Application Support/Cursor/User/globalStorage/state.vscdb
Cursor request timing: ~/Library/Application Support/Cursor/logs/**/cursor.requestTraces.log
Cursor conversation data (macOS): ~/Library/Application Support/Cursor/User/globalStorage/state.vscdb
Cursor request timing (macOS): ~/Library/Application Support/Cursor/logs/**/cursor.requestTraces.log
Claude Desktop data (Linux): ~/.config/{Claude,Claude-3p}/...
Cursor conversation data (Linux): ~/.config/Cursor/User/globalStorage/state.vscdb
Cursor request timing (Linux): ~/.config/Cursor/logs/**/cursor.requestTraces.log
```

Claude Desktop metadata contains the Desktop title, project directory, model,
Expand Down Expand Up @@ -406,7 +425,7 @@ The summary above the matching sessions recalculates filtered cost, total input
(fresh plus cached), output tokens, executions, cumulative wait, and per-model
cost and token mix whenever any filter changes.
Each row has a Delete action. Deletion requires an explicit confirmation and
moves the exact discovered JSONL file to macOS Trash so it remains recoverable.
moves the exact discovered JSONL file to the system Trash so it remains recoverable.
Provider metadata, project files, and configuration are not changed.
Its live snapshot watches every discovered session, so a background Claude update
appears without waiting for a newer Codex session (or vice versa). If a browser
Expand Down Expand Up @@ -600,9 +619,9 @@ Use the notification toggle in the top-right of the dashboard. If notifications
were previously blocked for `localhost`, clear the block in browser site
settings and toggle notifications again.

### The menu bar companion will not build
### The desktop companion will not start

Check that `swiftc` is available:
On macOS, check that `swiftc` is available:

```bash
swiftc --version
Expand All @@ -614,12 +633,32 @@ On macOS, install the Xcode Command Line Tools if needed:
xcode-select --install
```

On Linux, install the tray dependencies for your distribution:

```bash
# Debian / Ubuntu
sudo apt install python3-gi gir1.2-ayatanaappindicator3-0.1

# Fedora
sudo dnf install python3-gobject libayatana-appindicator-gtk3

# Arch Linux
sudo pacman -S python-gobject libayatana-appindicator
```

KDE Plasma displays the tray item through StatusNotifier. On GNOME, enable an
AppIndicator/KStatusNotifierItem shell extension if the item does not appear.
Check service logs with `journalctl --user -u token-meter-tray.service -n 50`.

## Validate

Run these checks from the repository root:

```bash
PYTHONPYCACHEPREFIX=/private/tmp/token-meter-pycache python3 -m py_compile meter.py
PYTHONPYCACHEPREFIX=/tmp/token-meter-pycache python3 -m py_compile meter.py token_meter_mcp.py menubar/token_meter_tray.py
bash -n scripts/*

# macOS companion
swiftc menubar/TokenMeterMenuBar.swift -o /private/tmp/token-meter-menubar
TOKEN_METER_MENUBAR_SMOKE=1 /private/tmp/token-meter-menubar
node -e "const fs=require('fs'); const html=fs.readFileSync('page.html','utf8'); const m=html.match(/<script>([\\s\\S]*)<\\/script>/); new Function(m[1]); console.log('js ok')"
Expand All @@ -642,13 +681,17 @@ The final command requires at least one supported local Claude, Codex, or Cursor
| |-- tool-analytics.png # README tools and skills screenshot
| `-- menu-bar-widget.png # README menu bar screenshot
|-- menubar/
| `-- TokenMeterMenuBar.swift # native macOS menu bar companion
| |-- TokenMeterMenuBar.swift # native macOS menu bar companion
| `-- token_meter_tray.py # Linux KDE/GNOME AppIndicator tray
|-- scripts/
| |-- install # install the local runtime and login items
| |-- install # select the OS and install the macOS runtime
| |-- install-linux # install the Linux runtime and user services
| |-- run-menubar # build and run the menu bar companion
| |-- start-token-meter # start server if needed, then menu bar
| |-- install-launch-agent # install server and menu login items
| `-- uninstall-launch-agent # remove both macOS login items
| |-- install-launch-agent # install macOS login items
| |-- uninstall-launch-agent # remove macOS login items
| |-- install-systemd-user # install Linux user services
| `-- uninstall-systemd-user # remove Linux user services
|-- REQUIREMENTS.md # product rationale and historical notes
|-- CONTRIBUTING.md
|-- SECURITY.md
Expand Down
2 changes: 1 addition & 1 deletion SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ themselves cannot change configuration, budgets, sessions, or Token Meter state.

Dashboard session deletion uses the same local-origin action token and accepts
only a canonical ID from the currently discovered session inventory. It moves
the exact discovered `.jsonl` file to macOS Trash with collision-safe naming;
the exact discovered `.jsonl` file to the system Trash with collision-safe naming;
it does not delete provider metadata, project files, configuration, Cursor's
shared `state.vscdb` database/WAL, or Cursor request logs. The UI
requires an explicit confirmation and warns when the target appears to be the
Expand Down
Loading