tokentrail 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.
- tokentrail-0.1.0/LICENSE +202 -0
- tokentrail-0.1.0/NOTICE +4 -0
- tokentrail-0.1.0/PKG-INFO +423 -0
- tokentrail-0.1.0/README.md +388 -0
- tokentrail-0.1.0/pyproject.toml +80 -0
- tokentrail-0.1.0/setup.cfg +4 -0
- tokentrail-0.1.0/src/tokentrail/__init__.py +3 -0
- tokentrail-0.1.0/src/tokentrail/__main__.py +3 -0
- tokentrail-0.1.0/src/tokentrail/adapters/__init__.py +21 -0
- tokentrail-0.1.0/src/tokentrail/adapters/base.py +34 -0
- tokentrail-0.1.0/src/tokentrail/adapters/claude_code.py +126 -0
- tokentrail-0.1.0/src/tokentrail/adapters/generic_jsonl.py +62 -0
- tokentrail-0.1.0/src/tokentrail/analytics.py +111 -0
- tokentrail-0.1.0/src/tokentrail/cli.py +318 -0
- tokentrail-0.1.0/src/tokentrail/config.py +61 -0
- tokentrail-0.1.0/src/tokentrail/emit.py +78 -0
- tokentrail-0.1.0/src/tokentrail/git_collector.py +99 -0
- tokentrail-0.1.0/src/tokentrail/mirror.py +206 -0
- tokentrail-0.1.0/src/tokentrail/models.py +109 -0
- tokentrail-0.1.0/src/tokentrail/pricing.py +62 -0
- tokentrail-0.1.0/src/tokentrail/segment.py +153 -0
- tokentrail-0.1.0/src/tokentrail/server.py +75 -0
- tokentrail-0.1.0/src/tokentrail/service.py +104 -0
- tokentrail-0.1.0/src/tokentrail/state.py +83 -0
- tokentrail-0.1.0/src/tokentrail/static/dashboard.html +499 -0
- tokentrail-0.1.0/src/tokentrail/store.py +182 -0
- tokentrail-0.1.0/src/tokentrail/sync.py +109 -0
- tokentrail-0.1.0/src/tokentrail.egg-info/PKG-INFO +423 -0
- tokentrail-0.1.0/src/tokentrail.egg-info/SOURCES.txt +32 -0
- tokentrail-0.1.0/src/tokentrail.egg-info/dependency_links.txt +1 -0
- tokentrail-0.1.0/src/tokentrail.egg-info/entry_points.txt +2 -0
- tokentrail-0.1.0/src/tokentrail.egg-info/requires.txt +14 -0
- tokentrail-0.1.0/src/tokentrail.egg-info/top_level.txt +1 -0
- tokentrail-0.1.0/tests/test_telemetry.py +531 -0
tokentrail-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
|
|
2
|
+
Apache License
|
|
3
|
+
Version 2.0, January 2004
|
|
4
|
+
http://www.apache.org/licenses/
|
|
5
|
+
|
|
6
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
7
|
+
|
|
8
|
+
1. Definitions.
|
|
9
|
+
|
|
10
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
11
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
12
|
+
|
|
13
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
14
|
+
the copyright owner that is granting the License.
|
|
15
|
+
|
|
16
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
17
|
+
other entities that control, are controlled by, or are under common
|
|
18
|
+
control with that entity. For the purposes of this definition,
|
|
19
|
+
"control" means (i) the power, direct or indirect, to cause the
|
|
20
|
+
direction or management of such entity, whether by contract or
|
|
21
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
22
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
23
|
+
|
|
24
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
25
|
+
exercising permissions granted by this License.
|
|
26
|
+
|
|
27
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
28
|
+
including but not limited to software source code, documentation
|
|
29
|
+
source, and configuration files.
|
|
30
|
+
|
|
31
|
+
"Object" form shall mean any form resulting from mechanical
|
|
32
|
+
transformation or translation of a Source form, including but
|
|
33
|
+
not limited to compiled object code, generated documentation,
|
|
34
|
+
and conversions to other media types.
|
|
35
|
+
|
|
36
|
+
"Work" shall mean the work of authorship, whether in Source or
|
|
37
|
+
Object form, made available under the License, as indicated by a
|
|
38
|
+
copyright notice that is included in or attached to the work
|
|
39
|
+
(an example is provided in the Appendix below).
|
|
40
|
+
|
|
41
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
42
|
+
form, that is based on (or derived from) the Work and for which the
|
|
43
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
44
|
+
represent, as a whole, an original work of authorship. For the purposes
|
|
45
|
+
of this License, Derivative Works shall not include works that remain
|
|
46
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
|
47
|
+
the Work and Derivative Works thereof.
|
|
48
|
+
|
|
49
|
+
"Contribution" shall mean any work of authorship, including
|
|
50
|
+
the original version of the Work and any modifications or additions
|
|
51
|
+
to that Work or Derivative Works thereof, that is intentionally
|
|
52
|
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
53
|
+
or by an individual or Legal Entity authorized to submit on behalf of
|
|
54
|
+
the copyright owner. For the purposes of this definition, "submitted"
|
|
55
|
+
means any form of electronic, verbal, or written communication sent
|
|
56
|
+
to the Licensor or its representatives, including but not limited to
|
|
57
|
+
communication on electronic mailing lists, source code control systems,
|
|
58
|
+
and issue tracking systems that are managed by, or on behalf of, the
|
|
59
|
+
Licensor for the purpose of discussing and improving the Work, but
|
|
60
|
+
excluding communication that is conspicuously marked or otherwise
|
|
61
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
|
62
|
+
|
|
63
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
64
|
+
on behalf of whom a Contribution has been received by Licensor and
|
|
65
|
+
subsequently incorporated within the Work.
|
|
66
|
+
|
|
67
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
68
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
69
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
70
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
71
|
+
publicly display, publicly perform, sublicense, and distribute the
|
|
72
|
+
Work and such Derivative Works in Source or Object form.
|
|
73
|
+
|
|
74
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
75
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
76
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
77
|
+
(except as stated in this section) patent license to make, have made,
|
|
78
|
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
79
|
+
where such license applies only to those patent claims licensable
|
|
80
|
+
by such Contributor that are necessarily infringed by their
|
|
81
|
+
Contribution(s) alone or by combination of their Contribution(s)
|
|
82
|
+
with the Work to which such Contribution(s) was submitted. If You
|
|
83
|
+
institute patent litigation against any entity (including a
|
|
84
|
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
85
|
+
or a Contribution incorporated within the Work constitutes direct
|
|
86
|
+
or contributory patent infringement, then any patent licenses
|
|
87
|
+
granted to You under this License for that Work shall terminate
|
|
88
|
+
as of the date such litigation is filed.
|
|
89
|
+
|
|
90
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
|
91
|
+
Work or Derivative Works thereof in any medium, with or without
|
|
92
|
+
modifications, and in Source or Object form, provided that You
|
|
93
|
+
meet the following conditions:
|
|
94
|
+
|
|
95
|
+
(a) You must give any other recipients of the Work or
|
|
96
|
+
Derivative Works a copy of this License; and
|
|
97
|
+
|
|
98
|
+
(b) You must cause any modified files to carry prominent notices
|
|
99
|
+
stating that You changed the files; and
|
|
100
|
+
|
|
101
|
+
(c) You must retain, in the Source form of any Derivative Works
|
|
102
|
+
that You distribute, all copyright, patent, trademark, and
|
|
103
|
+
attribution notices from the Source form of the Work,
|
|
104
|
+
excluding those notices that do not pertain to any part of
|
|
105
|
+
the Derivative Works; and
|
|
106
|
+
|
|
107
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
108
|
+
distribution, then any Derivative Works that You distribute must
|
|
109
|
+
include a readable copy of the attribution notices contained
|
|
110
|
+
within such NOTICE file, excluding those notices that do not
|
|
111
|
+
pertain to any part of the Derivative Works, in at least one
|
|
112
|
+
of the following places: within a NOTICE text file distributed
|
|
113
|
+
as part of the Derivative Works; within the Source form or
|
|
114
|
+
documentation, if provided along with the Derivative Works; or,
|
|
115
|
+
within a display generated by the Derivative Works, if and
|
|
116
|
+
wherever such third-party notices normally appear. The contents
|
|
117
|
+
of the NOTICE file are for informational purposes only and
|
|
118
|
+
do not modify the License. You may add Your own attribution
|
|
119
|
+
notices within Derivative Works that You distribute, alongside
|
|
120
|
+
or as an addendum to the NOTICE text from the Work, provided
|
|
121
|
+
that such additional attribution notices cannot be construed
|
|
122
|
+
as modifying the License.
|
|
123
|
+
|
|
124
|
+
You may add Your own copyright statement to Your modifications and
|
|
125
|
+
may provide additional or different license terms and conditions
|
|
126
|
+
for use, reproduction, or distribution of Your modifications, or
|
|
127
|
+
for any such Derivative Works as a whole, provided Your use,
|
|
128
|
+
reproduction, and distribution of the Work otherwise complies with
|
|
129
|
+
the conditions stated in this License.
|
|
130
|
+
|
|
131
|
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
132
|
+
any Contribution intentionally submitted for inclusion in the Work
|
|
133
|
+
by You to the Licensor shall be under the terms and conditions of
|
|
134
|
+
this License, without any additional terms or conditions.
|
|
135
|
+
Notwithstanding the above, nothing herein shall supersede or modify
|
|
136
|
+
the terms of any separate license agreement you may have executed
|
|
137
|
+
with Licensor regarding such Contributions.
|
|
138
|
+
|
|
139
|
+
6. Trademarks. This License does not grant permission to use the trade
|
|
140
|
+
names, trademarks, service marks, or product names of the Licensor,
|
|
141
|
+
except as required for reasonable and customary use in describing the
|
|
142
|
+
origin of the Work and reproducing the content of the NOTICE file.
|
|
143
|
+
|
|
144
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
145
|
+
agreed to in writing, Licensor provides the Work (and each
|
|
146
|
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
147
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
148
|
+
implied, including, without limitation, any warranties or conditions
|
|
149
|
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
150
|
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
151
|
+
appropriateness of using or redistributing the Work and assume any
|
|
152
|
+
risks associated with Your exercise of permissions under this License.
|
|
153
|
+
|
|
154
|
+
8. Limitation of Liability. In no event and under no legal theory,
|
|
155
|
+
whether in tort (including negligence), contract, or otherwise,
|
|
156
|
+
unless required by applicable law (such as deliberate and grossly
|
|
157
|
+
negligent acts) or agreed to in writing, shall any Contributor be
|
|
158
|
+
liable to You for damages, including any direct, indirect, special,
|
|
159
|
+
incidental, or consequential damages of any character arising as a
|
|
160
|
+
result of this License or out of the use or inability to use the
|
|
161
|
+
Work (including but not limited to damages for loss of goodwill,
|
|
162
|
+
work stoppage, computer failure or malfunction, or any and all
|
|
163
|
+
other commercial damages or losses), even if such Contributor
|
|
164
|
+
has been advised of the possibility of such damages.
|
|
165
|
+
|
|
166
|
+
9. Accepting Warranty or Additional Liability. While redistributing
|
|
167
|
+
the Work or Derivative Works thereof, You may choose to offer,
|
|
168
|
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
169
|
+
or other liability obligations and/or rights consistent with this
|
|
170
|
+
License. However, in accepting such obligations, You may act only
|
|
171
|
+
on Your own behalf and on Your sole responsibility, not on behalf
|
|
172
|
+
of any other Contributor, and only if You agree to indemnify,
|
|
173
|
+
defend, and hold each Contributor harmless for any liability
|
|
174
|
+
incurred by, or claims asserted against, such Contributor by reason
|
|
175
|
+
of your accepting any such warranty or additional liability.
|
|
176
|
+
|
|
177
|
+
END OF TERMS AND CONDITIONS
|
|
178
|
+
|
|
179
|
+
APPENDIX: How to apply the Apache License to your work.
|
|
180
|
+
|
|
181
|
+
To apply the Apache License to your work, attach the following
|
|
182
|
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
183
|
+
replaced with your own identifying information. (Don't include
|
|
184
|
+
the brackets!) The text should be enclosed in the appropriate
|
|
185
|
+
comment syntax for the file format. We also recommend that a
|
|
186
|
+
file or class name and description of purpose be included on the
|
|
187
|
+
same "printed page" as the copyright notice for easier
|
|
188
|
+
identification within third-party archives.
|
|
189
|
+
|
|
190
|
+
Copyright [yyyy] [name of copyright owner]
|
|
191
|
+
|
|
192
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
193
|
+
you may not use this file except in compliance with the License.
|
|
194
|
+
You may obtain a copy of the License at
|
|
195
|
+
|
|
196
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
197
|
+
|
|
198
|
+
Unless required by applicable law or agreed to in writing, software
|
|
199
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
200
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
201
|
+
See the License for the specific language governing permissions and
|
|
202
|
+
limitations under the License.
|
tokentrail-0.1.0/NOTICE
ADDED
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: tokentrail
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Local telemetry and dashboard for AI coding agents: tokens, tools, skills, health and shipped code.
|
|
5
|
+
Author: Sunil Bodeddula
|
|
6
|
+
License-Expression: Apache-2.0
|
|
7
|
+
Project-URL: Homepage, https://github.com/sunil-bodeddula-pro/tokentrail
|
|
8
|
+
Project-URL: Issues, https://github.com/sunil-bodeddula-pro/tokentrail/issues
|
|
9
|
+
Keywords: ai-agents,observability,telemetry,llm,claude-code,dashboard,tokens
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Environment :: Console
|
|
12
|
+
Classifier: Environment :: Web Environment
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
19
|
+
Classifier: Topic :: System :: Monitoring
|
|
20
|
+
Requires-Python: >=3.12
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
License-File: NOTICE
|
|
24
|
+
Provides-Extra: gcs
|
|
25
|
+
Requires-Dist: google-cloud-storage>=2.10; extra == "gcs"
|
|
26
|
+
Provides-Extra: s3
|
|
27
|
+
Requires-Dist: boto3>=1.28; extra == "s3"
|
|
28
|
+
Provides-Extra: all
|
|
29
|
+
Requires-Dist: google-cloud-storage>=2.10; extra == "all"
|
|
30
|
+
Requires-Dist: boto3>=1.28; extra == "all"
|
|
31
|
+
Provides-Extra: dev
|
|
32
|
+
Requires-Dist: ruff>=0.17; extra == "dev"
|
|
33
|
+
Requires-Dist: mypy>=2.4; extra == "dev"
|
|
34
|
+
Dynamic: license-file
|
|
35
|
+
|
|
36
|
+
# TokenTrail
|
|
37
|
+
|
|
38
|
+
[](https://github.com/sunil-bodeddula-pro/tokentrail/actions/workflows/ci.yml)
|
|
39
|
+
[](LICENSE)
|
|
40
|
+
|
|
41
|
+
**See what your AI agents actually do with your tokens.** TokenTrail is local-first observability for AI agents. It shows how they spend tokens, call tools and load skills, where they get stuck, and how all of that turns into shipped code. It runs on your own machine.
|
|
42
|
+
|
|
43
|
+

|
|
44
|
+
|
|
45
|
+
<sub>All screenshots use the [demo data](#try-it-with-demo-data), not real sessions.</sub>
|
|
46
|
+
|
|
47
|
+
## Why TokenTrail?
|
|
48
|
+
|
|
49
|
+
AI coding agents now do a lot of real work, but most of it happens out of sight. A session runs for twenty minutes, burns half a million tokens, and you only see the final answer. Was it efficient? Did it loop on a failing test? Did it ever use the skill you wrote for exactly this task? Is the expensive model worth it for this kind of work? And when the agent's history is cleared, the evidence is gone too.
|
|
50
|
+
|
|
51
|
+
TokenTrail answers those questions from data your agents already leave on disk, without changing how you work.
|
|
52
|
+
|
|
53
|
+
## What it does
|
|
54
|
+
|
|
55
|
+
1. **Collects** each agent's local session logs as they're written. Claude Code works out of the box, and any other agent can write a simple [JSON-lines event format](docs/event-format.md).
|
|
56
|
+
2. **Keeps its own record** in a store of plain JSON files, synced every 30 seconds. Clearing an agent's history loses nothing, and nothing is parsed twice.
|
|
57
|
+
3. **Measures every request:** tokens (input, output, cache reads and writes, reasoning), cache hit rate, estimated cost, steps, tool calls and errors, file writes, skills and subagents.
|
|
58
|
+
4. **Classifies each run's health:** High-Velocity, Positive, Tool Loops, Wandering (lots of steps, nothing written) or High Error Rate. You can see at a glance which requests went well and which didn't.
|
|
59
|
+
5. **Connects agent work to shipped code** by reading the git history of the repositories the agents worked in: your commits, AI-credited commits, linked issues, and tokens and cost per commit.
|
|
60
|
+
6. **Shows it all on a local dashboard,** with filters by time, agent, model, outcome and machine, ten charts, a searchable session table, and an inspector for every run.
|
|
61
|
+
7. **Optionally mirrors the store** to Google Cloud Storage, S3 or a shared folder, so you can see several machines in one place. Prompt text is removed before upload.
|
|
62
|
+
|
|
63
|
+
## Questions it answers
|
|
64
|
+
|
|
65
|
+
| Question | Where to look |
|
|
66
|
+
| :--- | :--- |
|
|
67
|
+
| How much are my agents costing me, and is prompt caching working? | Tokens consumed card (cache hit %, estimated cost), Token anatomy |
|
|
68
|
+
| Which requests went badly, and why? | Session health chart, the Health filter, the inspector (longest repeat, errors, writes) |
|
|
69
|
+
| Is the agent stuck in a loop re-running the same failing command? | Tool Loops outcome, Outcome token waste ("tool loop inflation") |
|
|
70
|
+
| Which model gets my kind of work done for the fewest tokens? | Token spend vs task effectiveness (tokens per successful run, by model) |
|
|
71
|
+
| Are my skills and agent instructions being used? | Top skills activated |
|
|
72
|
+
| Is the agent reading sensibly, or dumping whole files and logs? | Tool invocation frequency (read-to-edit ratio), Token anatomy (tool output share) |
|
|
73
|
+
| Which repositories take the most agent time? | Workspace distribution and turn latency |
|
|
74
|
+
| What does a commit cost me in agent tokens and dollars? | Cross-Domain ROI |
|
|
75
|
+
|
|
76
|
+
## Who it helps
|
|
77
|
+
|
|
78
|
+
- **Developers using AI agents every day** can tighten prompts, catch loops early, keep cache hit rates high, and pick the right model for each job.
|
|
79
|
+
- **Authors of skills, agent instructions and custom agents** can check whether their skills fire and whether a change made runs faster or slower.
|
|
80
|
+
- **Team leads and platform teams** can mirror several machines into one bucket and see usage, cost and health across the team, with prompts redacted.
|
|
81
|
+
- **Anyone curious about cost** gets an API-equivalent estimate per run, per model and per commit, even on a flat-rate plan.
|
|
82
|
+
|
|
83
|
+
## What it isn't
|
|
84
|
+
|
|
85
|
+
- **Not a cloud service.** There's no account and no backend. Data stays on your machine unless you configure a remote.
|
|
86
|
+
- **Not a tracing SDK for production LLM apps.** It watches agents you run, from their logs, with no code changes. To trace an application you're deploying, use an APM or LLM tracing tool.
|
|
87
|
+
- **It doesn't call any model.** Analysis is plain counting, so using TokenTrail costs no tokens.
|
|
88
|
+
- **Costs are estimates** at API list prices, not your invoice.
|
|
89
|
+
|
|
90
|
+
## Screenshots
|
|
91
|
+
|
|
92
|
+
| | |
|
|
93
|
+
| :---: | :---: |
|
|
94
|
+
|  |  |
|
|
95
|
+
| **Health, skills, tools and velocity.** Ten charts in all, grouped by tokens, effectiveness, time and tools. | **The inspector.** One run flagged as a tool loop: the same command repeated six times. |
|
|
96
|
+
|  | |
|
|
97
|
+
| **Cross-Domain ROI.** Agent tokens, steps and cost per commit, and what caching saved. | |
|
|
98
|
+
|
|
99
|
+
## Try it with demo data
|
|
100
|
+
|
|
101
|
+
No agent needed. The demo script writes a month of made-up sessions for three agents and four small git repositories into one folder. Your real history and store aren't touched.
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
git clone https://github.com/sunil-bodeddula-pro/tokentrail && cd tokentrail
|
|
105
|
+
python3 examples/demo_data.py # writes ./tokentrail-demo
|
|
106
|
+
PYTHONPATH=src python3 -m tokentrail --config tokentrail-demo/config.json
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Then open http://127.0.0.1:8765. Delete the `tokentrail-demo` folder when you're done.
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## Table of contents
|
|
114
|
+
|
|
115
|
+
1. [Install and quick start](#1-install-and-quick-start)
|
|
116
|
+
2. [Commands and settings](#2-commands-and-settings)
|
|
117
|
+
3. [The store, remote mirrors and privacy](#3-the-store-remote-mirrors-and-privacy)
|
|
118
|
+
4. [Architecture](#4-architecture)
|
|
119
|
+
5. [Dashboard guide](#5-dashboard-guide)
|
|
120
|
+
6. [Engineer's playbook](#6-engineers-playbook)
|
|
121
|
+
7. [Adding an agent](#7-adding-an-agent)
|
|
122
|
+
8. [Pricing](#8-pricing)
|
|
123
|
+
9. [Co-located agent skill](#9-co-located-agent-skill)
|
|
124
|
+
10. [Testing and contributing](#10-testing-and-contributing)
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## 1. Install and quick start
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
pip install tokentrail # or: pipx install tokentrail
|
|
132
|
+
pip install 'tokentrail[gcs]' # add Google Cloud Storage support
|
|
133
|
+
pip install 'tokentrail[s3]' # add AWS S3 (and S3-compatible) support
|
|
134
|
+
|
|
135
|
+
tokentrail init # choose the store folder and an optional remote; runs the first sync
|
|
136
|
+
tokentrail # open the dashboard at http://127.0.0.1:8765 (it keeps syncing while open)
|
|
137
|
+
tokentrail service install # optional: keep syncing in the background at login
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Until the first release is on PyPI, install from GitHub with `pip install git+https://github.com/sunil-bodeddula-pro/tokentrail`. From a source checkout, run `pip install -e .` or use `PYTHONPATH=src python3 -m tokentrail …`.
|
|
141
|
+
|
|
142
|
+
`tokentrail init` asks three questions; `--yes` accepts the defaults:
|
|
143
|
+
|
|
144
|
+
| Question | Default |
|
|
145
|
+
| :--- | :--- |
|
|
146
|
+
| Local store folder | `~/.tokentrail/store` |
|
|
147
|
+
| Remote mirror | none (`gs://bucket/path`, `s3://bucket/path`, or a folder) |
|
|
148
|
+
| Seconds between syncs | 30 |
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
## 2. Commands and settings
|
|
153
|
+
|
|
154
|
+
| Command | What it does |
|
|
155
|
+
| :--- | :--- |
|
|
156
|
+
| `tokentrail init` | Save settings, check the remote is reachable, run the first sync. `--service` also installs the background service; `--keep-prompts-remote` uploads prompt text too |
|
|
157
|
+
| `tokentrail` or `tokentrail dashboard` | Pull other machines' data, sync, and serve the dashboard. `--port`, `--host`, `--sync-interval SECONDS` (0 = read the store only) |
|
|
158
|
+
| `tokentrail daemon` | Sync on a timer with no dashboard. This is what the service runs |
|
|
159
|
+
| `tokentrail sync` | Sync once and exit |
|
|
160
|
+
| `tokentrail pull` | Download other machines' data from the remote, and restore any of this machine's files missing locally |
|
|
161
|
+
| `tokentrail status` | Where data lives, how much there is, which machines, when it last synced |
|
|
162
|
+
| `tokentrail summary --days 30` | Headline numbers in the terminal |
|
|
163
|
+
| `tokentrail export --json F --csv F` | Everything as JSON (runs, commits, KPIs, breakdowns, ROI), or one CSV row per task run |
|
|
164
|
+
| `tokentrail service install \| uninstall \| print` | Run `daemon` at login: a systemd user unit (Linux), a launchd agent (macOS) or a Task Scheduler task (Windows). `print` shows what would be installed |
|
|
165
|
+
|
|
166
|
+
**Sync interval:** `--sync-interval SECONDS` (or `--interval`) on `init`, `dashboard` and `daemon` sets how often TokenTrail syncs, for example `tokentrail --port 8765 --sync-interval 60`. Without it, the `sync_interval` setting is used, which is 30 seconds unless you changed it. With `init`, the value is saved to the config. The dashboard page refreshes at the same interval until you pick another one in its Auto-sync menu.
|
|
167
|
+
|
|
168
|
+
Options that work with every command except `service`: `--config FILE`, `--store DIR`, `--remote URI`, `--no-remote`, `--days N` (0 = everything) and `--no-git`.
|
|
169
|
+
|
|
170
|
+
Settings live in `~/.config/tokentrail/config.json` (`%APPDATA%\tokentrail\config.json` on Windows; `TOKENTRAIL_CONFIG` points elsewhere). Command-line options win over the file.
|
|
171
|
+
|
|
172
|
+
| Setting | Default | Meaning |
|
|
173
|
+
| :--- | :--- | :--- |
|
|
174
|
+
| `store` | `~/.tokentrail/store` | The local store, the system of record |
|
|
175
|
+
| `remote` | `""` | Optional mirror: `gs://…`, `s3://…`, `file://…` or a folder path |
|
|
176
|
+
| `redact_remote` | `true` | Remove prompt text and titles before upload |
|
|
177
|
+
| `sync_interval` | 30 | Seconds between syncs |
|
|
178
|
+
| `machine_id` | `""` | Blank: a stable name, your hostname plus four hex characters, is created and kept in `<store>/.machine-id` |
|
|
179
|
+
| `adapters` | `["claude-code", "generic"]` | Which sources to read |
|
|
180
|
+
| `claude_dir` | `~/.claude/projects` | Claude Code transcripts |
|
|
181
|
+
| `events_dir` | `~/.tokentrail/events` | Generic events from any agent |
|
|
182
|
+
| `pricing` | `""` | JSON file overriding prices per model ([Pricing](#8-pricing)) |
|
|
183
|
+
| `repos` | `[]` | Extra git repositories to include, besides those the agents worked in |
|
|
184
|
+
| `author_emails` | `[]` | Count commits by these emails as yours (default: `git config user.email`) |
|
|
185
|
+
| `ai_tag` | `""` | Extra regex marking AI-assisted commits, besides `Co-Authored-By` trailers |
|
|
186
|
+
| `git_days` | 365 | How much git history to read |
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## 3. The store, remote mirrors and privacy
|
|
191
|
+
|
|
192
|
+
### The store
|
|
193
|
+
|
|
194
|
+
The store is a folder of plain JSON files. There is one file per conversation, written atomically (to a temporary file, then renamed into place):
|
|
195
|
+
|
|
196
|
+
```
|
|
197
|
+
~/.tokentrail/store/
|
|
198
|
+
.machine-id this machine's name
|
|
199
|
+
.mirror-state.json what has been uploaded and downloaded (never uploaded)
|
|
200
|
+
v1/<machine>/
|
|
201
|
+
runs/<agent>/<conversation>.json the task runs of one conversation
|
|
202
|
+
commits/<repo>.json commits from that repository
|
|
203
|
+
manifest.json counts and the last sync time
|
|
204
|
+
sources.json which agent files have been read, by size and mtime (never uploaded)
|
|
205
|
+
v1/<other-machine>/… pulled from the remote
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
- **Incremental:** a sync re-reads an agent file only when its size or modification time changes, or when prices change. A quiet sync takes milliseconds and costs no tokens; TokenTrail never calls a model.
|
|
209
|
+
- **Never deletes:** when an agent's history file disappears, its conversations stay in the store. When a file shrinks, the stored runs and the new runs are merged, so nothing is lost.
|
|
210
|
+
- **Git** is re-read every five minutes, not every sync, and commits are merged by SHA.
|
|
211
|
+
|
|
212
|
+
### Remote mirrors
|
|
213
|
+
|
|
214
|
+
| Remote | Needs | Credentials |
|
|
215
|
+
| :--- | :--- | :--- |
|
|
216
|
+
| `gs://bucket/prefix` | `pip install 'tokentrail[gcs]'` | Application Default Credentials (`gcloud auth application-default login`, or a service account) |
|
|
217
|
+
| `s3://bucket/prefix` | `pip install 'tokentrail[s3]'` | The usual AWS chain (`AWS_PROFILE`, environment variables, SSO, instance roles). For MinIO, Cloudflare R2 and other S3-compatible stores, set `AWS_ENDPOINT_URL` |
|
|
218
|
+
| `file:///path` or a path | nothing | A network drive or a synced folder |
|
|
219
|
+
|
|
220
|
+
- **Push:** after each sync, this machine's changed files are uploaded. Files are compared by MD5, so an unchanged file is never sent twice.
|
|
221
|
+
- **Pull:** when the dashboard starts, and every five minutes while it runs, other machines' new files are downloaded. Each machine writes only under its own `v1/<machine>/` prefix, so machines never overwrite each other.
|
|
222
|
+
- **Restore:** `tokentrail pull` on a machine whose store was wiped brings its files back from the remote. They come back redacted if they were uploaded redacted.
|
|
223
|
+
|
|
224
|
+
### Privacy
|
|
225
|
+
|
|
226
|
+
- **Local only by default.** The dashboard binds to `127.0.0.1`. Your prompts are in the data, so don't expose the dashboard on a network.
|
|
227
|
+
- **Redacted remotes.** With `redact_remote` on (the default), the `prompt` and `title` of every run are emptied before upload, and the run is marked `redacted`. Token counts, tool names, models, workspaces and timings are still uploaded.
|
|
228
|
+
- **Use a private bucket.** Workspace and repository names, commit subjects and author emails are not redacted.
|
|
229
|
+
- **No telemetry about you.** TokenTrail makes no network calls except to the remote you configure.
|
|
230
|
+
|
|
231
|
+
---
|
|
232
|
+
|
|
233
|
+
## 4. Architecture
|
|
234
|
+
|
|
235
|
+
```
|
|
236
|
+
agent logs ──▶ adapter ──▶ Events ──▶ segment.build_runs ──▶ TaskRun records ──┐
|
|
237
|
+
git repos ──▶ git_collector ──▶ Commit records ───────────────────────────────┤
|
|
238
|
+
▼
|
|
239
|
+
Syncer (every 30 s) ──▶ Store (JSON files) ◀──▶ Mirror (gs:// · s3:// · folder)
|
|
240
|
+
│
|
|
241
|
+
▼
|
|
242
|
+
TelemetryState ──▶ HTTP API ──▶ dashboard, summary, export
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
- **Adapters** (`adapters/`) turn one agent's logs into normalized `Event`s: prompt, response, tool call, tool result and title. This is the only agent-specific code.
|
|
246
|
+
- **Segmentation** (`segment.py`) groups events into task runs, totals tokens, tools, errors, writes and skills, prices each step, and classifies health.
|
|
247
|
+
- **Syncer, Store and Mirror** (`sync.py`, `store.py`, `mirror.py`) keep the durable record described above.
|
|
248
|
+
- **Analytics** (`analytics.py`) computes the KPIs for the CLI and the JSON export. The dashboard computes the same figures in the browser, so its filters respond instantly.
|
|
249
|
+
|
|
250
|
+
| Source | Default path | What's extracted |
|
|
251
|
+
| :--- | :--- | :--- |
|
|
252
|
+
| Claude Code | `~/.claude/projects/<project>/<session>.jsonl` | Prompts, per-response token usage (input, output, cache read and write, reasoning), model, tool calls and their errors, skills (`Skill` tool, or reads of `*/skills/<name>/SKILL.md`), subagent steps, working directory, title |
|
|
253
|
+
| Generic events | `~/.tokentrail/events/**/*.jsonl` | The same fields, written by any agent ([format](docs/event-format.md)) |
|
|
254
|
+
| Git history | Repositories found from the sessions' working directories, plus `repos` | Conventional commit type and scope, linked issues (`#123`, `ABC-123`, `b/123`), your commits, and AI-credited commits (`Co-Authored-By: Claude / Copilot / Gemini / Cursor / Codex…`, or `ai_tag`) |
|
|
255
|
+
|
|
256
|
+
The browser polls `/api/telemetry` at the interval you choose (15 s, 30 s, 60 s, 5 min or off), and again when you switch back to the tab. **Sync now** forces an immediate sync through `POST /api/sync`.
|
|
257
|
+
|
|
258
|
+
---
|
|
259
|
+
|
|
260
|
+
## 5. Dashboard guide
|
|
261
|
+
|
|
262
|
+
### 5.1 Top bar
|
|
263
|
+
|
|
264
|
+
- **Mode tabs:**
|
|
265
|
+
- **TokenTrail:** sessions, tokens, models, skills and tool friction.
|
|
266
|
+
- **Code Deliverables:** your local git commits.
|
|
267
|
+
- **Cross-Domain ROI:** agent spend set against commits shipped.
|
|
268
|
+
- **Auto-sync and Sync now:** how often the page refreshes, the time of the last sync, and a manual re-scan button.
|
|
269
|
+
- **Theme toggle:** dark (the default) or light. Your choice is remembered.
|
|
270
|
+
|
|
271
|
+
### 5.2 Filter bar
|
|
272
|
+
|
|
273
|
+
- **Time window:** Today, Last 7 days, Last 30 days or All, or a custom From/To range. It applies to every KPI, chart and table.
|
|
274
|
+
- **Granularity:**
|
|
275
|
+
- **Task runs** (default) split each conversation at every prompt (`<id>#1`, `<id>#2`…). Use this to measure what one request costs.
|
|
276
|
+
- **Conversations** merge a whole thread into one record. Use this to measure what a feature cost end to end.
|
|
277
|
+
- **Search:** case-insensitive, across run ID, prompt, title, model, workspace, agent, skills and tool names.
|
|
278
|
+
- **Agent, model and health outcome filters:** narrow down to one agent, one model or one outcome to see why runs struggled.
|
|
279
|
+
- **Machine filter:** appears when the store holds more than one machine's data.
|
|
280
|
+
- **Store line:** under the top bar, the store path, this machine's name, the remote and the last sync.
|
|
281
|
+
|
|
282
|
+
### 5.3 KPI cards
|
|
283
|
+
|
|
284
|
+
| Card | Definition | How to read it |
|
|
285
|
+
| :--- | :--- | :--- |
|
|
286
|
+
| Total sessions | Task runs (or conversations) in the filter, plus distinct conversations | Overall usage volume |
|
|
287
|
+
| Tokens consumed | `input + cache_write + output`; the sub-label shows cache reads, **cache hit %** = `cache_read / (input + cache_write + cache_read)`, and estimated cost | Target cache hit **≥ 85%**: prompt caching is working and input costs fall sharply |
|
|
288
|
+
| Average velocity | `steps / sessions`, where a step is one model response | Lower is faster. 15 to 35 steps per run means well-scoped prompts; over 60 suggests broad prompts or retry loops |
|
|
289
|
+
| Healthy sessions | Share of runs that are High-Velocity or Positive | Target **≥ 80%**. Below 75%, look at the Tool Loops and High Error Rate slices |
|
|
290
|
+
| High velocity rate | Share of runs finishing in **≤ 30 steps with 0 errors** | One-shot efficiency. 50% or more at task-run granularity means prompts and skills lead the agent straight to the right files |
|
|
291
|
+
| Tool invocations | Total tool calls, and **tool error rate** = `errors / max(tool_calls, steps)` | Target **< 1.5%**. Spikes usually mean failing builds or tests, missing environment variables, or stale edit targets |
|
|
292
|
+
|
|
293
|
+
### 5.4 The ten charts
|
|
294
|
+
|
|
295
|
+
Chart sub-tabs filter them: All (10), Tokens (4), Effectiveness (4), Time and latency (3), Tools and skills (3).
|
|
296
|
+
|
|
297
|
+
1. **Model utilization** (donut): share of sessions per model. Check that light work runs on fast models and hard work on strong ones.
|
|
298
|
+
2. **Token anatomy** (donut): new context split into **tool outputs**, **model reasoning**, **model responses** and **user instructions**. Tool outputs and prompts are estimated at 4 characters per token. When tool outputs dominate (often over 90%), prefer targeted searches and line-bounded reads over dumping whole files or logs.
|
|
299
|
+
3. **Session health and friction** (donut): the five mutually exclusive outcomes, checked in this order.
|
|
300
|
+
|
|
301
|
+
| Outcome | Rule |
|
|
302
|
+
| :--- | :--- |
|
|
303
|
+
| Failure: High Error Rate | ≥ 4 tool errors, or an error rate ≥ 20% with ≥ 6 steps |
|
|
304
|
+
| Friction: Tool Loops | ≥ 4 identical consecutive tool calls on the same target |
|
|
305
|
+
| Wandering: Zero File Writes | > 45 steps with no file writes and no skills |
|
|
306
|
+
| High-Velocity (≤30 steps) | ≤ 30 steps and 0 errors |
|
|
307
|
+
| Positive (Standard) | Everything else: clean, longer runs |
|
|
308
|
+
|
|
309
|
+
4. **Top skills activated** (bars): skills the agent loaded. If a skill you wrote never appears, sharpen the trigger words in its description.
|
|
310
|
+
5. **Tool invocation frequency** (bars), with the read-to-edit ratio. Healthy is about 3:1 to 5:1. If a shell tool dwarfs reads and edits by 10:1, the agent is probably using shell commands to view files or polling in a loop.
|
|
311
|
+
6. **Model step velocity** (bars): average steps per run by model. Lower finishes faster.
|
|
312
|
+
7. **Token spend vs task effectiveness** (bars and line): average tokens per run, **tokens per healthy run**, and success rate by model, with the most effective model named. Tokens per success is the real efficiency measure: a model that costs more per run but rarely loops often costs less per solved task.
|
|
313
|
+
8. **Outcome token waste** (bars): average tokens per outcome, with a **Tool loop inflation** banner showing extra tokens burned by looping runs compared with clean ones.
|
|
314
|
+
9. **Daily activity and token volume** (wide): sessions per day for the last 14 active days, with tokens as a line.
|
|
315
|
+
10. **Workspace distribution and turn latency** (wide): sessions per repository, with average steps and seconds per step.
|
|
316
|
+
|
|
317
|
+
### 5.5 Session explorer and inspector
|
|
318
|
+
|
|
319
|
+
- **Table:** run ID, prompt, agent, model, workspace, steps, tokens, cache hit, tools, skills, health and start time. Click a column to sort.
|
|
320
|
+
- **Inspector:** click a row to open it. It shows the machine, the full prompt (or "redacted" for runs pulled from a redacted remote), every tool with its call count, skills, writes and errors, the longest repeat, duration and seconds per step, the token split, estimated cost and cache savings.
|
|
321
|
+
|
|
322
|
+
### 5.6 Code Deliverables
|
|
323
|
+
|
|
324
|
+
- **KPIs:** matching commits, your commits, AI-credited commits and linked issues.
|
|
325
|
+
- **Charts:** commits by repository, and by conventional commit type.
|
|
326
|
+
- **Table:** recent commits.
|
|
327
|
+
- **Filters:** the time window and search apply here too.
|
|
328
|
+
|
|
329
|
+
### 5.7 Cross-Domain ROI
|
|
330
|
+
|
|
331
|
+
- **KPIs:**
|
|
332
|
+
- Tokens per commit of yours.
|
|
333
|
+
- Agent steps per commit.
|
|
334
|
+
- Estimated cost per commit.
|
|
335
|
+
- Context cache savings: what cached input would have cost at the full input price, minus what it did cost.
|
|
336
|
+
- Issues linked.
|
|
337
|
+
- **Chart:** tokens against commits by day.
|
|
338
|
+
|
|
339
|
+
Sessions and commits are matched by day only. Read it as correlation, not attribution.
|
|
340
|
+
|
|
341
|
+
---
|
|
342
|
+
|
|
343
|
+
## 6. Engineer's playbook
|
|
344
|
+
|
|
345
|
+
| Signal | Likely cause | What to do |
|
|
346
|
+
| :--- | :--- | :--- |
|
|
347
|
+
| Tool loop inflation above +300% | The agent keeps re-running a failing build or test, or retrying a broken edit | Stop the turn after the same command fails twice. Put the exact test and lint commands in your agent instructions file or a skill |
|
|
348
|
+
| Wandering: Zero File Writes runs | An open-ended prompt with no clear deliverable | Name the target files or package in the prompt, or plan first for exploratory work |
|
|
349
|
+
| Cache hit below 75% | Many short one-turn conversations, or switching workspaces mid-thread | Keep related work in one thread and workspace. Compact rather than restart when context grows |
|
|
350
|
+
| Rare skill activations on common workflows | The agent solves recurring tasks from scratch | Write or refine a skill with explicit trigger phrases in its description |
|
|
351
|
+
| Tool error rate above 1.5% | Failing commands, missing environment, stale edit targets | Open the High Error Rate runs in the inspector and fix the commonest failing tool |
|
|
352
|
+
| One model has a far higher tokens per success | It loops or wanders more on your work | Route that kind of task to the more effective model |
|
|
353
|
+
|
|
354
|
+
---
|
|
355
|
+
|
|
356
|
+
## 7. Adding an agent
|
|
357
|
+
|
|
358
|
+
There are two ways, and neither touches the analytics.
|
|
359
|
+
|
|
360
|
+
1. **Write generic events** from the agent, a wrapper or a log converter. See [docs/event-format.md](docs/event-format.md). From Python:
|
|
361
|
+
|
|
362
|
+
```python
|
|
363
|
+
from tokentrail.emit import EventLog
|
|
364
|
+
|
|
365
|
+
log = EventLog(agent="My Agent")
|
|
366
|
+
log.prompt("Refactor billing")
|
|
367
|
+
log.response(model="my-model", input=1200, output=300)
|
|
368
|
+
log.tool_call("edit_file", target="billing.py")
|
|
369
|
+
log.tool_result(error=False, chars=420)
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
2. **Write an adapter** in `src/tokentrail/adapters/`: a class with `name`, `sources()` (files to read) and `events(path)` (a list of `Event`). Register it in `ADAPTERS`, add a branch to `make_adapters` in `cli.py`, and add a fixture test. [CONTRIBUTING.md](CONTRIBUTING.md) walks through it. `claude_code.py` is a complete example in about 100 lines.
|
|
373
|
+
|
|
374
|
+
---
|
|
375
|
+
|
|
376
|
+
## 8. Pricing
|
|
377
|
+
|
|
378
|
+
Costs are **estimates at API list prices**, calculated per response from the model name.
|
|
379
|
+
|
|
380
|
+
- **Built-in prices:** Anthropic's published rates (input, output, cache read, cache write per million tokens) in `pricing.py`.
|
|
381
|
+
- **Subscriptions:** if you're on a flat-rate plan, read cost as "what this would have cost on the API".
|
|
382
|
+
- **Unknown models** are shown as unpriced, not guessed.
|
|
383
|
+
- **Overrides:** add or override any model, including other vendors' and local ones, with a JSON file:
|
|
384
|
+
|
|
385
|
+
```json
|
|
386
|
+
{"gpt-x": [1.25, 10.0, 0.125, 1.25], "local-llama": [0, 0, 0, 0]}
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
Each value is `[input, output, cache_read, cache_write]` in US dollars per million tokens. Matching is by prefix, so `claude-opus-5-5` covers dated variants. Point the `pricing` setting at the file. Changing prices re-prices every agent file that still exists on the next sync; conversations whose source file is gone keep the prices they were stored with.
|
|
390
|
+
|
|
391
|
+
---
|
|
392
|
+
|
|
393
|
+
## 9. Co-located agent skill
|
|
394
|
+
|
|
395
|
+
`skills/tokentrail/` is an agent skill. Copy or link it into your agent's skills folder so the agent can run the tool and interpret it for you.
|
|
396
|
+
|
|
397
|
+
- `SKILL.md`: when to use it, the commands, and how to act on the signals.
|
|
398
|
+
- `references/telemetry_schema.md`: the `TaskRun` and `Commit` fields, the health rules, and the HTTP API.
|
|
399
|
+
- `evals/evals.json`: trigger and behaviour checks for the skill.
|
|
400
|
+
|
|
401
|
+
---
|
|
402
|
+
|
|
403
|
+
## 10. Testing and contributing
|
|
404
|
+
|
|
405
|
+
```bash
|
|
406
|
+
python3 -m unittest discover -s tests -v # standard library only
|
|
407
|
+
python3 -m pytest -v # also works, if pytest is installed
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
Lint, formatting and strict type checks, as CI runs them:
|
|
411
|
+
|
|
412
|
+
```bash
|
|
413
|
+
pip install -e '.[dev]' # ruff and mypy
|
|
414
|
+
ruff check . && ruff format --check . && mypy
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
The tests write fixtures to a temporary directory. They never read your real agent logs or touch the network: the GCS and S3 backends are tested against in-memory fakes.
|
|
418
|
+
|
|
419
|
+
Contributions are welcome, especially adapters for other agents. See [CONTRIBUTING.md](CONTRIBUTING.md), and [SECURITY.md](SECURITY.md) for reporting a vulnerability.
|
|
420
|
+
|
|
421
|
+
## License
|
|
422
|
+
|
|
423
|
+
Apache License 2.0. See [LICENSE](LICENSE) and [NOTICE](NOTICE).
|