* Add agent usage collectors that write display-ready data files
One omarchy-agent-usage-scan-<agent> collector per AI coding agent prints a
complete display-ready usage record — identity, tier, status, rate limits,
and today/week/all-time stats. omarchy-agent-usage-update runs every
collector it finds and writes the records atomically to
~/.local/state/omarchy/agents/usage/, so anything that displays usage only
ever reads JSON from there.
The Claude collector absorbs what the shell previously did in-process:
transcript scanning, the stats-cache/history fallback, credentials parsing,
and the OAuth limits probe, now with a probe throttle and last-good limits
kept across network failures. The Codex collector is the existing scanner
reshaped to the shared record contract.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Redo the model-usage plugin as omarchy.agents watching usage data files
The panel is now strictly a display. It discovers the JSON records that
omarchy-agent-usage-update maintains under
~/.local/state/omarchy/agents/usage/, watches them for changes, and draws
whatever appears — so adding an agent means shipping a collector, never
touching the panel. Marks resolve by convention (assets/<id>.svg with an
optional -light twin), the limits meters read a generic limits array, and
the per-provider QML adapters and in-plugin scanner scripts are gone.
Cross-device sync aggregation stays in the shell and keeps the snapshot
field names older versions wrote, so mixed-version fleets still merge in
both directions.
With the provider fan-out gone, the widget takes its real name: the plugin
id becomes omarchy.agents. A migration renames it wherever a user's config
mentions it — layout entries keep their settings and position, a disabled
widget stays disabled — then primes the data files once and drops the old
scanner cache. The migration test also drops a stale assertion that expected
migrations to restart the shell themselves, which c992cdff moved to
omarchy update.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Address Codex review: synced-only tabs, limits retry, history fallback
Three data-availability gaps from review. An agent whose records only exist
in synced snapshots — a collector installed on just one machine — now gets
its tab by unioning the synced aggregate into the provider list, with rate
limits blank since those never travel. A Claude limits probe that reaches no
server at all writes retryAdvised into its record, and the shell honors it
with one 30-second retry instead of waiting out the full refresh interval,
restoring the old boot-before-DHCP behavior. And a machine with only
history.jsonl — no transcripts, no stats-cache — still reports today's
prompt and session counts.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Address second Codex pass: history-only visibility, targeted retries
Today's prompt and session counts now count toward an agent's presence in
the bar, so a machine whose only Claude source is history.jsonl shows up
without waiting for limits. And the 30-second limits retry passes the
advising agent ids to the updater, so an outage at one provider no longer
puts every other collector on a retry treadmill.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Drop omarchy-cmd-present jq guards from the agents migrations
jq ships in the default package set, which makes it a runtime invariant per
AGENTS.md — call it directly. The migration tests lose their now-unused
omarchy-cmd-present stubs with it.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Drop the scan infix from the collector command names
Collectors are omarchy-agent-usage-<agent>; the updater skips its own name
when globbing them, and the update test proves it with a decoy.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Keep the credential store out of the printed usage record
The Claude collector now reads .credentials.json once into three scalars —
the access token, its expiry, and the plan label — instead of passing the
parsed store around. The token reaches nothing but the Authorization header
of the limits probe, and only the plan label may travel into the record,
which is what CodeQL's clear-text-logging alert on the record print was
unable to see when the whole dict flowed through.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Agents
One bar icon and one panel for every AI coding subscription on the machine.
The panel is strictly a display: it watches the usage records that
omarchy-agent-usage-update writes to ~/.local/state/omarchy/agents/usage/
and draws whatever appears there. Panel.qml owns the bar button and the
popup; Main.qml discovers and watches the records (and handles the optional
cross-device aggregation); Agent.qml is the per-record file watcher.
Panel
- Hero — the mark, the tool, and the plan it runs on ("Max 20x", "Pro"). Auth and endpoint problems replace the plan line and repeat in a card.
- Subscription switch — one chip per enabled agent (
h/lor click). It appears only when more than one agent is enabled. - Limits — the percentage of each allowance used, a matching meter, and the time until the session or weekly window resets.
- Tokens by day — one row per day for the last week: day, bar, tokens, with today bolded at the bottom. Hover today for its prompt and session count.
- Tokens by model — tokens per model with the bar behind each row scaled to the heaviest model, the same way the weekly chart scales to its busiest day. Hover for the input / output / cache split.
A subscription appears only when it is enabled in settings and has actually recorded usage — on this machine or on a synced one. With one such agent there is no switch row at all; with none, the module leaves the bar entirely rather than sitting there with nothing to say. A CLI installed mid-session shows up at the next refresh, so nothing polls the disk waiting for it.
That self-hiding is why the widget ships in the default bar layout: a machine
that has never run an AI coding agent draws nothing, and the icon arrives on
its own the first time a scan finds usage. Drop it with
omarchy plugin disable omarchy.agents.
Data
Each agent is one JSON record in ~/.local/state/omarchy/agents/usage/,
written by omarchy-agent-usage-update. That command runs one
omarchy-agent-usage-<agent> collector per agent; the widget invokes it
on its refresh timer and whenever you ask for a refresh, and picks up any
record that lands in the directory regardless of who wrote it.
Adding an agent therefore never touches this plugin: ship a collector that
prints the record contract (see the claude and codex collectors in
bin/), and the panel gains a tab. An assets/<id>.svg mark is optional —
with an assets/<id>-light.svg twin if the mark needs a dark variant for
light surfaces — and the bar glyph stands in when there is none.
| Collector | Limits | Local stats |
|---|---|---|
claude |
Anthropic's OAuth usage endpoint (5-hour session + 7-day weekly) | ~/.claude/projects transcripts, plus stats-cache.json and history.jsonl as fallback |
codex |
The Codex app-server RPC | native Codex CLI session files (and pi sessions) |
Claude limits need a signed-in CLI; without credentials the panel says so and
falls back to local stats only. A non-default Claude directory is honored via
CLAUDE_CONFIG_DIR, Codex via CODEX_HOME.
Interactions
- Bar icon: left = panel, right = refresh, middle = next subscription.
- Panel:
h/lswitch subscription,j/kscroll,ror Enter refresh, Tab moves to the neighboring bar panel, Esc closes. - IPC:
omarchy-shell omarchy.agents <open|close|toggle|refresh|next>.
Settings
Settings live in the widget's entry in ~/.config/omarchy/shell.json. The
top-level keys can be set with
omarchy bar set omarchy.agents <key> <value>:
| Key | Default | What it does |
|---|---|---|
refreshIntervalSec |
900 |
How often the usage records regenerate |
syncMode |
"Off" |
"On" writes this machine's snapshot and merges the others |
syncDir |
"" |
A folder synced by Syncthing, Dropbox, rsync, … |
syncFileName |
<hostname>.json |
This machine's snapshot file |
syncDeviceId |
hostname | Stable device name inside the snapshot |
Numbers need --json, or they land in shell.json as strings:
omarchy bar set omarchy.agents refreshIntervalSec 300 --json
omarchy bar set omarchy.agents syncDir '~/Sync/agent-usage'
Per-agent enablement is nested, and set writes its key literally rather
than walking a dotted path — so pass the whole providers object as JSON (or
edit shell.json directly):
omarchy bar set omarchy.agents providers '{
"claude": { "enabled": true },
"codex": { "enabled": false }
}' --json
enabled defaults to true for every discovered agent; set it to false to
hide a subscription that is installed. Disabled agents are also skipped when
the records regenerate.
With syncMode on, every *.json snapshot in syncDir is merged, so today,
the last 7 days, and the all-time totals cover every machine you code on —
active days are unioned by date rather than summed. Rate limits stay
per-account and are never merged.
One caveat on "all-time": the Codex collector only reads native session files touched in the last 30 days, so Codex totals and its day count cover that window. Claude's cover every transcript still on disk.