-
Notifications
You must be signed in to change notification settings - Fork 4
CLI Usage
ed usage reports what your coding agents cost and how close you are to a
provider's rate limit. Every number is read back out of the two files behind the
app's dashboard, usage.json and limits-history.jsonl, so the reporting verbs
never recompute anything and the CLI and the UI cannot disagree. Reach for it
when you want a spend figure in a script, a per-project breakdown without
opening the window, or a gate on how much session budget is left.
Both files live in Repo.dataDir, which is
~/Library/Application Support/Edith/data unless the repoPath setting names a
confirmed development checkout, in which case it is apps/dashboard/data inside
that checkout. Every read verb here works whether or not Edith is running. Two
invocations go further. ed usage refresh runs the collection pipeline itself,
in this process, and rewrites usage.json with the app open or closed.
ed usage limits --refresh asks the app to poll the providers first, which
makes it the one invocation here that needs Edith running and exits 4 when it is
closed.
| Command | What it does |
|---|---|
ed usage |
Runs ed usage summary, the default subcommand |
ed usage limits |
Session and weekly rate limits per provider, newest observation per provider |
ed usage summary |
Cost and tokens over a window, in total and per source |
ed usage daily |
Cost and tokens per calendar day, oldest first |
ed usage models |
Cost and tokens per model, most expensive first |
ed usage projects |
Cost and tokens per project, most expensive first |
ed usage sources |
The agents that produced the history, with their ids |
ed usage machines |
Runs ed usage machines ls, the default subcommand |
ed usage machines ls |
Every configured machine, whether it is counted, and what it adds up to |
ed usage machines collect |
Runs the collector on a machine over SSH and brings its numbers back |
ed usage machines enable |
Counts a machine on every later refresh |
ed usage machines disable |
Stops collecting from a machine, keeping what it already gave |
ed usage machines forget |
Drops what a machine gave and stops counting it |
ed usage refresh |
Re-collects usage data from every agent on this Mac |
Prints the most recent rate limit observation for each provider Edith tracks.
ed usage limits [--refresh] [--json]
| Name | Type / values | Default | What it does |
|---|---|---|---|
--refresh |
flag | off | Asks the app to poll the providers again and waits up to 20 seconds for it to say it did, before reading the file. Fails when nothing answers |
--json |
flag | off | Emit JSON on stdout |
A top-level array, one object per provider that has ever been recorded, in the
fixed order codex then claude. session and weekly are each either an
object or null.
[
{
"label": "Codex",
"observedAt": "2026-08-08T16:39:59Z",
"provider": "codex",
"session": null,
"weekly": {
"percent": 0,
"resetsAt": "2026-08-15T16:39:59Z",
"resetsInSeconds": 604797.62
}
},
{
"label": "Claude",
"observedAt": "2026-08-08T16:39:58Z",
"provider": "claude",
"session": {
"percent": 30,
"resetsAt": "2026-08-08T19:50:00Z",
"resetsInSeconds": 11402.481
},
"weekly": {
"percent": 61,
"resetsAt": "2026-08-13T08:00:00Z",
"resetsInSeconds": 400798.117
}
}
]ed usage limits
ed usage limits --json
ed usage limits --refresh
ed usage limits --json | jq -r '.[] | select(.provider == "claude") | .session.percent'
Without --refresh the command mutates nothing and needs no app: it reads the
tail of limits-history.jsonl and reports the last line it finds for each
provider. Only the final 8 KB of that file is read, so a provider whose newest
row has scrolled out of that window is treated as never seen and is left out of
the output entirely.
percent is what the provider reported, stored rounded to one decimal place.
resetsAt is the reset time the provider gave, or null when it gave none, and
resetsInSeconds is computed at print time from your clock, so it goes negative
once the reset moment has passed. The human table shows the session reset as a
coarse duration instead, 3h 10m or 2d 4h, clamped at zero, and a - in any
column the provider has not reported.
--refresh is the refresh button on the rate limit cards. It needs the menu bar
app and exits 4 with refreshing the rate limits needs the Edith menu bar app to be running when Edith is closed. The reply it waits for is only posted when a
poll actually succeeds, so a provider that is failing to answer costs you the
full 20 seconds and then the command fails rather than printing the old numbers:
exit 4 with Edith did not answer for refreshing the rate limits in time, or
with the extension behind refreshing the rate limits is off when
tabUsageEnabled is false. After one second of waiting ed prints waiting for Edith to answer... once, on stderr.
The listener goes up before the request goes out, so an app that answers within the same instant cannot beat it and a poll that worked is never reported as silence. The numbers printed afterwards are read from the file rather than out of the reply.
Even a successful refresh does not guarantee a newer observedAt: the app
appends a history row only when the values differ from the previous one, so
polling twice inside a quiet window leaves the timestamp where it was.
When no provider has ever been recorded the command exits 4 with no limit history yet, hinted with enable the Agent Usage extension and let Edith poll once. That check comes after the refresh, so a --refresh the app answers on a
fresh install reports the emptiness afterwards if nothing landed.
$ ed usage limits
PROVIDER SESSION WEEKLY SESSION RESETS OBSERVED
Codex - 0.0% - 2026-08-08T16:39:59Z
Claude 30.0% 61.0% 3h 10m 2026-08-08T16:39:58Z
Totals cost and tokens over a window, then breaks the same totals down by
source. This is what a bare ed usage runs.
ed usage summary [--range <range>] [--source <source>]... [--machine <machine>]... [--json]
| Name | Type / values | Default | What it does |
|---|---|---|---|
--range |
today, week, month, all
|
all |
Which days to include: today only, the last 7 days, the last 30 days, or everything on file |
--source |
string, repeatable | every source | Count only these source ids. Repeat the flag to include several. An id the file does not list is an error |
--machine |
machine name, ssh alias, id, or local
|
every machine | Count only the agents that ran on these machines. local is this Mac. Repeat the flag to include several. Union with --source rather than an intersection |
--json |
flag | off | Emit JSON on stdout |
{
"bySource": {
"cli": {
"cacheCreationTokens": 175571245,
"cacheReadTokens": 5445483888,
"cost": 5094.730294150003,
"inputTokens": 348913,
"outputTokens": 16022050,
"tokens": 5637426096
},
"codex": {
"cacheCreationTokens": 0,
"cacheReadTokens": 39030016,
"cost": 28.771853,
"inputTokens": 919731,
"outputTokens": 155273,
"tokens": 40105020
}
},
"days": 7,
"generatedAt": "2026-08-08T16:44:18Z",
"range": "week",
"totals": {
"cacheCreationTokens": 175571245,
"cacheReadTokens": 5484513904,
"cost": 5123.502147150003,
"inputTokens": 1268644,
"outputTokens": 16177323,
"tokens": 5677531116
}
}tokens is the sum of the other four token fields, not a separate figure from
the collector. days counts the days in the window that exist in the file, not
the length of the window, so a week range over four days of history reports
4. generatedAt is the string usage.json carries verbatim, and is null
when the file has no such field; ed does not reformat it.
ed usage summary
ed usage summary --range week
ed usage summary --range month --source cli --source codex
ed usage summary --range today --json | jq .totals.cost
Reads only, mutates nothing, and needs no app. It exits 4 when usage.json is
missing, 1 when the file is there but will not decode, and 3 when --range is
not one of the four ranges.
--source is validated against the file. An id nobody recognises exits 3 with
no usage source named <id>, hinted with the ids the file does list, or with a
pointer to ed usage refresh when it lists none, so a typo can no longer come
back as a confident all-zero report. Run ed usage sources first to get ids
that exist. --machine is checked the same way: a machine nothing was collected
from exits 3 with no collected usage from a machine called <name>.
The human output puts three lines above the table, a dollar sign only on the cost line, and orders the table by source id:
$ ed usage summary --range week
cost $5123.50
tokens 5677531116
days 7
SOURCE COST TOKENS
cli 5094.73 5637426096
codex 28.77 40105020
One row per day in the window, cost and tokens.
ed usage daily [--range <range>] [--source <source>]... [--machine <machine>]... [--json]
| Name | Type / values | Default | What it does |
|---|---|---|---|
--range |
today, week, month, all
|
all |
Which days to include |
--source |
string, repeatable | every source | Count only these source ids. Repeat the flag to include several. An id the file does not list is an error |
--machine |
machine name, ssh alias, id, or local
|
every machine | Count only the agents that ran on these machines. local is this Mac. Repeat the flag to include several. Union with --source rather than an intersection |
--json |
flag | off | Emit JSON on stdout |
A top-level array sorted by date ascending. totals is the same six-field
object ed usage summary uses.
[
{
"date": "2026-08-07",
"totals": {
"cacheCreationTokens": 26904348,
"cacheReadTokens": 670275994,
"cost": 647.5789594999999,
"inputTokens": 180723,
"outputTokens": 3836938,
"tokens": 701198003
}
},
{
"date": "2026-08-08",
"totals": {
"cacheCreationTokens": 15319939,
"cacheReadTokens": 765744244,
"cost": 587.5631597500012,
"inputTokens": 97362,
"outputTokens": 3066068,
"tokens": 784227613
}
}
]ed usage daily --range week
ed usage daily --range month --source codex
ed usage daily --json | jq -r '.[] | [.date, .totals.cost] | @tsv'
Reads only, mutates nothing, and needs no app. Same exit codes as
ed usage summary: 4 with no usage.json, 1 on a file that will not decode, 3
on a bad --range or a --source the file does not list.
Days are not filtered out by --source. A day that exists in the window but has
no rows for the sources you asked for still gets a row, with every total at
zero, so the date sequence stays continuous over the days the collector saw. It
is still not a calendar: days the collector never recorded are absent, not
zero-filled.
$ ed usage daily --range week
DATE COST TOKENS
2026-08-02 620.79 877878788
2026-08-03 761.36 729558198
2026-08-04 547.72 705959878
2026-08-05 1035.51 535978079
2026-08-06 922.99 1342730557
2026-08-07 647.58 701198003
2026-08-08 587.56 784227613
Cost and tokens per model, so you can see which model is actually spending the money.
ed usage models [--range <range>] [--source <source>]... [--machine <machine>]... [--json]
| Name | Type / values | Default | What it does |
|---|---|---|---|
--range |
today, week, month, all
|
all |
Which days to include |
--source |
string, repeatable | every source | Count only these source ids. Repeat the flag to include several. An id the file does not list is an error |
--machine |
machine name, ssh alias, id, or local
|
every machine | Count only the agents that ran on these machines. local is this Mac. Repeat the flag to include several. Union with --source rather than an intersection |
--json |
flag | off | Emit JSON on stdout |
A top-level array sorted by totals.cost descending.
[
{
"model": "claude-opus-5",
"totals": {
"cacheCreationTokens": 153031472,
"cacheReadTokens": 4093821515,
"cost": 3747.5389512500024,
"inputTokens": 335270,
"outputTokens": 13006480,
"tokens": 4260194737
}
},
{
"model": "gpt-5.6-sol",
"totals": {
"cacheCreationTokens": 0,
"cacheReadTokens": 39030016,
"cost": 28.771853,
"inputTokens": 919731,
"outputTokens": 155273,
"tokens": 40105020
}
}
]ed usage models
ed usage models --range week
ed usage models --range month --source cli
ed usage models --json | jq -r '.[0].model'
Reads only, mutates nothing, and needs no app. Same exit codes as
ed usage summary.
A row whose model name is missing from the file is grouped under the literal
name unknown rather than dropped, so the model totals always add up to the
summary totals for the same window and sources.
$ ed usage models --range week
MODEL COST TOKENS
claude-opus-5 3747.54 4260194737
claude-fable-5 1202.34 777247635
claude-sonnet-5 144.57 598911741
gpt-5.6-sol 28.77 40105020
claude-haiku-4-5-20251001 0.28 1071983
Cost and tokens per project, from the per-project rollup the collector attaches to each day.
ed usage projects [--range <range>] [--limit <n>] [--json]
| Name | Type / values | Default | What it does |
|---|---|---|---|
--range |
today, week, month, all
|
all |
Which days to include |
--limit |
integer greater than zero | 25 |
Show at most this many projects, taken from the top of the cost order |
--json |
flag | off | Emit JSON on stdout |
This is the one window command that does not take --source. It declares its
own --range, so --source here is an unknown option and exits 2.
A top-level array sorted by cost descending, truncated to --limit. The
per-project rows carry only cost and tokens, not the six-field totals object the
other commands use.
[
{
"cost": 1837.7667801071357,
"project": "noveum-app-nextjs",
"tokens": 1887083203
},
{
"cost": 1340.774043018298,
"project": "edith",
"tokens": 1664124164
},
{
"cost": 988.1540715389959,
"project": "fable",
"tokens": 919092634
}
]ed usage projects
ed usage projects --range week --limit 5
ed usage projects --range today --json | jq -r '.[] | .project'
Reads only, mutates nothing, and needs no app. It exits 4 with no usage.json,
1 on a file that will not decode, 3 on a bad --range, and 2 on --limit 0 or
a negative limit, which is checked as "must be greater than zero" rather than
read as "all of them".
A project's name is the collector's projectName, falling back to its path and
then to the literal unknown. Names come from the git root of the working
directory a chat ran in, which is why a chat run inside a worktree is attributed
to the repository rather than to the worktree folder, and why a machine's remote
projects arrive suffixed with the machine name.
These numbers come from a different part of the file than every other verb here:
ed usage summary, daily and models read bySource, while projects reads
the projects array. They are derived from the same transcripts but rolled up
separately, so the project totals will not tie out to the summary totals to the
cent, and no --source filter applies to them.
$ ed usage projects --range week --limit 5
PROJECT COST TOKENS
noveum-app-nextjs 1837.77 1887083203
edith 1340.77 1664124164
fable 988.15 919092634
macos 303.80 383653333
x-convo-exporter 228.97 191821868
Lists the agents that produced the history, which is where the ids --source
expects come from.
ed usage sources [--json]
| Name | Type / values | Default | What it does |
|---|---|---|---|
--json |
flag | off | Emit JSON on stdout |
A top-level array in the file's own order, not sorted. label, tool,
machine and machineID are null when the file carries no such metadata for
that id, and an agent that ran on this Mac carries no machine at all.
[
{
"default": true,
"id": "cli",
"label": "Claude Code",
"machine": null,
"machineID": null,
"tool": "Claude Code"
},
{
"default": true,
"id": "codex",
"label": "Codex",
"machine": null,
"machineID": null,
"tool": "Codex"
},
{
"default": true,
"id": "commandcode",
"label": "Command Code",
"machine": null,
"machineID": null,
"tool": "Command Code"
},
{
"default": true,
"id": "asus-tuf-7:cli",
"label": "Claude Code · Asus TUF 7",
"machine": "Asus TUF 7",
"machineID": "4303DCF1-52D8-4075-AE9B-C2FD86D3821A",
"tool": "Claude Code"
},
{
"default": true,
"id": "opencode",
"label": "OpenCode",
"machine": null,
"machineID": null,
"tool": "OpenCode"
},
{
"default": true,
"id": "cowork",
"label": "Cowork",
"machine": null,
"machineID": null,
"tool": "Claude Code"
}
]default says whether the id is in the file's defaultSources, which is the
set the dashboard pre-selects. It is not a filter ed applies anywhere: every
read command counts every source unless you pass --source.
ed usage sources
ed usage sources --json
ed usage sources --json | jq -r '.[].id'
Reads only, mutates nothing, and needs no app. It exits 4 with no usage.json
and 1 on a file that will not decode. It takes no window options, so there is no
exit 3 here.
The human table falls back to the id in the LABEL column when the file has no
label, and prints an empty TOOL cell when it has no tool. The MACHINE column
reads this Mac for a source with no machine metadata and the machine's name
for one the collector brought back over SSH; --json carries the same name as
machine, alongside the machineID the machine directory knows it by. When the
file lists no sources at all the command prints the header line by itself and
exits 0.
$ ed usage sources
ID LABEL TOOL MACHINE
cli Claude Code Claude Code this Mac
codex Codex Codex this Mac
commandcode Command Code Command Code this Mac
asus-tuf-7:cli Claude Code · Asus TUF 7 Claude Code Asus TUF 7
opencode OpenCode OpenCode this Mac
cowork Cowork Claude Code this Mac
Counts the agents running on your SSH machines alongside the ones on this Mac.
ed usage machines on its own runs ls.
The collector Edith runs here is piped to the machine and run against that
machine's home directory, and the numbers come back into the same usage.json
the dashboard reads. Each agent on a machine arrives as its own source, named
<machine-slug>:<agent>, so ed usage summary counts the fleet, --source asus-tuf-7:cli narrows to one agent on one machine, and --machine narrows to
everything one machine ran.
Whatever the collector needs and cannot find there, jq, bun and ccusage, is
installed under ~/.cache/edith on that machine. That is why collecting waits
to be asked rather than happening for every machine you have configured, and why
the first run on a machine can take minutes.
Lists every configured machine, whether it is counted, and what it has given.
ed usage machines ls [--json]
| Name | Type / values | Default | What it does |
|---|---|---|---|
--json |
flag | off | Emit JSON on stdout |
--json shape, an array with one object per configured machine, whether or not
it has ever been collected:
[
{
"collectedAt": "2026-08-08T16:14:51Z",
"cost": 249.81,
"counted": true,
"days": 81,
"host": "asus-tuf-7",
"id": "1F0A9C22-4E64-4C63-9E0B-2F5A1E7D2C10",
"machine": "Asus TUF 7",
"sources": ["asus-tuf-7:cli"],
"tokens": 321812580
}
]A machine that has never been collected still appears, with collectedAt and
host as null, sources empty, and days, cost and tokens at zero. The
human table writes - in those columns instead.
$ ed usage machines
MACHINE COUNTED COLLECTED SOURCES COST TOKENS
Asus TUF 7 yes 2026-08-08T16:14:51Z 1 249.81 321812580
Reads only, mutates nothing, needs no app. With no machines configured at all it
exits 3 with no machines are configured.
Runs the collector on a machine over the shared SSH connection and folds the result in.
ed usage machines collect [<machine>] [--once] [--verbose] [--timeout <seconds>] [--json]
| Name | Type / values | Default | What it does |
|---|---|---|---|
<machine> |
machine name, ssh alias or id | every machine already taking part | Which machine to collect. Naming one also signs it up for later refreshes unless --once is passed |
--once |
flag | off | Collect without signing the machine up, so later refreshes skip it |
--verbose |
flag | off | Print everything the collector said on the machine, on stderr |
--timeout |
integer seconds, greater than 0 | 900 |
Give up on a machine after this long |
--json |
flag | off | Emit JSON on stdout |
--json shape:
{
"collected": [
{
"cost": 249.81,
"days": 81,
"id": "1F0A9C22-4E64-4C63-9E0B-2F5A1E7D2C10",
"machine": "Asus TUF 7",
"sources": ["asus-tuf-7:cli"],
"tokens": 321812580
}
],
"failed": [],
"merging": true
}merging says whether the menu bar app was running and was asked to fold the
new numbers into the dashboard. When it is false the numbers are on disk but
the dashboard will not show them until Edith starts or you run
ed usage refresh.
ed usage machines collect "Asus TUF 7"
ed usage machines collect tuf --once
ed usage machines collect --timeout 1800 --verbose
ed usage machines collect --json | jq '.collected[].sources'
Failures are per machine rather than fatal: a machine that cannot be reached is
listed in failed with its error while the others still count. The command only
fails when nothing at all was collected, and then it exits 4 with the first
error. With no machine named and none signed up yet it exits 3 with no machine is counted towards usage yet. A --timeout of zero or less exits 2.
Collecting also prunes stored usage for machines that are no longer in the directory, so removing a machine and collecting again forgets it.
Signs a machine up so every later refresh collects it.
ed usage machines enable <machine> [--json]
| Name | Type / values | Default | What it does |
|---|---|---|---|
<machine> |
machine name, ssh alias or id | required | Which machine to count |
--json |
flag | off | Emit JSON on stdout |
{
"counted": true,
"machine": "Asus TUF 7"
}This only changes whether the machine takes part; it collects nothing by itself, so a machine enabled but never collected still reports nothing until a refresh runs. A name that matches no machine exits 3.
Stops collecting from a machine while keeping the numbers it already gave.
ed usage machines disable <machine> [--json]
| Name | Type / values | Default | What it does |
|---|---|---|---|
<machine> |
machine name, ssh alias or id | required | Which machine to stop collecting |
--json |
flag | off | Emit JSON on stdout |
{
"counted": false,
"machine": "Asus TUF 7"
}The machine's existing sources stay in usage.json and keep counting towards
every total. Use forget to drop them. A name that matches no machine exits 3.
Drops everything a machine gave and stops counting it.
ed usage machines forget <machine> [--json]
| Name | Type / values | Default | What it does |
|---|---|---|---|
<machine> |
machine name, ssh alias or id | required | Which machine to drop |
--json |
flag | off | Emit JSON on stdout |
{
"dropped": true,
"machine": "Asus TUF 7",
"merging": true
}dropped is false when there was nothing stored for that machine, and then
merging is false too, because the app is only asked to re-fold when
something actually went away. This is the one verb here that accepts a raw id
for a machine that is no longer in the directory, so usage left behind by a
deleted machine can still be cleared.
Re-collects usage data from every agent on this Mac and rewrites usage.json.
ed usage refresh [--follow] [--json]
| Name | Type / values | Default | What it does |
|---|---|---|---|
--follow |
flag | off | Attach to a refresh that is already running instead of starting one, and fail when there is nothing to watch |
--json |
flag | off | Emit JSON on stdout |
{
"completed": true,
"followed": false,
"phases": [
{
"detail": "cached",
"name": "ccusage",
"seconds": 0.01
},
{
"detail": "27 days",
"name": "cli",
"seconds": 1.47
},
{
"detail": "125311 messages",
"name": "walk",
"seconds": 3
}
],
"seconds": 9.98,
"summary": {
"machines": "Asus TUF 7",
"sources": "cli, codex, commandcode, asus-tuf-7:cli",
"spend": "$10876.85 · 378 sessions · 401 KB",
"window": "2026-07-08 to 2026-08-08 · 27 days · 7 models"
}
}completed is always true: reaching the JSON at all means the pipeline
finished, because every other outcome is an error. followed says whether this
invocation watched a run someone else had started instead of starting its own.
seconds is the pipeline's own total, phases carries every phase row in the
order they landed, three of the eight above, and summary is the closing block
keyed by label.
ed usage refresh
ed usage refresh --follow
ed usage refresh --json | jq -r '.summary.spend'
ed usage refresh && ed usage summary --range today
This is the only verb in the group that changes anything, and ed does the work
itself. It runs the same collection pipeline EdithKit hands the app, in this
process, so it needs no menu bar app and there is nothing to time out on. A
first run takes noticeably longer, because the collector installs ccusage, and
jq or bun when they are missing, before it can read anything.
Progress goes to stderr and stdout stays clean: one usage refreshed line at
the end, or the JSON object. Each phase is printed as it lands, with a spinner on
the phase in flight, and the whole display is skipped when --json is passed or
stderr is not a terminal, so a pipe sees nothing extra. NO_COLOR and
TERM=dumb switch it off too, rather than only dropping the colour.
A run holds a lock on refresh.lock in the data directory, so two of them
cannot clobber usage.json. When one is already running, in the app or in
another terminal, ed attaches to it instead of starting a second, printing a refresh is already running, attaching to it and reporting that run's phases as
they land. --follow asks for that explicitly, and that is the difference
between the two: with nothing running it exits 4 with no usage refresh is running, hinted drop --follow to start one, where a plain ed usage refresh
would have started one.
A pipeline failure is an error rather than a quiet success. What the collector
reported becomes the message, exit 4, hinted at data/refresh.log, which is
where the same transcript is written line by line while the run happens. A run
that was attached to and then stopped without finishing fails the same way.
$ ed usage refresh
EDITH · refresh usage · 2026-08-08 23:57:31
────────────────────────────────────────────────────
▸ ccusage cached 0.01s
· discovering sources
▸ cli 27 days 1.47s
▸ codex 12 days 0.83s
▸ commandcode 1 days 0.85s
· assembling usage.json
· walking 900 transcript files
▸ walk 125311 messages 3.00s
▸ projects 174 repos 2.35s
▸ merge hours + projects merged 1.32s
▸ machines 1 folded in 0.05s
────────────────────────────────────────────────────
✓ sources cli, codex, commandcode, asus-tuf-7:cli
✓ machines Asus TUF 7
✓ window 2026-07-08 to 2026-08-08 · 27 days · 7 models
✓ spend $10876.85 · 378 sessions · 401 KB
✓ done in 9.98s
usage refreshed
| Code | When this group produces it |
|---|---|
| 0 | The command printed its report, or the refresh finished. Also a read that legitimately found nothing to show |
| 1 |
usage.json exists but will not decode: could not read <path>: <reason>
|
| 2 |
--limit 0 or a negative limit on ed usage projects, plus the usual parse failures, an unknown flag, a missing value, or --source passed to ed usage projects
|
| 3 |
--range is not today, week, month or all, and the hint lists the four. Also a --source id or a --machine the file knows nothing about |
| 4 | No usage.json at all; no rate limit history at all; a usage refresh whose pipeline failed, or --follow with nothing running; or Edith not running, or not answering, for ed usage limits --refresh
|
-
ed usagewith no subcommand runsed usage summary, so a bareed usageprints the all-time totals rather than a help screen.ed usage --helpis still the help screen, and exits 0. - The two files are independent.
ed usage limitsreads onlylimits-history.jsonland works with nousage.jsonat all; every other verb reads onlyusage.jsonand works with no limit history. Neither absence affects the other. -
--range weekmeans the last 7 days and--range monththe last 30, both counted back from midnight today and both including today. The comparison is made on theYYYY-MM-DDstring, so it is your local calendar day, and there is no upper bound: a day stamped in the future is always included. - Cost and token figures are doubles all the way through, and the serialiser
prints an integral double as an integer.
"percent": 30is 30.0 and"cost": 0is a genuine zero, not a missing field. - Token counts in the human tables are truncated to a whole number, not rounded,
and costs are formatted to two decimal places. Only
--jsongives you the unrounded values. - Object keys in
--jsonare sorted, arrays keep the order the command chose: fixed provider order forlimits, date ascending fordaily, cost descending formodelsandprojects, and the file's own order forsources. - The read verbs never reach the network and only ever show the last thing that
was written.
ed usage limits --refreshposts a request and waits for the app to do the polling, whileed usage refreshruns the collector in this process, which makes it the one invocation here that goes out and fetches anything itself. - Both refreshing invocations fail rather than reporting stale numbers, so exit
0 from either does mean the work happened.
observedAtcan still repeat aftered usage limits --refresh, because the app appends a history row only when the values changed. -
ed config set tabUsageEnabled falseturns off the Agent Usage extension, and with it the app's own collection and the limit polling;claudeLimitsEnabledandcodexLimitsEnableddo the same for a single provider's polling.ed usage refreshruns the pipeline itself and collects either way. The read verbs keep working against whatever was collected before that, soed usage limitsgoes on printing a silenced provider's last row until it scrolls out of the 8 KB tail.
-
ed configfortabUsageEnabled,claudeLimitsEnabled,codexLimitsEnabledandrepoPath, which decide what gets collected and where it lands -
ed extensionsfor turning the Agent Usage extension on and off by id -
ed permissionsfor the grants the app needs before it can collect anything -
ed systemfor this Mac's metrics, the other read-only reporting group - All
edcommands
Auto-generated from docs/, edit the docs in the repo, not the wiki.
CLI reference
Companion
- Deploy
- Concepts
- Concepts Memory
- Concepts Ingestion
- Concepts Search
- Concepts Chat
- Concepts Learning
- Concepts Brain
- Concepts Friend
- Hosts
- Stack
- Status
- Doctor
- Search
- Index
- Ingest
- Episodes
- Sync
- Observations
- Reflect
- Beliefs
- Ask
- Extract
- Claims
- Corroborate
- Runs
- Chat
- Conversations
- Forget
- Export
- Import
- Erase
- Wipe
- Episode
- Nightly
- Reason
- Personas
- Council
- Lenses
- Core
- Why
- Hypotheses
- Predictions
- Commitments
- Discrepancies
- Calibration
- Inquire
- Entities
- Eval
- Standup
- Machines
- Baselines
- Connectors
- Facts
- Correct
- Weekly
- Db
Guides