smlflg commited on
Commit
10b5888
·
verified ·
1 Parent(s): 5d445fe

Initial public upload from Projekte/Codex_Usage_Profil

Browse files
.codex.pre-coding-mcp-20260908T010027 ADDED
File without changes
.codex/config.toml ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Coding MCPs: project-local registration (2026-09-07).
2
+
3
+ [mcp_servers.serena]
4
+ command = "/home/smlflg/.local/share/coding-mcp/serena/.venv/bin/serena"
5
+ args = ["start-mcp-server", "--context=codex", "--project", "/home/smlflg/Projekte/Codex_Usage_Profil", "--enable-web-dashboard", "false", "--open-web-dashboard", "false", "--enable-gui-log-window", "false"]
6
+ cwd = "/home/smlflg/Projekte/Codex_Usage_Profil"
7
+ enabled = true
8
+ startup_timeout_sec = 120
9
+ tool_timeout_sec = 180
10
+
11
+ [mcp_servers.serena.env]
12
+ "SERENA_HOME" = "/home/smlflg/.local/share/coding-mcp/serena/state"
13
+
14
+ [mcp_servers.gitnexus]
15
+ command = "/home/smlflg/.nvm/versions/node/v24.13.0/bin/node"
16
+ args = ["/home/smlflg/.local/share/coding-mcp/gitnexus/node_modules/gitnexus/dist/cli/index.js", "mcp"]
17
+ cwd = "/home/smlflg/Projekte/Codex_Usage_Profil"
18
+ enabled = true
19
+ startup_timeout_sec = 120
20
+ tool_timeout_sec = 180
21
+
22
+ [mcp_servers.gitnexus.env]
23
+ "GITNEXUS_HOME" = "/home/smlflg/.local/share/coding-mcp/gitnexus/runtime"
24
+
25
+ [mcp_servers.context7]
26
+ command = "/home/smlflg/.nvm/versions/node/v24.13.0/bin/node"
27
+ args = ["/home/smlflg/.local/share/coding-mcp/context7/node_modules/@upstash/context7-mcp/dist/index.js"]
28
+ cwd = "/home/smlflg/Projekte/Codex_Usage_Profil"
29
+ enabled = true
30
+ startup_timeout_sec = 120
31
+ tool_timeout_sec = 180
.gitignore ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ __pycache__/
2
+ *.py[cod]
3
+ .pytest_cache/
README.md ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Codex Usage Profiler
2
+
3
+ Local CLI for summarizing Codex usage from `~/.codex/state_5.sqlite` and rollout
4
+ JSONL files.
5
+
6
+ It reports:
7
+
8
+ - daily and ISO-week token totals
9
+ - tokens by cwd, model, role, and main vs subagent
10
+ - top sessions
11
+ - optional rollout token breakdowns for input, cached input, output, and
12
+ reasoning tokens when those events exist
13
+ - Markdown and static HTML output
14
+
15
+ ## Usage
16
+
17
+ ```bash
18
+ python3 -m codex_usage_profiler
19
+ ```
20
+
21
+ Default output is written to:
22
+
23
+ - `reports/codex-usage.md`
24
+ - `reports/codex-usage.html`
25
+
26
+ Useful options:
27
+
28
+ ```bash
29
+ python3 -m codex_usage_profiler \
30
+ --state ~/.codex/state_5.sqlite \
31
+ --sessions-dir ~/.codex/sessions \
32
+ --out reports \
33
+ --format both \
34
+ --tz Europe/Berlin \
35
+ --days 30 \
36
+ --top 25
37
+ ```
38
+
39
+ `--days N` includes the last `N` local calendar days including today. Week
40
+ buckets use ISO weeks, starting on Monday.
41
+
42
+ The report never includes raw prompts, messages, command output, or model
43
+ responses. It only uses metadata and token counters.
44
+
45
+ ## Development
46
+
47
+ Run tests with:
48
+
49
+ ```bash
50
+ python3 -m unittest discover -s tests
51
+ ```
codex_usage_profiler/__init__.py ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ """Local Codex usage profiler."""
2
+
3
+ from .core import build_report
4
+
5
+ __all__ = ["build_report"]
codex_usage_profiler/__main__.py ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ from .cli import main
2
+
3
+ if __name__ == "__main__":
4
+ raise SystemExit(main())
codex_usage_profiler/cli.py ADDED
@@ -0,0 +1,82 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+ import os
5
+ from pathlib import Path
6
+ from zoneinfo import ZoneInfo, ZoneInfoNotFoundError
7
+
8
+ from .core import build_report
9
+ from .render import write_reports
10
+
11
+
12
+ def main(argv: list[str] | None = None) -> int:
13
+ parser = _build_parser()
14
+ args = parser.parse_args(argv)
15
+
16
+ try:
17
+ ZoneInfo(args.tz)
18
+ except ZoneInfoNotFoundError:
19
+ parser.error(f"unknown timezone: {args.tz}")
20
+
21
+ report = build_report(
22
+ state_path=Path(args.state).expanduser(),
23
+ sessions_dir=Path(args.sessions_dir).expanduser(),
24
+ tz_name=args.tz,
25
+ days=args.days,
26
+ top=args.top,
27
+ )
28
+ written = write_reports(report, Path(args.out).expanduser(), args.format)
29
+
30
+ for path in written:
31
+ print(f"Wrote {path}")
32
+ print(f"Sessions: {len(report.sessions):,}")
33
+ print(f"Total tokens: {report.total_tokens:,}")
34
+ if report.warnings:
35
+ print(f"Warnings: {len(report.warnings):,}")
36
+ return 0
37
+
38
+
39
+ def _build_parser() -> argparse.ArgumentParser:
40
+ parser = argparse.ArgumentParser(
41
+ prog="codex-usage-profiler",
42
+ description="Summarize local Codex usage from state_5.sqlite and rollout JSONL files.",
43
+ )
44
+ parser.add_argument(
45
+ "--state",
46
+ default="~/.codex/state_5.sqlite",
47
+ help="Path to Codex state_5.sqlite. Default: %(default)s",
48
+ )
49
+ parser.add_argument(
50
+ "--sessions-dir",
51
+ default="~/.codex/sessions",
52
+ help="Root directory containing rollout JSONL files. Default: %(default)s",
53
+ )
54
+ parser.add_argument(
55
+ "--out",
56
+ default="reports",
57
+ help="Output directory. Default: %(default)s",
58
+ )
59
+ parser.add_argument(
60
+ "--format",
61
+ choices=["md", "html", "both"],
62
+ default="both",
63
+ help="Report format to write. Default: %(default)s",
64
+ )
65
+ parser.add_argument(
66
+ "--tz",
67
+ default=os.environ.get("TZ", "Europe/Berlin"),
68
+ help="Timezone for day/week grouping. Default: %(default)s",
69
+ )
70
+ parser.add_argument(
71
+ "--days",
72
+ type=int,
73
+ default=None,
74
+ help="Include the last N local calendar days including today.",
75
+ )
76
+ parser.add_argument(
77
+ "--top",
78
+ type=int,
79
+ default=20,
80
+ help="Number of top sessions to include. Default: %(default)s",
81
+ )
82
+ return parser
codex_usage_profiler/core.py ADDED
@@ -0,0 +1,411 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ import sqlite3
5
+ from collections import defaultdict
6
+ from dataclasses import dataclass, field
7
+ from datetime import datetime, timedelta, timezone
8
+ from pathlib import Path
9
+ from typing import Any, Callable, Iterable
10
+ from urllib.parse import quote
11
+ from zoneinfo import ZoneInfo
12
+
13
+
14
+ @dataclass(slots=True)
15
+ class TokenBreakdown:
16
+ input_tokens: int = 0
17
+ cached_input_tokens: int = 0
18
+ output_tokens: int = 0
19
+ reasoning_output_tokens: int = 0
20
+ total_tokens: int = 0
21
+
22
+ @classmethod
23
+ def from_usage(cls, usage: dict[str, Any]) -> "TokenBreakdown":
24
+ return cls(
25
+ input_tokens=_int_value(usage.get("input_tokens")),
26
+ cached_input_tokens=_int_value(usage.get("cached_input_tokens")),
27
+ output_tokens=_int_value(usage.get("output_tokens")),
28
+ reasoning_output_tokens=_int_value(usage.get("reasoning_output_tokens")),
29
+ total_tokens=_int_value(usage.get("total_tokens")),
30
+ )
31
+
32
+ def add(self, other: "TokenBreakdown | None") -> None:
33
+ if other is None:
34
+ return
35
+ self.input_tokens += other.input_tokens
36
+ self.cached_input_tokens += other.cached_input_tokens
37
+ self.output_tokens += other.output_tokens
38
+ self.reasoning_output_tokens += other.reasoning_output_tokens
39
+ self.total_tokens += other.total_tokens
40
+
41
+
42
+ @dataclass(slots=True)
43
+ class RolloutStats:
44
+ path: Path | None
45
+ found: bool
46
+ token_breakdown: TokenBreakdown | None = None
47
+ model: str | None = None
48
+ cwd: str | None = None
49
+ turn_count: int = 0
50
+ malformed_lines: int = 0
51
+ warnings: list[str] = field(default_factory=list)
52
+
53
+
54
+ @dataclass(slots=True)
55
+ class SessionUsage:
56
+ thread_id: str
57
+ created_at: datetime
58
+ updated_at: datetime
59
+ cwd: str
60
+ model: str
61
+ model_provider: str
62
+ role: str
63
+ agent_role: str
64
+ agent_nickname: str
65
+ kind: str
66
+ parent_thread_id: str | None
67
+ title: str
68
+ tokens: int
69
+ rollout_path: Path | None
70
+ rollout_found: bool
71
+ rollout_breakdown: TokenBreakdown | None
72
+ turn_count: int
73
+
74
+ @property
75
+ def week_label(self) -> str:
76
+ year, week, _ = self.created_at.isocalendar()
77
+ return f"{year}-W{week:02d}"
78
+
79
+ @property
80
+ def day_label(self) -> str:
81
+ return self.created_at.date().isoformat()
82
+
83
+
84
+ @dataclass(slots=True)
85
+ class Bucket:
86
+ label: str
87
+ sessions: int = 0
88
+ tokens: int = 0
89
+ rollout: TokenBreakdown = field(default_factory=TokenBreakdown)
90
+
91
+ def add(self, session: SessionUsage) -> None:
92
+ self.sessions += 1
93
+ self.tokens += session.tokens
94
+ self.rollout.add(session.rollout_breakdown)
95
+
96
+
97
+ @dataclass(slots=True)
98
+ class UsageReport:
99
+ generated_at: datetime
100
+ timezone_name: str
101
+ state_path: Path
102
+ sessions_dir: Path
103
+ sessions: list[SessionUsage]
104
+ daily: list[Bucket]
105
+ weekly: list[Bucket]
106
+ by_cwd: list[Bucket]
107
+ by_model: list[Bucket]
108
+ by_role: list[Bucket]
109
+ by_kind: list[Bucket]
110
+ top_sessions: list[SessionUsage]
111
+ rollout_totals: TokenBreakdown
112
+ warnings: list[str]
113
+ days_filter: int | None = None
114
+
115
+ @property
116
+ def total_tokens(self) -> int:
117
+ return sum(session.tokens for session in self.sessions)
118
+
119
+ @property
120
+ def parsed_rollout_count(self) -> int:
121
+ return sum(1 for session in self.sessions if session.rollout_breakdown is not None)
122
+
123
+ @property
124
+ def missing_rollout_count(self) -> int:
125
+ return sum(1 for session in self.sessions if not session.rollout_found)
126
+
127
+ @property
128
+ def date_range_label(self) -> str:
129
+ if not self.sessions:
130
+ return "n/a"
131
+ first = min(session.created_at for session in self.sessions)
132
+ last = max(session.created_at for session in self.sessions)
133
+ return f"{first.date().isoformat()} to {last.date().isoformat()}"
134
+
135
+
136
+ def build_report(
137
+ *,
138
+ state_path: Path,
139
+ sessions_dir: Path,
140
+ tz_name: str,
141
+ days: int | None = None,
142
+ top: int = 20,
143
+ now: datetime | None = None,
144
+ ) -> UsageReport:
145
+ tz = ZoneInfo(tz_name)
146
+ generated_at = (now or datetime.now(tz)).astimezone(tz)
147
+ rows, child_to_parent = _load_threads(state_path)
148
+ sessions: list[SessionUsage] = []
149
+ warnings: list[str] = []
150
+
151
+ if days is not None and days <= 0:
152
+ raise ValueError("--days must be greater than zero")
153
+ cutoff_date = None
154
+ if days is not None:
155
+ cutoff_date = generated_at.date() - timedelta(days=days - 1)
156
+
157
+ for row in rows:
158
+ created_at = _local_datetime(row.get("created_at_ms"), row.get("created_at"), tz)
159
+ if cutoff_date is not None and created_at.date() < cutoff_date:
160
+ continue
161
+
162
+ updated_at = _local_datetime(row.get("updated_at_ms"), row.get("updated_at"), tz)
163
+ thread_id = str(row["id"])
164
+ rollout_path = _resolve_rollout_path(row.get("rollout_path"), sessions_dir, thread_id)
165
+ rollout = parse_rollout(rollout_path)
166
+ warnings.extend(rollout.warnings)
167
+
168
+ parent_thread_id = child_to_parent.get(thread_id)
169
+ kind = "subagent" if parent_thread_id else "main"
170
+ agent_role = str(row.get("agent_role") or "")
171
+ role = agent_role or ("main" if kind == "main" else "unknown")
172
+ model_provider = str(row.get("model_provider") or "unknown")
173
+ model = str(row.get("model") or rollout.model or "unknown")
174
+ cwd = str(row.get("cwd") or rollout.cwd or "unknown")
175
+
176
+ sessions.append(
177
+ SessionUsage(
178
+ thread_id=thread_id,
179
+ created_at=created_at,
180
+ updated_at=updated_at,
181
+ cwd=cwd,
182
+ model=model,
183
+ model_provider=model_provider,
184
+ role=role,
185
+ agent_role=agent_role,
186
+ agent_nickname=str(row.get("agent_nickname") or ""),
187
+ kind=kind,
188
+ parent_thread_id=parent_thread_id,
189
+ title=str(row.get("title") or ""),
190
+ tokens=_int_value(row.get("tokens_used")),
191
+ rollout_path=rollout.path,
192
+ rollout_found=rollout.found,
193
+ rollout_breakdown=rollout.token_breakdown,
194
+ turn_count=rollout.turn_count,
195
+ )
196
+ )
197
+
198
+ sessions.sort(key=lambda session: (session.created_at, session.thread_id))
199
+ rollout_totals = TokenBreakdown()
200
+ for session in sessions:
201
+ rollout_totals.add(session.rollout_breakdown)
202
+
203
+ return UsageReport(
204
+ generated_at=generated_at,
205
+ timezone_name=tz_name,
206
+ state_path=Path(state_path).expanduser(),
207
+ sessions_dir=Path(sessions_dir).expanduser(),
208
+ sessions=sessions,
209
+ daily=_group_sessions(sessions, lambda session: session.day_label, sort_by_label=True),
210
+ weekly=_group_sessions(sessions, lambda session: session.week_label, sort_by_label=True),
211
+ by_cwd=_group_sessions(sessions, lambda session: _compact_path(session.cwd)),
212
+ by_model=_group_sessions(sessions, lambda session: session.model or "unknown"),
213
+ by_role=_group_sessions(sessions, lambda session: session.role or "unknown"),
214
+ by_kind=_group_sessions(sessions, lambda session: session.kind),
215
+ top_sessions=sorted(sessions, key=lambda session: session.tokens, reverse=True)[:top],
216
+ rollout_totals=rollout_totals,
217
+ warnings=warnings,
218
+ days_filter=days,
219
+ )
220
+
221
+
222
+ def parse_rollout(path: Path | None) -> RolloutStats:
223
+ if path is None:
224
+ return RolloutStats(path=None, found=False, warnings=["No rollout path for a session"])
225
+
226
+ expanded = path.expanduser()
227
+ if not expanded.exists():
228
+ return RolloutStats(
229
+ path=expanded,
230
+ found=False,
231
+ warnings=[f"Missing rollout file: {expanded}"],
232
+ )
233
+
234
+ stats = RolloutStats(path=expanded, found=True)
235
+ try:
236
+ with expanded.open("r", encoding="utf-8") as handle:
237
+ for line_number, line in enumerate(handle, start=1):
238
+ if not line.strip():
239
+ continue
240
+ try:
241
+ event = json.loads(line)
242
+ except json.JSONDecodeError:
243
+ stats.malformed_lines += 1
244
+ continue
245
+ _read_rollout_event(stats, event)
246
+ except OSError as exc:
247
+ stats.found = False
248
+ stats.warnings.append(f"Could not read rollout file {expanded}: {exc}")
249
+ return stats
250
+
251
+ if stats.malformed_lines:
252
+ stats.warnings.append(
253
+ f"Malformed JSONL lines in {expanded}: {stats.malformed_lines}"
254
+ )
255
+ return stats
256
+
257
+
258
+ def _read_rollout_event(stats: RolloutStats, event: dict[str, Any]) -> None:
259
+ event_type = event.get("type")
260
+ payload = event.get("payload")
261
+ if not isinstance(payload, dict):
262
+ payload = {}
263
+
264
+ if event_type == "session_meta":
265
+ stats.cwd = stats.cwd or _string_or_none(payload.get("cwd"))
266
+ return
267
+
268
+ if event_type == "turn_context":
269
+ stats.model = stats.model or _string_or_none(payload.get("model"))
270
+ stats.cwd = stats.cwd or _string_or_none(payload.get("cwd"))
271
+ return
272
+
273
+ if event_type != "event_msg":
274
+ return
275
+
276
+ payload_type = payload.get("type")
277
+ if payload_type == "task_started":
278
+ stats.turn_count += 1
279
+ return
280
+ if payload_type != "token_count":
281
+ return
282
+
283
+ info = payload.get("info")
284
+ if not isinstance(info, dict):
285
+ return
286
+ usage = info.get("total_token_usage")
287
+ if isinstance(usage, dict):
288
+ stats.token_breakdown = TokenBreakdown.from_usage(usage)
289
+
290
+
291
+ def _load_threads(state_path: Path) -> tuple[list[dict[str, Any]], dict[str, str]]:
292
+ expanded = Path(state_path).expanduser()
293
+ if not expanded.exists():
294
+ raise FileNotFoundError(f"State database not found: {expanded}")
295
+
296
+ uri = f"file:{quote(str(expanded), safe='/')}?mode=ro"
297
+ with sqlite3.connect(uri, uri=True) as conn:
298
+ conn.row_factory = sqlite3.Row
299
+ conn.execute("PRAGMA query_only = ON")
300
+ rows = [
301
+ dict(row)
302
+ for row in conn.execute(
303
+ """
304
+ SELECT
305
+ id,
306
+ rollout_path,
307
+ created_at,
308
+ updated_at,
309
+ created_at_ms,
310
+ updated_at_ms,
311
+ model_provider,
312
+ cwd,
313
+ title,
314
+ tokens_used,
315
+ agent_nickname,
316
+ agent_role,
317
+ model
318
+ FROM threads
319
+ ORDER BY created_at_ms ASC, id ASC
320
+ """
321
+ )
322
+ ]
323
+ edges = [
324
+ dict(edge)
325
+ for edge in conn.execute(
326
+ """
327
+ SELECT parent_thread_id, child_thread_id
328
+ FROM thread_spawn_edges
329
+ """
330
+ )
331
+ ]
332
+ return rows, {str(edge["child_thread_id"]): str(edge["parent_thread_id"]) for edge in edges}
333
+
334
+
335
+ def _resolve_rollout_path(
336
+ rollout_path: Any, sessions_dir: Path, thread_id: str
337
+ ) -> Path | None:
338
+ sessions_root = Path(sessions_dir).expanduser()
339
+ if rollout_path:
340
+ candidate = Path(str(rollout_path)).expanduser()
341
+ if not candidate.is_absolute():
342
+ candidate = sessions_root / candidate
343
+ if candidate.exists():
344
+ return candidate
345
+
346
+ if sessions_root.exists():
347
+ matches = sorted(sessions_root.rglob(f"*{thread_id}.jsonl"))
348
+ if matches:
349
+ return matches[0]
350
+
351
+ if rollout_path:
352
+ return candidate
353
+ return None
354
+
355
+
356
+ def _group_sessions(
357
+ sessions: Iterable[SessionUsage],
358
+ key: Callable[[SessionUsage], str],
359
+ *,
360
+ sort_by_label: bool = False,
361
+ ) -> list[Bucket]:
362
+ buckets: dict[str, Bucket] = {}
363
+ for session in sessions:
364
+ label = key(session)
365
+ bucket = buckets.setdefault(label, Bucket(label=label))
366
+ bucket.add(session)
367
+
368
+ values = list(buckets.values())
369
+ if sort_by_label:
370
+ values.sort(key=lambda bucket: bucket.label)
371
+ else:
372
+ values.sort(key=lambda bucket: bucket.tokens, reverse=True)
373
+ return values
374
+
375
+
376
+ def _local_datetime(ms_value: Any, seconds_value: Any, tz: ZoneInfo) -> datetime:
377
+ if ms_value is not None:
378
+ timestamp = _int_value(ms_value) / 1000
379
+ else:
380
+ timestamp = _int_value(seconds_value)
381
+ return datetime.fromtimestamp(timestamp, timezone.utc).astimezone(tz)
382
+
383
+
384
+ def _compact_path(value: str) -> str:
385
+ if not value:
386
+ return "unknown"
387
+ try:
388
+ path = Path(value).expanduser()
389
+ home = Path.home()
390
+ if path.is_absolute():
391
+ relative = path.relative_to(home)
392
+ return "~" if str(relative) == "." else "~/" + str(relative)
393
+ return str(path)
394
+ except ValueError:
395
+ return value
396
+
397
+
398
+ def _int_value(value: Any) -> int:
399
+ if value is None:
400
+ return 0
401
+ try:
402
+ return int(value)
403
+ except (TypeError, ValueError):
404
+ return 0
405
+
406
+
407
+ def _string_or_none(value: Any) -> str | None:
408
+ if value is None:
409
+ return None
410
+ text = str(value)
411
+ return text if text else None
codex_usage_profiler/render.py ADDED
@@ -0,0 +1,436 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import html
4
+ from pathlib import Path
5
+
6
+ from .core import Bucket, SessionUsage, UsageReport
7
+
8
+
9
+ def render_markdown(report: UsageReport) -> str:
10
+ lines: list[str] = [
11
+ "# Codex Usage Report",
12
+ "",
13
+ f"Generated: {report.generated_at.isoformat(timespec='seconds')}",
14
+ f"Timezone: `{report.timezone_name}`",
15
+ f"State DB: `{report.state_path}`",
16
+ f"Sessions dir: `{report.sessions_dir}`",
17
+ f"Date range: {report.date_range_label}",
18
+ ]
19
+ if report.days_filter is not None:
20
+ lines.append(f"Filter: last {report.days_filter} local calendar days")
21
+
22
+ lines.extend(
23
+ [
24
+ "",
25
+ "## Summary",
26
+ "",
27
+ _markdown_table(
28
+ ["Metric", "Value"],
29
+ [
30
+ ["Sessions", _fmt(report.sessions)],
31
+ ["Total tokens", _fmt(report.total_tokens)],
32
+ ["Rollouts with token breakdown", _fmt(report.parsed_rollout_count)],
33
+ ["Missing rollouts", _fmt(report.missing_rollout_count)],
34
+ ["Warnings", _fmt(report.warnings)],
35
+ ],
36
+ ),
37
+ "",
38
+ ]
39
+ )
40
+
41
+ if report.parsed_rollout_count:
42
+ lines.extend(
43
+ [
44
+ "## Rollout Token Breakdown",
45
+ "",
46
+ _markdown_table(
47
+ ["Input", "Cached input", "Output", "Reasoning output", "Rollout total"],
48
+ [
49
+ [
50
+ _fmt(report.rollout_totals.input_tokens),
51
+ _fmt(report.rollout_totals.cached_input_tokens),
52
+ _fmt(report.rollout_totals.output_tokens),
53
+ _fmt(report.rollout_totals.reasoning_output_tokens),
54
+ _fmt(report.rollout_totals.total_tokens),
55
+ ]
56
+ ],
57
+ ),
58
+ "",
59
+ ]
60
+ )
61
+
62
+ sections: list[tuple[str, list[Bucket]]] = [
63
+ ("Daily Tokens", report.daily),
64
+ ("Weekly Tokens", report.weekly),
65
+ ("Tokens By Cwd", report.by_cwd),
66
+ ("Tokens By Model", report.by_model),
67
+ ("Tokens By Role", report.by_role),
68
+ ("Main Vs Subagent", report.by_kind),
69
+ ]
70
+ for title, buckets in sections:
71
+ lines.extend(["## " + title, "", _render_bucket_markdown(buckets), ""])
72
+
73
+ lines.extend(["## Top Sessions", "", _render_top_sessions_markdown(report.top_sessions), ""])
74
+
75
+ if report.warnings:
76
+ lines.extend(
77
+ [
78
+ "## Data Warnings",
79
+ "",
80
+ *[f"- `{_escape_md(warning)}`" for warning in report.warnings[:50]],
81
+ ]
82
+ )
83
+ if len(report.warnings) > 50:
84
+ lines.append(f"- ... {len(report.warnings) - 50} more")
85
+ lines.append("")
86
+
87
+ return "\n".join(lines).rstrip() + "\n"
88
+
89
+
90
+ def render_html(report: UsageReport) -> str:
91
+ sections = "\n".join(
92
+ [
93
+ _html_section("Daily Tokens", _render_bucket_html(report.daily)),
94
+ _html_section("Weekly Tokens", _render_bucket_html(report.weekly)),
95
+ _html_section("Tokens By Cwd", _render_bucket_html(report.by_cwd)),
96
+ _html_section("Tokens By Model", _render_bucket_html(report.by_model)),
97
+ _html_section("Tokens By Role", _render_bucket_html(report.by_role)),
98
+ _html_section("Main Vs Subagent", _render_bucket_html(report.by_kind)),
99
+ _html_section("Top Sessions", _render_top_sessions_html(report.top_sessions)),
100
+ ]
101
+ )
102
+
103
+ rollout_section = ""
104
+ if report.parsed_rollout_count:
105
+ rollout_section = _html_section(
106
+ "Rollout Token Breakdown",
107
+ _html_table(
108
+ ["Input", "Cached input", "Output", "Reasoning output", "Rollout total"],
109
+ [
110
+ [
111
+ _fmt(report.rollout_totals.input_tokens),
112
+ _fmt(report.rollout_totals.cached_input_tokens),
113
+ _fmt(report.rollout_totals.output_tokens),
114
+ _fmt(report.rollout_totals.reasoning_output_tokens),
115
+ _fmt(report.rollout_totals.total_tokens),
116
+ ]
117
+ ],
118
+ ),
119
+ )
120
+
121
+ warnings_section = ""
122
+ if report.warnings:
123
+ items = "\n".join(
124
+ f"<li><code>{html.escape(warning)}</code></li>" for warning in report.warnings[:50]
125
+ )
126
+ if len(report.warnings) > 50:
127
+ items += f"\n<li>{len(report.warnings) - 50} more</li>"
128
+ warnings_section = _html_section("Data Warnings", f"<ul>{items}</ul>")
129
+
130
+ filter_line = ""
131
+ if report.days_filter is not None:
132
+ filter_line = f"<p>Filter: last {report.days_filter} local calendar days</p>"
133
+
134
+ return f"""<!doctype html>
135
+ <html lang="en">
136
+ <head>
137
+ <meta charset="utf-8">
138
+ <meta name="viewport" content="width=device-width, initial-scale=1">
139
+ <title>Codex Usage Report</title>
140
+ <style>
141
+ :root {{
142
+ color-scheme: light dark;
143
+ --bg: #f7f7f4;
144
+ --panel: #ffffff;
145
+ --text: #1f2528;
146
+ --muted: #667078;
147
+ --border: #d9ddd8;
148
+ --accent: #176b5d;
149
+ --row: #f1f4f2;
150
+ }}
151
+ @media (prefers-color-scheme: dark) {{
152
+ :root {{
153
+ --bg: #151716;
154
+ --panel: #1d211f;
155
+ --text: #eef1ee;
156
+ --muted: #a6aea9;
157
+ --border: #373d39;
158
+ --accent: #74c7b8;
159
+ --row: #242a27;
160
+ }}
161
+ }}
162
+ body {{
163
+ margin: 0;
164
+ background: var(--bg);
165
+ color: var(--text);
166
+ font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
167
+ line-height: 1.45;
168
+ }}
169
+ main {{
170
+ max-width: 1180px;
171
+ margin: 0 auto;
172
+ padding: 32px 20px 56px;
173
+ }}
174
+ h1 {{
175
+ margin: 0 0 10px;
176
+ font-size: 2rem;
177
+ letter-spacing: 0;
178
+ }}
179
+ h2 {{
180
+ margin: 32px 0 12px;
181
+ font-size: 1.1rem;
182
+ letter-spacing: 0;
183
+ }}
184
+ .meta {{
185
+ color: var(--muted);
186
+ display: grid;
187
+ gap: 4px;
188
+ margin-bottom: 24px;
189
+ }}
190
+ .summary {{
191
+ display: grid;
192
+ grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
193
+ gap: 12px;
194
+ }}
195
+ .metric {{
196
+ background: var(--panel);
197
+ border: 1px solid var(--border);
198
+ border-radius: 8px;
199
+ padding: 14px 16px;
200
+ }}
201
+ .metric span {{
202
+ display: block;
203
+ color: var(--muted);
204
+ font-size: .85rem;
205
+ }}
206
+ .metric strong {{
207
+ display: block;
208
+ margin-top: 4px;
209
+ font-size: 1.25rem;
210
+ }}
211
+ .table-wrap {{
212
+ overflow-x: auto;
213
+ border: 1px solid var(--border);
214
+ background: var(--panel);
215
+ border-radius: 8px;
216
+ }}
217
+ table {{
218
+ border-collapse: collapse;
219
+ width: 100%;
220
+ min-width: 640px;
221
+ }}
222
+ th, td {{
223
+ padding: 9px 11px;
224
+ border-bottom: 1px solid var(--border);
225
+ text-align: left;
226
+ vertical-align: top;
227
+ white-space: nowrap;
228
+ }}
229
+ th {{
230
+ color: var(--muted);
231
+ font-weight: 650;
232
+ font-size: .82rem;
233
+ background: var(--row);
234
+ }}
235
+ tr:last-child td {{
236
+ border-bottom: 0;
237
+ }}
238
+ td.num {{
239
+ text-align: right;
240
+ font-variant-numeric: tabular-nums;
241
+ }}
242
+ code {{
243
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
244
+ font-size: .9em;
245
+ }}
246
+ .empty {{
247
+ color: var(--muted);
248
+ margin: 0;
249
+ }}
250
+ </style>
251
+ </head>
252
+ <body>
253
+ <main>
254
+ <h1>Codex Usage Report</h1>
255
+ <div class="meta">
256
+ <div>Generated: {html.escape(report.generated_at.isoformat(timespec="seconds"))}</div>
257
+ <div>Timezone: <code>{html.escape(report.timezone_name)}</code></div>
258
+ <div>State DB: <code>{html.escape(str(report.state_path))}</code></div>
259
+ <div>Sessions dir: <code>{html.escape(str(report.sessions_dir))}</code></div>
260
+ <div>Date range: {html.escape(report.date_range_label)}</div>
261
+ {filter_line}
262
+ </div>
263
+ <section class="summary">
264
+ {_metric("Sessions", _fmt(report.sessions))}
265
+ {_metric("Total tokens", _fmt(report.total_tokens))}
266
+ {_metric("Rollout breakdowns", _fmt(report.parsed_rollout_count))}
267
+ {_metric("Missing rollouts", _fmt(report.missing_rollout_count))}
268
+ {_metric("Warnings", _fmt(report.warnings))}
269
+ </section>
270
+ {rollout_section}
271
+ {sections}
272
+ {warnings_section}
273
+ </main>
274
+ </body>
275
+ </html>
276
+ """
277
+
278
+
279
+ def write_reports(report: UsageReport, out_dir: Path, output_format: str) -> list[Path]:
280
+ out_dir.mkdir(parents=True, exist_ok=True)
281
+ written: list[Path] = []
282
+ if output_format in {"md", "both"}:
283
+ path = out_dir / "codex-usage.md"
284
+ path.write_text(render_markdown(report), encoding="utf-8")
285
+ written.append(path)
286
+ if output_format in {"html", "both"}:
287
+ path = out_dir / "codex-usage.html"
288
+ path.write_text(render_html(report), encoding="utf-8")
289
+ written.append(path)
290
+ return written
291
+
292
+
293
+ def _render_bucket_markdown(buckets: list[Bucket]) -> str:
294
+ return _markdown_table(
295
+ ["Label", "Sessions", "Tokens", "Rollout total", "Input", "Cached input", "Output", "Reasoning"],
296
+ [
297
+ [
298
+ bucket.label,
299
+ _fmt(bucket.sessions),
300
+ _fmt(bucket.tokens),
301
+ _fmt(bucket.rollout.total_tokens),
302
+ _fmt(bucket.rollout.input_tokens),
303
+ _fmt(bucket.rollout.cached_input_tokens),
304
+ _fmt(bucket.rollout.output_tokens),
305
+ _fmt(bucket.rollout.reasoning_output_tokens),
306
+ ]
307
+ for bucket in buckets
308
+ ],
309
+ )
310
+
311
+
312
+ def _render_bucket_html(buckets: list[Bucket]) -> str:
313
+ return _html_table(
314
+ ["Label", "Sessions", "Tokens", "Rollout total", "Input", "Cached input", "Output", "Reasoning"],
315
+ [
316
+ [
317
+ bucket.label,
318
+ _fmt(bucket.sessions),
319
+ _fmt(bucket.tokens),
320
+ _fmt(bucket.rollout.total_tokens),
321
+ _fmt(bucket.rollout.input_tokens),
322
+ _fmt(bucket.rollout.cached_input_tokens),
323
+ _fmt(bucket.rollout.output_tokens),
324
+ _fmt(bucket.rollout.reasoning_output_tokens),
325
+ ]
326
+ for bucket in buckets
327
+ ],
328
+ numeric_columns={1, 2, 3, 4, 5, 6, 7},
329
+ )
330
+
331
+
332
+ def _render_top_sessions_markdown(sessions: list[SessionUsage]) -> str:
333
+ return _markdown_table(
334
+ ["Created", "Tokens", "Kind", "Model", "Role", "Cwd", "Session", "Rollout"],
335
+ [
336
+ [
337
+ session.created_at.strftime("%Y-%m-%d %H:%M"),
338
+ _fmt(session.tokens),
339
+ session.kind,
340
+ session.model,
341
+ session.role,
342
+ _compact_for_report(session.cwd),
343
+ session.thread_id,
344
+ str(session.rollout_path or ""),
345
+ ]
346
+ for session in sessions
347
+ ],
348
+ )
349
+
350
+
351
+ def _render_top_sessions_html(sessions: list[SessionUsage]) -> str:
352
+ return _html_table(
353
+ ["Created", "Tokens", "Kind", "Model", "Role", "Cwd", "Session", "Rollout"],
354
+ [
355
+ [
356
+ session.created_at.strftime("%Y-%m-%d %H:%M"),
357
+ _fmt(session.tokens),
358
+ session.kind,
359
+ session.model,
360
+ session.role,
361
+ _compact_for_report(session.cwd),
362
+ session.thread_id,
363
+ str(session.rollout_path or ""),
364
+ ]
365
+ for session in sessions
366
+ ],
367
+ numeric_columns={1},
368
+ )
369
+
370
+
371
+ def _markdown_table(headers: list[str], rows: list[list[str]]) -> str:
372
+ if not rows:
373
+ return "_No rows._"
374
+ escaped_headers = [_escape_md(header) for header in headers]
375
+ lines = [
376
+ "| " + " | ".join(escaped_headers) + " |",
377
+ "| " + " | ".join("---" for _ in headers) + " |",
378
+ ]
379
+ for row in rows:
380
+ lines.append("| " + " | ".join(_escape_md(str(cell)) for cell in row) + " |")
381
+ return "\n".join(lines)
382
+
383
+
384
+ def _html_table(
385
+ headers: list[str], rows: list[list[str]], *, numeric_columns: set[int] | None = None
386
+ ) -> str:
387
+ if not rows:
388
+ return '<p class="empty">No rows.</p>'
389
+ numeric_columns = numeric_columns or set()
390
+ head = "".join(f"<th>{html.escape(header)}</th>" for header in headers)
391
+ body_rows = []
392
+ for row in rows:
393
+ cells = []
394
+ for index, cell in enumerate(row):
395
+ klass = ' class="num"' if index in numeric_columns else ""
396
+ cells.append(f"<td{klass}>{html.escape(str(cell))}</td>")
397
+ body_rows.append("<tr>" + "".join(cells) + "</tr>")
398
+ return (
399
+ '<div class="table-wrap"><table><thead><tr>'
400
+ + head
401
+ + "</tr></thead><tbody>"
402
+ + "".join(body_rows)
403
+ + "</tbody></table></div>"
404
+ )
405
+
406
+
407
+ def _html_section(title: str, content: str) -> str:
408
+ return f"<section><h2>{html.escape(title)}</h2>{content}</section>"
409
+
410
+
411
+ def _metric(label: str, value: str) -> str:
412
+ return f'<div class="metric"><span>{html.escape(label)}</span><strong>{html.escape(value)}</strong></div>'
413
+
414
+
415
+ def _fmt(value: int | list[object]) -> str:
416
+ if isinstance(value, list):
417
+ value = len(value)
418
+ return f"{value:,}"
419
+
420
+
421
+ def _escape_md(value: str) -> str:
422
+ return value.replace("\\", "\\\\").replace("|", "\\|").replace("\n", " ")
423
+
424
+
425
+ def _compact_for_report(value: str) -> str:
426
+ if not value:
427
+ return "unknown"
428
+ try:
429
+ path = Path(value).expanduser()
430
+ home = Path.home()
431
+ if path.is_absolute():
432
+ relative = path.relative_to(home)
433
+ return "~" if str(relative) == "." else "~/" + str(relative)
434
+ return str(path)
435
+ except ValueError:
436
+ return value
pyproject.toml ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [build-system]
2
+ requires = ["setuptools>=68"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "codex-usage-profiler"
7
+ version = "0.1.0"
8
+ description = "Local profiler for Codex state_5.sqlite and rollout JSONL usage data"
9
+ readme = "README.md"
10
+ requires-python = ">=3.11"
11
+ dependencies = []
12
+
13
+ [project.scripts]
14
+ codex-usage-profiler = "codex_usage_profiler.cli:main"
15
+
16
+ [tool.setuptools.packages.find]
17
+ include = ["codex_usage_profiler*"]
reports-last7/codex-usage.md ADDED
@@ -0,0 +1,99 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Codex Usage Report
2
+
3
+ Generated: 2026-04-22T00:49:13+02:00
4
+ Timezone: `Europe/Berlin`
5
+ State DB: `/home/smlflg/.codex/state_5.sqlite`
6
+ Sessions dir: `/home/smlflg/.codex/sessions`
7
+ Date range: 2026-04-16 to 2026-04-22
8
+ Filter: last 7 local calendar days
9
+
10
+ ## Summary
11
+
12
+ | Metric | Value |
13
+ | --- | --- |
14
+ | Sessions | 134 |
15
+ | Total tokens | 396,472,202 |
16
+ | Rollouts with token breakdown | 132 |
17
+ | Missing rollouts | 0 |
18
+ | Warnings | 1 |
19
+
20
+ ## Rollout Token Breakdown
21
+
22
+ | Input | Cached input | Output | Reasoning output | Rollout total |
23
+ | --- | --- | --- | --- | --- |
24
+ | 394,419,162 | 366,772,096 | 2,309,042 | 820,743 | 396,728,204 |
25
+
26
+ ## Daily Tokens
27
+
28
+ | Label | Sessions | Tokens | Rollout total | Input | Cached input | Output | Reasoning |
29
+ | --- | --- | --- | --- | --- | --- | --- | --- |
30
+ | 2026-04-16 | 3 | 59,357,456 | 59,357,456 | 59,092,558 | 56,559,360 | 264,898 | 125,030 |
31
+ | 2026-04-20 | 1 | 13,711,641 | 13,711,641 | 13,653,855 | 13,032,832 | 57,786 | 12,196 |
32
+ | 2026-04-21 | 115 | 300,116,344 | 300,116,344 | 298,325,385 | 276,096,768 | 1,790,959 | 610,982 |
33
+ | 2026-04-22 | 15 | 23,286,761 | 23,542,763 | 23,347,364 | 21,083,136 | 195,399 | 72,535 |
34
+
35
+ ## Weekly Tokens
36
+
37
+ | Label | Sessions | Tokens | Rollout total | Input | Cached input | Output | Reasoning |
38
+ | --- | --- | --- | --- | --- | --- | --- | --- |
39
+ | 2026-W16 | 3 | 59,357,456 | 59,357,456 | 59,092,558 | 56,559,360 | 264,898 | 125,030 |
40
+ | 2026-W17 | 131 | 337,114,746 | 337,370,748 | 335,326,604 | 310,212,736 | 2,044,144 | 695,713 |
41
+
42
+ ## Tokens By Cwd
43
+
44
+ | Label | Sessions | Tokens | Rollout total | Input | Cached input | Output | Reasoning |
45
+ | --- | --- | --- | --- | --- | --- | --- | --- |
46
+ | ~/Projekte/PromptBoost | 40 | 91,369,695 | 91,369,695 | 90,715,571 | 84,423,552 | 654,124 | 254,702 |
47
+ | ~/Projekte/HeumandenParty | 23 | 81,899,777 | 81,899,777 | 81,449,087 | 76,069,888 | 450,690 | 171,495 |
48
+ | ~/Projekte/FirstRealHarnessEvaluation_KarpathiesMD | 2 | 59,357,456 | 59,357,456 | 59,092,558 | 56,559,360 | 264,898 | 125,030 |
49
+ | ~ | 23 | 48,541,135 | 48,541,135 | 48,305,111 | 44,374,144 | 236,024 | 68,175 |
50
+ | ~/Projekte | 18 | 37,257,578 | 37,257,578 | 37,030,877 | 33,269,376 | 226,701 | 61,080 |
51
+ | ~/Projekte/PromptBoost/personalPromptBoost | 13 | 22,802,481 | 22,802,481 | 22,611,147 | 20,876,160 | 191,334 | 57,401 |
52
+ | ~/Projekte/PromptGarage | 1 | 19,452,133 | 19,452,133 | 19,394,544 | 18,764,544 | 57,589 | 18,018 |
53
+ | ~/Projekte/PseudoLogikPyhthonCPP | 2 | 16,329,762 | 16,329,762 | 16,254,080 | 15,190,656 | 75,682 | 20,994 |
54
+ | ~/Codex | 3 | 7,952,365 | 8,166,946 | 8,114,601 | 7,161,344 | 52,345 | 14,392 |
55
+ | ~/Projekte/BahnAgent | 2 | 4,575,173 | 4,575,173 | 4,549,935 | 3,969,920 | 25,238 | 3,688 |
56
+ | ~/.claude | 1 | 2,724,909 | 2,724,909 | 2,707,930 | 2,457,344 | 16,979 | 4,749 |
57
+ | ~/Projekte/Codex_Usage_Profil | 1 | 2,167,223 | 2,167,223 | 2,142,329 | 1,986,304 | 24,894 | 6,969 |
58
+ | ~/Projekte/ACPcodex | 1 | 1,059,170 | 1,059,170 | 1,043,792 | 910,848 | 15,378 | 8,018 |
59
+ | ~/Projekte/Kaggle5dayAgent | 2 | 913,047 | 913,047 | 897,573 | 686,592 | 15,474 | 5,673 |
60
+ | ~/Projekte/HarnessEcosystem/sidebyside | 2 | 70,298 | 111,719 | 110,027 | 72,064 | 1,692 | 359 |
61
+
62
+ ## Tokens By Model
63
+
64
+ | Label | Sessions | Tokens | Rollout total | Input | Cached input | Output | Reasoning |
65
+ | --- | --- | --- | --- | --- | --- | --- | --- |
66
+ | gpt-5.4 | 81 | 327,418,371 | 327,658,970 | 325,872,479 | 302,350,848 | 1,786,491 | 532,886 |
67
+ | gpt-5.4-mini | 52 | 69,053,831 | 69,069,234 | 68,546,683 | 64,421,248 | 522,551 | 287,857 |
68
+ | unknown | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
69
+
70
+ ## Tokens By Role
71
+
72
+ | Label | Sessions | Tokens | Rollout total | Input | Cached input | Output | Reasoning |
73
+ | --- | --- | --- | --- | --- | --- | --- | --- |
74
+ | main | 34 | 344,072,714 | 344,313,313 | 342,760,455 | 322,165,888 | 1,552,858 | 493,488 |
75
+ | unknown | 17 | 31,239,166 | 31,239,166 | 30,924,883 | 27,394,176 | 314,283 | 116,098 |
76
+ | explorer | 72 | 15,482,699 | 15,498,102 | 15,170,418 | 12,131,712 | 327,684 | 163,970 |
77
+ | worker | 5 | 5,588,454 | 5,588,454 | 5,474,360 | 5,029,376 | 114,094 | 47,118 |
78
+ | default | 6 | 89,169 | 89,169 | 89,046 | 50,944 | 123 | 69 |
79
+
80
+ ## Main Vs Subagent
81
+
82
+ | Label | Sessions | Tokens | Rollout total | Input | Cached input | Output | Reasoning |
83
+ | --- | --- | --- | --- | --- | --- | --- | --- |
84
+ | main | 34 | 344,072,714 | 344,313,313 | 342,760,455 | 322,165,888 | 1,552,858 | 493,488 |
85
+ | subagent | 100 | 52,399,488 | 52,414,891 | 51,658,707 | 44,606,208 | 756,184 | 327,255 |
86
+
87
+ ## Top Sessions
88
+
89
+ | Created | Tokens | Kind | Model | Role | Cwd | Session | Rollout |
90
+ | --- | --- | --- | --- | --- | --- | --- | --- |
91
+ | 2026-04-16 13:01 | 47,959,797 | main | gpt-5.4-mini | main | ~/Projekte/FirstRealHarnessEvaluation_KarpathiesMD | 019d95f4-0198-7e10-9c95-ecd79e771e27 | /home/smlflg/.codex/sessions/2026/04/16/rollout-2026-04-16T13-01-29-019d95f4-0198-7e10-9c95-ecd79e771e27.jsonl |
92
+ | 2026-04-21 23:03 | 32,619,865 | main | gpt-5.4 | main | ~/Projekte/HeumandenParty | 019db1db-150f-7662-b607-30871c33af75 | /home/smlflg/.codex/sessions/2026/04/21/rollout-2026-04-21T23-03-38-019db1db-150f-7662-b607-30871c33af75.jsonl |
93
+ | 2026-04-21 23:28 | 21,430,259 | main | gpt-5.4 | main | ~/Projekte/HeumandenParty | 019db1f1-e994-75c0-94d8-6edc93203dd7 | /home/smlflg/.codex/sessions/2026/04/21/rollout-2026-04-21T23-28-34-019db1f1-e994-75c0-94d8-6edc93203dd7.jsonl |
94
+ | 2026-04-21 15:43 | 21,410,253 | main | gpt-5.4 | main | ~ | 019db048-0123-7242-89b9-d6083591212b | /home/smlflg/.codex/sessions/2026/04/21/rollout-2026-04-21T15-43-22-019db048-0123-7242-89b9-d6083591212b.jsonl |
95
+ | 2026-04-21 15:31 | 21,194,654 | main | gpt-5.4 | main | ~/Projekte/PromptBoost | 019db03d-1f96-7592-8fef-1f10125ebe0c | /home/smlflg/.codex/sessions/2026/04/21/rollout-2026-04-21T15-31-29-019db03d-1f96-7592-8fef-1f10125ebe0c.jsonl |
96
+
97
+ ## Data Warnings
98
+
99
+ - `Malformed JSONL lines in /home/smlflg/.codex/sessions/2026/04/21/rollout-2026-04-21T18-15-04-019db0d2-e62b-78b3-b8f3-e0c70af3aa6c.jsonl: 1`
reports/codex-usage.html ADDED
@@ -0,0 +1,148 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <title>Codex Usage Report</title>
7
+ <style>
8
+ :root {
9
+ color-scheme: light dark;
10
+ --bg: #f7f7f4;
11
+ --panel: #ffffff;
12
+ --text: #1f2528;
13
+ --muted: #667078;
14
+ --border: #d9ddd8;
15
+ --accent: #176b5d;
16
+ --row: #f1f4f2;
17
+ }
18
+ @media (prefers-color-scheme: dark) {
19
+ :root {
20
+ --bg: #151716;
21
+ --panel: #1d211f;
22
+ --text: #eef1ee;
23
+ --muted: #a6aea9;
24
+ --border: #373d39;
25
+ --accent: #74c7b8;
26
+ --row: #242a27;
27
+ }
28
+ }
29
+ body {
30
+ margin: 0;
31
+ background: var(--bg);
32
+ color: var(--text);
33
+ font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
34
+ line-height: 1.45;
35
+ }
36
+ main {
37
+ max-width: 1180px;
38
+ margin: 0 auto;
39
+ padding: 32px 20px 56px;
40
+ }
41
+ h1 {
42
+ margin: 0 0 10px;
43
+ font-size: 2rem;
44
+ letter-spacing: 0;
45
+ }
46
+ h2 {
47
+ margin: 32px 0 12px;
48
+ font-size: 1.1rem;
49
+ letter-spacing: 0;
50
+ }
51
+ .meta {
52
+ color: var(--muted);
53
+ display: grid;
54
+ gap: 4px;
55
+ margin-bottom: 24px;
56
+ }
57
+ .summary {
58
+ display: grid;
59
+ grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
60
+ gap: 12px;
61
+ }
62
+ .metric {
63
+ background: var(--panel);
64
+ border: 1px solid var(--border);
65
+ border-radius: 8px;
66
+ padding: 14px 16px;
67
+ }
68
+ .metric span {
69
+ display: block;
70
+ color: var(--muted);
71
+ font-size: .85rem;
72
+ }
73
+ .metric strong {
74
+ display: block;
75
+ margin-top: 4px;
76
+ font-size: 1.25rem;
77
+ }
78
+ .table-wrap {
79
+ overflow-x: auto;
80
+ border: 1px solid var(--border);
81
+ background: var(--panel);
82
+ border-radius: 8px;
83
+ }
84
+ table {
85
+ border-collapse: collapse;
86
+ width: 100%;
87
+ min-width: 640px;
88
+ }
89
+ th, td {
90
+ padding: 9px 11px;
91
+ border-bottom: 1px solid var(--border);
92
+ text-align: left;
93
+ vertical-align: top;
94
+ white-space: nowrap;
95
+ }
96
+ th {
97
+ color: var(--muted);
98
+ font-weight: 650;
99
+ font-size: .82rem;
100
+ background: var(--row);
101
+ }
102
+ tr:last-child td {
103
+ border-bottom: 0;
104
+ }
105
+ td.num {
106
+ text-align: right;
107
+ font-variant-numeric: tabular-nums;
108
+ }
109
+ code {
110
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
111
+ font-size: .9em;
112
+ }
113
+ .empty {
114
+ color: var(--muted);
115
+ margin: 0;
116
+ }
117
+ </style>
118
+ </head>
119
+ <body>
120
+ <main>
121
+ <h1>Codex Usage Report</h1>
122
+ <div class="meta">
123
+ <div>Generated: 2026-04-22T00:48:49+02:00</div>
124
+ <div>Timezone: <code>Europe/Berlin</code></div>
125
+ <div>State DB: <code>/home/smlflg/.codex/state_5.sqlite</code></div>
126
+ <div>Sessions dir: <code>/home/smlflg/.codex/sessions</code></div>
127
+ <div>Date range: 2026-02-03 to 2026-04-22</div>
128
+
129
+ </div>
130
+ <section class="summary">
131
+ <div class="metric"><span>Sessions</span><strong>375</strong></div>
132
+ <div class="metric"><span>Total tokens</span><strong>1,255,210,700</strong></div>
133
+ <div class="metric"><span>Rollout breakdowns</span><strong>359</strong></div>
134
+ <div class="metric"><span>Missing rollouts</span><strong>0</strong></div>
135
+ <div class="metric"><span>Warnings</span><strong>1</strong></div>
136
+ </section>
137
+ <section><h2>Rollout Token Breakdown</h2><div class="table-wrap"><table><thead><tr><th>Input</th><th>Cached input</th><th>Output</th><th>Reasoning output</th><th>Rollout total</th></tr></thead><tbody><tr><td>1,247,663,109</td><td>1,120,145,792</td><td>7,547,591</td><td>2,657,540</td><td>1,255,210,700</td></tr></tbody></table></div></section>
138
+ <section><h2>Daily Tokens</h2><div class="table-wrap"><table><thead><tr><th>Label</th><th>Sessions</th><th>Tokens</th><th>Rollout total</th><th>Input</th><th>Cached input</th><th>Output</th><th>Reasoning</th></tr></thead><tbody><tr><td>2026-02-03</td><td class="num">4</td><td class="num">2,592,334</td><td class="num">2,592,334</td><td class="num">2,568,243</td><td class="num">2,210,560</td><td class="num">24,091</td><td class="num">11,520</td></tr><tr><td>2026-02-04</td><td class="num">1</td><td class="num">1,714,675</td><td class="num">1,714,675</td><td class="num">1,654,679</td><td class="num">1,327,104</td><td class="num">59,996</td><td class="num">47,296</td></tr><tr><td>2026-02-05</td><td class="num">3</td><td class="num">41,998,810</td><td class="num">41,998,810</td><td class="num">41,824,072</td><td class="num">36,333,696</td><td class="num">174,738</td><td class="num">62,720</td></tr><tr><td>2026-02-06</td><td class="num">2</td><td class="num">3,102,257</td><td class="num">3,102,257</td><td class="num">3,087,487</td><td class="num">2,501,760</td><td class="num">14,770</td><td class="num">5,248</td></tr><tr><td>2026-02-07</td><td class="num">3</td><td class="num">28,416,733</td><td class="num">28,416,733</td><td class="num">28,275,656</td><td class="num">24,109,568</td><td class="num">141,077</td><td class="num">51,584</td></tr><tr><td>2026-02-08</td><td class="num">1</td><td class="num">1,722,562</td><td class="num">1,722,562</td><td class="num">1,705,968</td><td class="num">1,052,672</td><td class="num">16,594</td><td class="num">9,536</td></tr><tr><td>2026-02-09</td><td class="num">3</td><td class="num">8,276,308</td><td class="num">8,276,308</td><td class="num">8,233,458</td><td class="num">6,579,200</td><td class="num">42,850</td><td class="num">18,560</td></tr><tr><td>2026-02-10</td><td class="num">2</td><td class="num">110,210</td><td class="num">110,210</td><td class="num">106,170</td><td class="num">77,184</td><td class="num">4,040</td><td class="num">2,688</td></tr><tr><td>2026-02-14</td><td class="num">1</td><td class="num">18,724</td><td class="num">18,724</td><td class="num">17,236</td><td class="num">13,824</td><td class="num">1,488</td><td class="num">960</td></tr><tr><td>2026-02-18</td><td class="num">6</td><td class="num">38,042,984</td><td class="num">38,042,984</td><td class="num">37,824,219</td><td class="num">34,982,272</td><td class="num">218,765</td><td class="num">96,508</td></tr><tr><td>2026-02-19</td><td class="num">3</td><td class="num">2,374,671</td><td class="num">2,374,671</td><td class="num">2,336,358</td><td class="num">2,010,240</td><td class="num">38,313</td><td class="num">21,859</td></tr><tr><td>2026-02-20</td><td class="num">1</td><td class="num">815,392</td><td class="num">815,392</td><td class="num">793,001</td><td class="num">672,512</td><td class="num">22,391</td><td class="num">14,469</td></tr><tr><td>2026-02-22</td><td class="num">1</td><td class="num">86,970</td><td class="num">86,970</td><td class="num">85,224</td><td class="num">67,584</td><td class="num">1,746</td><td class="num">493</td></tr><tr><td>2026-02-23</td><td class="num">3</td><td class="num">1,503,367</td><td class="num">1,503,367</td><td class="num">1,490,803</td><td class="num">1,300,480</td><td class="num">12,564</td><td class="num">5,869</td></tr><tr><td>2026-02-24</td><td class="num">4</td><td class="num">915,167</td><td class="num">915,167</td><td class="num">894,983</td><td class="num">785,280</td><td class="num">20,184</td><td class="num">11,311</td></tr><tr><td>2026-02-25</td><td class="num">6</td><td class="num">1,153,635</td><td class="num">1,153,635</td><td class="num">1,129,519</td><td class="num">927,360</td><td class="num">24,116</td><td class="num">13,381</td></tr><tr><td>2026-02-26</td><td class="num">4</td><td class="num">4,842,727</td><td class="num">4,842,727</td><td class="num">4,769,518</td><td class="num">4,068,224</td><td class="num">73,209</td><td class="num">29,303</td></tr><tr><td>2026-02-28</td><td class="num">2</td><td class="num">203,849</td><td class="num">203,849</td><td class="num">196,188</td><td class="num">170,880</td><td class="num">7,661</td><td class="num">5,165</td></tr><tr><td>2026-03-01</td><td class="num">1</td><td class="num">144,226</td><td class="num">144,226</td><td class="num">139,396</td><td class="num">81,280</td><td class="num">4,830</td><td class="num">3,606</td></tr><tr><td>2026-03-02</td><td class="num">11</td><td class="num">1,628,800</td><td class="num">1,628,800</td><td class="num">1,593,771</td><td class="num">1,470,208</td><td class="num">35,029</td><td class="num">18,398</td></tr><tr><td>2026-03-03</td><td class="num">4</td><td class="num">1,176,373</td><td class="num">1,176,373</td><td class="num">1,157,419</td><td class="num">1,009,024</td><td class="num">18,954</td><td class="num">10,514</td></tr><tr><td>2026-03-05</td><td class="num">4</td><td class="num">1,751,326</td><td class="num">1,751,326</td><td class="num">1,725,852</td><td class="num">1,489,152</td><td class="num">25,474</td><td class="num">15,895</td></tr><tr><td>2026-03-06</td><td class="num">14</td><td class="num">3,427,861</td><td class="num">3,427,861</td><td class="num">3,348,617</td><td class="num">2,956,288</td><td class="num">79,244</td><td class="num">56,569</td></tr><tr><td>2026-03-10</td><td class="num">9</td><td class="num">2,482,191</td><td class="num">2,482,191</td><td class="num">2,423,969</td><td class="num">2,024,448</td><td class="num">58,222</td><td class="num">43,369</td></tr><tr><td>2026-03-11</td><td class="num">5</td><td class="num">707,822</td><td class="num">707,822</td><td class="num">681,540</td><td class="num">562,944</td><td class="num">26,282</td><td class="num">18,943</td></tr><tr><td>2026-03-12</td><td class="num">18</td><td class="num">103,444,689</td><td class="num">103,444,689</td><td class="num">102,734,723</td><td class="num">89,554,560</td><td class="num">709,966</td><td class="num">340,105</td></tr><tr><td>2026-03-13</td><td class="num">7</td><td class="num">68,599,649</td><td class="num">68,599,649</td><td class="num">68,188,511</td><td class="num">55,110,528</td><td class="num">411,138</td><td class="num">185,043</td></tr><tr><td>2026-03-15</td><td class="num">6</td><td class="num">972,313</td><td class="num">972,313</td><td class="num">952,374</td><td class="num">838,912</td><td class="num">19,939</td><td class="num">13,994</td></tr><tr><td>2026-03-16</td><td class="num">8</td><td class="num">5,367,296</td><td class="num">5,367,296</td><td class="num">5,288,510</td><td class="num">4,711,680</td><td class="num">78,786</td><td class="num">38,822</td></tr><tr><td>2026-03-17</td><td class="num">1</td><td class="num">3,009,062</td><td class="num">3,009,062</td><td class="num">2,988,236</td><td class="num">2,400,000</td><td class="num">20,826</td><td class="num">9,320</td></tr><tr><td>2026-03-19</td><td class="num">6</td><td class="num">5,953,315</td><td class="num">5,953,315</td><td class="num">5,903,652</td><td class="num">5,102,208</td><td class="num">49,663</td><td class="num">7,583</td></tr><tr><td>2026-03-20</td><td class="num">9</td><td class="num">14,247,345</td><td class="num">14,247,345</td><td class="num">14,098,575</td><td class="num">12,846,592</td><td class="num">148,770</td><td class="num">26,244</td></tr><tr><td>2026-03-22</td><td class="num">1</td><td class="num">3,317,062</td><td class="num">3,317,062</td><td class="num">3,305,352</td><td class="num">2,819,456</td><td class="num">11,710</td><td class="num">2,378</td></tr><tr><td>2026-03-24</td><td class="num">6</td><td class="num">21,773,327</td><td class="num">21,773,327</td><td class="num">21,545,181</td><td class="num">18,719,872</td><td class="num">228,146</td><td class="num">28,934</td></tr><tr><td>2026-03-25</td><td class="num">2</td><td class="num">15,794,732</td><td class="num">15,794,732</td><td class="num">15,689,027</td><td class="num">14,278,272</td><td class="num">105,705</td><td class="num">14,028</td></tr><tr><td>2026-03-26</td><td class="num">4</td><td class="num">17,475,352</td><td class="num">17,475,352</td><td class="num">17,365,616</td><td class="num">16,159,360</td><td class="num">109,736</td><td class="num">11,644</td></tr><tr><td>2026-03-27</td><td class="num">1</td><td class="num">98,877</td><td class="num">98,877</td><td class="num">97,169</td><td class="num">71,552</td><td class="num">1,708</td><td class="num">604</td></tr><tr><td>2026-03-28</td><td class="num">3</td><td class="num">7,712,399</td><td class="num">7,712,399</td><td class="num">7,664,563</td><td class="num">7,005,440</td><td class="num">47,836</td><td class="num">13,515</td></tr><tr><td>2026-03-31</td><td class="num">1</td><td class="num">0</td><td class="num">0</td><td class="num">0</td><td class="num">0</td><td class="num">0</td><td class="num">0</td></tr><tr><td>2026-04-01</td><td class="num">3</td><td class="num">25,508,023</td><td class="num">25,508,023</td><td class="num">25,350,746</td><td class="num">20,315,904</td><td class="num">157,277</td><td class="num">37,958</td></tr><tr><td>2026-04-02</td><td class="num">4</td><td class="num">17,199,934</td><td class="num">17,199,934</td><td class="num">17,062,790</td><td class="num">14,398,848</td><td class="num">137,144</td><td class="num">35,101</td></tr><tr><td>2026-04-04</td><td class="num">3</td><td class="num">46,566,280</td><td class="num">46,566,280</td><td class="num">46,287,856</td><td class="num">41,528,704</td><td class="num">278,424</td><td class="num">75,164</td></tr><tr><td>2026-04-05</td><td class="num">6</td><td class="num">39,855,513</td><td class="num">39,855,513</td><td class="num">39,651,697</td><td class="num">33,805,568</td><td class="num">203,816</td><td class="num">50,687</td></tr><tr><td>2026-04-06</td><td class="num">9</td><td class="num">65,364,640</td><td class="num">65,364,640</td><td class="num">64,956,269</td><td class="num">56,659,584</td><td class="num">408,371</td><td class="num">98,417</td></tr><tr><td>2026-04-08</td><td class="num">7</td><td class="num">28,703,787</td><td class="num">28,703,787</td><td class="num">28,511,836</td><td class="num">23,291,904</td><td class="num">191,951</td><td class="num">61,081</td></tr><tr><td>2026-04-10</td><td class="num">2</td><td class="num">6,955,652</td><td class="num">6,955,652</td><td class="num">6,911,550</td><td class="num">5,532,928</td><td class="num">44,102</td><td class="num">11,076</td></tr><tr><td>2026-04-11</td><td class="num">7</td><td class="num">40,151,055</td><td class="num">40,151,055</td><td class="num">40,010,387</td><td class="num">37,590,016</td><td class="num">140,668</td><td class="num">44,009</td></tr><tr><td>2026-04-12</td><td class="num">24</td><td class="num">119,779,328</td><td class="num">119,779,328</td><td class="num">119,335,097</td><td class="num">114,489,472</td><td class="num">444,231</td><td class="num">126,296</td></tr><tr><td>2026-04-13</td><td class="num">2</td><td class="num">44,278,404</td><td class="num">44,278,404</td><td class="num">44,178,204</td><td class="num">41,139,200</td><td class="num">100,200</td><td class="num">16,762</td></tr><tr><td>2026-04-14</td><td class="num">4</td><td class="num">8,627,447</td><td class="num">8,627,447</td><td class="num">8,582,567</td><td class="num">7,647,232</td><td class="num">44,880</td><td class="num">13,293</td></tr><tr><td>2026-04-16</td><td class="num">3</td><td class="num">59,357,456</td><td class="num">59,357,456</td><td class="num">59,092,558</td><td class="num">56,559,360</td><td class="num">264,898</td><td class="num">125,030</td></tr><tr><td>2026-04-20</td><td class="num">1</td><td class="num">13,711,641</td><td class="num">13,711,641</td><td class="num">13,653,855</td><td class="num">13,032,832</td><td class="num">57,786</td><td class="num">12,196</td></tr><tr><td>2026-04-21</td><td class="num">115</td><td class="num">300,116,344</td><td class="num">300,116,344</td><td class="num">298,325,385</td><td class="num">276,096,768</td><td class="num">1,790,959</td><td class="num">610,982</td></tr><tr><td>2026-04-22</td><td class="num">14</td><td class="num">22,059,804</td><td class="num">22,059,804</td><td class="num">21,867,477</td><td class="num">19,655,296</td><td class="num">192,327</td><td class="num">71,510</td></tr></tbody></table></div></section>
139
+ <section><h2>Weekly Tokens</h2><div class="table-wrap"><table><thead><tr><th>Label</th><th>Sessions</th><th>Tokens</th><th>Rollout total</th><th>Input</th><th>Cached input</th><th>Output</th><th>Reasoning</th></tr></thead><tbody><tr><td>2026-W06</td><td class="num">14</td><td class="num">79,547,371</td><td class="num">79,547,371</td><td class="num">79,116,105</td><td class="num">67,535,360</td><td class="num">431,266</td><td class="num">187,904</td></tr><tr><td>2026-W07</td><td class="num">6</td><td class="num">8,405,242</td><td class="num">8,405,242</td><td class="num">8,356,864</td><td class="num">6,670,208</td><td class="num">48,378</td><td class="num">22,208</td></tr><tr><td>2026-W08</td><td class="num">11</td><td class="num">41,320,017</td><td class="num">41,320,017</td><td class="num">41,038,802</td><td class="num">37,732,608</td><td class="num">281,215</td><td class="num">133,329</td></tr><tr><td>2026-W09</td><td class="num">20</td><td class="num">8,762,971</td><td class="num">8,762,971</td><td class="num">8,620,407</td><td class="num">7,333,504</td><td class="num">142,564</td><td class="num">68,635</td></tr><tr><td>2026-W10</td><td class="num">33</td><td class="num">7,984,360</td><td class="num">7,984,360</td><td class="num">7,825,659</td><td class="num">6,924,672</td><td class="num">158,701</td><td class="num">101,376</td></tr><tr><td>2026-W11</td><td class="num">45</td><td class="num">176,206,664</td><td class="num">176,206,664</td><td class="num">174,981,117</td><td class="num">148,091,392</td><td class="num">1,225,547</td><td class="num">601,454</td></tr><tr><td>2026-W12</td><td class="num">25</td><td class="num">31,894,080</td><td class="num">31,894,080</td><td class="num">31,584,325</td><td class="num">27,879,936</td><td class="num">309,755</td><td class="num">84,347</td></tr><tr><td>2026-W13</td><td class="num">16</td><td class="num">62,854,687</td><td class="num">62,854,687</td><td class="num">62,361,556</td><td class="num">56,234,496</td><td class="num">493,131</td><td class="num">68,725</td></tr><tr><td>2026-W14</td><td class="num">17</td><td class="num">129,129,750</td><td class="num">129,129,750</td><td class="num">128,353,089</td><td class="num">110,049,024</td><td class="num">776,661</td><td class="num">198,910</td></tr><tr><td>2026-W15</td><td class="num">49</td><td class="num">260,954,462</td><td class="num">260,954,462</td><td class="num">259,725,139</td><td class="num">237,563,904</td><td class="num">1,229,323</td><td class="num">340,879</td></tr><tr><td>2026-W16</td><td class="num">9</td><td class="num">112,263,307</td><td class="num">112,263,307</td><td class="num">111,853,329</td><td class="num">105,345,792</td><td class="num">409,978</td><td class="num">155,085</td></tr><tr><td>2026-W17</td><td class="num">130</td><td class="num">335,887,789</td><td class="num">335,887,789</td><td class="num">333,846,717</td><td class="num">308,784,896</td><td class="num">2,041,072</td><td class="num">694,688</td></tr></tbody></table></div></section>
140
+ <section><h2>Tokens By Cwd</h2><div class="table-wrap"><table><thead><tr><th>Label</th><th>Sessions</th><th>Tokens</th><th>Rollout total</th><th>Input</th><th>Cached input</th><th>Output</th><th>Reasoning</th></tr></thead><tbody><tr><td>~/Projekte/HeumandenParty</td><td class="num">25</td><td class="num">147,920,810</td><td class="num">147,920,810</td><td class="num">147,263,059</td><td class="num">135,344,768</td><td class="num">657,751</td><td class="num">224,690</td></tr><tr><td>~</td><td class="num">65</td><td class="num">143,305,952</td><td class="num">143,305,952</td><td class="num">142,271,611</td><td class="num">118,259,584</td><td class="num">1,034,341</td><td class="num">411,954</td></tr><tr><td>~/Projekte/UEBER_AGENT</td><td class="num">14</td><td class="num">95,265,645</td><td class="num">95,265,645</td><td class="num">94,690,320</td><td class="num">82,054,784</td><td class="num">575,325</td><td class="num">136,176</td></tr><tr><td>~/Projekte/PromptBoost</td><td class="num">40</td><td class="num">91,369,695</td><td class="num">91,369,695</td><td class="num">90,715,571</td><td class="num">84,423,552</td><td class="num">654,124</td><td class="num">254,702</td></tr><tr><td>~/Projekte/Zentrale</td><td class="num">19</td><td class="num">86,591,689</td><td class="num">86,591,689</td><td class="num">86,233,084</td><td class="num">82,599,424</td><td class="num">358,605</td><td class="num">98,470</td></tr><tr><td>~/Projekte/Sidecar-V7</td><td class="num">9</td><td class="num">84,675,641</td><td class="num">84,675,641</td><td class="num">84,245,938</td><td class="num">74,833,280</td><td class="num">429,703</td><td class="num">197,775</td></tr><tr><td>~/Projekte</td><td class="num">28</td><td class="num">83,595,490</td><td class="num">83,595,490</td><td class="num">83,172,046</td><td class="num">74,665,344</td><td class="num">423,444</td><td class="num">112,523</td></tr><tr><td>~/Dokumente/Pläne</td><td class="num">4</td><td class="num">66,513,874</td><td class="num">66,513,874</td><td class="num">66,247,523</td><td class="num">57,384,832</td><td class="num">266,351</td><td class="num">83,776</td></tr><tr><td>~/Projekte/FirstRealHarnessEvaluation_KarpathiesMD</td><td class="num">2</td><td class="num">59,357,456</td><td class="num">59,357,456</td><td class="num">59,092,558</td><td class="num">56,559,360</td><td class="num">264,898</td><td class="num">125,030</td></tr><tr><td>~/clawd</td><td class="num">4</td><td class="num">49,462,644</td><td class="num">49,462,644</td><td class="num">49,155,998</td><td class="num">43,810,432</td><td class="num">306,646</td><td class="num">91,996</td></tr><tr><td>~/DataEngeeneeringKEEPA</td><td class="num">6</td><td class="num">46,940,456</td><td class="num">46,940,456</td><td class="num">46,696,473</td><td class="num">41,869,440</td><td class="num">243,983</td><td class="num">105,385</td></tr><tr><td>~/SetUP/Monitor_my_Monitors</td><td class="num">3</td><td class="num">37,573,267</td><td class="num">37,573,267</td><td class="num">37,477,005</td><td class="num">36,243,584</td><td class="num">96,262</td><td class="num">33,239</td></tr><tr><td>~/Projekte/PromptBoost/personalPromptBoost</td><td class="num">13</td><td class="num">22,802,481</td><td class="num">22,802,481</td><td class="num">22,611,147</td><td class="num">20,876,160</td><td class="num">191,334</td><td class="num">57,401</td></tr><tr><td>~/Projekte/Jobs_Selbständigkeit_Geldverdienen/AgentTestUniSupport</td><td class="num">2</td><td class="num">19,887,811</td><td class="num">19,887,811</td><td class="num">19,747,782</td><td class="num">16,509,568</td><td class="num">140,029</td><td class="num">26,289</td></tr><tr><td>~/Projekte/PromptGarage</td><td class="num">1</td><td class="num">19,452,133</td><td class="num">19,452,133</td><td class="num">19,394,544</td><td class="num">18,764,544</td><td class="num">57,589</td><td class="num">18,018</td></tr><tr><td>~/Projekte/Sonnenuhr</td><td class="num">7</td><td class="num">18,900,534</td><td class="num">18,900,534</td><td class="num">18,712,969</td><td class="num">16,705,024</td><td class="num">187,565</td><td class="num">107,257</td></tr><tr><td>~/Projekte/PseudoLogikPyhthonCPP</td><td class="num">2</td><td class="num">16,329,762</td><td class="num">16,329,762</td><td class="num">16,254,080</td><td class="num">15,190,656</td><td class="num">75,682</td><td class="num">20,994</td></tr><tr><td>~/Projekte/Jobs_Selbständigkeit_Geldverdienen/aidvance-proposal</td><td class="num">2</td><td class="num">15,236,493</td><td class="num">15,236,493</td><td class="num">15,153,630</td><td class="num">14,106,752</td><td class="num">82,863</td><td class="num">7,162</td></tr><tr><td>~/Projekte/KomandoZentral</td><td class="num">1</td><td class="num">10,463,900</td><td class="num">10,463,900</td><td class="num">10,379,137</td><td class="num">9,012,224</td><td class="num">84,763</td><td class="num">11,443</td></tr><tr><td>~/Projekte/PortfolioTimeline</td><td class="num">1</td><td class="num">10,249,632</td><td class="num">10,249,632</td><td class="num">10,174,172</td><td class="num">9,088,640</td><td class="num">75,460</td><td class="num">10,612</td></tr><tr><td>~/.claude</td><td class="num">3</td><td class="num">9,009,529</td><td class="num">9,009,529</td><td class="num">8,957,065</td><td class="num">8,283,264</td><td class="num">52,464</td><td class="num">16,602</td></tr><tr><td>~/ProjekteV2/CodexDashboard</td><td class="num">2</td><td class="num">8,661,587</td><td class="num">8,661,587</td><td class="num">8,596,572</td><td class="num">7,898,368</td><td class="num">65,015</td><td class="num">10,400</td></tr><tr><td>~/Projekte/Sidecar-V8</td><td class="num">1</td><td class="num">8,647,140</td><td class="num">8,647,140</td><td class="num">8,563,822</td><td class="num">6,135,040</td><td class="num">83,318</td><td class="num">36,118</td></tr><tr><td>~/Projekte/Amazon</td><td class="num">2</td><td class="num">8,419,747</td><td class="num">8,419,747</td><td class="num">8,378,736</td><td class="num">7,515,136</td><td class="num">41,011</td><td class="num">12,014</td></tr><tr><td>~/Projekte/AgentArena</td><td class="num">13</td><td class="num">7,849,846</td><td class="num">7,849,846</td><td class="num">7,764,724</td><td class="num">7,166,464</td><td class="num">85,122</td><td class="num">43,235</td></tr><tr><td>~/Codex</td><td class="num">3</td><td class="num">7,099,187</td><td class="num">7,099,187</td><td class="num">7,047,299</td><td class="num">6,103,680</td><td class="num">51,888</td><td class="num">14,249</td></tr><tr><td>~/Projekte/NasaCode/Autoresearch</td><td class="num">1</td><td class="num">6,896,321</td><td class="num">6,896,321</td><td class="num">6,864,934</td><td class="num">6,334,464</td><td class="num">31,387</td><td class="num">8,024</td></tr><tr><td>~/Projekte/MultiHarnessStudio</td><td class="num">6</td><td class="num">6,580,156</td><td class="num">6,580,156</td><td class="num">6,497,175</td><td class="num">4,835,584</td><td class="num">82,981</td><td class="num">24,300</td></tr><tr><td>~/Projekte/BahnAgent</td><td class="num">3</td><td class="num">5,287,171</td><td class="num">5,287,171</td><td class="num">5,247,750</td><td class="num">4,559,872</td><td class="num">39,421</td><td class="num">7,976</td></tr><tr><td>~/Projekte/MetaMetaMeta</td><td class="num">1</td><td class="num">5,180,427</td><td class="num">5,180,427</td><td class="num">5,107,914</td><td class="num">4,216,576</td><td class="num">72,513</td><td class="num">5,337</td></tr><tr><td>~/Projekte/ClaudeCodePanel</td><td class="num">21</td><td class="num">5,004,177</td><td class="num">5,004,177</td><td class="num">4,896,768</td><td class="num">4,237,568</td><td class="num">107,409</td><td class="num">70,091</td></tr><tr><td>~/ProjekteV2/CodexWebsiteSamuelClaudecode</td><td class="num">6</td><td class="num">4,856,550</td><td class="num">4,856,550</td><td class="num">4,797,674</td><td class="num">4,300,544</td><td class="num">58,876</td><td class="num">11,598</td></tr><tr><td>~/Projekte/Jobs_Selbständigkeit_Geldverdienen/AgentTestUniSupport/docs</td><td class="num">1</td><td class="num">4,068,531</td><td class="num">4,068,531</td><td class="num">4,048,457</td><td class="num">3,692,928</td><td class="num">20,074</td><td class="num">5,899</td></tr><tr><td>~/Projekte/Sidecar-ng</td><td class="num">2</td><td class="num">3,778,526</td><td class="num">3,778,526</td><td class="num">3,753,634</td><td class="num">3,067,776</td><td class="num">24,892</td><td class="num">10,022</td></tr><tr><td>~/Projekte/BahnAgent/HD-St.Anton</td><td class="num">1</td><td class="num">3,588,293</td><td class="num">3,588,293</td><td class="num">3,566,427</td><td class="num">3,453,056</td><td class="num">21,866</td><td class="num">9,190</td></tr><tr><td>~/Projekte/Sidecar-ng-dashboard</td><td class="num">1</td><td class="num">3,565,535</td><td class="num">3,565,535</td><td class="num">3,533,244</td><td class="num">3,355,264</td><td class="num">32,291</td><td class="num">4,937</td></tr><tr><td>~/.hermes</td><td class="num">2</td><td class="num">3,317,062</td><td class="num">3,317,062</td><td class="num">3,305,352</td><td class="num">2,819,456</td><td class="num">11,710</td><td class="num">2,378</td></tr><tr><td>~/Projekte/schloss_PDF</td><td class="num">1</td><td class="num">3,245,804</td><td class="num">3,245,804</td><td class="num">3,229,768</td><td class="num">3,069,824</td><td class="num">16,036</td><td class="num">4,866</td></tr><tr><td>~/ClaudesReich</td><td class="num">3</td><td class="num">2,206,746</td><td class="num">2,206,746</td><td class="num">2,139,356</td><td class="num">1,719,296</td><td class="num">67,390</td><td class="num">51,059</td></tr><tr><td>~/Dokumente/durchstarten</td><td class="num">1</td><td class="num">2,177,869</td><td class="num">2,177,869</td><td class="num">2,165,792</td><td class="num">1,844,224</td><td class="num">12,077</td><td class="num">3,264</td></tr><tr><td>~/Projekte/Sidecar-V7-V2</td><td class="num">1</td><td class="num">1,906,923</td><td class="num">1,906,923</td><td class="num">1,893,090</td><td class="num">1,818,624</td><td class="num">13,833</td><td class="num">9,278</td></tr><tr><td>~/abgabe</td><td class="num">3</td><td class="num">1,904,474</td><td class="num">1,904,474</td><td class="num">1,885,225</td><td class="num">1,680,128</td><td class="num">19,249</td><td class="num">9,211</td></tr><tr><td>~/Projekte/Codex_Usage_Profil</td><td class="num">1</td><td class="num">1,863,742</td><td class="num">1,863,742</td><td class="num">1,839,771</td><td class="num">1,688,192</td><td class="num">23,971</td><td class="num">6,446</td></tr><tr><td>~/Projekte/AgentIDE</td><td class="num">3</td><td class="num">1,595,515</td><td class="num">1,595,515</td><td class="num">1,563,469</td><td class="num">1,397,760</td><td class="num">32,046</td><td class="num">22,910</td></tr><tr><td>~/Projekte/Jobs_Selbständigkeit_Geldverdienen</td><td class="num">1</td><td class="num">1,482,737</td><td class="num">1,482,737</td><td class="num">1,459,527</td><td class="num">1,327,488</td><td class="num">23,210</td><td class="num">3,945</td></tr><tr><td>~/.claude/usage</td><td class="num">1</td><td class="num">1,205,428</td><td class="num">1,205,428</td><td class="num">1,179,696</td><td class="num">1,085,696</td><td class="num">25,732</td><td class="num">8,416</td></tr><tr><td>~/DataEngeeneeringKEEPA/KeepaProjectsforDataEngeneering3BranchesMerge</td><td class="num">6</td><td class="num">1,152,226</td><td class="num">1,152,226</td><td class="num">1,129,759</td><td class="num">927,360</td><td class="num">22,467</td><td class="num">11,740</td></tr><tr><td>~/Projekte/ACPcodex</td><td class="num">1</td><td class="num">1,059,170</td><td class="num">1,059,170</td><td class="num">1,043,792</td><td class="num">910,848</td><td class="num">15,378</td><td class="num">8,018</td></tr><tr><td>~/Projekte/NasaCode</td><td class="num">1</td><td class="num">985,209</td><td class="num">985,209</td><td class="num">970,106</td><td class="num">897,408</td><td class="num">15,103</td><td class="num">1,784</td></tr><tr><td>~/Projekte/Kaggle5dayAgent</td><td class="num">2</td><td class="num">913,047</td><td class="num">913,047</td><td class="num">897,573</td><td class="num">686,592</td><td class="num">15,474</td><td class="num">5,673</td></tr><tr><td>~/ProjekteV2/CodexEval2</td><td class="num">1</td><td class="num">729,208</td><td class="num">729,208</td><td class="num">704,329</td><td class="num">647,680</td><td class="num">24,879</td><td class="num">4,246</td></tr><tr><td>~/Meta</td><td class="num">1</td><td class="num">718,880</td><td class="num">718,880</td><td class="num">707,059</td><td class="num">528,512</td><td class="num">11,821</td><td class="num">4,379</td></tr><tr><td>~/Projekte/HarnessEcosystem</td><td class="num">1</td><td class="num">600,507</td><td class="num">600,507</td><td class="num">592,621</td><td class="num">502,656</td><td class="num">7,886</td><td class="num">1,399</td></tr><tr><td>~/Projekte/StudyAgent</td><td class="num">1</td><td class="num">511,185</td><td class="num">511,185</td><td class="num">501,306</td><td class="num">464,768</td><td class="num">9,879</td><td class="num">7,380</td></tr><tr><td>~/Projekte/ShortcutCounter</td><td class="num">1</td><td class="num">441,229</td><td class="num">441,229</td><td class="num">435,073</td><td class="num">398,976</td><td class="num">6,156</td><td class="num">3,416</td></tr><tr><td>~/Projekte/TypoTuner</td><td class="num">3</td><td class="num">430,804</td><td class="num">430,804</td><td class="num">412,494</td><td class="num">324,992</td><td class="num">18,310</td><td class="num">13,352</td></tr><tr><td>~/Projekte/SandrasWritingWorld</td><td class="num">3</td><td class="num">347,623</td><td class="num">347,623</td><td class="num">340,146</td><td class="num">290,560</td><td class="num">7,477</td><td class="num">4,607</td></tr><tr><td>~/CodexReich</td><td class="num">2</td><td class="num">282,250</td><td class="num">282,250</td><td class="num">271,237</td><td class="num">254,208</td><td class="num">11,013</td><td class="num">8,192</td></tr><tr><td>~/Projekte/Sidecar</td><td class="num">1</td><td class="num">251,167</td><td class="num">251,167</td><td class="num">245,022</td><td class="num">213,504</td><td class="num">6,145</td><td class="num">4,675</td></tr><tr><td>~/Projekte/PromptEngeneering</td><td class="num">2</td><td class="num">207,700</td><td class="num">207,700</td><td class="num">203,831</td><td class="num">132,096</td><td class="num">3,869</td><td class="num">1,279</td></tr><tr><td>~/ClaudesReich/SessionBrowser</td><td class="num">2</td><td class="num">203,849</td><td class="num">203,849</td><td class="num">196,188</td><td class="num">170,880</td><td class="num">7,661</td><td class="num">5,165</td></tr><tr><td>~/Projekte/Sidecar-V7-Lite</td><td class="num">1</td><td class="num">197,279</td><td class="num">197,279</td><td class="num">190,627</td><td class="num">177,792</td><td class="num">6,652</td><td class="num">4,599</td></tr><tr><td>~/Projekte/FireTracker</td><td class="num">2</td><td class="num">191,892</td><td class="num">191,892</td><td class="num">184,419</td><td class="num">153,344</td><td class="num">7,473</td><td class="num">5,715</td></tr><tr><td>~/Bilder/Anzug/Logo</td><td class="num">1</td><td class="num">141,042</td><td class="num">141,042</td><td class="num">138,537</td><td class="num">102,016</td><td class="num">2,505</td><td class="num">1,280</td></tr><tr><td>~/DataEngeeneeringKEEPA/VomProfPDF</td><td class="num">1</td><td class="num">135,655</td><td class="num">135,655</td><td class="num">131,074</td><td class="num">119,168</td><td class="num">4,581</td><td class="num">2,463</td></tr><tr><td>~/Orderformyaistuff</td><td class="num">1</td><td class="num">132,215</td><td class="num">132,215</td><td class="num">131,214</td><td class="num">112,128</td><td class="num">1,001</td><td class="num">64</td></tr><tr><td>~/OrdnungvonGedanken/git</td><td class="num">1</td><td class="num">113,347</td><td class="num">113,347</td><td class="num">108,699</td><td class="num">96,384</td><td class="num">4,648</td><td class="num">1,633</td></tr><tr><td>~/ClaudesReich/Visualisierung</td><td class="num">3</td><td class="num">86,970</td><td class="num">86,970</td><td class="num">85,224</td><td class="num">67,584</td><td class="num">1,746</td><td class="num">493</td></tr><tr><td>~/Projekte/MyAIGame</td><td class="num">2</td><td class="num">72,823</td><td class="num">72,823</td><td class="num">62,967</td><td class="num">51,328</td><td class="num">9,856</td><td class="num">6,964</td></tr><tr><td>/tmp/MyAIGame</td><td class="num">1</td><td class="num">11,035</td><td class="num">11,035</td><td class="num">7,924</td><td class="num">6,784</td><td class="num">3,111</td><td class="num">2,367</td></tr><tr><td>~/SetUP</td><td class="num">1</td><td class="num">0</td><td class="num">0</td><td class="num">0</td><td class="num">0</td><td class="num">0</td><td class="num">0</td></tr><tr><td>~/Projekte/HarnessEcosystem/sidebyside</td><td class="num">1</td><td class="num">0</td><td class="num">0</td><td class="num">0</td><td class="num">0</td><td class="num">0</td><td class="num">0</td></tr></tbody></table></div></section>
141
+ <section><h2>Tokens By Model</h2><div class="table-wrap"><table><thead><tr><th>Label</th><th>Sessions</th><th>Tokens</th><th>Rollout total</th><th>Input</th><th>Cached input</th><th>Output</th><th>Reasoning</th></tr></thead><tbody><tr><td>gpt-5.4</td><td class="num">190</td><td class="num">1,002,621,471</td><td class="num">1,002,621,471</td><td class="num">997,085,786</td><td class="num">895,809,024</td><td class="num">5,535,685</td><td class="num">1,652,172</td></tr><tr><td>gpt-5.4-mini</td><td class="num">64</td><td class="num">94,242,789</td><td class="num">94,242,789</td><td class="num">93,515,945</td><td class="num">87,385,344</td><td class="num">726,844</td><td class="num">349,506</td></tr><tr><td>gpt-5.1-codex-max</td><td class="num">14</td><td class="num">86,258,755</td><td class="num">86,258,755</td><td class="num">85,848,562</td><td class="num">72,738,816</td><td class="num">410,193</td><td class="num">157,571</td></tr><tr><td>gpt-5.3-codex</td><td class="num">97</td><td class="num">63,196,733</td><td class="num">63,196,733</td><td class="num">62,443,450</td><td class="num">56,599,040</td><td class="num">753,283</td><td class="num">432,430</td></tr><tr><td>gpt-5.1-codex-mini</td><td class="num">2</td><td class="num">4,583,943</td><td class="num">4,583,943</td><td class="num">4,546,444</td><td class="num">4,075,904</td><td class="num">37,499</td><td class="num">7,045</td></tr><tr><td>gpt-5.2-codex</td><td class="num">5</td><td class="num">4,307,009</td><td class="num">4,307,009</td><td class="num">4,222,922</td><td class="num">3,537,664</td><td class="num">84,087</td><td class="num">58,816</td></tr><tr><td>unknown</td><td class="num">3</td><td class="num">0</td><td class="num">0</td><td class="num">0</td><td class="num">0</td><td class="num">0</td><td class="num">0</td></tr></tbody></table></div></section>
142
+ <section><h2>Tokens By Role</h2><div class="table-wrap"><table><thead><tr><th>Label</th><th>Sessions</th><th>Tokens</th><th>Rollout total</th><th>Input</th><th>Cached input</th><th>Output</th><th>Reasoning</th></tr></thead><tbody><tr><td>main</td><td class="num">240</td><td class="num">1,162,370,493</td><td class="num">1,162,370,493</td><td class="num">1,155,950,486</td><td class="num">1,039,647,488</td><td class="num">6,420,007</td><td class="num">2,223,740</td></tr><tr><td>unknown</td><td class="num">17</td><td class="num">31,239,166</td><td class="num">31,239,166</td><td class="num">30,924,883</td><td class="num">27,394,176</td><td class="num">314,283</td><td class="num">116,098</td></tr><tr><td>worker</td><td class="num">18</td><td class="num">30,777,412</td><td class="num">30,777,412</td><td class="num">30,458,569</td><td class="num">28,003,584</td><td class="num">318,843</td><td class="num">108,953</td></tr><tr><td>explorer</td><td class="num">94</td><td class="num">30,734,460</td><td class="num">30,734,460</td><td class="num">30,240,125</td><td class="num">25,049,600</td><td class="num">494,335</td><td class="num">208,680</td></tr><tr><td>default</td><td class="num">6</td><td class="num">89,169</td><td class="num">89,169</td><td class="num">89,046</td><td class="num">50,944</td><td class="num">123</td><td class="num">69</td></tr></tbody></table></div></section>
143
+ <section><h2>Main Vs Subagent</h2><div class="table-wrap"><table><thead><tr><th>Label</th><th>Sessions</th><th>Tokens</th><th>Rollout total</th><th>Input</th><th>Cached input</th><th>Output</th><th>Reasoning</th></tr></thead><tbody><tr><td>main</td><td class="num">250</td><td class="num">1,170,627,399</td><td class="num">1,170,627,399</td><td class="num">1,164,127,535</td><td class="num">1,046,924,928</td><td class="num">6,499,864</td><td class="num">2,236,967</td></tr><tr><td>subagent</td><td class="num">125</td><td class="num">84,583,301</td><td class="num">84,583,301</td><td class="num">83,535,574</td><td class="num">73,220,864</td><td class="num">1,047,727</td><td class="num">420,573</td></tr></tbody></table></div></section>
144
+ <section><h2>Top Sessions</h2><div class="table-wrap"><table><thead><tr><th>Created</th><th>Tokens</th><th>Kind</th><th>Model</th><th>Role</th><th>Cwd</th><th>Session</th><th>Rollout</th></tr></thead><tbody><tr><td>2026-04-16 13:01</td><td class="num">47,959,797</td><td>main</td><td>gpt-5.4-mini</td><td>main</td><td>~/Projekte/FirstRealHarnessEvaluation_KarpathiesMD</td><td>019d95f4-0198-7e10-9c95-ecd79e771e27</td><td>/home/smlflg/.codex/sessions/2026/04/16/rollout-2026-04-16T13-01-29-019d95f4-0198-7e10-9c95-ecd79e771e27.jsonl</td></tr><tr><td>2026-04-04 16:27</td><td class="num">45,688,987</td><td>main</td><td>gpt-5.4</td><td>main</td><td>~/clawd</td><td>019d58e4-046a-7c10-a832-f8c706647456</td><td>/home/smlflg/.codex/sessions/2026/04/04/rollout-2026-04-04T16-27-11-019d58e4-046a-7c10-a832-f8c706647456.jsonl</td></tr><tr><td>2026-04-13 07:09</td><td class="num">43,897,402</td><td>main</td><td>gpt-5.4</td><td>main</td><td>~/Projekte/HeumandenParty</td><td>019d853e-b868-7053-bb8c-630df03c6eea</td><td>/home/smlflg/.codex/sessions/2026/04/13/rollout-2026-04-13T07-09-33-019d853e-b868-7053-bb8c-630df03c6eea.jsonl</td></tr><tr><td>2026-03-13 12:03</td><td class="num">42,283,906</td><td>main</td><td>gpt-5.4</td><td>main</td><td>~/Projekte/Sidecar-V7</td><td>019ce6dd-5a1c-7fe3-a300-b98983ae4bb8</td><td>/home/smlflg/.codex/sessions/2026/03/13/rollout-2026-03-13T12-03-12-019ce6dd-5a1c-7fe3-a300-b98983ae4bb8.jsonl</td></tr><tr><td>2026-02-05 12:11</td><td class="num">40,984,928</td><td>main</td><td>gpt-5.1-codex-max</td><td>main</td><td>~/Dokumente/Pläne</td><td>019c2d80-2f19-7521-9c87-4d6be1ffc9f1</td><td>/home/smlflg/.codex/sessions/2026/02/05/rollout-2026-02-05T12-11-41-019c2d80-2f19-7521-9c87-4d6be1ffc9f1.jsonl</td></tr><tr><td>2026-03-12 00:59</td><td class="num">34,165,684</td><td>main</td><td>gpt-5.4</td><td>main</td><td>~</td><td>019cdf57-c2c6-7a92-9096-6dac18fc5177</td><td>/home/smlflg/.codex/sessions/2026/03/12/rollout-2026-03-12T00-59-56-019cdf57-c2c6-7a92-9096-6dac18fc5177.jsonl</td></tr><tr><td>2026-02-18 17:07</td><td class="num">32,848,911</td><td>main</td><td>gpt-5.3-codex</td><td>main</td><td>~/DataEngeeneeringKEEPA</td><td>019c7181-a37e-7ae2-8870-c4c16655ec52</td><td>/home/smlflg/.codex/sessions/2026/02/18/rollout-2026-02-18T17-07-27-019c7181-a37e-7ae2-8870-c4c16655ec52.jsonl</td></tr><tr><td>2026-04-21 23:03</td><td class="num">32,619,865</td><td>main</td><td>gpt-5.4</td><td>main</td><td>~/Projekte/HeumandenParty</td><td>019db1db-150f-7662-b607-30871c33af75</td><td>/home/smlflg/.codex/sessions/2026/04/21/rollout-2026-04-21T23-03-38-019db1db-150f-7662-b607-30871c33af75.jsonl</td></tr><tr><td>2026-04-05 18:49</td><td class="num">29,145,038</td><td>main</td><td>gpt-5.4</td><td>main</td><td>~/Projekte/UEBER_AGENT</td><td>019d5e8c-39f3-7db1-a48b-d4eb2b50298e</td><td>/home/smlflg/.codex/sessions/2026/04/05/rollout-2026-04-05T18-49-01-019d5e8c-39f3-7db1-a48b-d4eb2b50298e.jsonl</td></tr><tr><td>2026-04-06 12:58</td><td class="num">25,127,211</td><td>main</td><td>gpt-5.4</td><td>main</td><td>~/Projekte/UEBER_AGENT</td><td>019d6271-60b8-7621-a2c4-7a66afca9f80</td><td>/home/smlflg/.codex/sessions/2026/04/06/rollout-2026-04-06T12-58-10-019d6271-60b8-7621-a2c4-7a66afca9f80.jsonl</td></tr><tr><td>2026-02-07 19:08</td><td class="num">22,356,063</td><td>main</td><td>gpt-5.1-codex-max</td><td>main</td><td>~/Dokumente/Pläne</td><td>019c394a-8761-7823-8f7e-7457d21d79af</td><td>/home/smlflg/.codex/sessions/2026/02/07/rollout-2026-02-07T19-08-31-019c394a-8761-7823-8f7e-7457d21d79af.jsonl</td></tr><tr><td>2026-04-08 10:23</td><td class="num">22,123,631</td><td>main</td><td>gpt-5.4</td><td>main</td><td>~/Projekte/HeumandenParty</td><td>019d6c30-e1c5-7441-9ed6-afc8f2bc9861</td><td>/home/smlflg/.codex/sessions/2026/04/08/rollout-2026-04-08T10-23-56-019d6c30-e1c5-7441-9ed6-afc8f2bc9861.jsonl</td></tr><tr><td>2026-04-21 23:28</td><td class="num">21,430,259</td><td>main</td><td>gpt-5.4</td><td>main</td><td>~/Projekte/HeumandenParty</td><td>019db1f1-e994-75c0-94d8-6edc93203dd7</td><td>/home/smlflg/.codex/sessions/2026/04/21/rollout-2026-04-21T23-28-34-019db1f1-e994-75c0-94d8-6edc93203dd7.jsonl</td></tr><tr><td>2026-04-21 15:43</td><td class="num">21,410,253</td><td>main</td><td>gpt-5.4</td><td>main</td><td>~</td><td>019db048-0123-7242-89b9-d6083591212b</td><td>/home/smlflg/.codex/sessions/2026/04/21/rollout-2026-04-21T15-43-22-019db048-0123-7242-89b9-d6083591212b.jsonl</td></tr><tr><td>2026-04-21 15:31</td><td class="num">21,194,654</td><td>main</td><td>gpt-5.4</td><td>main</td><td>~/Projekte/PromptBoost</td><td>019db03d-1f96-7592-8fef-1f10125ebe0c</td><td>/home/smlflg/.codex/sessions/2026/04/21/rollout-2026-04-21T15-31-29-019db03d-1f96-7592-8fef-1f10125ebe0c.jsonl</td></tr><tr><td>2026-03-12 15:10</td><td class="num">21,018,788</td><td>main</td><td>gpt-5.4</td><td>main</td><td>~/Projekte/Sidecar-V7</td><td>019ce262-7359-7ae2-b3c1-e1c5d1a63e66</td><td>/home/smlflg/.codex/sessions/2026/03/12/rollout-2026-03-12T15-10-28-019ce262-7359-7ae2-b3c1-e1c5d1a63e66.jsonl</td></tr><tr><td>2026-04-21 15:27</td><td class="num">20,456,527</td><td>main</td><td>gpt-5.4</td><td>main</td><td>~/Projekte/PromptBoost</td><td>019db039-1b8f-7370-bab6-9e25fd16e912</td><td>/home/smlflg/.codex/sessions/2026/04/21/rollout-2026-04-21T15-27-05-019db039-1b8f-7370-bab6-9e25fd16e912.jsonl</td></tr><tr><td>2026-04-12 15:58</td><td class="num">20,372,968</td><td>main</td><td>gpt-5.4</td><td>main</td><td>~/Projekte/Zentrale</td><td>019d81fc-7347-7523-b30f-4d3ddce562e1</td><td>/home/smlflg/.codex/sessions/2026/04/12/rollout-2026-04-12T15-58-18-019d81fc-7347-7523-b30f-4d3ddce562e1.jsonl</td></tr><tr><td>2026-03-12 15:14</td><td class="num">19,745,610</td><td>main</td><td>gpt-5.4</td><td>main</td><td>~/Projekte/Sidecar-V7</td><td>019ce266-3a71-79e2-ada1-226867a34de3</td><td>/home/smlflg/.codex/sessions/2026/03/12/rollout-2026-03-12T15-14-36-019ce266-3a71-79e2-ada1-226867a34de3.jsonl</td></tr><tr><td>2026-04-21 14:53</td><td class="num">19,452,133</td><td>main</td><td>gpt-5.4</td><td>main</td><td>~/Projekte/PromptGarage</td><td>019db01a-8e1c-7560-b78f-63857f297f47</td><td>/home/smlflg/.codex/sessions/2026/04/21/rollout-2026-04-21T14-53-43-019db01a-8e1c-7560-b78f-63857f297f47.jsonl</td></tr></tbody></table></div></section>
145
+ <section><h2>Data Warnings</h2><ul><li><code>Malformed JSONL lines in /home/smlflg/.codex/sessions/2026/04/21/rollout-2026-04-21T18-15-04-019db0d2-e62b-78b3-b8f3-e0c70af3aa6c.jsonl: 1</code></li></ul></section>
146
+ </main>
147
+ </body>
148
+ </html>
reports/codex-usage.md ADDED
@@ -0,0 +1,234 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Codex Usage Report
2
+
3
+ Generated: 2026-04-22T00:48:49+02:00
4
+ Timezone: `Europe/Berlin`
5
+ State DB: `/home/smlflg/.codex/state_5.sqlite`
6
+ Sessions dir: `/home/smlflg/.codex/sessions`
7
+ Date range: 2026-02-03 to 2026-04-22
8
+
9
+ ## Summary
10
+
11
+ | Metric | Value |
12
+ | --- | --- |
13
+ | Sessions | 375 |
14
+ | Total tokens | 1,255,210,700 |
15
+ | Rollouts with token breakdown | 359 |
16
+ | Missing rollouts | 0 |
17
+ | Warnings | 1 |
18
+
19
+ ## Rollout Token Breakdown
20
+
21
+ | Input | Cached input | Output | Reasoning output | Rollout total |
22
+ | --- | --- | --- | --- | --- |
23
+ | 1,247,663,109 | 1,120,145,792 | 7,547,591 | 2,657,540 | 1,255,210,700 |
24
+
25
+ ## Daily Tokens
26
+
27
+ | Label | Sessions | Tokens | Rollout total | Input | Cached input | Output | Reasoning |
28
+ | --- | --- | --- | --- | --- | --- | --- | --- |
29
+ | 2026-02-03 | 4 | 2,592,334 | 2,592,334 | 2,568,243 | 2,210,560 | 24,091 | 11,520 |
30
+ | 2026-02-04 | 1 | 1,714,675 | 1,714,675 | 1,654,679 | 1,327,104 | 59,996 | 47,296 |
31
+ | 2026-02-05 | 3 | 41,998,810 | 41,998,810 | 41,824,072 | 36,333,696 | 174,738 | 62,720 |
32
+ | 2026-02-06 | 2 | 3,102,257 | 3,102,257 | 3,087,487 | 2,501,760 | 14,770 | 5,248 |
33
+ | 2026-02-07 | 3 | 28,416,733 | 28,416,733 | 28,275,656 | 24,109,568 | 141,077 | 51,584 |
34
+ | 2026-02-08 | 1 | 1,722,562 | 1,722,562 | 1,705,968 | 1,052,672 | 16,594 | 9,536 |
35
+ | 2026-02-09 | 3 | 8,276,308 | 8,276,308 | 8,233,458 | 6,579,200 | 42,850 | 18,560 |
36
+ | 2026-02-10 | 2 | 110,210 | 110,210 | 106,170 | 77,184 | 4,040 | 2,688 |
37
+ | 2026-02-14 | 1 | 18,724 | 18,724 | 17,236 | 13,824 | 1,488 | 960 |
38
+ | 2026-02-18 | 6 | 38,042,984 | 38,042,984 | 37,824,219 | 34,982,272 | 218,765 | 96,508 |
39
+ | 2026-02-19 | 3 | 2,374,671 | 2,374,671 | 2,336,358 | 2,010,240 | 38,313 | 21,859 |
40
+ | 2026-02-20 | 1 | 815,392 | 815,392 | 793,001 | 672,512 | 22,391 | 14,469 |
41
+ | 2026-02-22 | 1 | 86,970 | 86,970 | 85,224 | 67,584 | 1,746 | 493 |
42
+ | 2026-02-23 | 3 | 1,503,367 | 1,503,367 | 1,490,803 | 1,300,480 | 12,564 | 5,869 |
43
+ | 2026-02-24 | 4 | 915,167 | 915,167 | 894,983 | 785,280 | 20,184 | 11,311 |
44
+ | 2026-02-25 | 6 | 1,153,635 | 1,153,635 | 1,129,519 | 927,360 | 24,116 | 13,381 |
45
+ | 2026-02-26 | 4 | 4,842,727 | 4,842,727 | 4,769,518 | 4,068,224 | 73,209 | 29,303 |
46
+ | 2026-02-28 | 2 | 203,849 | 203,849 | 196,188 | 170,880 | 7,661 | 5,165 |
47
+ | 2026-03-01 | 1 | 144,226 | 144,226 | 139,396 | 81,280 | 4,830 | 3,606 |
48
+ | 2026-03-02 | 11 | 1,628,800 | 1,628,800 | 1,593,771 | 1,470,208 | 35,029 | 18,398 |
49
+ | 2026-03-03 | 4 | 1,176,373 | 1,176,373 | 1,157,419 | 1,009,024 | 18,954 | 10,514 |
50
+ | 2026-03-05 | 4 | 1,751,326 | 1,751,326 | 1,725,852 | 1,489,152 | 25,474 | 15,895 |
51
+ | 2026-03-06 | 14 | 3,427,861 | 3,427,861 | 3,348,617 | 2,956,288 | 79,244 | 56,569 |
52
+ | 2026-03-10 | 9 | 2,482,191 | 2,482,191 | 2,423,969 | 2,024,448 | 58,222 | 43,369 |
53
+ | 2026-03-11 | 5 | 707,822 | 707,822 | 681,540 | 562,944 | 26,282 | 18,943 |
54
+ | 2026-03-12 | 18 | 103,444,689 | 103,444,689 | 102,734,723 | 89,554,560 | 709,966 | 340,105 |
55
+ | 2026-03-13 | 7 | 68,599,649 | 68,599,649 | 68,188,511 | 55,110,528 | 411,138 | 185,043 |
56
+ | 2026-03-15 | 6 | 972,313 | 972,313 | 952,374 | 838,912 | 19,939 | 13,994 |
57
+ | 2026-03-16 | 8 | 5,367,296 | 5,367,296 | 5,288,510 | 4,711,680 | 78,786 | 38,822 |
58
+ | 2026-03-17 | 1 | 3,009,062 | 3,009,062 | 2,988,236 | 2,400,000 | 20,826 | 9,320 |
59
+ | 2026-03-19 | 6 | 5,953,315 | 5,953,315 | 5,903,652 | 5,102,208 | 49,663 | 7,583 |
60
+ | 2026-03-20 | 9 | 14,247,345 | 14,247,345 | 14,098,575 | 12,846,592 | 148,770 | 26,244 |
61
+ | 2026-03-22 | 1 | 3,317,062 | 3,317,062 | 3,305,352 | 2,819,456 | 11,710 | 2,378 |
62
+ | 2026-03-24 | 6 | 21,773,327 | 21,773,327 | 21,545,181 | 18,719,872 | 228,146 | 28,934 |
63
+ | 2026-03-25 | 2 | 15,794,732 | 15,794,732 | 15,689,027 | 14,278,272 | 105,705 | 14,028 |
64
+ | 2026-03-26 | 4 | 17,475,352 | 17,475,352 | 17,365,616 | 16,159,360 | 109,736 | 11,644 |
65
+ | 2026-03-27 | 1 | 98,877 | 98,877 | 97,169 | 71,552 | 1,708 | 604 |
66
+ | 2026-03-28 | 3 | 7,712,399 | 7,712,399 | 7,664,563 | 7,005,440 | 47,836 | 13,515 |
67
+ | 2026-03-31 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
68
+ | 2026-04-01 | 3 | 25,508,023 | 25,508,023 | 25,350,746 | 20,315,904 | 157,277 | 37,958 |
69
+ | 2026-04-02 | 4 | 17,199,934 | 17,199,934 | 17,062,790 | 14,398,848 | 137,144 | 35,101 |
70
+ | 2026-04-04 | 3 | 46,566,280 | 46,566,280 | 46,287,856 | 41,528,704 | 278,424 | 75,164 |
71
+ | 2026-04-05 | 6 | 39,855,513 | 39,855,513 | 39,651,697 | 33,805,568 | 203,816 | 50,687 |
72
+ | 2026-04-06 | 9 | 65,364,640 | 65,364,640 | 64,956,269 | 56,659,584 | 408,371 | 98,417 |
73
+ | 2026-04-08 | 7 | 28,703,787 | 28,703,787 | 28,511,836 | 23,291,904 | 191,951 | 61,081 |
74
+ | 2026-04-10 | 2 | 6,955,652 | 6,955,652 | 6,911,550 | 5,532,928 | 44,102 | 11,076 |
75
+ | 2026-04-11 | 7 | 40,151,055 | 40,151,055 | 40,010,387 | 37,590,016 | 140,668 | 44,009 |
76
+ | 2026-04-12 | 24 | 119,779,328 | 119,779,328 | 119,335,097 | 114,489,472 | 444,231 | 126,296 |
77
+ | 2026-04-13 | 2 | 44,278,404 | 44,278,404 | 44,178,204 | 41,139,200 | 100,200 | 16,762 |
78
+ | 2026-04-14 | 4 | 8,627,447 | 8,627,447 | 8,582,567 | 7,647,232 | 44,880 | 13,293 |
79
+ | 2026-04-16 | 3 | 59,357,456 | 59,357,456 | 59,092,558 | 56,559,360 | 264,898 | 125,030 |
80
+ | 2026-04-20 | 1 | 13,711,641 | 13,711,641 | 13,653,855 | 13,032,832 | 57,786 | 12,196 |
81
+ | 2026-04-21 | 115 | 300,116,344 | 300,116,344 | 298,325,385 | 276,096,768 | 1,790,959 | 610,982 |
82
+ | 2026-04-22 | 14 | 22,059,804 | 22,059,804 | 21,867,477 | 19,655,296 | 192,327 | 71,510 |
83
+
84
+ ## Weekly Tokens
85
+
86
+ | Label | Sessions | Tokens | Rollout total | Input | Cached input | Output | Reasoning |
87
+ | --- | --- | --- | --- | --- | --- | --- | --- |
88
+ | 2026-W06 | 14 | 79,547,371 | 79,547,371 | 79,116,105 | 67,535,360 | 431,266 | 187,904 |
89
+ | 2026-W07 | 6 | 8,405,242 | 8,405,242 | 8,356,864 | 6,670,208 | 48,378 | 22,208 |
90
+ | 2026-W08 | 11 | 41,320,017 | 41,320,017 | 41,038,802 | 37,732,608 | 281,215 | 133,329 |
91
+ | 2026-W09 | 20 | 8,762,971 | 8,762,971 | 8,620,407 | 7,333,504 | 142,564 | 68,635 |
92
+ | 2026-W10 | 33 | 7,984,360 | 7,984,360 | 7,825,659 | 6,924,672 | 158,701 | 101,376 |
93
+ | 2026-W11 | 45 | 176,206,664 | 176,206,664 | 174,981,117 | 148,091,392 | 1,225,547 | 601,454 |
94
+ | 2026-W12 | 25 | 31,894,080 | 31,894,080 | 31,584,325 | 27,879,936 | 309,755 | 84,347 |
95
+ | 2026-W13 | 16 | 62,854,687 | 62,854,687 | 62,361,556 | 56,234,496 | 493,131 | 68,725 |
96
+ | 2026-W14 | 17 | 129,129,750 | 129,129,750 | 128,353,089 | 110,049,024 | 776,661 | 198,910 |
97
+ | 2026-W15 | 49 | 260,954,462 | 260,954,462 | 259,725,139 | 237,563,904 | 1,229,323 | 340,879 |
98
+ | 2026-W16 | 9 | 112,263,307 | 112,263,307 | 111,853,329 | 105,345,792 | 409,978 | 155,085 |
99
+ | 2026-W17 | 130 | 335,887,789 | 335,887,789 | 333,846,717 | 308,784,896 | 2,041,072 | 694,688 |
100
+
101
+ ## Tokens By Cwd
102
+
103
+ | Label | Sessions | Tokens | Rollout total | Input | Cached input | Output | Reasoning |
104
+ | --- | --- | --- | --- | --- | --- | --- | --- |
105
+ | ~/Projekte/HeumandenParty | 25 | 147,920,810 | 147,920,810 | 147,263,059 | 135,344,768 | 657,751 | 224,690 |
106
+ | ~ | 65 | 143,305,952 | 143,305,952 | 142,271,611 | 118,259,584 | 1,034,341 | 411,954 |
107
+ | ~/Projekte/UEBER_AGENT | 14 | 95,265,645 | 95,265,645 | 94,690,320 | 82,054,784 | 575,325 | 136,176 |
108
+ | ~/Projekte/PromptBoost | 40 | 91,369,695 | 91,369,695 | 90,715,571 | 84,423,552 | 654,124 | 254,702 |
109
+ | ~/Projekte/Zentrale | 19 | 86,591,689 | 86,591,689 | 86,233,084 | 82,599,424 | 358,605 | 98,470 |
110
+ | ~/Projekte/Sidecar-V7 | 9 | 84,675,641 | 84,675,641 | 84,245,938 | 74,833,280 | 429,703 | 197,775 |
111
+ | ~/Projekte | 28 | 83,595,490 | 83,595,490 | 83,172,046 | 74,665,344 | 423,444 | 112,523 |
112
+ | ~/Dokumente/Pläne | 4 | 66,513,874 | 66,513,874 | 66,247,523 | 57,384,832 | 266,351 | 83,776 |
113
+ | ~/Projekte/FirstRealHarnessEvaluation_KarpathiesMD | 2 | 59,357,456 | 59,357,456 | 59,092,558 | 56,559,360 | 264,898 | 125,030 |
114
+ | ~/clawd | 4 | 49,462,644 | 49,462,644 | 49,155,998 | 43,810,432 | 306,646 | 91,996 |
115
+ | ~/DataEngeeneeringKEEPA | 6 | 46,940,456 | 46,940,456 | 46,696,473 | 41,869,440 | 243,983 | 105,385 |
116
+ | ~/SetUP/Monitor_my_Monitors | 3 | 37,573,267 | 37,573,267 | 37,477,005 | 36,243,584 | 96,262 | 33,239 |
117
+ | ~/Projekte/PromptBoost/personalPromptBoost | 13 | 22,802,481 | 22,802,481 | 22,611,147 | 20,876,160 | 191,334 | 57,401 |
118
+ | ~/Projekte/Jobs_Selbständigkeit_Geldverdienen/AgentTestUniSupport | 2 | 19,887,811 | 19,887,811 | 19,747,782 | 16,509,568 | 140,029 | 26,289 |
119
+ | ~/Projekte/PromptGarage | 1 | 19,452,133 | 19,452,133 | 19,394,544 | 18,764,544 | 57,589 | 18,018 |
120
+ | ~/Projekte/Sonnenuhr | 7 | 18,900,534 | 18,900,534 | 18,712,969 | 16,705,024 | 187,565 | 107,257 |
121
+ | ~/Projekte/PseudoLogikPyhthonCPP | 2 | 16,329,762 | 16,329,762 | 16,254,080 | 15,190,656 | 75,682 | 20,994 |
122
+ | ~/Projekte/Jobs_Selbständigkeit_Geldverdienen/aidvance-proposal | 2 | 15,236,493 | 15,236,493 | 15,153,630 | 14,106,752 | 82,863 | 7,162 |
123
+ | ~/Projekte/KomandoZentral | 1 | 10,463,900 | 10,463,900 | 10,379,137 | 9,012,224 | 84,763 | 11,443 |
124
+ | ~/Projekte/PortfolioTimeline | 1 | 10,249,632 | 10,249,632 | 10,174,172 | 9,088,640 | 75,460 | 10,612 |
125
+ | ~/.claude | 3 | 9,009,529 | 9,009,529 | 8,957,065 | 8,283,264 | 52,464 | 16,602 |
126
+ | ~/ProjekteV2/CodexDashboard | 2 | 8,661,587 | 8,661,587 | 8,596,572 | 7,898,368 | 65,015 | 10,400 |
127
+ | ~/Projekte/Sidecar-V8 | 1 | 8,647,140 | 8,647,140 | 8,563,822 | 6,135,040 | 83,318 | 36,118 |
128
+ | ~/Projekte/Amazon | 2 | 8,419,747 | 8,419,747 | 8,378,736 | 7,515,136 | 41,011 | 12,014 |
129
+ | ~/Projekte/AgentArena | 13 | 7,849,846 | 7,849,846 | 7,764,724 | 7,166,464 | 85,122 | 43,235 |
130
+ | ~/Codex | 3 | 7,099,187 | 7,099,187 | 7,047,299 | 6,103,680 | 51,888 | 14,249 |
131
+ | ~/Projekte/NasaCode/Autoresearch | 1 | 6,896,321 | 6,896,321 | 6,864,934 | 6,334,464 | 31,387 | 8,024 |
132
+ | ~/Projekte/MultiHarnessStudio | 6 | 6,580,156 | 6,580,156 | 6,497,175 | 4,835,584 | 82,981 | 24,300 |
133
+ | ~/Projekte/BahnAgent | 3 | 5,287,171 | 5,287,171 | 5,247,750 | 4,559,872 | 39,421 | 7,976 |
134
+ | ~/Projekte/MetaMetaMeta | 1 | 5,180,427 | 5,180,427 | 5,107,914 | 4,216,576 | 72,513 | 5,337 |
135
+ | ~/Projekte/ClaudeCodePanel | 21 | 5,004,177 | 5,004,177 | 4,896,768 | 4,237,568 | 107,409 | 70,091 |
136
+ | ~/ProjekteV2/CodexWebsiteSamuelClaudecode | 6 | 4,856,550 | 4,856,550 | 4,797,674 | 4,300,544 | 58,876 | 11,598 |
137
+ | ~/Projekte/Jobs_Selbständigkeit_Geldverdienen/AgentTestUniSupport/docs | 1 | 4,068,531 | 4,068,531 | 4,048,457 | 3,692,928 | 20,074 | 5,899 |
138
+ | ~/Projekte/Sidecar-ng | 2 | 3,778,526 | 3,778,526 | 3,753,634 | 3,067,776 | 24,892 | 10,022 |
139
+ | ~/Projekte/BahnAgent/HD-St.Anton | 1 | 3,588,293 | 3,588,293 | 3,566,427 | 3,453,056 | 21,866 | 9,190 |
140
+ | ~/Projekte/Sidecar-ng-dashboard | 1 | 3,565,535 | 3,565,535 | 3,533,244 | 3,355,264 | 32,291 | 4,937 |
141
+ | ~/.hermes | 2 | 3,317,062 | 3,317,062 | 3,305,352 | 2,819,456 | 11,710 | 2,378 |
142
+ | ~/Projekte/schloss_PDF | 1 | 3,245,804 | 3,245,804 | 3,229,768 | 3,069,824 | 16,036 | 4,866 |
143
+ | ~/ClaudesReich | 3 | 2,206,746 | 2,206,746 | 2,139,356 | 1,719,296 | 67,390 | 51,059 |
144
+ | ~/Dokumente/durchstarten | 1 | 2,177,869 | 2,177,869 | 2,165,792 | 1,844,224 | 12,077 | 3,264 |
145
+ | ~/Projekte/Sidecar-V7-V2 | 1 | 1,906,923 | 1,906,923 | 1,893,090 | 1,818,624 | 13,833 | 9,278 |
146
+ | ~/abgabe | 3 | 1,904,474 | 1,904,474 | 1,885,225 | 1,680,128 | 19,249 | 9,211 |
147
+ | ~/Projekte/Codex_Usage_Profil | 1 | 1,863,742 | 1,863,742 | 1,839,771 | 1,688,192 | 23,971 | 6,446 |
148
+ | ~/Projekte/AgentIDE | 3 | 1,595,515 | 1,595,515 | 1,563,469 | 1,397,760 | 32,046 | 22,910 |
149
+ | ~/Projekte/Jobs_Selbständigkeit_Geldverdienen | 1 | 1,482,737 | 1,482,737 | 1,459,527 | 1,327,488 | 23,210 | 3,945 |
150
+ | ~/.claude/usage | 1 | 1,205,428 | 1,205,428 | 1,179,696 | 1,085,696 | 25,732 | 8,416 |
151
+ | ~/DataEngeeneeringKEEPA/KeepaProjectsforDataEngeneering3BranchesMerge | 6 | 1,152,226 | 1,152,226 | 1,129,759 | 927,360 | 22,467 | 11,740 |
152
+ | ~/Projekte/ACPcodex | 1 | 1,059,170 | 1,059,170 | 1,043,792 | 910,848 | 15,378 | 8,018 |
153
+ | ~/Projekte/NasaCode | 1 | 985,209 | 985,209 | 970,106 | 897,408 | 15,103 | 1,784 |
154
+ | ~/Projekte/Kaggle5dayAgent | 2 | 913,047 | 913,047 | 897,573 | 686,592 | 15,474 | 5,673 |
155
+ | ~/ProjekteV2/CodexEval2 | 1 | 729,208 | 729,208 | 704,329 | 647,680 | 24,879 | 4,246 |
156
+ | ~/Meta | 1 | 718,880 | 718,880 | 707,059 | 528,512 | 11,821 | 4,379 |
157
+ | ~/Projekte/HarnessEcosystem | 1 | 600,507 | 600,507 | 592,621 | 502,656 | 7,886 | 1,399 |
158
+ | ~/Projekte/StudyAgent | 1 | 511,185 | 511,185 | 501,306 | 464,768 | 9,879 | 7,380 |
159
+ | ~/Projekte/ShortcutCounter | 1 | 441,229 | 441,229 | 435,073 | 398,976 | 6,156 | 3,416 |
160
+ | ~/Projekte/TypoTuner | 3 | 430,804 | 430,804 | 412,494 | 324,992 | 18,310 | 13,352 |
161
+ | ~/Projekte/SandrasWritingWorld | 3 | 347,623 | 347,623 | 340,146 | 290,560 | 7,477 | 4,607 |
162
+ | ~/CodexReich | 2 | 282,250 | 282,250 | 271,237 | 254,208 | 11,013 | 8,192 |
163
+ | ~/Projekte/Sidecar | 1 | 251,167 | 251,167 | 245,022 | 213,504 | 6,145 | 4,675 |
164
+ | ~/Projekte/PromptEngeneering | 2 | 207,700 | 207,700 | 203,831 | 132,096 | 3,869 | 1,279 |
165
+ | ~/ClaudesReich/SessionBrowser | 2 | 203,849 | 203,849 | 196,188 | 170,880 | 7,661 | 5,165 |
166
+ | ~/Projekte/Sidecar-V7-Lite | 1 | 197,279 | 197,279 | 190,627 | 177,792 | 6,652 | 4,599 |
167
+ | ~/Projekte/FireTracker | 2 | 191,892 | 191,892 | 184,419 | 153,344 | 7,473 | 5,715 |
168
+ | ~/Bilder/Anzug/Logo | 1 | 141,042 | 141,042 | 138,537 | 102,016 | 2,505 | 1,280 |
169
+ | ~/DataEngeeneeringKEEPA/VomProfPDF | 1 | 135,655 | 135,655 | 131,074 | 119,168 | 4,581 | 2,463 |
170
+ | ~/Orderformyaistuff | 1 | 132,215 | 132,215 | 131,214 | 112,128 | 1,001 | 64 |
171
+ | ~/OrdnungvonGedanken/git | 1 | 113,347 | 113,347 | 108,699 | 96,384 | 4,648 | 1,633 |
172
+ | ~/ClaudesReich/Visualisierung | 3 | 86,970 | 86,970 | 85,224 | 67,584 | 1,746 | 493 |
173
+ | ~/Projekte/MyAIGame | 2 | 72,823 | 72,823 | 62,967 | 51,328 | 9,856 | 6,964 |
174
+ | /tmp/MyAIGame | 1 | 11,035 | 11,035 | 7,924 | 6,784 | 3,111 | 2,367 |
175
+ | ~/SetUP | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
176
+ | ~/Projekte/HarnessEcosystem/sidebyside | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
177
+
178
+ ## Tokens By Model
179
+
180
+ | Label | Sessions | Tokens | Rollout total | Input | Cached input | Output | Reasoning |
181
+ | --- | --- | --- | --- | --- | --- | --- | --- |
182
+ | gpt-5.4 | 190 | 1,002,621,471 | 1,002,621,471 | 997,085,786 | 895,809,024 | 5,535,685 | 1,652,172 |
183
+ | gpt-5.4-mini | 64 | 94,242,789 | 94,242,789 | 93,515,945 | 87,385,344 | 726,844 | 349,506 |
184
+ | gpt-5.1-codex-max | 14 | 86,258,755 | 86,258,755 | 85,848,562 | 72,738,816 | 410,193 | 157,571 |
185
+ | gpt-5.3-codex | 97 | 63,196,733 | 63,196,733 | 62,443,450 | 56,599,040 | 753,283 | 432,430 |
186
+ | gpt-5.1-codex-mini | 2 | 4,583,943 | 4,583,943 | 4,546,444 | 4,075,904 | 37,499 | 7,045 |
187
+ | gpt-5.2-codex | 5 | 4,307,009 | 4,307,009 | 4,222,922 | 3,537,664 | 84,087 | 58,816 |
188
+ | unknown | 3 | 0 | 0 | 0 | 0 | 0 | 0 |
189
+
190
+ ## Tokens By Role
191
+
192
+ | Label | Sessions | Tokens | Rollout total | Input | Cached input | Output | Reasoning |
193
+ | --- | --- | --- | --- | --- | --- | --- | --- |
194
+ | main | 240 | 1,162,370,493 | 1,162,370,493 | 1,155,950,486 | 1,039,647,488 | 6,420,007 | 2,223,740 |
195
+ | unknown | 17 | 31,239,166 | 31,239,166 | 30,924,883 | 27,394,176 | 314,283 | 116,098 |
196
+ | worker | 18 | 30,777,412 | 30,777,412 | 30,458,569 | 28,003,584 | 318,843 | 108,953 |
197
+ | explorer | 94 | 30,734,460 | 30,734,460 | 30,240,125 | 25,049,600 | 494,335 | 208,680 |
198
+ | default | 6 | 89,169 | 89,169 | 89,046 | 50,944 | 123 | 69 |
199
+
200
+ ## Main Vs Subagent
201
+
202
+ | Label | Sessions | Tokens | Rollout total | Input | Cached input | Output | Reasoning |
203
+ | --- | --- | --- | --- | --- | --- | --- | --- |
204
+ | main | 250 | 1,170,627,399 | 1,170,627,399 | 1,164,127,535 | 1,046,924,928 | 6,499,864 | 2,236,967 |
205
+ | subagent | 125 | 84,583,301 | 84,583,301 | 83,535,574 | 73,220,864 | 1,047,727 | 420,573 |
206
+
207
+ ## Top Sessions
208
+
209
+ | Created | Tokens | Kind | Model | Role | Cwd | Session | Rollout |
210
+ | --- | --- | --- | --- | --- | --- | --- | --- |
211
+ | 2026-04-16 13:01 | 47,959,797 | main | gpt-5.4-mini | main | ~/Projekte/FirstRealHarnessEvaluation_KarpathiesMD | 019d95f4-0198-7e10-9c95-ecd79e771e27 | /home/smlflg/.codex/sessions/2026/04/16/rollout-2026-04-16T13-01-29-019d95f4-0198-7e10-9c95-ecd79e771e27.jsonl |
212
+ | 2026-04-04 16:27 | 45,688,987 | main | gpt-5.4 | main | ~/clawd | 019d58e4-046a-7c10-a832-f8c706647456 | /home/smlflg/.codex/sessions/2026/04/04/rollout-2026-04-04T16-27-11-019d58e4-046a-7c10-a832-f8c706647456.jsonl |
213
+ | 2026-04-13 07:09 | 43,897,402 | main | gpt-5.4 | main | ~/Projekte/HeumandenParty | 019d853e-b868-7053-bb8c-630df03c6eea | /home/smlflg/.codex/sessions/2026/04/13/rollout-2026-04-13T07-09-33-019d853e-b868-7053-bb8c-630df03c6eea.jsonl |
214
+ | 2026-03-13 12:03 | 42,283,906 | main | gpt-5.4 | main | ~/Projekte/Sidecar-V7 | 019ce6dd-5a1c-7fe3-a300-b98983ae4bb8 | /home/smlflg/.codex/sessions/2026/03/13/rollout-2026-03-13T12-03-12-019ce6dd-5a1c-7fe3-a300-b98983ae4bb8.jsonl |
215
+ | 2026-02-05 12:11 | 40,984,928 | main | gpt-5.1-codex-max | main | ~/Dokumente/Pläne | 019c2d80-2f19-7521-9c87-4d6be1ffc9f1 | /home/smlflg/.codex/sessions/2026/02/05/rollout-2026-02-05T12-11-41-019c2d80-2f19-7521-9c87-4d6be1ffc9f1.jsonl |
216
+ | 2026-03-12 00:59 | 34,165,684 | main | gpt-5.4 | main | ~ | 019cdf57-c2c6-7a92-9096-6dac18fc5177 | /home/smlflg/.codex/sessions/2026/03/12/rollout-2026-03-12T00-59-56-019cdf57-c2c6-7a92-9096-6dac18fc5177.jsonl |
217
+ | 2026-02-18 17:07 | 32,848,911 | main | gpt-5.3-codex | main | ~/DataEngeeneeringKEEPA | 019c7181-a37e-7ae2-8870-c4c16655ec52 | /home/smlflg/.codex/sessions/2026/02/18/rollout-2026-02-18T17-07-27-019c7181-a37e-7ae2-8870-c4c16655ec52.jsonl |
218
+ | 2026-04-21 23:03 | 32,619,865 | main | gpt-5.4 | main | ~/Projekte/HeumandenParty | 019db1db-150f-7662-b607-30871c33af75 | /home/smlflg/.codex/sessions/2026/04/21/rollout-2026-04-21T23-03-38-019db1db-150f-7662-b607-30871c33af75.jsonl |
219
+ | 2026-04-05 18:49 | 29,145,038 | main | gpt-5.4 | main | ~/Projekte/UEBER_AGENT | 019d5e8c-39f3-7db1-a48b-d4eb2b50298e | /home/smlflg/.codex/sessions/2026/04/05/rollout-2026-04-05T18-49-01-019d5e8c-39f3-7db1-a48b-d4eb2b50298e.jsonl |
220
+ | 2026-04-06 12:58 | 25,127,211 | main | gpt-5.4 | main | ~/Projekte/UEBER_AGENT | 019d6271-60b8-7621-a2c4-7a66afca9f80 | /home/smlflg/.codex/sessions/2026/04/06/rollout-2026-04-06T12-58-10-019d6271-60b8-7621-a2c4-7a66afca9f80.jsonl |
221
+ | 2026-02-07 19:08 | 22,356,063 | main | gpt-5.1-codex-max | main | ~/Dokumente/Pläne | 019c394a-8761-7823-8f7e-7457d21d79af | /home/smlflg/.codex/sessions/2026/02/07/rollout-2026-02-07T19-08-31-019c394a-8761-7823-8f7e-7457d21d79af.jsonl |
222
+ | 2026-04-08 10:23 | 22,123,631 | main | gpt-5.4 | main | ~/Projekte/HeumandenParty | 019d6c30-e1c5-7441-9ed6-afc8f2bc9861 | /home/smlflg/.codex/sessions/2026/04/08/rollout-2026-04-08T10-23-56-019d6c30-e1c5-7441-9ed6-afc8f2bc9861.jsonl |
223
+ | 2026-04-21 23:28 | 21,430,259 | main | gpt-5.4 | main | ~/Projekte/HeumandenParty | 019db1f1-e994-75c0-94d8-6edc93203dd7 | /home/smlflg/.codex/sessions/2026/04/21/rollout-2026-04-21T23-28-34-019db1f1-e994-75c0-94d8-6edc93203dd7.jsonl |
224
+ | 2026-04-21 15:43 | 21,410,253 | main | gpt-5.4 | main | ~ | 019db048-0123-7242-89b9-d6083591212b | /home/smlflg/.codex/sessions/2026/04/21/rollout-2026-04-21T15-43-22-019db048-0123-7242-89b9-d6083591212b.jsonl |
225
+ | 2026-04-21 15:31 | 21,194,654 | main | gpt-5.4 | main | ~/Projekte/PromptBoost | 019db03d-1f96-7592-8fef-1f10125ebe0c | /home/smlflg/.codex/sessions/2026/04/21/rollout-2026-04-21T15-31-29-019db03d-1f96-7592-8fef-1f10125ebe0c.jsonl |
226
+ | 2026-03-12 15:10 | 21,018,788 | main | gpt-5.4 | main | ~/Projekte/Sidecar-V7 | 019ce262-7359-7ae2-b3c1-e1c5d1a63e66 | /home/smlflg/.codex/sessions/2026/03/12/rollout-2026-03-12T15-10-28-019ce262-7359-7ae2-b3c1-e1c5d1a63e66.jsonl |
227
+ | 2026-04-21 15:27 | 20,456,527 | main | gpt-5.4 | main | ~/Projekte/PromptBoost | 019db039-1b8f-7370-bab6-9e25fd16e912 | /home/smlflg/.codex/sessions/2026/04/21/rollout-2026-04-21T15-27-05-019db039-1b8f-7370-bab6-9e25fd16e912.jsonl |
228
+ | 2026-04-12 15:58 | 20,372,968 | main | gpt-5.4 | main | ~/Projekte/Zentrale | 019d81fc-7347-7523-b30f-4d3ddce562e1 | /home/smlflg/.codex/sessions/2026/04/12/rollout-2026-04-12T15-58-18-019d81fc-7347-7523-b30f-4d3ddce562e1.jsonl |
229
+ | 2026-03-12 15:14 | 19,745,610 | main | gpt-5.4 | main | ~/Projekte/Sidecar-V7 | 019ce266-3a71-79e2-ada1-226867a34de3 | /home/smlflg/.codex/sessions/2026/03/12/rollout-2026-03-12T15-14-36-019ce266-3a71-79e2-ada1-226867a34de3.jsonl |
230
+ | 2026-04-21 14:53 | 19,452,133 | main | gpt-5.4 | main | ~/Projekte/PromptGarage | 019db01a-8e1c-7560-b78f-63857f297f47 | /home/smlflg/.codex/sessions/2026/04/21/rollout-2026-04-21T14-53-43-019db01a-8e1c-7560-b78f-63857f297f47.jsonl |
231
+
232
+ ## Data Warnings
233
+
234
+ - `Malformed JSONL lines in /home/smlflg/.codex/sessions/2026/04/21/rollout-2026-04-21T18-15-04-019db0d2-e62b-78b3-b8f3-e0c70af3aa6c.jsonl: 1`
tests/test_profiler.py ADDED
@@ -0,0 +1,296 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ import sqlite3
5
+ import tempfile
6
+ import unittest
7
+ from datetime import datetime
8
+ from pathlib import Path
9
+ from zoneinfo import ZoneInfo
10
+
11
+ from codex_usage_profiler.core import build_report
12
+ from codex_usage_profiler.render import render_html, render_markdown
13
+
14
+
15
+ class UsageProfilerTests(unittest.TestCase):
16
+ def test_aggregates_threads_edges_and_rollout_breakdowns(self) -> None:
17
+ with tempfile.TemporaryDirectory() as tmp:
18
+ root = Path(tmp)
19
+ state = root / "state_5.sqlite"
20
+ sessions_dir = root / "sessions"
21
+ sessions_dir.mkdir()
22
+ main_rollout = sessions_dir / "rollout-main.jsonl"
23
+ child_rollout = sessions_dir / "rollout-child.jsonl"
24
+
25
+ _write_rollout(
26
+ main_rollout,
27
+ [
28
+ {"type": "turn_context", "payload": {"model": "gpt-5.4", "cwd": "/home/test/project"}},
29
+ {"type": "event_msg", "payload": {"type": "task_started"}},
30
+ {
31
+ "type": "event_msg",
32
+ "payload": {
33
+ "type": "token_count",
34
+ "info": {
35
+ "total_token_usage": {
36
+ "input_tokens": 70,
37
+ "cached_input_tokens": 20,
38
+ "output_tokens": 25,
39
+ "reasoning_output_tokens": 5,
40
+ "total_tokens": 100,
41
+ }
42
+ },
43
+ },
44
+ },
45
+ ],
46
+ malformed=True,
47
+ )
48
+ _write_rollout(
49
+ child_rollout,
50
+ [
51
+ {"type": "turn_context", "payload": {"model": "gpt-5.4-mini", "cwd": "/home/test/project"}},
52
+ {
53
+ "type": "event_msg",
54
+ "payload": {
55
+ "type": "token_count",
56
+ "info": {
57
+ "total_token_usage": {
58
+ "input_tokens": 35,
59
+ "cached_input_tokens": 10,
60
+ "output_tokens": 12,
61
+ "reasoning_output_tokens": 3,
62
+ "total_tokens": 50,
63
+ }
64
+ },
65
+ },
66
+ },
67
+ ],
68
+ )
69
+ _create_state(
70
+ state,
71
+ [
72
+ {
73
+ "id": "main",
74
+ "rollout_path": str(main_rollout),
75
+ "created_at_ms": _epoch_ms("2026-04-20T22:30:00+00:00"),
76
+ "updated_at_ms": _epoch_ms("2026-04-20T23:00:00+00:00"),
77
+ "model_provider": "openai",
78
+ "cwd": "/home/test/project",
79
+ "title": "Main work",
80
+ "tokens_used": 100,
81
+ "agent_nickname": "",
82
+ "agent_role": "",
83
+ "model": None,
84
+ },
85
+ {
86
+ "id": "child",
87
+ "rollout_path": str(child_rollout),
88
+ "created_at_ms": _epoch_ms("2026-04-21T10:00:00+00:00"),
89
+ "updated_at_ms": _epoch_ms("2026-04-21T10:05:00+00:00"),
90
+ "model_provider": "openai",
91
+ "cwd": "/home/test/project",
92
+ "title": "Explore",
93
+ "tokens_used": 50,
94
+ "agent_nickname": "Noether",
95
+ "agent_role": "explorer",
96
+ "model": "gpt-5.4-mini",
97
+ },
98
+ ],
99
+ [("main", "child")],
100
+ )
101
+
102
+ report = build_report(
103
+ state_path=state,
104
+ sessions_dir=sessions_dir,
105
+ tz_name="Europe/Berlin",
106
+ now=datetime(2026, 4, 22, 12, tzinfo=ZoneInfo("Europe/Berlin")),
107
+ )
108
+
109
+ self.assertEqual(report.total_tokens, 150)
110
+ self.assertEqual(report.daily[0].label, "2026-04-21")
111
+ self.assertEqual(report.daily[0].tokens, 150)
112
+ self.assertEqual(report.weekly[0].label, "2026-W17")
113
+ self.assertEqual({bucket.label: bucket.tokens for bucket in report.by_kind}, {"main": 100, "subagent": 50})
114
+ self.assertEqual({bucket.label: bucket.tokens for bucket in report.by_role}, {"main": 100, "explorer": 50})
115
+ self.assertEqual({bucket.label: bucket.tokens for bucket in report.by_model}, {"gpt-5.4": 100, "gpt-5.4-mini": 50})
116
+ self.assertEqual(report.rollout_totals.total_tokens, 150)
117
+ self.assertEqual(report.rollout_totals.cached_input_tokens, 30)
118
+ self.assertEqual(len(report.warnings), 1)
119
+
120
+ def test_days_filter_uses_local_calendar_days(self) -> None:
121
+ with tempfile.TemporaryDirectory() as tmp:
122
+ root = Path(tmp)
123
+ state = root / "state_5.sqlite"
124
+ sessions_dir = root / "sessions"
125
+ sessions_dir.mkdir()
126
+ _create_state(
127
+ state,
128
+ [
129
+ {
130
+ "id": "old",
131
+ "rollout_path": "",
132
+ "created_at_ms": _epoch_ms("2026-04-18T12:00:00+00:00"),
133
+ "updated_at_ms": _epoch_ms("2026-04-18T12:00:00+00:00"),
134
+ "model_provider": "openai",
135
+ "cwd": "/tmp/a",
136
+ "title": "Old",
137
+ "tokens_used": 99,
138
+ "agent_nickname": "",
139
+ "agent_role": "",
140
+ "model": "gpt-5.4",
141
+ },
142
+ {
143
+ "id": "new",
144
+ "rollout_path": "",
145
+ "created_at_ms": _epoch_ms("2026-04-21T12:00:00+00:00"),
146
+ "updated_at_ms": _epoch_ms("2026-04-21T12:00:00+00:00"),
147
+ "model_provider": "openai",
148
+ "cwd": "/tmp/a",
149
+ "title": "New",
150
+ "tokens_used": 10,
151
+ "agent_nickname": "",
152
+ "agent_role": "",
153
+ "model": "gpt-5.4",
154
+ },
155
+ ],
156
+ [],
157
+ )
158
+
159
+ report = build_report(
160
+ state_path=state,
161
+ sessions_dir=sessions_dir,
162
+ tz_name="Europe/Berlin",
163
+ days=2,
164
+ now=datetime(2026, 4, 22, 12, tzinfo=ZoneInfo("Europe/Berlin")),
165
+ )
166
+
167
+ self.assertEqual(len(report.sessions), 1)
168
+ self.assertEqual(report.sessions[0].thread_id, "new")
169
+ self.assertEqual(report.total_tokens, 10)
170
+
171
+ def test_renderers_include_expected_sections_and_escape_html(self) -> None:
172
+ with tempfile.TemporaryDirectory() as tmp:
173
+ root = Path(tmp)
174
+ state = root / "state_5.sqlite"
175
+ sessions_dir = root / "sessions"
176
+ sessions_dir.mkdir()
177
+ _create_state(
178
+ state,
179
+ [
180
+ {
181
+ "id": "s1",
182
+ "rollout_path": "",
183
+ "created_at_ms": _epoch_ms("2026-04-21T12:00:00+00:00"),
184
+ "updated_at_ms": _epoch_ms("2026-04-21T12:00:00+00:00"),
185
+ "model_provider": "openai",
186
+ "cwd": "/tmp/a",
187
+ "title": "<unsafe>",
188
+ "tokens_used": 10,
189
+ "agent_nickname": "",
190
+ "agent_role": "",
191
+ "model": "gpt-5.4",
192
+ }
193
+ ],
194
+ [],
195
+ )
196
+ report = build_report(
197
+ state_path=state,
198
+ sessions_dir=sessions_dir,
199
+ tz_name="Europe/Berlin",
200
+ now=datetime(2026, 4, 22, 12, tzinfo=ZoneInfo("Europe/Berlin")),
201
+ )
202
+
203
+ markdown = render_markdown(report)
204
+ html = render_html(report)
205
+ self.assertIn("## Daily Tokens", markdown)
206
+ self.assertIn("## Top Sessions", markdown)
207
+ self.assertNotIn("&lt;unsafe&gt;", html)
208
+ self.assertNotIn("<unsafe>", html)
209
+
210
+
211
+ def _create_state(state: Path, rows: list[dict[str, object]], edges: list[tuple[str, str]]) -> None:
212
+ with sqlite3.connect(state) as conn:
213
+ conn.execute(
214
+ """
215
+ CREATE TABLE threads (
216
+ id TEXT PRIMARY KEY,
217
+ rollout_path TEXT NOT NULL,
218
+ created_at INTEGER NOT NULL,
219
+ updated_at INTEGER NOT NULL,
220
+ created_at_ms INTEGER,
221
+ updated_at_ms INTEGER,
222
+ model_provider TEXT NOT NULL,
223
+ cwd TEXT NOT NULL,
224
+ title TEXT NOT NULL,
225
+ tokens_used INTEGER NOT NULL,
226
+ agent_nickname TEXT,
227
+ agent_role TEXT,
228
+ model TEXT
229
+ )
230
+ """
231
+ )
232
+ conn.execute(
233
+ """
234
+ CREATE TABLE thread_spawn_edges (
235
+ parent_thread_id TEXT NOT NULL,
236
+ child_thread_id TEXT NOT NULL PRIMARY KEY
237
+ )
238
+ """
239
+ )
240
+ for row in rows:
241
+ conn.execute(
242
+ """
243
+ INSERT INTO threads (
244
+ id,
245
+ rollout_path,
246
+ created_at,
247
+ updated_at,
248
+ created_at_ms,
249
+ updated_at_ms,
250
+ model_provider,
251
+ cwd,
252
+ title,
253
+ tokens_used,
254
+ agent_nickname,
255
+ agent_role,
256
+ model
257
+ )
258
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
259
+ """,
260
+ (
261
+ row["id"],
262
+ row["rollout_path"],
263
+ int(row["created_at_ms"]) // 1000,
264
+ int(row["updated_at_ms"]) // 1000,
265
+ row["created_at_ms"],
266
+ row["updated_at_ms"],
267
+ row["model_provider"],
268
+ row["cwd"],
269
+ row["title"],
270
+ row["tokens_used"],
271
+ row["agent_nickname"],
272
+ row["agent_role"],
273
+ row["model"],
274
+ ),
275
+ )
276
+ for parent, child in edges:
277
+ conn.execute(
278
+ "INSERT INTO thread_spawn_edges (parent_thread_id, child_thread_id) VALUES (?, ?)",
279
+ (parent, child),
280
+ )
281
+
282
+
283
+ def _write_rollout(path: Path, events: list[dict[str, object]], malformed: bool = False) -> None:
284
+ with path.open("w", encoding="utf-8") as handle:
285
+ for event in events:
286
+ handle.write(json.dumps(event) + "\n")
287
+ if malformed:
288
+ handle.write("{not-json\n")
289
+
290
+
291
+ def _epoch_ms(value: str) -> int:
292
+ return int(datetime.fromisoformat(value).timestamp() * 1000)
293
+
294
+
295
+ if __name__ == "__main__":
296
+ unittest.main()