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.
@@ -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.
@@ -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
+ ![Tour of the pages](https://raw.githubusercontent.com/nWidart/ai-ledger/main/docs/tour.gif)
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
+ ![Activity](https://raw.githubusercontent.com/nWidart/ai-ledger/main/docs/activity.gif)
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
+ ![Cost](https://raw.githubusercontent.com/nWidart/ai-ledger/main/docs/cost.gif)
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
+ ![Errors](https://raw.githubusercontent.com/nWidart/ai-ledger/main/docs/errors.gif)
104
+
105
+ **Limits**: usage of each plan limit window, with a forecast to its reset.
106
+
107
+ ![Limits](https://raw.githubusercontent.com/nWidart/ai-ledger/main/docs/limits.gif)
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
+ ![Tour of the pages](https://raw.githubusercontent.com/nWidart/ai-ledger/main/docs/tour.gif)
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
+ ![Activity](https://raw.githubusercontent.com/nWidart/ai-ledger/main/docs/activity.gif)
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
+ ![Cost](https://raw.githubusercontent.com/nWidart/ai-ledger/main/docs/cost.gif)
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
+ ![Errors](https://raw.githubusercontent.com/nWidart/ai-ledger/main/docs/errors.gif)
79
+
80
+ **Limits**: usage of each plan limit window, with a forecast to its reset.
81
+
82
+ ![Limits](https://raw.githubusercontent.com/nWidart/ai-ledger/main/docs/limits.gif)
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
@@ -0,0 +1,3 @@
1
+ from .app import main
2
+
3
+ main()