ctxprof 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,8 @@
1
+ # Python build/test artifacts
2
+ __pycache__/
3
+ *.pyc
4
+ *.egg-info/
5
+ build/
6
+ dist/
7
+ .eggs/
8
+ .pytest_cache/
ctxprof-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Maria Dubyaga
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
ctxprof-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,294 @@
1
+ Metadata-Version: 2.4
2
+ Name: ctxprof
3
+ Version: 0.1.0
4
+ Summary: Live dashboard and offline context/cache audit for Claude Code sessions
5
+ Project-URL: Homepage, https://github.com/kraftaa/claude_workflow
6
+ Project-URL: Source, https://github.com/kraftaa/claude_workflow/tree/main/claude-context-tools
7
+ Author: Maria Dubyaga
8
+ License: MIT License
9
+
10
+ Copyright (c) 2026 Maria Dubyaga
11
+
12
+ Permission is hereby granted, free of charge, to any person obtaining a copy
13
+ of this software and associated documentation files (the "Software"), to deal
14
+ in the Software without restriction, including without limitation the rights
15
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16
+ copies of the Software, and to permit persons to whom the Software is
17
+ furnished to do so, subject to the following conditions:
18
+
19
+ The above copyright notice and this permission notice shall be included in all
20
+ copies or substantial portions of the Software.
21
+
22
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28
+ SOFTWARE.
29
+ License-File: LICENSE
30
+ Keywords: cache,claude,claude-code,observability,statusline,tokens
31
+ Classifier: Environment :: Console
32
+ Classifier: License :: OSI Approved :: MIT License
33
+ Classifier: Programming Language :: Python :: 3
34
+ Requires-Python: >=3.9
35
+ Description-Content-Type: text/markdown
36
+
37
+ # ctxprof
38
+
39
+ A **context profiler for Claude Code sessions** (package `ctxprof`, command `ctx`) — a small, dependency-free CLI
40
+ (`ctx`) for understanding where a session's context and cache budget actually
41
+ goes. Like a CPU/memory profiler, but for tokens. Several lenses:
42
+
43
+ - **Live** — `ctx dashboard` (all sessions) / `ctx watch` (one session): how much,
44
+ right now.
45
+ - **Per-turn** — `ctx steps` / `ctx digest` / `ctx rates`: what each turn cost and
46
+ where the money went.
47
+ - **Offline** — `ctx audit`: why one session burned context/cache, after the fact.
48
+ - **Explain** — `ctx explain`: ranks a session's biggest *avoidable* costs
49
+ (idle cache rebuilds, repeated reads, large inserts) with $ impact and a fix
50
+ for each, splitting measured (real billed rebuilds) from estimated waste.
51
+
52
+ All read the same per-session **heartbeat** files that a statusline writes. The
53
+ statusline is the only piece that runs inside Claude Code; everything else is an
54
+ ordinary command you run in any terminal (or via `!ctx …` / `/ctx` inside Claude).
55
+
56
+ ```text
57
+ Claude Code session
58
+ │ (each statusline refresh)
59
+
60
+ heartbeat statusline ──writes──► ~/.claude/session-status/<session>.json
61
+ ~/.claude/session-status/steps/<session>.jsonl
62
+ ▲ │
63
+ │ one stdout line ├──► ctx dashboard (live, all sessions)
64
+ in-app status bar └──► ctx audit (offline, one session)
65
+ ```
66
+
67
+ Requires `python3` (3.9+). The heartbeat statusline also needs `jq` + `awk`
68
+ (standard on macOS/Linux).
69
+
70
+ ## Install
71
+
72
+ ```bash
73
+ # Recommended: isolated global install with pipx
74
+ pipx install ctxprof # from PyPI
75
+ # or from a git checkout (replace <your-repo-url>):
76
+ pipx install "git+<your-repo-url>#subdirectory=claude-context-tools"
77
+
78
+ # Or plain pip (ideally in a venv)
79
+ pip install ctxprof
80
+
81
+ # Or straight from a clone, editable (path is the directory in the repo)
82
+ pip install -e claude-context-tools
83
+ ```
84
+
85
+ This installs one command, `ctx`, an umbrella with subcommands:
86
+ `dashboard`, `watch`, `explain`, `show`, `steps`, `digest`, `rates`, `audit`,
87
+ `tui`, `install` (plus `statusline`/`hook` plumbing). Run `ctx` with no
88
+ arguments to see them all.
89
+
90
+ No clone needed after install. To run without installing, use
91
+ `python3 -m claude_context_tools.cli <subcommand>` from this directory.
92
+
93
+ ## When to run what
94
+
95
+ | I want to… | Run |
96
+ |---|---|
97
+ | See what all my open sessions cost **right now** | `ctx dashboard` |
98
+ | Find **which session is the money sink** | `ctx digest` (ranks sessions by cost) |
99
+ | Know **why a session got expensive + how to fix it** | `ctx explain <id>` |
100
+ | **Watch one session live** while I work (split pane) | `ctx watch <id>` |
101
+ | See **per-turn** costs / catch a spike as it happens | `ctx steps` |
102
+ | **Deep offline** breakdown of one session's transcript | `ctx audit <id>` |
103
+ | Check **prices / keep-warm-vs-rebuild** math | `ctx rates` |
104
+
105
+ Typical flow: **`ctx digest`** to see which session is costing the most →
106
+ **`ctx explain <id>`** on that one to see the avoidable costs and the fix.
107
+
108
+ **Which session do the single-session commands act on?** With no id they pick the
109
+ **newest** (most recently active) session, and the **header line shows its name**
110
+ so you can confirm. To target another, pass a **session id or prefix** — get the
111
+ ids from `ctx dashboard` (the `ID` column) and run `ctx show <id>` to see a
112
+ session's repo/cwd. No time window: `ctx explain`/`audit` cover the **whole
113
+ session**; `ctx digest --since 2h` and `ctx steps --limit N` are the windowed ones.
114
+
115
+ ## Use it
116
+
117
+ ```bash
118
+ # Live table of all active sessions (Ctrl-C to quit):
119
+ ctx dashboard
120
+
121
+ # Print once and exit (good for tmux panes / scripts):
122
+ ctx dashboard --refresh 0
123
+
124
+ # Include sessions idle past the stale timeout (shown dimmed, with `!`):
125
+ ctx dashboard --include-stale
126
+
127
+ # Details + a ready-to-run audit command for one session (or the newest):
128
+ ctx show
129
+ ctx show <session-id-or-prefix>
130
+
131
+ # Live single-session panel + recommendations (the "sidebar"; run in a split pane):
132
+ ctx watch
133
+ ctx watch <session-id>
134
+
135
+ # Rank a session's biggest avoidable costs (the "profiler" view):
136
+ ctx explain
137
+ ctx explain <session-id> --top 5
138
+ ```
139
+
140
+ `ctx explain` looks like:
141
+
142
+ ```text
143
+ ctx explain Make Claude workflow utility installable … — top avoidable costs
144
+
145
+ 1. $ 51.29 Cache rebuilds after idle >5min (×15)
146
+ → rebuilt ~7.2M cache tok — /clear before breaks; keep sessions short
147
+ 2. $ 0.02 ~est Large Read result (~35.2k tok)
148
+ → summarize/cap big output before it enters context
149
+ 3. $ 0.01 ~est Re-reading dashboard.py 27×
150
+ → ~12.5k redundant tok — read targeted ranges / keep a summary
151
+
152
+ Total avoidable: ~$51.32 ($51.29 measured + $0.03 estimated)
153
+ ```
154
+
155
+ ```bash
156
+ # Recent per-turn cost feed across all sessions (catches expensive turns):
157
+ ctx steps
158
+ ctx steps --limit 40
159
+ ctx steps --json --limit 200 # machine-readable (feed to Claude to analyze)
160
+
161
+ # Rollup summary: totals, top-cost turns, biggest cache writes, longest gaps:
162
+ ctx digest --since 2h
163
+
164
+ # Price table + keep-warm-vs-rebuild economics for the current context:
165
+ ctx rates
166
+ ctx rates --context 100000 --model "Opus 4.8"
167
+ # (edit prices without touching code via ~/.claude/ctx-pricing.json)
168
+
169
+ # Interactive browser (scroll/filter/drill into a turn):
170
+ ctx tui
171
+ ```
172
+
173
+ ### Inside Claude Code
174
+
175
+ Prefix any command with `!` in the Claude prompt to run it and drop the output
176
+ into the conversation, or use the bundled `/ctx` slash command:
177
+
178
+ ```text
179
+ !ctx digest --since 2h
180
+ /ctx steps
181
+ /ctx steps --json --limit 200 # then ask Claude to summarize the big turns
182
+
183
+ # Offline "why did it burn?" audit:
184
+ ctx audit --latest
185
+ ctx audit --session <session-id>
186
+ ctx audit --transcript ~/.claude/projects/<proj>/<session>.jsonl
187
+ ctx audit --latest --json # machine-readable
188
+ ```
189
+
190
+ ## Turn on the heartbeat (one-time)
191
+
192
+ The dashboard and audit need a statusline that writes heartbeat files. Claude
193
+ Code supports **exactly one** `statusLine`, so this never silently replaces an
194
+ existing one:
195
+
196
+ ```bash
197
+ ctx install --statusline # safe: refuses if a statusLine exists
198
+ ctx install --statusline --force # replace it (writes a timestamped backup)
199
+ ctx install --print-path # just print the heartbeat script path
200
+ ```
201
+
202
+ If you already have a statusline you like, keep it — just make it also write the
203
+ `~/.claude/session-status/<session>.json` and `steps/<session>.jsonl` shapes (see
204
+ `claude_context_tools/data/claude-statusline-heartbeat.sh` for the exact fields)
205
+ and these tools will read it. To wire it by hand instead:
206
+
207
+ ```json
208
+ {
209
+ "statusLine": {
210
+ "type": "command",
211
+ "command": "bash /ABSOLUTE/PATH/TO/claude-statusline-heartbeat.sh"
212
+ }
213
+ }
214
+ ```
215
+
216
+ ### Global vs per-repo
217
+
218
+ - **Global** (all sessions): set the heartbeat in `~/.claude/settings.json`.
219
+ This is what `ctx install --statusline` does. Usual choice.
220
+ - **Per-repo**: set `statusLine` in a project's `.claude/settings.json`; it wins
221
+ for sessions in that repo. Use an absolute path to the heartbeat script.
222
+
223
+ ## What the audit reports
224
+
225
+ - **What burned context** — per-category token estimates (assistant/user text,
226
+ thinking, tool inputs, per-tool results, attachments).
227
+ - **Attachment breakdown** — system-injected context (skill listings, hook
228
+ output, deferred tool lists) totalled separately.
229
+ - **Repeated file reads / commands / duplicate output blobs** — content paid for
230
+ more than once.
231
+ - **Large pasted logs / large tool results** and **subagent report weight**.
232
+ - **Cache telemetry** — per-turn behavior, separating expected initial
233
+ **warm-up** from likely mid-session **invalidation** (cache was warm, then
234
+ largely rewritten).
235
+ - **Recommendations** derived from the findings.
236
+
237
+ ### Honest limits
238
+
239
+ - Token counts in `ctx audit` are **estimates** (`~4 chars/token`, scaled by the
240
+ model's tokenizer — ×1.35 for Opus 4.7+; override with `--token-factor`). The
241
+ live per-turn numbers (statusline, `ctx steps`, COST) are Claude Code's own
242
+ exact usage fields, not estimates.
243
+ - Cache analysis is **heuristic and token-level** — the heartbeat exposes per-turn
244
+ token *counts*, not cache-block boundaries, so it flags *likely* invalidation,
245
+ not exact cache-block attribution.
246
+ - **Unknown is not zero.** With no step file, the audit says per-turn cache
247
+ behavior is unknown rather than reporting `0`.
248
+
249
+ ## Dashboard notes
250
+
251
+ - **LABEL** is the session name/task (from `session_name`) so you identify
252
+ sessions by what they're doing, not by UUID. **ID** is a short id prefix
253
+ (enough for `ctx show <prefix>`).
254
+ - **CONTEXT** is a fill bar + percent; **RECENT** is a per-session sparkline of
255
+ the last few turns' token volume, colored by cache-**read** share
256
+ (green = cheap cache hits, cyan = fresh input / rebuild) so big-write rebuild
257
+ turns show as expensive, not green.
258
+ - The table is **responsive**: on narrow terminals lower-priority columns
259
+ (MODE, AGENT, 5H/7D, IN/OUT, API, DUR, CHG) drop out, always keeping REPO,
260
+ the CONTEXT bar, COST, RECENT and LABEL.
261
+ - `ctx steps` is a separate cross-session **per-turn** feed (STEP, CTX, tokens,
262
+ CACHE R/W, COST, APIΔ, GAP) — costs over $0.25/$1.00 a turn are highlighted.
263
+ - **Stale sessions** are hidden by default; the header shows `stale-hidden:N` so
264
+ you know they exist. `--include-stale` shows them dimmed with an `!`. The
265
+ cutoff is `CLAUDE_STATUS_STALE_AFTER_SECONDS` (default 900s). An open session
266
+ that's idle (not generating turns) stops writing heartbeats and goes stale.
267
+ - **COST and TIME are cumulative session totals**; **live-ctx / IN / OUT** are
268
+ the current context, not lifetime. An old session legitimately shows a large
269
+ frozen cost/time — its lifetime total at the last heartbeat, not ongoing spend.
270
+
271
+ ## Files written
272
+
273
+ | Path | Written by | Used by |
274
+ |---|---|---|
275
+ | `~/.claude/session-status/<session>.json` | heartbeat statusline | dashboard, audit |
276
+ | `~/.claude/session-status/steps/<session>.jsonl` | heartbeat statusline | audit (cache telemetry) |
277
+ | Claude transcript JSONL (under `~/.claude/projects/`) | Claude Code | audit |
278
+
279
+ Override the state dir with `CLAUDE_STATUS_STATE_DIR`. Nothing is deleted
280
+ automatically. These tools only ever **read** your transcripts — they never
281
+ modify or upload them.
282
+
283
+ ## Tests
284
+
285
+ Fixture-based smoke tests, stdlib only (synthetic data, generated by
286
+ `tests/make_fixtures.py` — no private content):
287
+
288
+ ```bash
289
+ python3 tests/test_claude_context_tools.py
290
+ python3 tests/make_fixtures.py # regenerate fixtures after changing shapes
291
+ ```
292
+
293
+ See [`../03-harnesses.md`](../03-harnesses.md) → "Status line" for how this fits
294
+ the broader harness guidance.
@@ -0,0 +1,258 @@
1
+ # ctxprof
2
+
3
+ A **context profiler for Claude Code sessions** (package `ctxprof`, command `ctx`) — a small, dependency-free CLI
4
+ (`ctx`) for understanding where a session's context and cache budget actually
5
+ goes. Like a CPU/memory profiler, but for tokens. Several lenses:
6
+
7
+ - **Live** — `ctx dashboard` (all sessions) / `ctx watch` (one session): how much,
8
+ right now.
9
+ - **Per-turn** — `ctx steps` / `ctx digest` / `ctx rates`: what each turn cost and
10
+ where the money went.
11
+ - **Offline** — `ctx audit`: why one session burned context/cache, after the fact.
12
+ - **Explain** — `ctx explain`: ranks a session's biggest *avoidable* costs
13
+ (idle cache rebuilds, repeated reads, large inserts) with $ impact and a fix
14
+ for each, splitting measured (real billed rebuilds) from estimated waste.
15
+
16
+ All read the same per-session **heartbeat** files that a statusline writes. The
17
+ statusline is the only piece that runs inside Claude Code; everything else is an
18
+ ordinary command you run in any terminal (or via `!ctx …` / `/ctx` inside Claude).
19
+
20
+ ```text
21
+ Claude Code session
22
+ │ (each statusline refresh)
23
+
24
+ heartbeat statusline ──writes──► ~/.claude/session-status/<session>.json
25
+ ~/.claude/session-status/steps/<session>.jsonl
26
+ ▲ │
27
+ │ one stdout line ├──► ctx dashboard (live, all sessions)
28
+ in-app status bar └──► ctx audit (offline, one session)
29
+ ```
30
+
31
+ Requires `python3` (3.9+). The heartbeat statusline also needs `jq` + `awk`
32
+ (standard on macOS/Linux).
33
+
34
+ ## Install
35
+
36
+ ```bash
37
+ # Recommended: isolated global install with pipx
38
+ pipx install ctxprof # from PyPI
39
+ # or from a git checkout (replace <your-repo-url>):
40
+ pipx install "git+<your-repo-url>#subdirectory=claude-context-tools"
41
+
42
+ # Or plain pip (ideally in a venv)
43
+ pip install ctxprof
44
+
45
+ # Or straight from a clone, editable (path is the directory in the repo)
46
+ pip install -e claude-context-tools
47
+ ```
48
+
49
+ This installs one command, `ctx`, an umbrella with subcommands:
50
+ `dashboard`, `watch`, `explain`, `show`, `steps`, `digest`, `rates`, `audit`,
51
+ `tui`, `install` (plus `statusline`/`hook` plumbing). Run `ctx` with no
52
+ arguments to see them all.
53
+
54
+ No clone needed after install. To run without installing, use
55
+ `python3 -m claude_context_tools.cli <subcommand>` from this directory.
56
+
57
+ ## When to run what
58
+
59
+ | I want to… | Run |
60
+ |---|---|
61
+ | See what all my open sessions cost **right now** | `ctx dashboard` |
62
+ | Find **which session is the money sink** | `ctx digest` (ranks sessions by cost) |
63
+ | Know **why a session got expensive + how to fix it** | `ctx explain <id>` |
64
+ | **Watch one session live** while I work (split pane) | `ctx watch <id>` |
65
+ | See **per-turn** costs / catch a spike as it happens | `ctx steps` |
66
+ | **Deep offline** breakdown of one session's transcript | `ctx audit <id>` |
67
+ | Check **prices / keep-warm-vs-rebuild** math | `ctx rates` |
68
+
69
+ Typical flow: **`ctx digest`** to see which session is costing the most →
70
+ **`ctx explain <id>`** on that one to see the avoidable costs and the fix.
71
+
72
+ **Which session do the single-session commands act on?** With no id they pick the
73
+ **newest** (most recently active) session, and the **header line shows its name**
74
+ so you can confirm. To target another, pass a **session id or prefix** — get the
75
+ ids from `ctx dashboard` (the `ID` column) and run `ctx show <id>` to see a
76
+ session's repo/cwd. No time window: `ctx explain`/`audit` cover the **whole
77
+ session**; `ctx digest --since 2h` and `ctx steps --limit N` are the windowed ones.
78
+
79
+ ## Use it
80
+
81
+ ```bash
82
+ # Live table of all active sessions (Ctrl-C to quit):
83
+ ctx dashboard
84
+
85
+ # Print once and exit (good for tmux panes / scripts):
86
+ ctx dashboard --refresh 0
87
+
88
+ # Include sessions idle past the stale timeout (shown dimmed, with `!`):
89
+ ctx dashboard --include-stale
90
+
91
+ # Details + a ready-to-run audit command for one session (or the newest):
92
+ ctx show
93
+ ctx show <session-id-or-prefix>
94
+
95
+ # Live single-session panel + recommendations (the "sidebar"; run in a split pane):
96
+ ctx watch
97
+ ctx watch <session-id>
98
+
99
+ # Rank a session's biggest avoidable costs (the "profiler" view):
100
+ ctx explain
101
+ ctx explain <session-id> --top 5
102
+ ```
103
+
104
+ `ctx explain` looks like:
105
+
106
+ ```text
107
+ ctx explain Make Claude workflow utility installable … — top avoidable costs
108
+
109
+ 1. $ 51.29 Cache rebuilds after idle >5min (×15)
110
+ → rebuilt ~7.2M cache tok — /clear before breaks; keep sessions short
111
+ 2. $ 0.02 ~est Large Read result (~35.2k tok)
112
+ → summarize/cap big output before it enters context
113
+ 3. $ 0.01 ~est Re-reading dashboard.py 27×
114
+ → ~12.5k redundant tok — read targeted ranges / keep a summary
115
+
116
+ Total avoidable: ~$51.32 ($51.29 measured + $0.03 estimated)
117
+ ```
118
+
119
+ ```bash
120
+ # Recent per-turn cost feed across all sessions (catches expensive turns):
121
+ ctx steps
122
+ ctx steps --limit 40
123
+ ctx steps --json --limit 200 # machine-readable (feed to Claude to analyze)
124
+
125
+ # Rollup summary: totals, top-cost turns, biggest cache writes, longest gaps:
126
+ ctx digest --since 2h
127
+
128
+ # Price table + keep-warm-vs-rebuild economics for the current context:
129
+ ctx rates
130
+ ctx rates --context 100000 --model "Opus 4.8"
131
+ # (edit prices without touching code via ~/.claude/ctx-pricing.json)
132
+
133
+ # Interactive browser (scroll/filter/drill into a turn):
134
+ ctx tui
135
+ ```
136
+
137
+ ### Inside Claude Code
138
+
139
+ Prefix any command with `!` in the Claude prompt to run it and drop the output
140
+ into the conversation, or use the bundled `/ctx` slash command:
141
+
142
+ ```text
143
+ !ctx digest --since 2h
144
+ /ctx steps
145
+ /ctx steps --json --limit 200 # then ask Claude to summarize the big turns
146
+
147
+ # Offline "why did it burn?" audit:
148
+ ctx audit --latest
149
+ ctx audit --session <session-id>
150
+ ctx audit --transcript ~/.claude/projects/<proj>/<session>.jsonl
151
+ ctx audit --latest --json # machine-readable
152
+ ```
153
+
154
+ ## Turn on the heartbeat (one-time)
155
+
156
+ The dashboard and audit need a statusline that writes heartbeat files. Claude
157
+ Code supports **exactly one** `statusLine`, so this never silently replaces an
158
+ existing one:
159
+
160
+ ```bash
161
+ ctx install --statusline # safe: refuses if a statusLine exists
162
+ ctx install --statusline --force # replace it (writes a timestamped backup)
163
+ ctx install --print-path # just print the heartbeat script path
164
+ ```
165
+
166
+ If you already have a statusline you like, keep it — just make it also write the
167
+ `~/.claude/session-status/<session>.json` and `steps/<session>.jsonl` shapes (see
168
+ `claude_context_tools/data/claude-statusline-heartbeat.sh` for the exact fields)
169
+ and these tools will read it. To wire it by hand instead:
170
+
171
+ ```json
172
+ {
173
+ "statusLine": {
174
+ "type": "command",
175
+ "command": "bash /ABSOLUTE/PATH/TO/claude-statusline-heartbeat.sh"
176
+ }
177
+ }
178
+ ```
179
+
180
+ ### Global vs per-repo
181
+
182
+ - **Global** (all sessions): set the heartbeat in `~/.claude/settings.json`.
183
+ This is what `ctx install --statusline` does. Usual choice.
184
+ - **Per-repo**: set `statusLine` in a project's `.claude/settings.json`; it wins
185
+ for sessions in that repo. Use an absolute path to the heartbeat script.
186
+
187
+ ## What the audit reports
188
+
189
+ - **What burned context** — per-category token estimates (assistant/user text,
190
+ thinking, tool inputs, per-tool results, attachments).
191
+ - **Attachment breakdown** — system-injected context (skill listings, hook
192
+ output, deferred tool lists) totalled separately.
193
+ - **Repeated file reads / commands / duplicate output blobs** — content paid for
194
+ more than once.
195
+ - **Large pasted logs / large tool results** and **subagent report weight**.
196
+ - **Cache telemetry** — per-turn behavior, separating expected initial
197
+ **warm-up** from likely mid-session **invalidation** (cache was warm, then
198
+ largely rewritten).
199
+ - **Recommendations** derived from the findings.
200
+
201
+ ### Honest limits
202
+
203
+ - Token counts in `ctx audit` are **estimates** (`~4 chars/token`, scaled by the
204
+ model's tokenizer — ×1.35 for Opus 4.7+; override with `--token-factor`). The
205
+ live per-turn numbers (statusline, `ctx steps`, COST) are Claude Code's own
206
+ exact usage fields, not estimates.
207
+ - Cache analysis is **heuristic and token-level** — the heartbeat exposes per-turn
208
+ token *counts*, not cache-block boundaries, so it flags *likely* invalidation,
209
+ not exact cache-block attribution.
210
+ - **Unknown is not zero.** With no step file, the audit says per-turn cache
211
+ behavior is unknown rather than reporting `0`.
212
+
213
+ ## Dashboard notes
214
+
215
+ - **LABEL** is the session name/task (from `session_name`) so you identify
216
+ sessions by what they're doing, not by UUID. **ID** is a short id prefix
217
+ (enough for `ctx show <prefix>`).
218
+ - **CONTEXT** is a fill bar + percent; **RECENT** is a per-session sparkline of
219
+ the last few turns' token volume, colored by cache-**read** share
220
+ (green = cheap cache hits, cyan = fresh input / rebuild) so big-write rebuild
221
+ turns show as expensive, not green.
222
+ - The table is **responsive**: on narrow terminals lower-priority columns
223
+ (MODE, AGENT, 5H/7D, IN/OUT, API, DUR, CHG) drop out, always keeping REPO,
224
+ the CONTEXT bar, COST, RECENT and LABEL.
225
+ - `ctx steps` is a separate cross-session **per-turn** feed (STEP, CTX, tokens,
226
+ CACHE R/W, COST, APIΔ, GAP) — costs over $0.25/$1.00 a turn are highlighted.
227
+ - **Stale sessions** are hidden by default; the header shows `stale-hidden:N` so
228
+ you know they exist. `--include-stale` shows them dimmed with an `!`. The
229
+ cutoff is `CLAUDE_STATUS_STALE_AFTER_SECONDS` (default 900s). An open session
230
+ that's idle (not generating turns) stops writing heartbeats and goes stale.
231
+ - **COST and TIME are cumulative session totals**; **live-ctx / IN / OUT** are
232
+ the current context, not lifetime. An old session legitimately shows a large
233
+ frozen cost/time — its lifetime total at the last heartbeat, not ongoing spend.
234
+
235
+ ## Files written
236
+
237
+ | Path | Written by | Used by |
238
+ |---|---|---|
239
+ | `~/.claude/session-status/<session>.json` | heartbeat statusline | dashboard, audit |
240
+ | `~/.claude/session-status/steps/<session>.jsonl` | heartbeat statusline | audit (cache telemetry) |
241
+ | Claude transcript JSONL (under `~/.claude/projects/`) | Claude Code | audit |
242
+
243
+ Override the state dir with `CLAUDE_STATUS_STATE_DIR`. Nothing is deleted
244
+ automatically. These tools only ever **read** your transcripts — they never
245
+ modify or upload them.
246
+
247
+ ## Tests
248
+
249
+ Fixture-based smoke tests, stdlib only (synthetic data, generated by
250
+ `tests/make_fixtures.py` — no private content):
251
+
252
+ ```bash
253
+ python3 tests/test_claude_context_tools.py
254
+ python3 tests/make_fixtures.py # regenerate fixtures after changing shapes
255
+ ```
256
+
257
+ See [`../03-harnesses.md`](../03-harnesses.md) → "Status line" for how this fits
258
+ the broader harness guidance.
@@ -0,0 +1,3 @@
1
+ """Claude Code context & cache tools: live dashboard + offline audit."""
2
+
3
+ __version__ = "0.1.0"