cctrail 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.
- cctrail-0.1.0/.github/workflows/main.yml +70 -0
- cctrail-0.1.0/.github/workflows/pull.yml +25 -0
- cctrail-0.1.0/.gitignore +6 -0
- cctrail-0.1.0/LICENSE +21 -0
- cctrail-0.1.0/Makefile +28 -0
- cctrail-0.1.0/PKG-INFO +233 -0
- cctrail-0.1.0/cctrail/__init__.py +37 -0
- cctrail-0.1.0/cctrail/claude.py +450 -0
- cctrail-0.1.0/cctrail/cli.py +743 -0
- cctrail-0.1.0/cctrail/codex.py +579 -0
- cctrail-0.1.0/cctrail/config.py +184 -0
- cctrail-0.1.0/cctrail/history.py +33 -0
- cctrail-0.1.0/cctrail/metrics.py +393 -0
- cctrail-0.1.0/cctrail/models.py +147 -0
- cctrail-0.1.0/cctrail/pricing.json +334 -0
- cctrail-0.1.0/cctrail/pricing.py +167 -0
- cctrail-0.1.0/cctrail/py.typed +0 -0
- cctrail-0.1.0/cctrail/utils.py +163 -0
- cctrail-0.1.0/cctrail/week.py +75 -0
- cctrail-0.1.0/changelog.md +16 -0
- cctrail-0.1.0/pyproject.toml +40 -0
- cctrail-0.1.0/readme.md +221 -0
- cctrail-0.1.0/scripts/update-pricing.py +71 -0
- cctrail-0.1.0/tests/fixtures/claude/projects/testproj/s-main-1/subagents/agent-a-explore-1.jsonl +5 -0
- cctrail-0.1.0/tests/fixtures/claude/projects/testproj/s-main-1.jsonl +13 -0
- cctrail-0.1.0/tests/fixtures/claude_dedupe/projects/testproj/copy.jsonl +1 -0
- cctrail-0.1.0/tests/fixtures/claude_dedupe/projects/testproj/main/subagents/agent-side.jsonl +2 -0
- cctrail-0.1.0/tests/fixtures/claude_dedupe/projects/testproj/main.jsonl +2 -0
- cctrail-0.1.0/tests/fixtures/codex/session_index.jsonl +2 -0
- cctrail-0.1.0/tests/fixtures/codex/sessions/2026/01/03/rollout-agent.jsonl +11 -0
- cctrail-0.1.0/tests/fixtures/codex/sessions/2026/01/03/rollout-fork.jsonl +9 -0
- cctrail-0.1.0/tests/fixtures/codex/sessions/2026/01/03/rollout-main.jsonl +16 -0
- cctrail-0.1.0/tests/test_claude.py +222 -0
- cctrail-0.1.0/tests/test_cli.py +486 -0
- cctrail-0.1.0/tests/test_codex.py +241 -0
- cctrail-0.1.0/tests/test_config.py +219 -0
- cctrail-0.1.0/tests/test_metrics.py +276 -0
- cctrail-0.1.0/tests/test_pricing.py +108 -0
- cctrail-0.1.0/tests/test_serialize.py +88 -0
- cctrail-0.1.0/tests/test_week.py +65 -0
- cctrail-0.1.0/uv.lock +434 -0
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
name: main
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
tags: ["v*"]
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
test:
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
continue-on-error: ${{ matrix.python-version == '3.15' }}
|
|
15
|
+
strategy:
|
|
16
|
+
fail-fast: false
|
|
17
|
+
matrix:
|
|
18
|
+
python-version: ["3.11", "3.12", "3.13", "3.14", "3.15"]
|
|
19
|
+
steps:
|
|
20
|
+
- uses: actions/checkout@v7
|
|
21
|
+
- uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
|
|
22
|
+
with:
|
|
23
|
+
python-version: ${{ matrix.python-version }}
|
|
24
|
+
|
|
25
|
+
- run: uv sync --frozen
|
|
26
|
+
- run: make check
|
|
27
|
+
- run: make test
|
|
28
|
+
|
|
29
|
+
release:
|
|
30
|
+
if: ${{ startsWith(github.ref, 'refs/tags/v') }}
|
|
31
|
+
runs-on: ubuntu-latest
|
|
32
|
+
needs: test
|
|
33
|
+
permissions:
|
|
34
|
+
contents: write
|
|
35
|
+
id-token: write
|
|
36
|
+
steps:
|
|
37
|
+
- uses: actions/checkout@v7
|
|
38
|
+
- uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
|
|
39
|
+
|
|
40
|
+
- name: Check pyproject.toml version matches tag
|
|
41
|
+
run: |
|
|
42
|
+
TAG="${{ github.ref_name }}"
|
|
43
|
+
PKG_VERSION="v$(grep '^version = ' pyproject.toml | cut -d'"' -f2)"
|
|
44
|
+
if [ "$TAG" != "$PKG_VERSION" ]; then
|
|
45
|
+
echo "Error: tag ${TAG} does not match pyproject.toml version ${PKG_VERSION}"
|
|
46
|
+
exit 1
|
|
47
|
+
fi
|
|
48
|
+
|
|
49
|
+
- name: Prepare README for PyPI
|
|
50
|
+
run: |
|
|
51
|
+
BASE_URL="https://raw.githubusercontent.com/${{ github.repository }}/${{ github.ref_name }}"
|
|
52
|
+
sed -i "s#src=\"\\.github/#src=\"${BASE_URL}/.github/#g" readme.md
|
|
53
|
+
|
|
54
|
+
- run: uv build
|
|
55
|
+
|
|
56
|
+
- name: Extract changelog entry
|
|
57
|
+
run: |
|
|
58
|
+
VERSION="${{ github.ref_name }}"
|
|
59
|
+
NOTES=$(awk "/^## ${VERSION}/{found=1; next} /^## /{found=0} found && !/^---$/" changelog.md)
|
|
60
|
+
if [ -z "$NOTES" ]; then
|
|
61
|
+
echo "Error: no changelog entry found for ${VERSION}"
|
|
62
|
+
exit 1
|
|
63
|
+
fi
|
|
64
|
+
echo "$NOTES" > release_notes.txt
|
|
65
|
+
|
|
66
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
67
|
+
|
|
68
|
+
- run: gh release create ${{ github.ref_name }} --title ${{ github.ref_name }} --notes-file release_notes.txt
|
|
69
|
+
env:
|
|
70
|
+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
name: pull
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
|
|
6
|
+
permissions:
|
|
7
|
+
contents: read
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
continue-on-error: ${{ matrix.python-version == '3.15' }}
|
|
13
|
+
strategy:
|
|
14
|
+
fail-fast: false
|
|
15
|
+
matrix:
|
|
16
|
+
python-version: ["3.11", "3.12", "3.13", "3.14", "3.15"]
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v7
|
|
19
|
+
- uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
|
|
20
|
+
with:
|
|
21
|
+
python-version: ${{ matrix.python-version }}
|
|
22
|
+
|
|
23
|
+
- run: uv sync --frozen
|
|
24
|
+
- run: make check
|
|
25
|
+
- run: make test
|
cctrail-0.1.0/.gitignore
ADDED
cctrail-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 vladkens
|
|
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 OF OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
cctrail-0.1.0/Makefile
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
.PHONY: prepare lint check test update install
|
|
2
|
+
|
|
3
|
+
prepare: lint check
|
|
4
|
+
|
|
5
|
+
lint:
|
|
6
|
+
uv run ruff check --select I --fix .
|
|
7
|
+
uv run ruff format .
|
|
8
|
+
|
|
9
|
+
check:
|
|
10
|
+
uv run ruff format --check .
|
|
11
|
+
uv run ruff check .
|
|
12
|
+
uv run ty check
|
|
13
|
+
|
|
14
|
+
test:
|
|
15
|
+
uv run pytest -s --cov=cctrail tests/
|
|
16
|
+
|
|
17
|
+
update:
|
|
18
|
+
uv sync --upgrade --all-groups
|
|
19
|
+
uv run --script scripts/update-pricing.py
|
|
20
|
+
|
|
21
|
+
install:
|
|
22
|
+
uv sync
|
|
23
|
+
|
|
24
|
+
perf:
|
|
25
|
+
CCTRAIL_WORKERS=1 /usr/bin/time uv run cctrail groups --provider claude
|
|
26
|
+
CCTRAIL_WORKERS=4 /usr/bin/time uv run cctrail groups --provider claude
|
|
27
|
+
CCTRAIL_WORKERS=1 /usr/bin/time uv run cctrail groups --provider codex
|
|
28
|
+
CCTRAIL_WORKERS=4 /usr/bin/time uv run cctrail groups --provider codex
|
cctrail-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: cctrail
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Parser and analytics toolkit for Claude Code and Codex history
|
|
5
|
+
Author: vladkens
|
|
6
|
+
License: MIT
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Requires-Python: >=3.11
|
|
9
|
+
Requires-Dist: orjson>=3.10.0
|
|
10
|
+
Requires-Dist: rich>=15.0.0
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
|
|
13
|
+
# cctrail
|
|
14
|
+
|
|
15
|
+
<div align="center">
|
|
16
|
+
|
|
17
|
+
[<img src="https://badges.ws/pypi/v/cctrail" alt="version" />](https://pypi.org/project/cctrail)
|
|
18
|
+
[<img src="https://badges.ws/pypi/python/cctrail" alt="py versions" />](https://pypi.org/project/cctrail)
|
|
19
|
+
[<img src="https://badges.ws/pypi/dm/cctrail" alt="downloads" />](https://pypi.org/project/cctrail)
|
|
20
|
+
[<img src="https://badges.ws/github/license/vladkens/cctrail" alt="license" />](https://github.com/vladkens/cctrail/blob/main/LICENSE)
|
|
21
|
+
[<img src="https://badges.ws/badge/-/buy%20me%20a%20coffee/ff813f?icon=buymeacoffee&label" alt="donate" />](https://buymeacoffee.com/vladkens)
|
|
22
|
+
|
|
23
|
+
</div>
|
|
24
|
+
|
|
25
|
+
`cctrail` reads local Claude Code and Codex history and reports token usage, estimated cost, and project statistics. It can also be used as a Python library for working with parsed sessions, messages, tool calls, and agents.
|
|
26
|
+
|
|
27
|
+
```console
|
|
28
|
+
$ uvx cctrail groups today
|
|
29
|
+
Group Projects Sessions Tokens Last active Cost Time
|
|
30
|
+
exp 2 2 32.36M 2026-08-09 $24.00 1h 15m
|
|
31
|
+
wrk 1 1 24.93M 2026-08-09 $19.45 0h 49m
|
|
32
|
+
ungrouped 2 4 20.56M 2026-08-09 $17.31 1h 26m
|
|
33
|
+
oss 1 1 10.35M 2026-08-09 $7.90 0h 31m
|
|
34
|
+
comms 1 1 71.1K 2026-08-09 $0.10 0h 06m
|
|
35
|
+
total 7 9 88.27M 2026-08-09 $68.74 4h 08m
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
```console
|
|
39
|
+
$ uvx cctrail projects today
|
|
40
|
+
Project Sessions Total tokens Last active Cost Time
|
|
41
|
+
~/Code/vibe/cctrail 1 32.04M 2026-08-09 $23.43 1h 10m
|
|
42
|
+
atlas 1 24.93M 2026-08-09 $19.45 0h 49m
|
|
43
|
+
starship 2 17.87M 2026-08-09 $14.37 1h 02m
|
|
44
|
+
~/Code/pub/macmon 1 10.35M 2026-08-09 $7.90 0h 31m
|
|
45
|
+
~/Code/sideproj 2 2.68M 2026-08-09 $2.93 0h 24m
|
|
46
|
+
~/Code/labs 1 322.1K 2026-08-09 $0.57 0h 05m
|
|
47
|
+
~/Code/client-app 1 71.1K 2026-08-09 $0.10 0h 06m
|
|
48
|
+
total 9 88.27M 2026-08-09 $68.74 4h 08m
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
```console
|
|
52
|
+
$ uvx cctrail usage this-month
|
|
53
|
+
Date Input Output Total Cost Time
|
|
54
|
+
2026-08-01 5.75M 1.30M 281.22M $174.00 12h 45m
|
|
55
|
+
2026-08-02 6.93M 780.8K 204.76M $276.40 10h 24m
|
|
56
|
+
2026-08-03 4.88M 338.4K 138.49M $193.10 6h 02m
|
|
57
|
+
2026-08-04 4.55M 693.6K 244.77M $92.25 6h 39m
|
|
58
|
+
2026-08-05 4.43M 444.6K 166.19M $102.47 6h 06m
|
|
59
|
+
2026-08-06 4.52M 226.4K 93.27M $83.17 6h 22m
|
|
60
|
+
2026-08-07 6.15M 631.3K 232.52M $153.22 9h 14m
|
|
61
|
+
2026-08-08 24.5K 4.0K 123.3K $0.31 0h 07m
|
|
62
|
+
2026-08-09 3.06M 196.9K 92.68M $72.05 4h 14m
|
|
63
|
+
total 40.30M 4.61M 1.45B $1146.97 61h 56m
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Why cctrail?
|
|
67
|
+
|
|
68
|
+
Before coding agents, I tracked time with a VS Code extension. That worked while most of the job happened inside the editor. In the new agentic coding era, much of my work happens in terminal sessions instead: I start an agent, review its results, send another prompt, and move between several projects. The editor no longer sees enough of that activity to answer a simple question: where did my time go?
|
|
69
|
+
|
|
70
|
+
I tried several ways to recover that information, and local agent history turned out to be the most useful source. `cctrail` turns it into reports that help explore how agent-assisted work is distributed over time, projects, and configurable groups. Its purpose is broader than any single report: to make the work recorded by coding agents visible and understandable from different perspectives.
|
|
71
|
+
|
|
72
|
+
[ccusage](https://github.com/ccusage/ccusage) is an excellent alternative for ready-made token and cost reports across many coding agents. `cctrail` grew from a different question: not only how many tokens were used, but what I worked on and how my time was divided.
|
|
73
|
+
|
|
74
|
+
## CLI
|
|
75
|
+
|
|
76
|
+
Show token usage by day:
|
|
77
|
+
|
|
78
|
+
```sh
|
|
79
|
+
uvx cctrail usage
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Use named calendar periods and group longer reports by week or month:
|
|
83
|
+
|
|
84
|
+
```sh
|
|
85
|
+
uvx cctrail usage today
|
|
86
|
+
uvx cctrail usage last-week
|
|
87
|
+
uvx cctrail usage this-month --by week
|
|
88
|
+
uvx cctrail usage all --by month
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Available periods are `today`, `yesterday`, `this-week`, `last-week`, `this-month`, `last-month`, and `all`. Weeks follow the first weekday of the system locale.
|
|
92
|
+
|
|
93
|
+
Show a per-model breakdown or the detailed reasoning and cache token columns:
|
|
94
|
+
|
|
95
|
+
```sh
|
|
96
|
+
uvx cctrail usage this-month --models
|
|
97
|
+
uvx cctrail usage this-month --models --full
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
For an arbitrary date range, use `--since` and `--until`:
|
|
101
|
+
|
|
102
|
+
```sh
|
|
103
|
+
uvx cctrail usage --since 2026-07-01 --until 2026-07-31
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Show usage grouped by project directory:
|
|
107
|
+
|
|
108
|
+
```sh
|
|
109
|
+
uvx cctrail projects this-month
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Projects accept the same named periods and arbitrary date ranges as usage reports.
|
|
113
|
+
Paths inside your home directory are shortened to `~/…`; pass `--full` to show absolute paths.
|
|
114
|
+
|
|
115
|
+
Show usage aggregated across configured project groups:
|
|
116
|
+
|
|
117
|
+
```sh
|
|
118
|
+
uvx cctrail groups this-month
|
|
119
|
+
uvx cctrail groups --provider codex
|
|
120
|
+
uvx cctrail groups --json
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Groups accept the same periods, date ranges, and provider filter as project reports. Projects that do not match a configured group are included under `ungrouped`.
|
|
124
|
+
|
|
125
|
+
### Configuration
|
|
126
|
+
|
|
127
|
+
Project aliases can combine a project's main checkout and worktrees into a single project in the report. This is optional: without an alias, `cctrail` reports each path separately.
|
|
128
|
+
|
|
129
|
+
```toml
|
|
130
|
+
[aliases]
|
|
131
|
+
cctrail = ["~/Code/vibe/cctrail", "~/.worktrees/cctrail--*"]
|
|
132
|
+
|
|
133
|
+
[groups]
|
|
134
|
+
personal = ["cctrail", "~/Code/dotfiles"]
|
|
135
|
+
opensource = ["~/Code/pub/**"]
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Alias paths support `~` and glob patterns. `*` matches within one path segment, while `**` can match across directories. A trailing `/**` includes both the named directory and everything below it. For example, `~/.worktrees/cctrail--*` matches sibling worktrees and `~/Code/**/cctrail/**` matches the project at any depth below `~/Code` together with all of its checkouts.
|
|
139
|
+
|
|
140
|
+
Groups are resolved after aliases, so a group can contain an alias such as `cctrail`, an exact project path, or a glob pattern. A project can match only one group.
|
|
141
|
+
|
|
142
|
+
Use `--config` to select a file for one command, or `--no-config` to ignore every TOML configuration:
|
|
143
|
+
|
|
144
|
+
```sh
|
|
145
|
+
uvx cctrail --config ~/configs/work.toml projects
|
|
146
|
+
uvx cctrail --no-config projects
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Configuration is selected in this order:
|
|
150
|
+
|
|
151
|
+
1. `--no-config` disables configuration
|
|
152
|
+
2. `--config PATH` selects a specific file
|
|
153
|
+
3. `./cctrail.toml`
|
|
154
|
+
4. `~/.config/cctrail.toml`
|
|
155
|
+
|
|
156
|
+
An explicitly selected file must exist. The automatic locations are optional.
|
|
157
|
+
|
|
158
|
+
You can also configure every Claude Code and Codex history directory instead of setting `CLAUDE_CONFIG_DIR` or `CODEX_HOME` for each command:
|
|
159
|
+
|
|
160
|
+
```toml
|
|
161
|
+
[sources]
|
|
162
|
+
claude = ["~/.claude", "~/.claude-work"]
|
|
163
|
+
codex = ["~/.codex", "~/.codex-work"]
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
When a provider is present in `[sources]`, its list replaces the default directories. Environment variables still take precedence when set.
|
|
167
|
+
|
|
168
|
+
Claude data is read from `~/.config/claude` and `~/.claude`, while Codex data is read from `~/.codex`. Set `CLAUDE_CONFIG_DIR` or `CODEX_HOME` to replace these defaults. Both variables accept comma-separated directories:
|
|
169
|
+
|
|
170
|
+
```sh
|
|
171
|
+
CLAUDE_CONFIG_DIR="$HOME/.claude,$HOME/.claude-qh" uvx cctrail usage
|
|
172
|
+
CODEX_HOME="$HOME/.codex,$HOME/.codex-work" uvx cctrail usage
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Usage reports count each provider message once, while parsed sessions retain their original message and sub-agent structure. Costs are estimates based on the pricing catalog embedded in the installed cctrail version.
|
|
176
|
+
|
|
177
|
+
Active time is estimated by treating every activity event as a five-minute window. Overlapping sessions within a project are merged; when several projects are active at once, that time is divided evenly between them. This keeps the project and group totals equal to the overall active time.
|
|
178
|
+
|
|
179
|
+
## Python library
|
|
180
|
+
|
|
181
|
+
Add `cctrail` to a project:
|
|
182
|
+
|
|
183
|
+
```sh
|
|
184
|
+
uv add cctrail
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
Iterate over parsed sessions:
|
|
188
|
+
|
|
189
|
+
```python
|
|
190
|
+
from cctrail import iter_sessions, tool_call_counts
|
|
191
|
+
|
|
192
|
+
for session in iter_sessions():
|
|
193
|
+
print(session.provider, session.cwd, session.title, session.usage.total)
|
|
194
|
+
|
|
195
|
+
for call in session.iter_tool_calls():
|
|
196
|
+
print(call.name, call.input, call.duration)
|
|
197
|
+
|
|
198
|
+
for agent in session.iter_agents():
|
|
199
|
+
print(agent.agent_type, agent.usage.total)
|
|
200
|
+
|
|
201
|
+
print(tool_call_counts(session))
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
Provider-specific iterators are available as `iter_claude_sessions()` and `iter_codex_sessions()`. Sub-agent transcripts are attached to the tool call that launched them.
|
|
205
|
+
|
|
206
|
+
The main data types are `Session`, `Message`, `ToolCall`, and `Usage`. Every model supports `.as_dict()` and `.as_json()`.
|
|
207
|
+
|
|
208
|
+
```python
|
|
209
|
+
from cctrail import Usage, by_project, calculate_cost, get_pricing, iter_sessions, usage_by_period
|
|
210
|
+
|
|
211
|
+
sessions = list(iter_sessions())
|
|
212
|
+
weekly = usage_by_period(sessions, granularity="week")
|
|
213
|
+
projects = by_project(sessions)
|
|
214
|
+
|
|
215
|
+
pricing = get_pricing("claude-sonnet-5")
|
|
216
|
+
cost = calculate_cost("claude-sonnet-5", Usage(input=1_000, output=100))
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
Usage is grouped in the system timezone by default. `usage_by_period()` accepts `day`, `week`, and `month` granularities, while `usage_by_day()` remains the daily shortcut. Pass a `datetime.tzinfo` as the `timezone` argument to use another timezone. `UsageSummary` values expose `.cost`, `.active_time`, and per-model `.models`; `ProjectSummary` values expose `.cost` and `.active_time`.
|
|
220
|
+
|
|
221
|
+
## Development
|
|
222
|
+
|
|
223
|
+
The project requires Python 3.11 or newer and uses [uv](https://docs.astral.sh/uv/).
|
|
224
|
+
|
|
225
|
+
```sh
|
|
226
|
+
uv sync
|
|
227
|
+
make check
|
|
228
|
+
make test
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
## License
|
|
232
|
+
|
|
233
|
+
Distributed under the [MIT License](LICENSE).
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
from .claude import iter_sessions as iter_claude_sessions
|
|
2
|
+
from .codex import iter_sessions as iter_codex_sessions
|
|
3
|
+
from .history import iter_sessions
|
|
4
|
+
from .metrics import (
|
|
5
|
+
ModelSummary,
|
|
6
|
+
ProjectSummary,
|
|
7
|
+
UsageSummary,
|
|
8
|
+
active_time,
|
|
9
|
+
by_project,
|
|
10
|
+
tool_call_counts,
|
|
11
|
+
usage_by_day,
|
|
12
|
+
usage_by_period,
|
|
13
|
+
)
|
|
14
|
+
from .models import JsonTrait, Message, Session, ToolCall, Usage
|
|
15
|
+
from .pricing import Pricing, calculate_cost, get_pricing
|
|
16
|
+
|
|
17
|
+
__all__ = [
|
|
18
|
+
"JsonTrait",
|
|
19
|
+
"Message",
|
|
20
|
+
"ModelSummary",
|
|
21
|
+
"Pricing",
|
|
22
|
+
"ProjectSummary",
|
|
23
|
+
"Session",
|
|
24
|
+
"ToolCall",
|
|
25
|
+
"Usage",
|
|
26
|
+
"UsageSummary",
|
|
27
|
+
"active_time",
|
|
28
|
+
"by_project",
|
|
29
|
+
"calculate_cost",
|
|
30
|
+
"get_pricing",
|
|
31
|
+
"iter_claude_sessions",
|
|
32
|
+
"iter_codex_sessions",
|
|
33
|
+
"iter_sessions",
|
|
34
|
+
"tool_call_counts",
|
|
35
|
+
"usage_by_day",
|
|
36
|
+
"usage_by_period",
|
|
37
|
+
]
|