clocwork 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. clocwork-0.1.0/CHANGELOG.md +43 -0
  2. clocwork-0.1.0/LICENSE +21 -0
  3. clocwork-0.1.0/MANIFEST.in +7 -0
  4. clocwork-0.1.0/PKG-INFO +328 -0
  5. clocwork-0.1.0/README.md +300 -0
  6. clocwork-0.1.0/clocwork +11 -0
  7. clocwork-0.1.0/man/clocwork.1 +158 -0
  8. clocwork-0.1.0/pyproject.toml +47 -0
  9. clocwork-0.1.0/setup.cfg +4 -0
  10. clocwork-0.1.0/src/clocwork/__init__.py +15 -0
  11. clocwork-0.1.0/src/clocwork/__main__.py +4 -0
  12. clocwork-0.1.0/src/clocwork/agents.py +113 -0
  13. clocwork-0.1.0/src/clocwork/analyse.py +662 -0
  14. clocwork-0.1.0/src/clocwork/classify.py +124 -0
  15. clocwork-0.1.0/src/clocwork/cli.py +172 -0
  16. clocwork-0.1.0/src/clocwork/cloc.py +346 -0
  17. clocwork-0.1.0/src/clocwork/config.py +83 -0
  18. clocwork-0.1.0/src/clocwork/manpage.py +175 -0
  19. clocwork-0.1.0/src/clocwork/paths.py +171 -0
  20. clocwork-0.1.0/src/clocwork/render.py +172 -0
  21. clocwork-0.1.0/src/clocwork/sources/__init__.py +38 -0
  22. clocwork-0.1.0/src/clocwork/sources/claude_code.py +87 -0
  23. clocwork-0.1.0/src/clocwork/sources/codex.py +266 -0
  24. clocwork-0.1.0/src/clocwork/sources/gemini.py +161 -0
  25. clocwork-0.1.0/src/clocwork/template.html +1974 -0
  26. clocwork-0.1.0/src/clocwork/tokens.py +196 -0
  27. clocwork-0.1.0/src/clocwork.egg-info/PKG-INFO +328 -0
  28. clocwork-0.1.0/src/clocwork.egg-info/SOURCES.txt +82 -0
  29. clocwork-0.1.0/src/clocwork.egg-info/dependency_links.txt +1 -0
  30. clocwork-0.1.0/src/clocwork.egg-info/entry_points.txt +2 -0
  31. clocwork-0.1.0/src/clocwork.egg-info/top_level.txt +1 -0
  32. clocwork-0.1.0/tests/__init__.py +4 -0
  33. clocwork-0.1.0/tests/agent_logs.py +52 -0
  34. clocwork-0.1.0/tests/dashboard/check.js +7 -0
  35. clocwork-0.1.0/tests/dashboard/fixture.py +185 -0
  36. clocwork-0.1.0/tests/dashboard/harness.js +141 -0
  37. clocwork-0.1.0/tests/dashboard/run_all.js +15 -0
  38. clocwork-0.1.0/tests/dashboard/test_charts.js +58 -0
  39. clocwork-0.1.0/tests/dashboard/test_locale.js +128 -0
  40. clocwork-0.1.0/tests/dashboard/test_numbering.js +27 -0
  41. clocwork-0.1.0/tests/dashboard/test_region.js +47 -0
  42. clocwork-0.1.0/tests/dashboard/test_selection.js +95 -0
  43. clocwork-0.1.0/tests/dashboard/test_table.js +210 -0
  44. clocwork-0.1.0/tests/dashboard/test_tokens.js +107 -0
  45. clocwork-0.1.0/tests/dashboard/test_tokens_absent.js +10 -0
  46. clocwork-0.1.0/tests/dashboard/test_tokens_sources.js +32 -0
  47. clocwork-0.1.0/tests/dashboard/tokens_absent.js +31 -0
  48. clocwork-0.1.0/tests/dashboard/tokens_sources.js +54 -0
  49. clocwork-0.1.0/tests/fixtures/README.md +56 -0
  50. clocwork-0.1.0/tests/fixtures/codex/archived_sessions/rollout-2026-05-23T21-38-44-019e56c6-7526-7d03-9fd0-d8067191edf9.jsonl +6 -0
  51. clocwork-0.1.0/tests/fixtures/codex/sessions/2026/05/23/rollout-2026-05-23T19-34-28-019e5654-aee4-7d33-bf8e-c9c5eeb8e89e.jsonl +7 -0
  52. clocwork-0.1.0/tests/fixtures/codex/sessions/2026/05/29/rollout-2026-05-29T20-53-58-019e7583-0b33-7912-a209-4c0407cfa243.jsonl +5 -0
  53. clocwork-0.1.0/tests/fixtures/codex/sessions/2026/05/29/rollout-2026-05-29T20-54-27-019e7584-5201-7901-b1e7-a3f0c990c12f.jsonl +8 -0
  54. clocwork-0.1.0/tests/fixtures/codex/sessions/2026/08/26/rollout-2026-08-26T18-30-09-01a03eb1-6b82-78e3-87e0-2578e88e80cf.jsonl +23 -0
  55. clocwork-0.1.0/tests/fixtures/codex/sessions/2026/08/26/rollout-2026-08-26T18-33-46-01a03eb4-b805-7470-95d6-24f980e820df.jsonl +10 -0
  56. clocwork-0.1.0/tests/fixtures/codex/sessions/2026/08/26/rollout-2026-08-26T18-34-34-01a03eb5-7309-71a1-b9ea-3d76ee9f4968.jsonl +12 -0
  57. clocwork-0.1.0/tests/fixtures/codex/sessions/2026/08/26/rollout-2026-08-26T18-34-36-01a03eb5-7d3d-7bc3-a730-38a83bf1efda.jsonl +10 -0
  58. clocwork-0.1.0/tests/fixtures/codex/sessions/2026/09/07/rollout-2026-09-07T16-25-14-01a07c0b-5e16-70f2-ad21-7c2a3a228b22.jsonl +39 -0
  59. clocwork-0.1.0/tests/fixtures/codex/sessions/2026/09/07/rollout-2026-09-07T16-25-22-01a07c0b-7aaf-7d43-bca3-9b01faca045d.jsonl +14 -0
  60. clocwork-0.1.0/tests/fixtures/codex/sessions/2026/09/07/rollout-2026-09-07T16-25-26-01a07c0b-8d0c-7022-a0df-f7d14290e076.jsonl +27 -0
  61. clocwork-0.1.0/tests/fixtures/codex/sessions/2026/09/07/rollout-2026-09-07T16-25-31-01a07c0b-9e34-7d32-84fa-8a9f69d02e51.jsonl +18 -0
  62. clocwork-0.1.0/tests/fixtures/codex/sessions/2026/09/07/rollout-2026-09-07T16-25-56-01a07c0b-ff44-7180-adb2-c56ac1b7693d.jsonl +30 -0
  63. clocwork-0.1.0/tests/fixtures/gemini/tmp/agent-sample/chats/session-2026-06-12T10-17-466977ef.jsonl +12 -0
  64. clocwork-0.1.0/tests/fixtures/gemini/tmp/agent-sample/chats/session-2026-06-12T10-27-6ac3542c.jsonl +6 -0
  65. clocwork-0.1.0/tests/fixtures/gemini/tmp/agent-sample/chats/session-2026-06-12T10-28-1a4f2a8e.jsonl +6 -0
  66. clocwork-0.1.0/tests/fixtures/gemini/tmp/agent-sample/chats/session-2026-06-12T10-55-ca28c1ad.jsonl +36 -0
  67. clocwork-0.1.0/tests/fixtures/gemini/tmp/agent-sample/chats/session-2026-06-12T12-32-876f478d.jsonl +41 -0
  68. clocwork-0.1.0/tests/repo_fixture.py +122 -0
  69. clocwork-0.1.0/tests/test_agent_fixtures.py +78 -0
  70. clocwork-0.1.0/tests/test_agents.py +54 -0
  71. clocwork-0.1.0/tests/test_analyse.py +668 -0
  72. clocwork-0.1.0/tests/test_classify.py +101 -0
  73. clocwork-0.1.0/tests/test_cli.py +289 -0
  74. clocwork-0.1.0/tests/test_cloc_lines.py +464 -0
  75. clocwork-0.1.0/tests/test_config.py +72 -0
  76. clocwork-0.1.0/tests/test_fixture_shape.py +32 -0
  77. clocwork-0.1.0/tests/test_manpage.py +192 -0
  78. clocwork-0.1.0/tests/test_paths.py +190 -0
  79. clocwork-0.1.0/tests/test_render.py +171 -0
  80. clocwork-0.1.0/tests/test_repository.py +49 -0
  81. clocwork-0.1.0/tests/test_sources.py +193 -0
  82. clocwork-0.1.0/tests/test_sources_codex.py +444 -0
  83. clocwork-0.1.0/tests/test_sources_gemini.py +262 -0
  84. clocwork-0.1.0/tests/test_token_usage.py +269 -0
@@ -0,0 +1,43 @@
1
+ # Changelog
2
+
3
+ All notable changes to clocwork are recorded here. The format follows
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and versions follow
5
+ [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ ## [0.1.0] - 2026-09-16
8
+
9
+ First public release.
10
+
11
+ ### Added
12
+
13
+ - `clocwork [REPO]`: analyses a git repository's whole history into a
14
+ dashboard in a sibling workspace (`<repo>-stats`).
15
+ - Every commit is measured with `cloc --git --diff`, cached per file, and
16
+ reconciled against a `cloc` snapshot of HEAD.
17
+ - `cloc` runs once per CPU core by default (`--jobs`), and
18
+ `--max-commits` spreads a long history over several runs.
19
+ - `cloc` 2.06 or later is required. An older one is refused, because it
20
+ lists file extensions in a form clocwork misreads.
21
+ - Lines per language and per type (code, comment, blank) at every commit,
22
+ and the test-code share at the tip of the analysed branch.
23
+ - Built-in test-path rules cover common ecosystems.
24
+ - `clocwork.toml` can add to the rules, exclude from them or replace them.
25
+ - AI-assisted commits, read from `Co-Authored-By` trailers, with the date
26
+ each agent, and each Claude model, first appeared.
27
+ - Any Claude model is recognised, as are Copilot, Cursor, Codex, Devin,
28
+ aider, Gemini and Gemini Code Assist.
29
+ - `[agents].extra` names anything else.
30
+ - Token usage from Claude Code, Codex CLI and Gemini CLI logs.
31
+ - It is archived per day, agent and model in `token_usage.json`, which no
32
+ run shrinks.
33
+ - Days without logs are estimated from each agent's own tokens-per-line
34
+ ratio.
35
+ - Usage is priced at API list prices, and its electricity is estimated.
36
+ - `clocwork tokens` archives without analysing, for use from cron.
37
+ - `clocwork render` re-renders an existing workspace.
38
+ - `clocwork.json` is a workspace identity guard: a run against a different
39
+ repository is refused.
40
+ - Every number, date and unit on the page is formatted for a region locale.
41
+ - A `clocwork(1)` manual page.
42
+
43
+ [0.1.0]: https://github.com/nicktoumpelis/clocwork/releases/tag/v0.1.0
clocwork-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Nick Toumpelis
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,7 @@
1
+ # The source distribution carries everything the two test suites and the
2
+ # manual page need, so it can be tested and packaged on its own.
3
+ include CHANGELOG.md
4
+ include clocwork
5
+ include man/clocwork.1
6
+ graft tests
7
+ global-exclude __pycache__ *.py[cod] .DS_Store
@@ -0,0 +1,328 @@
1
+ Metadata-Version: 2.4
2
+ Name: clocwork
3
+ Version: 0.1.0
4
+ Summary: Lines per language, AI co-authored commits and token cost over a repository's whole history
5
+ Author: Nick Toumpelis
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/nicktoumpelis/clocwork
8
+ Project-URL: Issues, https://github.com/nicktoumpelis/clocwork/issues
9
+ Project-URL: Changelog, https://github.com/nicktoumpelis/clocwork/blob/main/CHANGELOG.md
10
+ Keywords: git,cloc,lines of code,code statistics,ai agents,tokens,dashboard
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Environment :: Console
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Operating System :: MacOS
15
+ Classifier: Operating System :: POSIX :: Linux
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3 :: Only
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Programming Language :: Python :: 3.14
22
+ Classifier: Topic :: Software Development :: Quality Assurance
23
+ Classifier: Topic :: Software Development :: Version Control :: Git
24
+ Requires-Python: >=3.11
25
+ Description-Content-Type: text/markdown
26
+ License-File: LICENSE
27
+ Dynamic: license-file
28
+
29
+ # clocwork
30
+
31
+ Run `clocwork` inside any git repository and get a dashboard of its whole
32
+ history: lines per language and type (code, comment, blank) at every commit,
33
+ which commits an AI agent co-authored and when each model first appeared, and,
34
+ when the repository was worked on with Claude Code, Codex CLI or Gemini CLI,
35
+ what that work cost in tokens, dollars and electricity. Every commit is
36
+ measured with `cloc --git --diff`, cached per file, and reconciled against a
37
+ `cloc` snapshot of HEAD so drift is visible rather than silent.
38
+
39
+ The output is one `index.html` (its charts load Chart.js and its plugins from
40
+ a CDN) plus a `commit_bodies.js` sidecar for the full commit messages, written
41
+ to a **workspace** next to the repository, never inside it.
42
+
43
+ ## Requirements
44
+
45
+ - Python 3.11 or later (standard library only)
46
+ - [`cloc`](https://github.com/AlDanial/cloc) 2.06 or later on `PATH`. On
47
+ macOS, `brew install cloc` gives a current release. Linux distributions
48
+ often package an older one (Ubuntu 24.04 has 1.98). clocwork refuses an
49
+ older cloc, because earlier releases list file extensions in a form it
50
+ misreads. If yours is older, save `cloc-<version>.pl` from the
51
+ [cloc releases](https://github.com/AlDanial/cloc/releases) as an
52
+ executable named `cloc` on `PATH`.
53
+ - `git`
54
+
55
+ ## Installing
56
+
57
+ ```bash
58
+ pipx install clocwork # or: pip install clocwork
59
+ ```
60
+
61
+ pip does not install the manual page; `man/clocwork.1` is in the repository
62
+ and in the source distribution.
63
+
64
+ Each release also carries `clocwork.pyz`, the whole command in one file, which
65
+ runs with no install step:
66
+
67
+ ```bash
68
+ curl -LO https://github.com/nicktoumpelis/clocwork/releases/latest/download/clocwork.pyz
69
+ chmod +x clocwork.pyz
70
+ ./clocwork.pyz ~/code/foo
71
+ ```
72
+
73
+ Or run it from a clone:
74
+
75
+ ```bash
76
+ git clone https://github.com/nicktoumpelis/clocwork.git ~/code/clocwork
77
+ cd ~/code/foo && ~/code/clocwork/clocwork
78
+ ```
79
+
80
+ Both run under the first `python3` on `PATH`, which must be 3.11 or later;
81
+ an older one is refused with a message naming it. On macOS,
82
+ `/usr/bin/python3` comes from Apple's developer tools and can be older
83
+ (Xcode's is 3.9); name a newer interpreter instead, as in
84
+ `python3.13 clocwork.pyz`.
85
+
86
+ For development, `pip install -e ~/code/clocwork` installs the `clocwork`
87
+ command from the clone.
88
+
89
+ ## Running
90
+
91
+ Run `clocwork` inside the repository to analyse, or pass its path. The first
92
+ run over a long history measures every commit with `cloc`, running one
93
+ `cloc` process per CPU core (`--jobs N` chooses the number). On a 10-core
94
+ machine the 289 commits of [spf13/cast](https://github.com/spf13/cast) take
95
+ 14 seconds (113 seconds with `--jobs 1`), and a repository of 3,800 commits,
96
+ 2,700 of them non-merge, takes about four minutes. Results are cached, so
97
+ later runs take seconds. `--max-commits N` caps one run and a later run
98
+ continues from where it stopped.
99
+
100
+ ## Commands
101
+
102
+ ```
103
+ clocwork [REPO] analyse, archive tokens, render, open the dashboard
104
+ clocwork tokens [REPO] archive agent token logs only
105
+ clocwork render -o DIR re-render the dashboard from existing workspace data
106
+ ```
107
+
108
+ `REPO` is the repository or any directory inside it; the default is the
109
+ current directory. A first argument that is not a subcommand is taken as
110
+ `REPO`, so `clocwork ~/code/foo` works.
111
+
112
+ `tokens` is a separate command because the two halves of the pipeline have
113
+ opposite economics. The `cloc` pass is slow and fully regenerable. The token
114
+ archive is cheap and irreplaceable: coding agents delete their logs (Claude
115
+ Code after roughly 30 days), and a day that is not archived while its logs
116
+ exist is gone for good. `clocwork tokens` is what to run from cron.
117
+
118
+ `render` needs no repository, only a workspace; it exists so the page can be
119
+ iterated on without re-analysing.
120
+
121
+ Options (`clocwork run --help`):
122
+
123
+ ```
124
+ -q, --quiet print nothing but errors
125
+ --config PATH explicit clocwork.toml
126
+ --locale TAG region locale for the page (default: $CLOCWORK_LOCALE,
127
+ else the machine's region)
128
+ --no-open do not open the dashboard in a browser
129
+ -o, --output DIR workspace directory (default: <repo-parent>/<repo-
130
+ name>-stats)
131
+ --branch REF ref to analyse (default: the checked-out branch)
132
+ --max-commits N measure at most N uncached commits this run
133
+ -j, --jobs N cloc processes to run at once (default: one per CPU core)
134
+ --no-tokens skip the agent log scan
135
+ --cache-dir DIR cache location (default: $XDG_CACHE_HOME/clocwork, else
136
+ ~/.cache/clocwork; wins over both)
137
+ ```
138
+
139
+ `tokens` takes only `-o` and `-q`: it writes no page. `render` takes the page
140
+ options and `-q`, and its `-o` is required. `--version` prints the version.
141
+ The same reference is a manual page: `man ./man/clocwork.1` from a clone.
142
+
143
+ The page formats every number, date and unit for a region locale. The
144
+ generator records it, because browsers expose only the language list: the
145
+ `CLOCWORK_LOCALE` environment variable wins (a BCP 47 tag such as `en-SE`),
146
+ then the macOS Language & Region setting, then `LC_ALL`, `LC_NUMERIC` and
147
+ `LANG`; `--locale` overrides all of them for one run.
148
+
149
+ ## The workspace
150
+
151
+ Output goes to a sibling of the repository: `~/code/foo` produces
152
+ `~/code/foo-stats`. It is deliberately not inside the repository, because the
153
+ tool would then be measuring its own output and dirtying the working tree of
154
+ the repository it reports on. Pass `-o DIR` to put it elsewhere.
155
+
156
+ ```
157
+ foo-stats/
158
+ clocwork.json which repository this workspace belongs to
159
+ clocwork.toml optional configuration (see below)
160
+ token_usage.json the per-day, per-agent token archive; cannot be regenerated
161
+ full_commit_data.json the analysis
162
+ index.html the dashboard
163
+ commit_bodies.js full commit messages, loaded when a row is expanded
164
+ ```
165
+
166
+ The workspace is meant to be committed to its own repository: that is the
167
+ backup for `token_usage.json`. `clocwork.json` is an identity guard. On every
168
+ run the target repository is compared against it, by remote URL first and
169
+ absolute path second, and a mismatch is refused with an error naming both
170
+ repositories, so no ordinary mistake can overwrite one repository's token
171
+ archive with another's.
172
+
173
+ The `cloc` cache lives outside the workspace, in
174
+ `$XDG_CACHE_HOME/clocwork/<name>-<hash>/` or `~/.cache/clocwork/`, keyed by
175
+ the repository's absolute path. It holds per-file rows rather than
176
+ per-language totals, so changing the language table or the test-path rules
177
+ below re-reads the cache instead of re-running `cloc`.
178
+
179
+ ## Configuration
180
+
181
+ Optional. Searched in this order, first hit wins: `--config PATH`, then
182
+ `<workspace>/clocwork.toml`, then `<repo>/.clocwork.toml`. The last is read and
183
+ never written, so a repository can commit its own settings while someone
184
+ analysing it can still override them from their workspace.
185
+
186
+ ```toml
187
+ title = "MyApp" # page heading; default is the repository's directory name
188
+
189
+ [tests]
190
+ include = ["integration/**", "e2e/**"] # added to the built-in test-path rules
191
+ exclude = ["tests/fixtures/**"] # applied last, wins over everything
192
+ replace = false # true drops the built-ins entirely
193
+
194
+ [agents]
195
+ extra = [{ match = "Jules", name = "Jules" }] # substring of a Co-Authored-By trailer, reported name
196
+ ```
197
+
198
+ Globs match the whole path from the repository root: `**` matches across
199
+ directories, `*` within one, `?` one character. `*.py` therefore matches only
200
+ top-level files; `**/*.py` matches at any depth.
201
+
202
+ ### What counts as test code
203
+
204
+ Built in, by directory: `test`, `tests`, `__tests__`, `testdata` (any
205
+ case); `spec` and `specs` for Ruby, JavaScript, TypeScript and CoffeeScript
206
+ files only, so a `specs/` directory of design documents is not counted; a directory named `*Test` or
207
+ `*Tests` (Xcode, JVM); the `src/test/`, `src/androidTest/` and
208
+ `src/integrationTest/` layouts. By filename: `*_test.go`; `test_*.py`, `*_test.py`, `conftest.py`; `*.test.*`
209
+ and `*.spec.*` for JavaScript and TypeScript; `*Test.*` and `*Tests.*` for
210
+ Java, Kotlin, C# and Swift; `*_spec.rb`, `*_test.rb`, `*_test.dart`,
211
+ `*_test.exs`. Inline test code (Rust's `#[cfg(test)]`, Go examples in a
212
+ non-test file) is not detectable from paths.
213
+
214
+ The run summary prints the test share of HEAD. A share that is obviously wrong
215
+ is the signal to add a rule; the fix costs a config line and a re-read, not a
216
+ re-measure.
217
+
218
+ ### Which commits are AI-assisted
219
+
220
+ Attribution comes from `Co-Authored-By:` trailers only, so a commit that
221
+ merely mentions an agent is not counted. Any Claude model is recognised and
222
+ normalised (`Claude Opus 4.6`, `Claude Opus 5 (1M)`), and Copilot, Cursor,
223
+ Codex, Devin, aider, Gemini and Gemini Code Assist are recognised by name.
224
+ Anything else stays unmatched rather than guessed at; `[agents].extra` names
225
+ the rest.
226
+
227
+ ### Token usage
228
+
229
+ The token section appears when the workspace's token archive holds at least
230
+ one day. Each run reads the logs coding agents keep on the machine and
231
+ archives per-day totals, per agent and model, into `token_usage.json`:
232
+
233
+ | Agent | Logs read | Override |
234
+ |---|---|---|
235
+ | Claude Code | `~/.claude/projects/`, the directory named after the repository's path | none |
236
+ | Codex CLI | `~/.codex/sessions/` and `~/.codex/archived_sessions/` | `CODEX_HOME` replaces `~/.codex` |
237
+ | Gemini CLI | `~/.gemini/tmp/` and `~/.cache/.gemini/tmp/`, sessions started in the repository or a directory it tracks | `GEMINI_CLI_HOME` replaces `~` |
238
+
239
+ A Codex session belongs to the repository when it records the same remote
240
+ as the repository's `origin`, so sessions from any clone or worktree count.
241
+ A session that recorded another remote still belongs when it ran in the
242
+ repository, or a directory inside it, from one of the repository's commits.
243
+ A renamed or transferred repository keeps its sessions that way, and a
244
+ different repository later cloned to the same path gets them only if it
245
+ holds the commit they started from. When the session records no remote, or
246
+ `origin` is missing or not a URL clocwork recognises, the session belongs
247
+ when it ran in the repository or a directory inside it.
248
+ Gemini CLI identifies a session's project only by a hash of the directory it
249
+ started in, so its sessions count when that is the repository's current path
250
+ or a directory tracked at `HEAD` below it.
251
+
252
+ Only dates, model names, and token and turn counts reach the archive;
253
+ prompts and replies are never kept. The archive keeps the larger record for
254
+ each day and agent, because agents delete their logs and a day not archived
255
+ in time is gone.
256
+
257
+ A day the archive does not cover for an agent, but on which that agent's
258
+ commits changed lines, is estimated from the agent's own tokens-per-line
259
+ ratio; a record that holds no tokens covers nothing. The result is priced at
260
+ API list prices, each measured day at the prices in force on it and the
261
+ estimated days at the measured mix, and its electricity is estimated. For
262
+ any repository not worked on with these agents on this machine, the section
263
+ and the commit table's Tokens column are simply absent; that is the normal
264
+ case, not an error.
265
+
266
+ Tokens land only on the commits of the agent whose logs measured them,
267
+ split across that agent's commits of the day by lines changed. A commit
268
+ carries no token figure when its agent's logs are not read (Copilot, Cursor,
269
+ Devin, aider, Gemini Code Assist or any other), or when they cover no day on
270
+ which that agent's commits changed lines, and it is never priced at another
271
+ agent's rate. When the repository has token data, the run summary counts
272
+ those commits and names their agents. Gemini Code Assist is the name for
273
+ `gemini-code-assist[bot]`, which GitHub credits when one of its review
274
+ suggestions is accepted.
275
+
276
+ Codex asks its model to end commit messages with
277
+ `Co-authored-by: Codex <noreply@openai.com>` unless attribution is turned
278
+ off. Gemini CLI adds no trailer, so its tokens reach a commit only when the
279
+ commit credits Gemini by hand, in a trailer such as
280
+ `Co-Authored-By: Gemini CLI <address>`; otherwise the page says its tokens
281
+ land on no commit. Codex rollouts that Codex has compressed are read on
282
+ Python 3.14 and later; earlier versions count them as unreadable and say so
283
+ in the log.
284
+
285
+ An archive written by an earlier version is read as Claude Code's and
286
+ rewritten in the per-agent shape the next time a scan finds logs; an archive
287
+ of a version this clocwork does not know is refused with an error rather
288
+ than read or overwritten.
289
+
290
+ ## Development
291
+
292
+ ```bash
293
+ python3 -m unittest discover -s tests -t . -q # the Python suite
294
+ node tests/dashboard/run_all.js # the page, in a fake DOM under node
295
+ ```
296
+
297
+ The dashboard suite renders a synthetic workspace (`tests/dashboard/fixture.py`)
298
+ through `./clocwork render`. Set `CLOCWORK_DASH_WORKSPACE=<dir>` to run the
299
+ checks over any rendered workspace, a real one included; the files that
300
+ exercise the token-less page and the page with several agents render their
301
+ own synthetic variants regardless. Checks that assume the fixture's size,
302
+ such as the 500-row cap, fail over a short history.
303
+
304
+ `tests/fixtures/` holds real Codex CLI and Gemini CLI sessions from two
305
+ MIT-licensed repositories, reduced to identity, model, usage and timestamps;
306
+ its README names the sources and carries their licence notices.
307
+
308
+ `man/clocwork.1` is generated from the argparse parsers, and a test checks the
309
+ committed page is current. After changing any help text or the version,
310
+ regenerate it:
311
+
312
+ ```bash
313
+ PYTHONPATH=src python3 -m clocwork.manpage > man/clocwork.1
314
+ ```
315
+
316
+ To exercise the command end to end against a throwaway repository with Go,
317
+ Python, JavaScript and Java test conventions:
318
+
319
+ ```bash
320
+ R=$(python3 -c 'import sys, tempfile, os; sys.path[:0] = ["src", "."]
321
+ from tests import repo_fixture as fx
322
+ d = tempfile.mkdtemp(); r = os.path.join(d, "poly"); os.makedirs(r); fx.make_polyglot_repo(r); print(r)')
323
+ ./clocwork "$R" --no-open --cache-dir /tmp/clocwork-cache
324
+ ```
325
+
326
+ ## Licence
327
+
328
+ MIT.