cli-consumption 0.0.18__tar.gz → 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 (88) hide show
  1. cli_consumption-0.1.0/PKG-INFO +232 -0
  2. cli_consumption-0.1.0/README.md +204 -0
  3. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/docs/architecture.md +6 -6
  4. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/docs/provider-support.md +52 -9
  5. cli_consumption-0.1.0/docs/roadmap.md +25 -0
  6. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/pyproject.toml +1 -1
  7. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/uv.lock +1 -1
  8. cli_consumption-0.0.18/PKG-INFO +0 -453
  9. cli_consumption-0.0.18/README.md +0 -425
  10. cli_consumption-0.0.18/docs/roadmap.md +0 -41
  11. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/.agents/skills/add-cli-adapter/SKILL.md +0 -0
  12. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/.agents/skills/add-cli-adapter/agents/openai.yaml +0 -0
  13. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/.agents/skills/audit-usage-privacy/SKILL.md +0 -0
  14. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/.agents/skills/audit-usage-privacy/agents/openai.yaml +0 -0
  15. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/.agents/skills/evolve-storage-schema/SKILL.md +0 -0
  16. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/.agents/skills/evolve-storage-schema/agents/openai.yaml +0 -0
  17. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/.agents/skills/yeet-github/SKILL.md +0 -0
  18. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/.agents/skills/yeet-github/agents/openai.yaml +0 -0
  19. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/.agents/skills/yolo/SKILL.md +0 -0
  20. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/.agents/skills/yolo/agents/openai.yaml +0 -0
  21. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/.github/workflows/ci.yml +0 -0
  22. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/.github/workflows/release.yaml +0 -0
  23. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/.gitignore +0 -0
  24. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/.pre-commit-config.yaml +0 -0
  25. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/.python-version +0 -0
  26. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/AGENTS.md +0 -0
  27. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/CONTRIBUTING.md +0 -0
  28. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/LICENSE +0 -0
  29. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/NOTICE +0 -0
  30. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/docs/privacy.md +0 -0
  31. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/src/cli_consumption/__init__.py +0 -0
  32. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/src/cli_consumption/__main__.py +0 -0
  33. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/src/cli_consumption/adapters/__init__.py +0 -0
  34. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/src/cli_consumption/adapters/_shared.py +0 -0
  35. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/src/cli_consumption/adapters/aider.py +0 -0
  36. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/src/cli_consumption/adapters/amazon_q.py +0 -0
  37. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/src/cli_consumption/adapters/amp.py +0 -0
  38. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/src/cli_consumption/adapters/base.py +0 -0
  39. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/src/cli_consumption/adapters/claude.py +0 -0
  40. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/src/cli_consumption/adapters/cline.py +0 -0
  41. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/src/cli_consumption/adapters/codex.py +0 -0
  42. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/src/cli_consumption/adapters/continue_cli.py +0 -0
  43. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/src/cli_consumption/adapters/copilot.py +0 -0
  44. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/src/cli_consumption/adapters/crush.py +0 -0
  45. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/src/cli_consumption/adapters/cursor.py +0 -0
  46. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/src/cli_consumption/adapters/gemini.py +0 -0
  47. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/src/cli_consumption/adapters/goose.py +0 -0
  48. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/src/cli_consumption/adapters/grok.py +0 -0
  49. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/src/cli_consumption/adapters/kilo.py +0 -0
  50. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/src/cli_consumption/adapters/kimi.py +0 -0
  51. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/src/cli_consumption/adapters/opencode.py +0 -0
  52. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/src/cli_consumption/adapters/openhands.py +0 -0
  53. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/src/cli_consumption/adapters/pi.py +0 -0
  54. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/src/cli_consumption/adapters/plandex.py +0 -0
  55. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/src/cli_consumption/adapters/qwen.py +0 -0
  56. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/src/cli_consumption/api.py +0 -0
  57. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/src/cli_consumption/cli.py +0 -0
  58. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/src/cli_consumption/dashboard.py +0 -0
  59. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/src/cli_consumption/exporting.py +0 -0
  60. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/src/cli_consumption/models.py +0 -0
  61. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/src/cli_consumption/py.typed +0 -0
  62. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/src/cli_consumption/storage.py +0 -0
  63. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/src/cli_consumption/sync.py +0 -0
  64. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/tests/conftest.py +0 -0
  65. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/tests/test_aider_adapter.py +0 -0
  66. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/tests/test_amazon_q_adapter.py +0 -0
  67. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/tests/test_amp_adapter.py +0 -0
  68. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/tests/test_api.py +0 -0
  69. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/tests/test_claude_adapter.py +0 -0
  70. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/tests/test_cli.py +0 -0
  71. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/tests/test_cline_adapter.py +0 -0
  72. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/tests/test_codex_adapter.py +0 -0
  73. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/tests/test_continue_adapter.py +0 -0
  74. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/tests/test_copilot_adapter.py +0 -0
  75. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/tests/test_crush_adapter.py +0 -0
  76. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/tests/test_cursor_adapter.py +0 -0
  77. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/tests/test_gemini_adapter.py +0 -0
  78. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/tests/test_goose_adapter.py +0 -0
  79. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/tests/test_grok_adapter.py +0 -0
  80. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/tests/test_kilo_adapter.py +0 -0
  81. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/tests/test_kimi_adapter.py +0 -0
  82. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/tests/test_opencode_adapter.py +0 -0
  83. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/tests/test_openhands_adapter.py +0 -0
  84. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/tests/test_pi_adapter.py +0 -0
  85. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/tests/test_plandex_adapter.py +0 -0
  86. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/tests/test_qwen_adapter.py +0 -0
  87. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/tests/test_storage_and_exports.py +0 -0
  88. {cli_consumption-0.0.18 → cli_consumption-0.1.0}/tests/test_sync.py +0 -0
@@ -0,0 +1,232 @@
1
+ Metadata-Version: 2.5
2
+ Name: cli-consumption
3
+ Version: 0.1.0
4
+ Summary: Analyze and consolidate AI coding CLI consumption across machines.
5
+ Project-URL: Homepage, https://github.com/Guillaume-Lombardo/cli-consumption
6
+ Project-URL: Documentation, https://github.com/Guillaume-Lombardo/cli-consumption#readme
7
+ Project-URL: Issues, https://github.com/Guillaume-Lombardo/cli-consumption/issues
8
+ Project-URL: Repository, https://github.com/Guillaume-Lombardo/cli-consumption.git
9
+ Author-email: Guillaume Lombardo <lombardo.guillaume@gmail.com>
10
+ License-Expression: Apache-2.0
11
+ License-File: LICENSE
12
+ License-File: NOTICE
13
+ Keywords: ai,cli,codex,observability,tokens,usage
14
+ Classifier: Development Status :: 3 - Alpha
15
+ Classifier: Environment :: Console
16
+ Classifier: License :: OSI Approved :: Apache Software License
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.14
19
+ Classifier: Topic :: Software Development :: Quality Assurance
20
+ Requires-Python: >=3.14
21
+ Requires-Dist: fastapi>=0.115
22
+ Requires-Dist: httpx>=0.27
23
+ Requires-Dist: psycopg[binary]>=3.2
24
+ Requires-Dist: sqlalchemy>=2.0
25
+ Requires-Dist: typer>=0.15
26
+ Requires-Dist: uvicorn>=0.34
27
+ Description-Content-Type: text/markdown
28
+
29
+ # CLI Consumption
30
+
31
+ CLI Consumption measures how AI coding CLIs use models, tokens, tools,
32
+ conversations, and turns. It runs locally, can consolidate copied data from several
33
+ machines, and can send metadata-only snapshots to a central collector.
34
+
35
+ It never stores prompts, responses, tool arguments, credentials, or raw provider
36
+ events. Local token counters are usage metadata, not billing records. Read the
37
+ [privacy boundary](docs/privacy.md) before sharing a database or report.
38
+
39
+ ## Quick start
40
+
41
+ CLI Consumption requires Python 3.14 or newer and uses
42
+ [`uv`](https://docs.astral.sh/uv/).
43
+
44
+ From a checkout, collect every supported CLI detected on the machine and generate a
45
+ self-contained dashboard:
46
+
47
+ ```bash
48
+ uv sync
49
+ uv run cli-consumption collect --provider all
50
+ uv run cli-consumption export --output reports
51
+ ```
52
+
53
+ Open `reports/dashboard.html` locally. It makes no network requests. Detailed
54
+ normalized CSV tables are generated only when `--csv` is passed.
55
+
56
+ To collect a single CLI, use its provider name. For example, with Codex:
57
+
58
+ ```bash
59
+ uv run cli-consumption collect --provider codex --database usage.sqlite
60
+ ```
61
+
62
+ From PyPI, no permanent installation is required:
63
+
64
+ ```bash
65
+ uv tool run cli-consumption collect --provider all
66
+ uv tool run cli-consumption export --output reports
67
+ ```
68
+
69
+ To run the latest unreleased GitHub source:
70
+
71
+ ```bash
72
+ uv tool run --from git+https://github.com/Guillaume-Lombardo/cli-consumption \
73
+ cli-consumption providers
74
+ ```
75
+
76
+ ## Supported CLIs
77
+
78
+ `--provider all` detects the supported data stores found in their default locations.
79
+ Use the provider name below with `--provider` to select one CLI explicitly.
80
+
81
+ | CLI | Provider name | Default local source | Particularities and limits |
82
+ | --- | --- | --- | --- |
83
+ | Aider | `aider` | `~/.aider/analytics.jsonl` | Requires opt-in analytics logging; no projects, tools, cache/reasoning split, or provider-reported durations. |
84
+ | Amazon Q Developer CLI | `amazon-q` | `~/.local/share/amazon-q/data.sqlite3` | Persistent conversations only; request timing is available, but token counters are not. |
85
+ | Amp | `amp` | `~/.local/share/amp/threads/` | Per-inference tokens and context windows; no subthreads, compactions, reasoning split, or latency. |
86
+ | Claude Code | `claude` | `~/.claude/projects/` | Main sessions, tokens, tools, and compactions; no subagents, context windows, or provider-reported durations. `claude-code` is accepted as an alias. |
87
+ | Cline CLI | `cline` | `~/.cline/data/sessions/sessions.db` | Uses the session index and message artifacts; no costs or arbitrary task metadata. |
88
+ | Codex | `codex` | `~/.codex/sessions/` | Richest support: timing, context pressure, settings, compactions, work items, and subagent relationships. |
89
+ | Continue CLI | `continue` | `~/.continue/sessions/` | Token usage when present; session files lack reliable per-message timing and duration. |
90
+ | Crush | `crush` | `~/.local/share/crush/` | Reads registered per-project SQLite stores; token counters are a latest-context snapshot, not additive usage. |
91
+ | Cursor CLI | `cursor` | `~/.cursor/` | Composer 2 transcripts and chat metadata; no per-message time or tokens, and model attribution is incomplete. |
92
+ | Gemini CLI | `gemini` | `~/.gemini/tmp/` | Replays active history and rewinds; hashed projects are not reversed and nested agents are excluded. |
93
+ | GitHub Copilot CLI | `copilot` | `~/.copilot/session-state/` | Tokens are latest shutdown aggregates and cannot be assigned to individual turns. |
94
+ | Goose | `goose` | `~/.local/share/goose/sessions/sessions.db` | Supports SQLite schema v16; no legacy JSONL, subagents, reasoning tokens, or latency. |
95
+ | Grok Build | `grok` | `~/.grok/sessions/` | Per-prompt aggregates, reasoning effort, TTFT, and auto-compactions; no costs or subagent relationships. |
96
+ | Kilo Code | `kilo` | `~/.local/share/kilo/kilo.db` | CLI SQLite store only; excludes legacy IDE tasks, cloud sessions, subagents, context windows, and costs. |
97
+ | Kimi Code CLI | `kimi` | `~/.kimi/sessions/` | Wire v1 events, context windows, and compactions; selected model is not persisted and is reported as `unknown`. |
98
+ | OpenCode | `opencode` | `~/.local/share/opencode/opencode.db` | SQLite v2 only; no legacy storage, child sessions, context windows, or costs. |
99
+ | OpenHands CLI | `openhands` | `~/.openhands/conversations/` | SDK persistence with context windows, reasoning effort, and condensations; excludes cloud-only conversations and delegates. |
100
+ | Pi | `pi` | `~/.pi/agent/sessions/` | Counts all persisted branches; no branch relationships, custom-directory auto-detection, context windows, or provider-reported durations. |
101
+ | Plandex | `plandex` | `/plandex-server` | Requires an offline copy of a self-hosted `PLANDEX_BASE_DIR`; hosted accounts are not accessed, and models/tools are unavailable. |
102
+ | Qwen Code | `qwen` | `~/.qwen/projects/` | Follows the active branch and records context windows and compactions; excludes archived and sidechain sessions. |
103
+
104
+ Provider formats are internal and can change without notice. The detailed extraction
105
+ rules and qualification versions are documented in
106
+ [Provider support](docs/provider-support.md).
107
+
108
+ ## Collect copied data
109
+
110
+ `--source [LABEL=]PATH` points to a provider home directory and can be repeated. With
111
+ `--provider all`, each path is inspected and unmatched sources are rejected. With one
112
+ provider selected, each path must contain that provider's expected store.
113
+
114
+ For example, consolidate trusted copies of Codex data from several machines:
115
+
116
+ ```bash
117
+ uv run cli-consumption collect --provider codex \
118
+ --source desktop=/data/codex/desktop \
119
+ --source laptop=/data/codex/laptop \
120
+ --source server=/data/codex/server \
121
+ --database usage.sqlite
122
+ ```
123
+
124
+ Copy only the required provider data. For Codex, copy the `sessions/` directory but
125
+ never `auth.json` or other credentials. Globally identical conversation IDs are
126
+ deduplicated, and the most complete copy wins.
127
+
128
+ Map original working-directory prefixes to stable project labels with repeated
129
+ `--project NAME=PATH_PREFIX` options. The longest matching prefix wins:
130
+
131
+ ```bash
132
+ uv run cli-consumption collect --provider codex \
133
+ --source desktop=/data/codex/desktop \
134
+ --project cli-consumption=/home/me/dev/cli-consumption
135
+ ```
136
+
137
+ Plandex auto-detection checks `/plandex-server`. For any other trusted offline copy of
138
+ a self-hosted server data directory, pass the path explicitly:
139
+
140
+ ```bash
141
+ uv run cli-consumption collect --provider plandex \
142
+ --source server=/srv/plandex-server --database usage.sqlite
143
+ ```
144
+
145
+ ## Explore and share reports
146
+
147
+ The dashboard can filter by time, provider, machine, project, and model. It reports
148
+ activity, token composition, cache efficiency, latency and duration distributions,
149
+ technical throughput, context pressure, work-item reliability, configuration cohorts,
150
+ compactions, subagent delegation, and ingestion quality. Availability varies by
151
+ provider, as summarized in the table above.
152
+
153
+ Generate a more shareable dashboard by pseudonymizing labels, grouping tool names,
154
+ rounding timestamps to days, and hiding small cohort rows:
155
+
156
+ ```bash
157
+ uv run cli-consumption export --output shared-report --share-safe
158
+ ```
159
+
160
+ Share-safe reports still disclose aggregate work patterns and remain private
161
+ operational data. A technically completed turn is not a measure of task quality or
162
+ productivity.
163
+
164
+ ## SQLite and PostgreSQL
165
+
166
+ A file path selects SQLite. A SQLAlchemy URL selects PostgreSQL:
167
+
168
+ ```bash
169
+ uv run cli-consumption collect --provider all --database usage.sqlite
170
+ uv run cli-consumption collect --provider all \
171
+ --database postgresql+psycopg://usage@localhost/cli_consumption
172
+ ```
173
+
174
+ Pass credentials through environment variables or a secret manager rather than shell
175
+ history. `CLI_CONSUMPTION_DATABASE` can provide the database setting.
176
+
177
+ ## Central collector API
178
+
179
+ Copied files are simplest for personal or air-gapped use. For recurring collection
180
+ across machines, start the metadata-only API:
181
+
182
+ ```bash
183
+ export CLI_CONSUMPTION_API_TOKEN="$(your-secret-provider)"
184
+ uv run cli-consumption serve \
185
+ --database postgresql+psycopg://usage@localhost/cli_consumption \
186
+ --host 0.0.0.0
187
+ ```
188
+
189
+ Then send all locally detected snapshots from another machine:
190
+
191
+ ```bash
192
+ export CLI_CONSUMPTION_API_TOKEN="$(your-secret-provider)"
193
+ uv run cli-consumption sync --provider all \
194
+ --endpoint https://usage.example.test
195
+ ```
196
+
197
+ The application refuses to bind beyond localhost without a token. Production
198
+ deployments also need TLS and standard operational controls. See
199
+ [Architecture](docs/architecture.md) for the trade-offs.
200
+
201
+ ## Commands
202
+
203
+ | Command | Purpose |
204
+ | --- | --- |
205
+ | `collect` | Collect local or copied provider data into SQL. |
206
+ | `sync` | Collect and send metadata-only snapshots to a central API. |
207
+ | `serve` | Run the central collection API. |
208
+ | `export` | Write the HTML dashboard and optional CSV tables. |
209
+ | `providers` | List provider names and support status. |
210
+
211
+ Run `uv run cli-consumption COMMAND --help` for all options.
212
+
213
+ ## Development
214
+
215
+ ```bash
216
+ uv sync --all-groups
217
+ uv run pre-commit install
218
+ uv run pre-commit run --all-files
219
+ uv run ruff format --check .
220
+ uv run ruff check .
221
+ uv run ty check
222
+ uv run pytest --cov --cov-report=term-missing
223
+ uv build
224
+ ```
225
+
226
+ Development uses short-lived branches and squash-merged pull requests into protected
227
+ `main`. Read [CONTRIBUTING.md](CONTRIBUTING.md) and [AGENTS.md](AGENTS.md) before
228
+ changing the project.
229
+
230
+ ## License
231
+
232
+ Licensed under the [Apache License 2.0](LICENSE).
@@ -0,0 +1,204 @@
1
+ # CLI Consumption
2
+
3
+ CLI Consumption measures how AI coding CLIs use models, tokens, tools,
4
+ conversations, and turns. It runs locally, can consolidate copied data from several
5
+ machines, and can send metadata-only snapshots to a central collector.
6
+
7
+ It never stores prompts, responses, tool arguments, credentials, or raw provider
8
+ events. Local token counters are usage metadata, not billing records. Read the
9
+ [privacy boundary](docs/privacy.md) before sharing a database or report.
10
+
11
+ ## Quick start
12
+
13
+ CLI Consumption requires Python 3.14 or newer and uses
14
+ [`uv`](https://docs.astral.sh/uv/).
15
+
16
+ From a checkout, collect every supported CLI detected on the machine and generate a
17
+ self-contained dashboard:
18
+
19
+ ```bash
20
+ uv sync
21
+ uv run cli-consumption collect --provider all
22
+ uv run cli-consumption export --output reports
23
+ ```
24
+
25
+ Open `reports/dashboard.html` locally. It makes no network requests. Detailed
26
+ normalized CSV tables are generated only when `--csv` is passed.
27
+
28
+ To collect a single CLI, use its provider name. For example, with Codex:
29
+
30
+ ```bash
31
+ uv run cli-consumption collect --provider codex --database usage.sqlite
32
+ ```
33
+
34
+ From PyPI, no permanent installation is required:
35
+
36
+ ```bash
37
+ uv tool run cli-consumption collect --provider all
38
+ uv tool run cli-consumption export --output reports
39
+ ```
40
+
41
+ To run the latest unreleased GitHub source:
42
+
43
+ ```bash
44
+ uv tool run --from git+https://github.com/Guillaume-Lombardo/cli-consumption \
45
+ cli-consumption providers
46
+ ```
47
+
48
+ ## Supported CLIs
49
+
50
+ `--provider all` detects the supported data stores found in their default locations.
51
+ Use the provider name below with `--provider` to select one CLI explicitly.
52
+
53
+ | CLI | Provider name | Default local source | Particularities and limits |
54
+ | --- | --- | --- | --- |
55
+ | Aider | `aider` | `~/.aider/analytics.jsonl` | Requires opt-in analytics logging; no projects, tools, cache/reasoning split, or provider-reported durations. |
56
+ | Amazon Q Developer CLI | `amazon-q` | `~/.local/share/amazon-q/data.sqlite3` | Persistent conversations only; request timing is available, but token counters are not. |
57
+ | Amp | `amp` | `~/.local/share/amp/threads/` | Per-inference tokens and context windows; no subthreads, compactions, reasoning split, or latency. |
58
+ | Claude Code | `claude` | `~/.claude/projects/` | Main sessions, tokens, tools, and compactions; no subagents, context windows, or provider-reported durations. `claude-code` is accepted as an alias. |
59
+ | Cline CLI | `cline` | `~/.cline/data/sessions/sessions.db` | Uses the session index and message artifacts; no costs or arbitrary task metadata. |
60
+ | Codex | `codex` | `~/.codex/sessions/` | Richest support: timing, context pressure, settings, compactions, work items, and subagent relationships. |
61
+ | Continue CLI | `continue` | `~/.continue/sessions/` | Token usage when present; session files lack reliable per-message timing and duration. |
62
+ | Crush | `crush` | `~/.local/share/crush/` | Reads registered per-project SQLite stores; token counters are a latest-context snapshot, not additive usage. |
63
+ | Cursor CLI | `cursor` | `~/.cursor/` | Composer 2 transcripts and chat metadata; no per-message time or tokens, and model attribution is incomplete. |
64
+ | Gemini CLI | `gemini` | `~/.gemini/tmp/` | Replays active history and rewinds; hashed projects are not reversed and nested agents are excluded. |
65
+ | GitHub Copilot CLI | `copilot` | `~/.copilot/session-state/` | Tokens are latest shutdown aggregates and cannot be assigned to individual turns. |
66
+ | Goose | `goose` | `~/.local/share/goose/sessions/sessions.db` | Supports SQLite schema v16; no legacy JSONL, subagents, reasoning tokens, or latency. |
67
+ | Grok Build | `grok` | `~/.grok/sessions/` | Per-prompt aggregates, reasoning effort, TTFT, and auto-compactions; no costs or subagent relationships. |
68
+ | Kilo Code | `kilo` | `~/.local/share/kilo/kilo.db` | CLI SQLite store only; excludes legacy IDE tasks, cloud sessions, subagents, context windows, and costs. |
69
+ | Kimi Code CLI | `kimi` | `~/.kimi/sessions/` | Wire v1 events, context windows, and compactions; selected model is not persisted and is reported as `unknown`. |
70
+ | OpenCode | `opencode` | `~/.local/share/opencode/opencode.db` | SQLite v2 only; no legacy storage, child sessions, context windows, or costs. |
71
+ | OpenHands CLI | `openhands` | `~/.openhands/conversations/` | SDK persistence with context windows, reasoning effort, and condensations; excludes cloud-only conversations and delegates. |
72
+ | Pi | `pi` | `~/.pi/agent/sessions/` | Counts all persisted branches; no branch relationships, custom-directory auto-detection, context windows, or provider-reported durations. |
73
+ | Plandex | `plandex` | `/plandex-server` | Requires an offline copy of a self-hosted `PLANDEX_BASE_DIR`; hosted accounts are not accessed, and models/tools are unavailable. |
74
+ | Qwen Code | `qwen` | `~/.qwen/projects/` | Follows the active branch and records context windows and compactions; excludes archived and sidechain sessions. |
75
+
76
+ Provider formats are internal and can change without notice. The detailed extraction
77
+ rules and qualification versions are documented in
78
+ [Provider support](docs/provider-support.md).
79
+
80
+ ## Collect copied data
81
+
82
+ `--source [LABEL=]PATH` points to a provider home directory and can be repeated. With
83
+ `--provider all`, each path is inspected and unmatched sources are rejected. With one
84
+ provider selected, each path must contain that provider's expected store.
85
+
86
+ For example, consolidate trusted copies of Codex data from several machines:
87
+
88
+ ```bash
89
+ uv run cli-consumption collect --provider codex \
90
+ --source desktop=/data/codex/desktop \
91
+ --source laptop=/data/codex/laptop \
92
+ --source server=/data/codex/server \
93
+ --database usage.sqlite
94
+ ```
95
+
96
+ Copy only the required provider data. For Codex, copy the `sessions/` directory but
97
+ never `auth.json` or other credentials. Globally identical conversation IDs are
98
+ deduplicated, and the most complete copy wins.
99
+
100
+ Map original working-directory prefixes to stable project labels with repeated
101
+ `--project NAME=PATH_PREFIX` options. The longest matching prefix wins:
102
+
103
+ ```bash
104
+ uv run cli-consumption collect --provider codex \
105
+ --source desktop=/data/codex/desktop \
106
+ --project cli-consumption=/home/me/dev/cli-consumption
107
+ ```
108
+
109
+ Plandex auto-detection checks `/plandex-server`. For any other trusted offline copy of
110
+ a self-hosted server data directory, pass the path explicitly:
111
+
112
+ ```bash
113
+ uv run cli-consumption collect --provider plandex \
114
+ --source server=/srv/plandex-server --database usage.sqlite
115
+ ```
116
+
117
+ ## Explore and share reports
118
+
119
+ The dashboard can filter by time, provider, machine, project, and model. It reports
120
+ activity, token composition, cache efficiency, latency and duration distributions,
121
+ technical throughput, context pressure, work-item reliability, configuration cohorts,
122
+ compactions, subagent delegation, and ingestion quality. Availability varies by
123
+ provider, as summarized in the table above.
124
+
125
+ Generate a more shareable dashboard by pseudonymizing labels, grouping tool names,
126
+ rounding timestamps to days, and hiding small cohort rows:
127
+
128
+ ```bash
129
+ uv run cli-consumption export --output shared-report --share-safe
130
+ ```
131
+
132
+ Share-safe reports still disclose aggregate work patterns and remain private
133
+ operational data. A technically completed turn is not a measure of task quality or
134
+ productivity.
135
+
136
+ ## SQLite and PostgreSQL
137
+
138
+ A file path selects SQLite. A SQLAlchemy URL selects PostgreSQL:
139
+
140
+ ```bash
141
+ uv run cli-consumption collect --provider all --database usage.sqlite
142
+ uv run cli-consumption collect --provider all \
143
+ --database postgresql+psycopg://usage@localhost/cli_consumption
144
+ ```
145
+
146
+ Pass credentials through environment variables or a secret manager rather than shell
147
+ history. `CLI_CONSUMPTION_DATABASE` can provide the database setting.
148
+
149
+ ## Central collector API
150
+
151
+ Copied files are simplest for personal or air-gapped use. For recurring collection
152
+ across machines, start the metadata-only API:
153
+
154
+ ```bash
155
+ export CLI_CONSUMPTION_API_TOKEN="$(your-secret-provider)"
156
+ uv run cli-consumption serve \
157
+ --database postgresql+psycopg://usage@localhost/cli_consumption \
158
+ --host 0.0.0.0
159
+ ```
160
+
161
+ Then send all locally detected snapshots from another machine:
162
+
163
+ ```bash
164
+ export CLI_CONSUMPTION_API_TOKEN="$(your-secret-provider)"
165
+ uv run cli-consumption sync --provider all \
166
+ --endpoint https://usage.example.test
167
+ ```
168
+
169
+ The application refuses to bind beyond localhost without a token. Production
170
+ deployments also need TLS and standard operational controls. See
171
+ [Architecture](docs/architecture.md) for the trade-offs.
172
+
173
+ ## Commands
174
+
175
+ | Command | Purpose |
176
+ | --- | --- |
177
+ | `collect` | Collect local or copied provider data into SQL. |
178
+ | `sync` | Collect and send metadata-only snapshots to a central API. |
179
+ | `serve` | Run the central collection API. |
180
+ | `export` | Write the HTML dashboard and optional CSV tables. |
181
+ | `providers` | List provider names and support status. |
182
+
183
+ Run `uv run cli-consumption COMMAND --help` for all options.
184
+
185
+ ## Development
186
+
187
+ ```bash
188
+ uv sync --all-groups
189
+ uv run pre-commit install
190
+ uv run pre-commit run --all-files
191
+ uv run ruff format --check .
192
+ uv run ruff check .
193
+ uv run ty check
194
+ uv run pytest --cov --cov-report=term-missing
195
+ uv build
196
+ ```
197
+
198
+ Development uses short-lived branches and squash-merged pull requests into protected
199
+ `main`. Read [CONTRIBUTING.md](CONTRIBUTING.md) and [AGENTS.md](AGENTS.md) before
200
+ changing the project.
201
+
202
+ ## License
203
+
204
+ Licensed under the [Apache License 2.0](LICENSE).
@@ -16,12 +16,12 @@ provider files -> adapter -> metadata-only snapshot -> SQL storage -> dashboard/
16
16
 
17
17
  - `adapters`: parse a CLI's local data into conversations, turns, model calls, tool
18
18
  calls, context-pressure samples, bounded turn settings, compactions, and content-free
19
- work-item intervals. Codex exposes the complete analytics contract; Aider, Amazon Q
19
+ work-item intervals. Codex exposes the complete analytics contract. Aider, Amazon Q
20
20
  Developer CLI, Amp, Cline CLI, Claude Code, Continue CLI, Crush, Cursor CLI, Gemini
21
- CLI, GitHub Copilot CLI, Goose, Kilo Code, Kimi Code CLI, OpenCode, Pi, Plandex, and
22
- Qwen Code expose the core dimensions available in their stores. OpenHands CLI
23
- exposes the same core dimensions plus context windows and condensation timestamps
24
- from its SDK persistence.
21
+ CLI, GitHub Copilot CLI, Goose, Grok Build, Kilo Code, Kimi Code CLI, OpenCode,
22
+ OpenHands CLI, Pi, Plandex, and Qwen Code expose the reliable subset available in
23
+ each local store. The exact differences are maintained in
24
+ [Provider support](provider-support.md).
25
25
  - `models`: define the transport boundary shared by offline and API ingestion.
26
26
  - `storage`: owns the normalized schema, idempotent replacement rules, SQLite, and
27
27
  PostgreSQL engine creation.
@@ -73,7 +73,7 @@ to an older strict API is rejected before ingestion, so central deployments must
73
73
  upgrade the server first. Downgrading a writer after rich metadata has been ingested is
74
74
  not supported because old writers do not know how to replace the new child rows.
75
75
 
76
- ## Adapter roadmap
76
+ ## Adapter qualification
77
77
 
78
78
  Adapters are introduced one at a time because local data formats are undocumented or
79
79
  can evolve independently. Each adapter must have synthetic fixtures, format detection,
@@ -31,6 +31,8 @@ It does not mean that token counters are equivalent to invoices.
31
31
  ingests each metadata-only snapshot independently. With no explicit source it checks
32
32
  the local default homes; repeated `--source` paths are filtered by detected format.
33
33
 
34
+ ## Codex
35
+
34
36
  Codex additionally exposes provider-reported turn duration and TTFT, model context
35
37
  window samples, bounded reasoning/collaboration/service-tier labels, timestamped
36
38
  compactions, technical work-item categories and durations, and local thread-spawn
@@ -38,6 +40,8 @@ relationships. Work-item content and rate-limit payloads are deliberately exclud
38
40
  Subagent state can remain `open` after a child thread is technically closed; reporting
39
41
  therefore derives closure from collected child turns when they are available.
40
42
 
43
+ ## Cursor CLI
44
+
41
45
  Cursor CLI reads Composer 2 transcripts from
42
46
  `~/.cursor/projects/*/agent-transcripts/<session-id>/<session-id>.jsonl` and optional
43
47
  session metadata from `~/.cursor/chats/*/<session-id>/store.db`. It extracts visible
@@ -58,13 +62,16 @@ transcripts, Cursor IDE history, background/cloud agents, subagent transcripts,
58
62
  compactions, context windows, costs, and provider-reported durations are not collected.
59
63
  The internal formats can change without notice, and local events are not billing data.
60
64
 
61
- Continue CLI reads session JSON files from `~/.continue/sessions/` (or
62
- `CONTINUE_GLOBAL_DIR`). The adapter was qualified against the current session format
63
- used by Continue CLI in August 2026. It extracts visible user turns, assistant model
64
- labels, per-response token usage when present, the cumulative session token snapshot,
65
- and function-call names while discarding titles, prompts, responses, reasoning, tool
66
- arguments/results, context items, editor state, rules, arbitrary metadata, costs, and
67
- credentials. Working directories are inspected only for explicit project mappings.
65
+ ## Continue CLI
66
+
67
+ Continue CLI reads session JSON files from `~/.continue/sessions/`. A custom
68
+ `CONTINUE_GLOBAL_DIR` must be passed with `--source`. The adapter was qualified against
69
+ the current session format used by Continue CLI in August 2026. It extracts visible
70
+ user turns, assistant model labels, per-response token usage when present, the
71
+ cumulative session token snapshot, and function-call names while discarding titles,
72
+ prompts, responses, reasoning, tool arguments/results, context items, editor state,
73
+ rules, arbitrary metadata, costs, and credentials. Working directories are inspected
74
+ only for explicit project mappings.
68
75
 
69
76
  Continue reports prompt and completion totals with optional cache-read, cache-write,
70
77
  and reasoning subsets. The adapter prefers per-response usage and adds only the
@@ -76,6 +83,8 @@ history stores, context-window sizes, compactions, provider-reported status, lat
76
83
  or cost. Continue's internal session format can change without notice, and local token
77
84
  events are not billing data.
78
85
 
86
+ ## Crush
87
+
79
88
  Crush reads its global project registry at
80
89
  `~/.local/share/crush/projects.json` and each registered project's `crush.db`, or a
81
90
  direct copied project/data directory. The adapter was qualified against Crush v0.91.2
@@ -92,8 +101,11 @@ data. Cache and reasoning splits are unavailable. Child agent sessions, costs,
92
101
  attachments, provider-reported latency, and context-window sizes are not collected.
93
102
  The SQLite schema is internal and can change without notice.
94
103
 
104
+ ## Claude Code
105
+
95
106
  Claude Code reads top-level sessions from
96
- `~/.claude/projects/<project>/<session-id>.jsonl` (or `CLAUDE_CONFIG_DIR`). It extracts
107
+ `~/.claude/projects/<project>/<session-id>.jsonl`. A custom `CLAUDE_CONFIG_DIR` must
108
+ be passed with `--source`. It extracts
97
109
  main-session turns, models, token usage, tool names, and compaction timestamps while
98
110
  discarding prompts, responses, tool inputs/results, paths, branches, and arbitrary
99
111
  metadata. Streaming fragments are deduplicated by request or message identifier.
@@ -105,6 +117,8 @@ is not billing data. This first increment does not collect subagent transcripts,
105
117
  context-window sizes, effort/service-tier settings, TTFT, provider-reported duration,
106
118
  or technical work-item intervals.
107
119
 
120
+ ## Gemini CLI
121
+
108
122
  Gemini CLI reads automatic session history from
109
123
  `~/.gemini/tmp/<project-hash>/chats/session-*.jsonl` and the legacy `.json` form. It
110
124
  replays append-only message updates, metadata checkpoints, and rewinds before extracting
@@ -122,6 +136,8 @@ context-window sizes, configuration labels, tool outcomes, or provider-reported
122
136
  durations. Gemini CLI's internal history schema can change without notice, and local
123
137
  token events are not billing data.
124
138
 
139
+ ## Goose
140
+
125
141
  Goose reads `sessions.db` from its sessions directory (normally
126
142
  `~/.local/share/goose/sessions/`). The adapter was qualified against Goose v1.47.0
127
143
  and schema v16. It extracts visible user turns, per-request model and token usage,
@@ -139,6 +155,8 @@ collect parent/subagent relationships, context-window sizes, reasoning tokens,
139
155
  provider-reported latency, or cost. Goose's internal schema can change without notice,
140
156
  and local token events are not billing data.
141
157
 
158
+ ## Grok Build
159
+
142
160
  Grok Build reads session directories under
143
161
  `~/.grok/sessions/<encoded-cwd>/<session-id>/`. It extracts stable session and
144
162
  prompt identifiers, timestamps, terminal turn status, model labels, per-turn
@@ -161,6 +179,8 @@ collected. The adapter was qualified against the open-source Grok Build session
161
179
  schema in August 2026. Local usage events are not billing records, and the
162
180
  internal format can change without notice.
163
181
 
182
+ ## OpenCode
183
+
164
184
  OpenCode reads `opencode.db` from its XDG data directory (normally
165
185
  `~/.local/share/opencode/`). It extracts v2 session messages, model references, token
166
186
  usage, tool names, and compaction timestamps while discarding message text, reasoning,
@@ -174,6 +194,8 @@ components. The adapter does not currently read pre-v2 JSON storage, legacy
174
194
  provider-reported cost. The SQLite schema is internal and may change without notice;
175
195
  local token events are not billing data.
176
196
 
197
+ ## OpenHands CLI
198
+
177
199
  OpenHands CLI reads SDK conversation persistence from
178
200
  `~/.openhands/conversations/<conversation-id>/`, including `base_state.json` and
179
201
  individual event JSON files. The adapter was qualified against OpenHands CLI v1.16.0
@@ -193,6 +215,8 @@ adapter does not collect cloud-only conversations, delegate relationships, cost,
193
215
  critic data, tool outcomes, or provider-reported response latency. OpenHands SDK
194
216
  persistence can change without notice, and local token events are not billing data.
195
217
 
218
+ ## Kilo Code
219
+
196
220
  Kilo Code reads `kilo.db` from its data directory (normally
197
221
  `~/.local/share/kilo/`). The adapter was qualified against Kilo Code CLI v7.5.5 and
198
222
  the matching current `session`, `message`, and `part` schema. It extracts user turns,
@@ -209,6 +233,8 @@ a non-default database, which must be passed explicitly with `--source`. Kilo Co
209
233
  SQLite schema can change without notice, and its local token events are not billing
210
234
  data.
211
235
 
236
+ ## Pi
237
+
212
238
  Pi reads session JSONL files under `~/.pi/agent/sessions/` (or copied agent
213
239
  directories). It extracts user turns, assistant and compaction model calls, provider
214
240
  and model identifiers, token usage, tool names, thinking-level changes, and compaction
@@ -224,6 +250,8 @@ session directories automatically, context-window sizes, costs, branch relations
224
250
  or provider-reported durations. Pi's JSONL schema can change without notice, and its
225
251
  local token events are not billing data.
226
252
 
253
+ ## GitHub Copilot CLI
254
+
227
255
  GitHub Copilot CLI reads session event logs from
228
256
  `~/.copilot/session-state/<session-id>/events.jsonl`. The adapter was qualified
229
257
  against GitHub Copilot CLI v1.0.80 and session event schema v1. It extracts root
@@ -245,8 +273,11 @@ cloud sessions, subagent relationships, context-window samples, cost, or billing
245
273
  data. The local session schema can change without notice, and local token aggregates
246
274
  are not billing records.
247
275
 
276
+ ## Qwen Code
277
+
248
278
  Qwen Code reads active session transcripts from
249
- `~/.qwen/projects/<project-id>/chats/<session-id>.jsonl` (or `QWEN_HOME`). It
279
+ `~/.qwen/projects/<project-id>/chats/<session-id>.jsonl`. A custom `QWEN_HOME` must
280
+ be passed with `--source`. It
250
281
  follows the latest `uuid`/`parentUuid` branch so turns abandoned by rewind are not
251
282
  counted, and extracts user turns, assistant model calls, token usage, context-window
252
283
  sizes, function-call names, and chat-compression timestamps. Prompts, responses,
@@ -264,6 +295,8 @@ input is unavailable in the serialized metadata. This adapter was qualified agai
264
295
  Qwen Code v0.22.2. Its internal transcript schema can change without notice, and local
265
296
  token events are not billing data.
266
297
 
298
+ ## Aider
299
+
267
300
  Aider reads an explicitly configured local analytics log named `analytics.jsonl` (for
268
301
  example, `AIDER_ANALYTICS_LOG=~/.aider/analytics.jsonl`). It groups events from
269
302
  `launched` through `exit`, extracts message-send attempts, model identifiers, and
@@ -280,6 +313,8 @@ identifier. Unknown custom model names may already be represented as
280
313
  `provider/REDACTED` by Aider. Its analytics event schema can change without notice,
281
314
  and local token events are not billing data.
282
315
 
316
+ ## Amp
317
+
283
318
  Amp reads thread JSON files under `~/.local/share/amp/threads/`. It extracts visible
284
319
  user turns, assistant model calls, per-inference token usage, tool names, and context
285
320
  window samples while discarding titles, prompts, responses, thinking, tool
@@ -297,6 +332,8 @@ collect thread content, subthread relationships, compaction markers, reasoning-t
297
332
  splits, costs, credits, or provider-reported latency. Amp's local mirror format is
298
333
  internal and can change without notice, and local token events are not billing data.
299
334
 
335
+ ## Cline CLI
336
+
300
337
  Cline CLI reads `~/.cline/data/sessions/sessions.db` and the referenced
301
338
  `*.messages.json` artifacts. It extracts session timestamps/status, configured model,
302
339
  visible user-turn boundaries, per-assistant token metrics, and tool names while
@@ -306,6 +343,8 @@ and writes; normalized uncached input is the non-negative remainder. Model and e
306
343
  timestamps come from each assistant artifact when present. The adapter was qualified
307
344
  against Cline CLI's current SDK session schema in August 2026.
308
345
 
346
+ ## Kimi Code CLI
347
+
309
348
  Kimi Code CLI reads `~/.kimi/sessions/*/*/wire.jsonl`. It extracts turn boundaries,
310
349
  step token usage, tool names, context-window samples, and completed compactions while
311
350
  discarding user input, model output, reasoning, tool arguments/results, approvals,
@@ -313,6 +352,8 @@ notifications, subagent payloads, paths, and arbitrary events. The wire log does
313
352
  persist the selected model label, so calls use `unknown`; hashed work-directory keys
314
353
  are not reversed. The adapter targets Wire v1 as qualified in August 2026.
315
354
 
355
+ ## Amazon Q Developer CLI
356
+
316
357
  Amazon Q Developer CLI reads persistent conversations from
317
358
  `~/.local/share/amazon-q/data.sqlite3`. It extracts user-turn timestamps, model labels,
318
359
  tool names, and request timing while discarding prompts, responses, transcripts,
@@ -322,6 +363,8 @@ conversation state contains no token counters, so all normalized token values ar
322
363
  Non-persistent sessions are unavailable. The adapter targets the current conversations
323
364
  table and serialized state format as qualified in August 2026.
324
365
 
366
+ ## Plandex
367
+
325
368
  Plandex reads an offline copy of a self-hosted server's `PLANDEX_BASE_DIR`, specifically
326
369
  `orgs/*/plans/*/conversation/*.json`. It extracts stable plan/message identifiers,
327
370
  timestamps, roles, stop status, and provider-reported per-message token totals while