ai-ledger 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.
- ai_ledger-0.1.0/LICENSE +21 -0
- ai_ledger-0.1.0/PKG-INFO +175 -0
- ai_ledger-0.1.0/README.md +150 -0
- ai_ledger-0.1.0/pyproject.toml +45 -0
- ai_ledger-0.1.0/pyproject.toml.orig +36 -0
- ai_ledger-0.1.0/src/ai_ledger/__init__.py +0 -0
- ai_ledger-0.1.0/src/ai_ledger/__main__.py +3 -0
- ai_ledger-0.1.0/src/ai_ledger/app.py +311 -0
- ai_ledger-0.1.0/src/ai_ledger/categorize.py +200 -0
- ai_ledger-0.1.0/src/ai_ledger/codex.py +332 -0
- ai_ledger-0.1.0/src/ai_ledger/insights.py +221 -0
- ai_ledger-0.1.0/src/ai_ledger/limits.py +681 -0
- ai_ledger-0.1.0/src/ai_ledger/live.py +331 -0
- ai_ledger-0.1.0/src/ai_ledger/metrics.py +697 -0
- ai_ledger-0.1.0/src/ai_ledger/prices.json +21 -0
- ai_ledger-0.1.0/src/ai_ledger/store.py +716 -0
- ai_ledger-0.1.0/src/ai_ledger/web/assets/index-BNG_24xz.css +1 -0
- ai_ledger-0.1.0/src/ai_ledger/web/assets/index-BUwVmoPw.js +10 -0
- ai_ledger-0.1.0/src/ai_ledger/web/index.html +18 -0
- ai_ledger-0.1.0/src/ai_ledger/web/source-hash.txt +1 -0
ai_ledger-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Nicolas Widart
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
ai_ledger-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ai-ledger
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Local store and dashboards for AI coding-agent transcripts
|
|
5
|
+
Keywords: claude-code,codex,transcripts,dashboard,duckdb,llm,cost
|
|
6
|
+
Author: Nicolas Widart
|
|
7
|
+
Author-email: Nicolas Widart <n.widart@gmail.com>
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Environment :: Web Environment
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Operating System :: MacOS
|
|
14
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
18
|
+
Classifier: Topic :: Software Development
|
|
19
|
+
Requires-Dist: duckdb==2.0.0
|
|
20
|
+
Requires-Python: >=3.14
|
|
21
|
+
Project-URL: Homepage, https://github.com/nWidart/ai-ledger
|
|
22
|
+
Project-URL: Issues, https://github.com/nWidart/ai-ledger/issues
|
|
23
|
+
Project-URL: Changelog, https://github.com/nWidart/ai-ledger/blob/main/CHANGELOG.md
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
|
|
26
|
+
# AI Ledger
|
|
27
|
+
|
|
28
|
+
A local ledger of your Claude Code and Codex transcripts, with six pages: Activity, Cost, Errors, Limits, Insights and Live.
|
|
29
|
+
|
|
30
|
+

|
|
31
|
+
|
|
32
|
+
## Why
|
|
33
|
+
|
|
34
|
+
Coding agents leave a full record of their work on disk, then delete or archive it. That record answers questions their own UIs don't:
|
|
35
|
+
|
|
36
|
+
- **What did the agents get done, and where did they struggle?**
|
|
37
|
+
- **What did it cost, and why did that change?**
|
|
38
|
+
- **Which errors keep coming back, and how do I stop them?**
|
|
39
|
+
- **Will I hit my plan limit before it resets?**
|
|
40
|
+
- **What are my agents doing right now?**
|
|
41
|
+
|
|
42
|
+
Everything stays on your machine: the server listens on `127.0.0.1` only. The store keeps every transcript line, even after the agent deletes the file. Claude Code and Codex share the same tables, so every page filters by source. Filters and open sheets live in the URL.
|
|
43
|
+
|
|
44
|
+
## Run
|
|
45
|
+
|
|
46
|
+
Needs [uv](https://docs.astral.sh/uv/); it fetches Python 3.14 when you have none. macOS and Linux.
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
uvx ai-ledger # http://127.0.0.1:8765/ (use 127.0.0.1, not localhost)
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Or install the `ai-ledger` command:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
uv tool install ai-ledger
|
|
56
|
+
ai-ledger
|
|
57
|
+
uv tool upgrade ai-ledger # later, to get a new version and its prices
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
The first start reads every transcript (about 4 minutes for 3.4 GB). After that the app reads new lines every 60 seconds, every second while a Live page is open, or when you click **Refresh**.
|
|
61
|
+
|
|
62
|
+
Stop the app before you run these commands, because the app keeps the store open (with `uvx`, run `uvx ai-ledger ingest`):
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
ai-ledger ingest # read new transcript lines and /insights data once
|
|
66
|
+
ai-ledger rebuild # recompute the derived tables, e.g. after a parser change
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
A store from before session titles needs one `rebuild` to title past Claude Code sessions.
|
|
70
|
+
|
|
71
|
+
Options: `--port <number>` (default `8765`), `--projects <dir>` (default `~/.claude/projects`), `--codex <dir>` (default `~/.codex`), `--usage-data <dir>` (default `~/.claude/usage-data`), `--db <file>` (default: the store in the data folder). `ai-ledger --version` prints the version.
|
|
72
|
+
|
|
73
|
+
The store is one file in your data folder:
|
|
74
|
+
|
|
75
|
+
- macOS: `~/Library/Application Support/ai-ledger/ai-ledger.duckdb`
|
|
76
|
+
- Linux: `$XDG_DATA_HOME/ai-ledger/ai-ledger.duckdb`, or `~/.local/share/ai-ledger/ai-ledger.duckdb` when `XDG_DATA_HOME` is unset
|
|
77
|
+
|
|
78
|
+
Upgrades keep it.
|
|
79
|
+
|
|
80
|
+
## What it reads and sends
|
|
81
|
+
|
|
82
|
+
- **It reads** your Claude Code transcripts (`~/.claude/projects`), Claude Code's `/insights` data (`~/.claude/usage-data`) and your Codex sessions (`~/.codex`).
|
|
83
|
+
- **It stores** every transcript line in full in the store, including any secrets that appeared in a session: API keys, tokens, passwords, file contents. The store and its folder are readable only by your user. Do not share the store.
|
|
84
|
+
- **It sends**, on macOS only, the Claude Code OAuth token from your Keychain to Anthropic's usage endpoint, every 5 minutes, for the Limits page. The endpoint is undocumented and can change without notice; Limits then falls back to estimates from your transcripts. The token goes only to that endpoint and is never stored or logged.
|
|
85
|
+
- **Your browser** loads the pages' font from Google Fonts. No transcript data goes with it. Nothing else leaves your machine.
|
|
86
|
+
- **It listens** on `127.0.0.1` only, and answers only requests addressed to it there.
|
|
87
|
+
- **Prices** for the Cost page ship with each release. Upgrade to get new ones.
|
|
88
|
+
|
|
89
|
+
## Pages
|
|
90
|
+
|
|
91
|
+
Pages name each session by its title: the name you gave it (`/rename` in Claude Code), else the title the agent wrote (Claude Code's own title, Codex's thread name), else the start of its first prompt.
|
|
92
|
+
|
|
93
|
+
**Activity**: what got done and what needs attention, per day, session and tool.
|
|
94
|
+
|
|
95
|
+

|
|
96
|
+
|
|
97
|
+
**Cost**: estimated cost at API list prices against the period before, per project, day, model and session. Prices come from `prices.json`, which ships with each release.
|
|
98
|
+
|
|
99
|
+

|
|
100
|
+
|
|
101
|
+
**Errors**: failed tool calls by type, the error rate over time, and a fix to paste into `CLAUDE.md` for each type.
|
|
102
|
+
|
|
103
|
+

|
|
104
|
+
|
|
105
|
+
**Limits**: usage of each plan limit window, with a forecast to its reset.
|
|
106
|
+
|
|
107
|
+

|
|
108
|
+
|
|
109
|
+
Codex writes its limits into its session files. For Claude Code, the app polls Anthropic's undocumented usage endpoint every 5 minutes, using the OAuth token from the macOS Keychain. The token goes only to that endpoint and is never stored or logged. Off macOS, the app does not poll. Between readings, the page estimates usage from transcripts and labels it as estimated.
|
|
110
|
+
|
|
111
|
+
**Insights**: how Claude Code's `/insights` command judged your sessions: outcomes, satisfaction, friction, goals. These are model judgments, not measurements. Run `/insights` in Claude Code to analyse more sessions, then **Refresh**.
|
|
112
|
+
|
|
113
|
+
**Live**: the sessions active in the last 10 minutes, as their lines arrive. Pick a session to follow its prompts, replies and tool calls, with a timer on each running call, subagent work in lanes you can fold, and its context window, cost and plan limits beside it. **Wall** shows every active session at once.
|
|
114
|
+
|
|
115
|
+
Each session has a state: running a tool, thinking, your turn, likely waiting for approval, or idle. Transcripts record neither a request in flight (Claude Code) nor a permission prompt, so *thinking* and *likely waiting for approval* are guesses and the page marks them as inferred: a shell call pending for more than 30 seconds counts as likely waiting for approval.
|
|
116
|
+
|
|
117
|
+
The stream shows prompts and replies as word counts and tool output as a size. **Full text** shows them as written; it is off each time the page loads. A title made from the first prompt is prompt text too, so Live shows it only with **Full text** on, and the project until then.
|
|
118
|
+
|
|
119
|
+
## Command palette
|
|
120
|
+
|
|
121
|
+
Press **Cmd+K** (**Ctrl+K** elsewhere) to build a view in one step. Type `#` to filter and `>` to go somewhere or run a command:
|
|
122
|
+
|
|
123
|
+
- `#` filters: a project, a source (`#claude`, `#codex`), a range (`#7d`, `#30d`, `#all`) or `#automated`.
|
|
124
|
+
- `>` destinations: a page (`>errors`), an inspector (`>bash`, an MCP server, a skill, a session), or a command (`>refresh`, `>copy link`).
|
|
125
|
+
|
|
126
|
+
Examples:
|
|
127
|
+
|
|
128
|
+
- `>errors #myproject` opens Errors filtered to `myproject`.
|
|
129
|
+
- `#myproject >bash` opens the Bash inspector on the current page, for `myproject`.
|
|
130
|
+
- `#myproject #codex #7d >cost` opens Cost with those three filters.
|
|
131
|
+
- `>errors >bash` opens Errors with the Bash inspector over it.
|
|
132
|
+
|
|
133
|
+
## Privacy
|
|
134
|
+
|
|
135
|
+
The store holds full transcript content, including any secrets that appeared in a session (see [What it reads and sends](#what-it-reads-and-sends)). Do not share it.
|
|
136
|
+
|
|
137
|
+
The Live page's **Full text** puts that content on screen, secrets included. The app sends it only while the toggle is on. Turn it off before you share your screen.
|
|
138
|
+
|
|
139
|
+
## Contributing
|
|
140
|
+
|
|
141
|
+
Needs uv, and Node for the pages.
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
uv sync
|
|
145
|
+
uv run ai-ledger # the app from your checkout, on http://127.0.0.1:8765/
|
|
146
|
+
uv run ai-ledger --db <copy> --port 8766 # a second app on a copy of the store, beside the running one
|
|
147
|
+
uv run python -m unittest discover -s tests
|
|
148
|
+
cd web && npm install && npm run dev # http://127.0.0.1:5173, /api proxied to the running app
|
|
149
|
+
cd web && npm run check # typecheck, tests and build: run before committing
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
The Python code lives in `src/ai_ledger/`. The pages build into `src/ai_ledger/web/`, which ships in the package: commit it with every `web/src` change. A test fails when the build is stale.
|
|
153
|
+
|
|
154
|
+
**Upgrading a checkout from before 0.1.0:** the app no longer runs with `uv run app.py`, and the store no longer lives in the checkout. Run `uv sync`, then `uv run ai-ledger`. On its first start the app moves `data/ai-ledger.duckdb` (or the older `data/claude.duckdb`), with its `.wal` file, to the data folder above. If you pass `--db data/ai-ledger.duckdb` in scripts, point them at the new path. If the data folder is on another disk, the app stops and says so: move the file by hand, or pass `--db` with its path.
|
|
155
|
+
|
|
156
|
+
To record the GIFs again from made-up data:
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
uv run tools/demo/seed.py # synthetic store in tools/demo/demo.duckdb
|
|
160
|
+
uv run tools/demo/serve.py # serves it on 127.0.0.1:8799
|
|
161
|
+
uv run tools/demo/replay.py # optional, second terminal: plays made-up sessions for the Live page
|
|
162
|
+
# in a second terminal:
|
|
163
|
+
cd tools/demo && npm install && npx playwright install chromium-headless-shell && npm run record # needs gifski
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Release
|
|
167
|
+
|
|
168
|
+
Pushing a tag `v<version>` runs `.github/workflows/release.yml`: the checks, a smoke test of the wheel on macOS and Linux, the PyPI upload and the GitHub release.
|
|
169
|
+
|
|
170
|
+
1. Set `version` in `pyproject.toml`, run `uv lock`, and add a `## [<version>] - <date>` section to `CHANGELOG.md`.
|
|
171
|
+
2. Commit on `main`, then `git tag v<version>` and `git push origin v<version>`.
|
|
172
|
+
|
|
173
|
+
## License
|
|
174
|
+
|
|
175
|
+
[MIT](LICENSE)
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# AI Ledger
|
|
2
|
+
|
|
3
|
+
A local ledger of your Claude Code and Codex transcripts, with six pages: Activity, Cost, Errors, Limits, Insights and Live.
|
|
4
|
+
|
|
5
|
+

|
|
6
|
+
|
|
7
|
+
## Why
|
|
8
|
+
|
|
9
|
+
Coding agents leave a full record of their work on disk, then delete or archive it. That record answers questions their own UIs don't:
|
|
10
|
+
|
|
11
|
+
- **What did the agents get done, and where did they struggle?**
|
|
12
|
+
- **What did it cost, and why did that change?**
|
|
13
|
+
- **Which errors keep coming back, and how do I stop them?**
|
|
14
|
+
- **Will I hit my plan limit before it resets?**
|
|
15
|
+
- **What are my agents doing right now?**
|
|
16
|
+
|
|
17
|
+
Everything stays on your machine: the server listens on `127.0.0.1` only. The store keeps every transcript line, even after the agent deletes the file. Claude Code and Codex share the same tables, so every page filters by source. Filters and open sheets live in the URL.
|
|
18
|
+
|
|
19
|
+
## Run
|
|
20
|
+
|
|
21
|
+
Needs [uv](https://docs.astral.sh/uv/); it fetches Python 3.14 when you have none. macOS and Linux.
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
uvx ai-ledger # http://127.0.0.1:8765/ (use 127.0.0.1, not localhost)
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Or install the `ai-ledger` command:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
uv tool install ai-ledger
|
|
31
|
+
ai-ledger
|
|
32
|
+
uv tool upgrade ai-ledger # later, to get a new version and its prices
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
The first start reads every transcript (about 4 minutes for 3.4 GB). After that the app reads new lines every 60 seconds, every second while a Live page is open, or when you click **Refresh**.
|
|
36
|
+
|
|
37
|
+
Stop the app before you run these commands, because the app keeps the store open (with `uvx`, run `uvx ai-ledger ingest`):
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
ai-ledger ingest # read new transcript lines and /insights data once
|
|
41
|
+
ai-ledger rebuild # recompute the derived tables, e.g. after a parser change
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
A store from before session titles needs one `rebuild` to title past Claude Code sessions.
|
|
45
|
+
|
|
46
|
+
Options: `--port <number>` (default `8765`), `--projects <dir>` (default `~/.claude/projects`), `--codex <dir>` (default `~/.codex`), `--usage-data <dir>` (default `~/.claude/usage-data`), `--db <file>` (default: the store in the data folder). `ai-ledger --version` prints the version.
|
|
47
|
+
|
|
48
|
+
The store is one file in your data folder:
|
|
49
|
+
|
|
50
|
+
- macOS: `~/Library/Application Support/ai-ledger/ai-ledger.duckdb`
|
|
51
|
+
- Linux: `$XDG_DATA_HOME/ai-ledger/ai-ledger.duckdb`, or `~/.local/share/ai-ledger/ai-ledger.duckdb` when `XDG_DATA_HOME` is unset
|
|
52
|
+
|
|
53
|
+
Upgrades keep it.
|
|
54
|
+
|
|
55
|
+
## What it reads and sends
|
|
56
|
+
|
|
57
|
+
- **It reads** your Claude Code transcripts (`~/.claude/projects`), Claude Code's `/insights` data (`~/.claude/usage-data`) and your Codex sessions (`~/.codex`).
|
|
58
|
+
- **It stores** every transcript line in full in the store, including any secrets that appeared in a session: API keys, tokens, passwords, file contents. The store and its folder are readable only by your user. Do not share the store.
|
|
59
|
+
- **It sends**, on macOS only, the Claude Code OAuth token from your Keychain to Anthropic's usage endpoint, every 5 minutes, for the Limits page. The endpoint is undocumented and can change without notice; Limits then falls back to estimates from your transcripts. The token goes only to that endpoint and is never stored or logged.
|
|
60
|
+
- **Your browser** loads the pages' font from Google Fonts. No transcript data goes with it. Nothing else leaves your machine.
|
|
61
|
+
- **It listens** on `127.0.0.1` only, and answers only requests addressed to it there.
|
|
62
|
+
- **Prices** for the Cost page ship with each release. Upgrade to get new ones.
|
|
63
|
+
|
|
64
|
+
## Pages
|
|
65
|
+
|
|
66
|
+
Pages name each session by its title: the name you gave it (`/rename` in Claude Code), else the title the agent wrote (Claude Code's own title, Codex's thread name), else the start of its first prompt.
|
|
67
|
+
|
|
68
|
+
**Activity**: what got done and what needs attention, per day, session and tool.
|
|
69
|
+
|
|
70
|
+

|
|
71
|
+
|
|
72
|
+
**Cost**: estimated cost at API list prices against the period before, per project, day, model and session. Prices come from `prices.json`, which ships with each release.
|
|
73
|
+
|
|
74
|
+

|
|
75
|
+
|
|
76
|
+
**Errors**: failed tool calls by type, the error rate over time, and a fix to paste into `CLAUDE.md` for each type.
|
|
77
|
+
|
|
78
|
+

|
|
79
|
+
|
|
80
|
+
**Limits**: usage of each plan limit window, with a forecast to its reset.
|
|
81
|
+
|
|
82
|
+

|
|
83
|
+
|
|
84
|
+
Codex writes its limits into its session files. For Claude Code, the app polls Anthropic's undocumented usage endpoint every 5 minutes, using the OAuth token from the macOS Keychain. The token goes only to that endpoint and is never stored or logged. Off macOS, the app does not poll. Between readings, the page estimates usage from transcripts and labels it as estimated.
|
|
85
|
+
|
|
86
|
+
**Insights**: how Claude Code's `/insights` command judged your sessions: outcomes, satisfaction, friction, goals. These are model judgments, not measurements. Run `/insights` in Claude Code to analyse more sessions, then **Refresh**.
|
|
87
|
+
|
|
88
|
+
**Live**: the sessions active in the last 10 minutes, as their lines arrive. Pick a session to follow its prompts, replies and tool calls, with a timer on each running call, subagent work in lanes you can fold, and its context window, cost and plan limits beside it. **Wall** shows every active session at once.
|
|
89
|
+
|
|
90
|
+
Each session has a state: running a tool, thinking, your turn, likely waiting for approval, or idle. Transcripts record neither a request in flight (Claude Code) nor a permission prompt, so *thinking* and *likely waiting for approval* are guesses and the page marks them as inferred: a shell call pending for more than 30 seconds counts as likely waiting for approval.
|
|
91
|
+
|
|
92
|
+
The stream shows prompts and replies as word counts and tool output as a size. **Full text** shows them as written; it is off each time the page loads. A title made from the first prompt is prompt text too, so Live shows it only with **Full text** on, and the project until then.
|
|
93
|
+
|
|
94
|
+
## Command palette
|
|
95
|
+
|
|
96
|
+
Press **Cmd+K** (**Ctrl+K** elsewhere) to build a view in one step. Type `#` to filter and `>` to go somewhere or run a command:
|
|
97
|
+
|
|
98
|
+
- `#` filters: a project, a source (`#claude`, `#codex`), a range (`#7d`, `#30d`, `#all`) or `#automated`.
|
|
99
|
+
- `>` destinations: a page (`>errors`), an inspector (`>bash`, an MCP server, a skill, a session), or a command (`>refresh`, `>copy link`).
|
|
100
|
+
|
|
101
|
+
Examples:
|
|
102
|
+
|
|
103
|
+
- `>errors #myproject` opens Errors filtered to `myproject`.
|
|
104
|
+
- `#myproject >bash` opens the Bash inspector on the current page, for `myproject`.
|
|
105
|
+
- `#myproject #codex #7d >cost` opens Cost with those three filters.
|
|
106
|
+
- `>errors >bash` opens Errors with the Bash inspector over it.
|
|
107
|
+
|
|
108
|
+
## Privacy
|
|
109
|
+
|
|
110
|
+
The store holds full transcript content, including any secrets that appeared in a session (see [What it reads and sends](#what-it-reads-and-sends)). Do not share it.
|
|
111
|
+
|
|
112
|
+
The Live page's **Full text** puts that content on screen, secrets included. The app sends it only while the toggle is on. Turn it off before you share your screen.
|
|
113
|
+
|
|
114
|
+
## Contributing
|
|
115
|
+
|
|
116
|
+
Needs uv, and Node for the pages.
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
uv sync
|
|
120
|
+
uv run ai-ledger # the app from your checkout, on http://127.0.0.1:8765/
|
|
121
|
+
uv run ai-ledger --db <copy> --port 8766 # a second app on a copy of the store, beside the running one
|
|
122
|
+
uv run python -m unittest discover -s tests
|
|
123
|
+
cd web && npm install && npm run dev # http://127.0.0.1:5173, /api proxied to the running app
|
|
124
|
+
cd web && npm run check # typecheck, tests and build: run before committing
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
The Python code lives in `src/ai_ledger/`. The pages build into `src/ai_ledger/web/`, which ships in the package: commit it with every `web/src` change. A test fails when the build is stale.
|
|
128
|
+
|
|
129
|
+
**Upgrading a checkout from before 0.1.0:** the app no longer runs with `uv run app.py`, and the store no longer lives in the checkout. Run `uv sync`, then `uv run ai-ledger`. On its first start the app moves `data/ai-ledger.duckdb` (or the older `data/claude.duckdb`), with its `.wal` file, to the data folder above. If you pass `--db data/ai-ledger.duckdb` in scripts, point them at the new path. If the data folder is on another disk, the app stops and says so: move the file by hand, or pass `--db` with its path.
|
|
130
|
+
|
|
131
|
+
To record the GIFs again from made-up data:
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
uv run tools/demo/seed.py # synthetic store in tools/demo/demo.duckdb
|
|
135
|
+
uv run tools/demo/serve.py # serves it on 127.0.0.1:8799
|
|
136
|
+
uv run tools/demo/replay.py # optional, second terminal: plays made-up sessions for the Live page
|
|
137
|
+
# in a second terminal:
|
|
138
|
+
cd tools/demo && npm install && npx playwright install chromium-headless-shell && npm run record # needs gifski
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Release
|
|
142
|
+
|
|
143
|
+
Pushing a tag `v<version>` runs `.github/workflows/release.yml`: the checks, a smoke test of the wheel on macOS and Linux, the PyPI upload and the GitHub release.
|
|
144
|
+
|
|
145
|
+
1. Set `version` in `pyproject.toml`, run `uv lock`, and add a `## [<version>] - <date>` section to `CHANGELOG.md`.
|
|
146
|
+
2. Commit on `main`, then `git tag v<version>` and `git push origin v<version>`.
|
|
147
|
+
|
|
148
|
+
## License
|
|
149
|
+
|
|
150
|
+
[MIT](LICENSE)
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "ai-ledger"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Local store and dashboards for AI coding-agent transcripts"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
license = "MIT"
|
|
7
|
+
license-files = ["LICENSE"]
|
|
8
|
+
keywords = [
|
|
9
|
+
"claude-code",
|
|
10
|
+
"codex",
|
|
11
|
+
"transcripts",
|
|
12
|
+
"dashboard",
|
|
13
|
+
"duckdb",
|
|
14
|
+
"llm",
|
|
15
|
+
"cost",
|
|
16
|
+
]
|
|
17
|
+
classifiers = [
|
|
18
|
+
"Development Status :: 4 - Beta",
|
|
19
|
+
"Environment :: Web Environment",
|
|
20
|
+
"Intended Audience :: Developers",
|
|
21
|
+
"Operating System :: MacOS",
|
|
22
|
+
"Operating System :: POSIX :: Linux",
|
|
23
|
+
"Programming Language :: Python :: 3",
|
|
24
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
25
|
+
"Programming Language :: Python :: 3.14",
|
|
26
|
+
"Topic :: Software Development",
|
|
27
|
+
]
|
|
28
|
+
requires-python = ">=3.14"
|
|
29
|
+
dependencies = ["duckdb==2.0.0"]
|
|
30
|
+
|
|
31
|
+
[[project.authors]]
|
|
32
|
+
name = "Nicolas Widart"
|
|
33
|
+
email = "n.widart@gmail.com"
|
|
34
|
+
|
|
35
|
+
[project.scripts]
|
|
36
|
+
ai-ledger = "ai_ledger.app:main"
|
|
37
|
+
|
|
38
|
+
[project.urls]
|
|
39
|
+
Homepage = "https://github.com/nWidart/ai-ledger"
|
|
40
|
+
Issues = "https://github.com/nWidart/ai-ledger/issues"
|
|
41
|
+
Changelog = "https://github.com/nWidart/ai-ledger/blob/main/CHANGELOG.md"
|
|
42
|
+
|
|
43
|
+
[build-system]
|
|
44
|
+
requires = ["uv_build>=0.13,<0.14"]
|
|
45
|
+
build-backend = "uv_build"
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "ai-ledger"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Local store and dashboards for AI coding-agent transcripts"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
license = "MIT"
|
|
7
|
+
license-files = ["LICENSE"]
|
|
8
|
+
authors = [{ name = "Nicolas Widart", email = "n.widart@gmail.com" }]
|
|
9
|
+
keywords = ["claude-code", "codex", "transcripts", "dashboard", "duckdb", "llm", "cost"]
|
|
10
|
+
classifiers = [
|
|
11
|
+
"Development Status :: 4 - Beta",
|
|
12
|
+
"Environment :: Web Environment",
|
|
13
|
+
"Intended Audience :: Developers",
|
|
14
|
+
"Operating System :: MacOS",
|
|
15
|
+
"Operating System :: POSIX :: Linux",
|
|
16
|
+
"Programming Language :: Python :: 3",
|
|
17
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
18
|
+
"Programming Language :: Python :: 3.14",
|
|
19
|
+
"Topic :: Software Development",
|
|
20
|
+
]
|
|
21
|
+
requires-python = ">=3.14"
|
|
22
|
+
dependencies = [
|
|
23
|
+
"duckdb==2.0.0",
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
[project.scripts]
|
|
27
|
+
ai-ledger = "ai_ledger.app:main"
|
|
28
|
+
|
|
29
|
+
[project.urls]
|
|
30
|
+
Homepage = "https://github.com/nWidart/ai-ledger"
|
|
31
|
+
Issues = "https://github.com/nWidart/ai-ledger/issues"
|
|
32
|
+
Changelog = "https://github.com/nWidart/ai-ledger/blob/main/CHANGELOG.md"
|
|
33
|
+
|
|
34
|
+
[build-system]
|
|
35
|
+
requires = ["uv_build>=0.13,<0.14"]
|
|
36
|
+
build-backend = "uv_build"
|
|
File without changes
|