Skip to main content
Version: dev

Read the numbers

You installed Cortex and started abctl observe. Now you see traffic. This page explains what the numbers mean and what to do with them.

Cortex shows you what your coding agent sent and what it cost. It shows the model calls, the tool calls and the token counts for each session, on your own computer, as they happen. Your agent does not report this. Your model provider reports a monthly total, not one session while you work. Cortex is the view between the two.

The data stays on your computer

Cortex captures this traffic on your computer and keeps it there. It does not collect the data and it does not send the data to Rossoctl or to any other service. The data is for you to read and to inspect. When you stop the service, the data goes with it. See Manage the service.

What the numbers tell you

The numbers support four decisions:

  • Find an expensive prompt. One session that costs much more than the others shows you where the cost is.
  • See whether caching operates. A high cache-read count means the model reuses your prompt. A low count means it does not, and you pay the full rate each turn.
  • Catch a session that does not end. A token count that grows without a result is an agent in a loop. You stop it before it costs more.
  • Decide whether to prune tool definitions. The pruning figure shows the tokens that Cortex removed, so you know if the feature is worth enabling. See Cost control.
  • See the spend for a day, a week or a month. The spend band holds one figure for each of four periods. See Read the spend band.
  • See which rate tier holds the cost. The spend breakdown divides the spend by tier and by model. A large cache-write figure and a small cache-read figure is a cache that does not hold.

You can read this page before you install Cortex. It describes what Cortex shows you that you cannot otherwise see.

Watch a session

abctl observe opens a terminal interface. You land on the Sessions view. The other views open with a key, and they return to the view that you opened them from.

  • Sessions. A list of the sessions, with the most recent one first. Each row shows the identifier, the title, the time of the last event, the event count, the token total, the cost, the saving and the context gauge.
  • Events. The calls in one session. Each row shows the time, the direction, the protocol, the model or the method, the status, the duration and the host. Press Enter on a session to open it.
  • Detail. The full content of one event, as formatted JSON. Press Enter on an event to open it.
  • Spend breakdown. Where the money went, by rate tier, and who spent it. Press $.
  • Usage charts. A metric over a time window, as a chart. Press u.

Keys

KeyAction
or k jMove between rows
EnterOpen the selected row
EscReturn to the previous view
/Filter the events
$Open the spend breakdown
uOpen the usage charts
cOpen the column picker, in the Events view
pPause and resume the stream
yWrite the event to a file in ~/.cortex/abctl-events/
g GMove to the top or the bottom
?Open the key help
q or Ctrl+CQuit

The key help (?) is a map of the views. It shows each key and the view that the key acts on.

The / key filters the events by a text match. For example, messages shows only the events that contain that text. The match covers many fields of an event, not the method alone — the host, the method, the plugin name, the reason, the path, and the message content all count.

Two searches are special:

  • deny shows only the events that a plugin denied.
  • plugin:<name> shows only the events that the named plugin acted on. For example, plugin:jwt-validation.

It is a text match, not a query language. You cannot filter on a condition such as a duration.

Read the tokens

A model call has a cost in tokens. Cortex prices the tokens in four categories, because each category has a different rate.

CategoryWhat it isWhy it is separate
InputThe prompt tokens that the model read for the first timeYou pay the full rate for these.
Cache writeThe prompt tokens that the model wrote to its cacheMore than the input rate. This is the one-time cost to store the prompt.
Cache readThe prompt tokens that the model read from its cacheMuch less than the input rate. This is caching that operates.
OutputThe tokens that the model generated

Cortex also captures a reasoning count. These are the output tokens that the model used to reason, on a model that reports them. They are a part of the output count, not a fifth priced category.

Why cache read and cache write are two numbers

A model can cache a part of your prompt. The next call that sends the same part reads it from the cache. This is useful for a coding agent, because the agent sends the same system prompt and the same files on each turn.

The two cache numbers have different prices, so Cortex keeps them apart:

  • A cache write costs more than an input token. You pay a premium once, to store the prompt.
  • A cache read costs a fraction of an input token. You save on each later turn that reuses the prompt.

The split tells you whether caching earns its cost:

  • A large cache-read count means the cache operates. You pay the low rate for most of the prompt.
  • A cache-write count that repeats, with little cache-read, means the cache does not hold. You pay the premium again and again and get no saving. This happens when the prompt changes on each turn.

Read the cost

Cortex applies a price to each token category and adds the results. The figure is the cost of the session.

  • The cost is an estimate, unless the provider returns an exact figure. Cortex computes the cost from published rates for each model. When the provider returns an exact cost (for example, the x-litellm-response-cost header from LiteLLM), Cortex uses that figure instead.
  • The rates come from a table for each model. A model that Cortex does not recognize has no rate. Cortex then shows no cost for that call, rather than a misleading zero, even though the token counts are still correct. A blank cost with correct tokens means the model is unpriced, not free.

Read the sessions table

The Sessions view is the table that you land on. This is one capture of it:

abctl · http://localhost:9094
LAST 1H TODAY 7 DAYS MONTH
$4.04 $18.80 $216.44 $703.18
────────────────────────────────────────────────────────────────────────────────────
SESSION TITLE UPDATED EVENTS TOKENS COST SAVED~ CONTEXT(1M)
ctx-abc-123… …pend-spans 3s ago 42 48.2k $0.12 $0.01 ▕███████▎ ▏
ctx-def-567… weather-ag… 18m ago 15 1.2k <$0.01 — ▕▏ ▏
ctx-ghi-901… 42m ago 7 2.9k — — ▕███▊ ▏
default 1h ago 8 — — — —

Read the columns as follows.

ColumnWhat it shows
SESSIONThe session identifier, truncated.
TITLEThe name of the session, from the transcript of Claude Code. It is empty for a session that nothing named.
UPDATEDThe time since the last event.
EVENTSThe count of the calls in the session.
TOKENSThe token total for the session.
COSTThe cost of the session.
SAVED~The cost that a reduction plugin avoided.
CONTEXT(1M)How full the context of the conversation was on its last turn.

An em dash () means that Cortex has no figure. It does not mean zero. A session with tokens and no cost holds a model that the rate table does not name.

The two money columns need a terminal of 97 columns or more. On a narrower terminal Cortex removes both columns. It does not show a rounded figure in their place.

Read the context gauge

CONTEXT(1M) is a gauge, not a figure. It shows how full the context of your conversation was on its last turn, against a window of one million tokens. The brackets are the scale, and Cortex draws them on each row. An almost empty session therefore reads as empty, and not as a blank cell.

Claude Code sends three kinds of traffic under one session identifier: your conversation, the subagents that it starts, and its own short internal calls. The gauge follows your conversation only. It reads the last turn of that conversation, and it does not average a set of recent turns.

Read the spend band

The four figures above the table are the spend band. Each cell covers one period, and the label names the period.

CellPeriod
LAST 1HA rolling hour.
TODAYFrom local midnight to now.
7 DAYSA rolling seven days.
MONTHFrom the first day of the local month to now.

TODAY and MONTH are boundaries, and not lengths. Each one is narrow at the start of its period, and it widens through the period. 7 DAYS is a rolling window, so it is the one cell that no calendar edge aligns to. Compare 7 DAYS against MONTH with that difference in mind.

A cell that shows is a period that your deployment cannot answer. Three of the four cells read from a cost ledger. A local install holds that ledger, and Kubernetes does not hold it by default. Cortex shows in place of a figure that covers a shorter period than the label states.

A cell also carries its own age when its data stops arriving. TODAY 7m is a figure from seven minutes ago. Each cell polls on its own schedule, so the age belongs to the cell and not to the band.

The band and the table cover different periods

The COST column of the sessions table can add up to less than TODAY. The session store is in memory, so the table reaches back only to the start of the current proxy process. TODAY reads from the cost ledger on disk, and it survives a restart of the service. A table that adds up to less than the band is therefore correct after a restart.

Read the spend breakdown

Press $ to expand the band. The breakdown holds two columns:

WHERE IT WENT BY MODEL
output ██████ $2.70 claude-opus-5 $4.55 35 req 5.6M tokens
cache-read ███▌ $1.62
input ▍ $0.22
cache-write —
[a] [model] · endpoint · agent [w] 1h esc closes

The left column is the four rate tiers. They are the same four token categories that Read the tokens describes, priced. The right column is who spent the money. Press a to change it between the model, the endpoint and the agent. Press w to change the period.

Cortex models the tier figures from the rate table. It does not measure them. A gateway reports one figure for a call, and it never divides that figure by tier. Cortex apportions the tiers, so the column adds up to the total of the period. A tier that the rate table does not name reads , and not $0.00, because $0.00 claims that the tier is free.

What a marker on a figure means

A figure carries a marker when Cortex cannot state it exactly. A figure with no marker is exact.

MarkerMeaning
~The figure is an estimate, so it is a lower bound and not an exact total.
+The figure is a floor. Cortex could not price some traffic, or the period reaches past what the ledger holds.
!The figure is short by an amount that Cortex cannot state.

The ~ on SAVED~ sits in the heading, and not on each value. Cortex estimates each saving, so a marker on each row distinguishes nothing.

How precise a money figure is

Cortex shows money in one of two forms, and which form depends on the surface.

  • Cents. The four cells of the spend band, the COST and SAVED~ columns of the sessions table, the COST of the usage charts, and both columns of the spend breakdown. You read these figures down a column, and you compare them against each other. Two more digits add noise.
  • Four decimals. The COST column of the events table. One request costs $0.000038, so cents render a whole column as the same value.

Cortex never prints a figure above zero as $0.00. A cents figure below one cent reads <$0.01, and a four-decimal figure reads <$0.0001. A figure of zero is a claim about the traffic, and never the result of rounding.

Read the cost of a longer period

abctl cost prints the spend for one period, without the terminal interface.

abctl cost # today, from local midnight
abctl cost --window month # this month, from the first day
abctl cost --window 7d # the last seven days
abctl cost --window 1h # a rolling hour
abctl cost --json # the totals as JSON, for a script

The command prints the period that the proxy answered, and not the period that you asked for. A deployment with no cost ledger answers with the longest period that it holds. A figure of six hours under the label of a month understates the month, so Cortex names the period it served.

Read the usage charts

Press u to open the usage charts. The charts show one metric over one time window. Four keys change what you see.

KeyAction
mChange the metric: tokens, requests, errors, latency or cost.
wChange the window: 10 minutes, 1 hour or 6 hours.
bChange the breakdown: none, status, method or plugin.
sChange between this session and all of the sessions.

The latency metric has no breakdown. Cortex records latency for a call, and not for a label.

abctl writes your choice of metric, window and breakdown to ~/.cortex/abctl-config.yaml. The charts open with the same choice the next time. abctl also writes the column selection and the filter of the events table to that file.

Read the latency

Cortex records two times for each model call.

  • Time to first token. The time from the request to the first part of the reply. For a reply that streams, this is the time until you see the first word. It is the number that decides how fast the agent feels.
  • Total response time. The time from the request to the last part of the reply. It depends on the length of the reply.

For a set of calls, Cortex reports percentiles.

  • p50 is the middle value. Half of the calls are faster. It is the typical experience.
  • p95 and p99 are the slow calls. Ninety-five or ninety-nine percent of the calls are faster. These are the calls that a user notices. A p50 that is good with a p99 that is bad means that most calls are fast, but the slow calls are very slow.

Read the pruning savings

If you enable tool pruning, Cortex removes the tool definitions that the agent does not use, before the request goes to the model. The savings figure is the tokens and the cost that the pruning removed. See Cost control.

  • A figure above zero is the saving for that session. You paid less because Cortex sent a smaller request.
  • A figure of zero means that Cortex removed nothing. The usual cause is an agent with no tools. An agent that sends no tool definitions has nothing to prune, so zero is the correct figure and not a failure.

This figure is the answer to one question: what does pruning do for me? You enable pruning, you read the figure, and you decide if the saving is worth the feature.

A worked example

note

These are representative figures for the data that Cortex captures. They show the shape of a real session. Replace them with a session that you capture before you rely on the exact values.

One session of a coding agent, with tool pruning enabled:

FieldValue
Modelclaude-sonnet-4
Events34
Input tokens12,400
Cache read486,000
Cache write61,200
Output tokens8,900
Reasoning tokens3,100
Cost2.14 USD
Time to first token (p50)0.7 s
Time to first token (p95)2.9 s
Total response time (p95)24 s
Tokens pruned41,000
Cost saved by pruning0.12 USD

How to read it:

  • Caching operates. The cache-read count (486,000) is much larger than the input count (12,400). The agent sends the same context on each turn, and the model reads almost all of it from the cache. Without the cache, the input cost is many times higher.
  • The cache-write count is a one-time cost. The 61,200 cache-write tokens are the first turn that stored the context. Later turns read it, and do not write it again.
  • The slow tail is visible. The typical first token arrives in 0.7 s, but the slowest calls take 2.9 s. If the agent felt slow, the p95 is the reason, not the p50.
  • Pruning earns a small amount here. It saved 0.12 USD, because it removed 41,000 tokens of unused tool definitions across the session. On an agent with many tools, this figure is larger.

Why leave Cortex running

One session is useful. A week of sessions is more useful. The value is in the change over time:

  • A prompt that grows more expensive each day.
  • A cache-read count that falls, because a change to the agent broke the cache.
  • A session that costs ten times the others.

You see these only if Cortex runs while you work. It runs as a background service and adds no step to your day. See Manage the service.

Give feedback

Did the numbers tell you what you needed, or not? Was a figure confusing? Tell us. Open the Laptop feedback form on rossoctl/cortex, or write a message in Slack. Feedback on the local tool is what makes the next release clearer.