eurysx 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,140 @@
1
+ # Changelog
2
+
3
+ ## [0.1.0] - Local observability, diagnostics, pacing, and stable exports
4
+
5
+ ### Fixed
6
+
7
+ - Parse Claude Code date-only timestamps correctly; aggregate rates use observed dates and omit false daily spikes.
8
+ - Attribute Pi sessions from session headers, retaining the legacy per-event fallback.
9
+ - Calculate pacing from the full calendar budget window; provider budgets override agent budgets for their routes.
10
+
11
+ ### Added
12
+
13
+ - Activity ratios for requests/turns/tool calls, reported as `N/A` when their inputs are absent.
14
+ - Read-only parser-drift and unreachable-source warnings; retained history is never deleted.
15
+ - `eurysx doctor` for terminal-only harness, source, pricing-cache, and configuration diagnostics. Failed-refresh report warnings are agent-scoped.
16
+ - Preference budgets, deterministic pacing, and exact unresolved-route diagnostics; subscription billing remains `N/A`.
17
+ - Stable JSON schema v1 plus CSV and Markdown exports from the shared analysis result.
18
+ - Operational manual with CLI/output redirects and a source-drift regression check.
19
+ - Trusted-Publishing GitHub workflow: validation, PyPI upload, and changelog-based GitHub Release.
20
+
21
+ ### Tests
22
+
23
+ - Coverage for timestamp scope, Pi attribution, ratios, diagnostics, stored-source failures, and the doctor command.
24
+
25
+ ## [0.0.5] - More hardening: pushdown, selectors, grouping, comparisons
26
+
27
+ ### Added
28
+
29
+ - `--model` and `--provider` selectors, SQL WHERE filters in `store.events()`,
30
+ combinable with `--agent` and the period selectors; NULL providers match
31
+ `--provider unknown` (COALESCE).
32
+ - `--billing-mode` (metered|subscription|credit|quota|local|unknown), applied
33
+ post-pricing via the `analyze_agent(billing_modes=...)` hook: billing_mode
34
+ is a pricing-time artifact flipped to `metered` on recorded-cost conflict,
35
+ so SQL cannot pre-filter it.
36
+ - `period_comparison`: bounded runs compare the current period against the
37
+ same-length previous window (`_previous_window`, same filters) — terminal
38
+ `PERIOD COMPARISON` (tokens, cost, entries, requests + Δ) and an additive
39
+ JSON block; all-time runs omit it.
40
+
41
+ ### Changed
42
+
43
+ - OpenCode timestamps stored as ISO-8601 (parser v3); epoch-millis rows
44
+ re-collect on refresh.
45
+ - Claude Code aggregate scope warning now via a store presence check, so it
46
+ survives SQL filtering.
47
+ - `store.events()` filters agents, dates, models, and providers in SQL; the
48
+ Python date filter remains as the equivalence reference.
49
+ - Indices on provider, model, project, session (additive, idempotent).
50
+ - `AgentStats` gained `project_breakdown`/`session_breakdown` (model_breakdown
51
+ shape; `unknown` bucket for unattributed rows), shown in terminal as
52
+ `BREAKDOWN BY SESSION`/`BREAKDOWN BY PROJECT` and in JSON; unattributed-only
53
+ sections print `No ... attribution available.`.
54
+
55
+ ### Tests
56
+
57
+ - SQL-vs-Python equivalence, presence check, indices, grouping (incl.
58
+ unattributed), two-period reuse/disjointness.
59
+ - Per-selector and combination tests incl.
60
+ recorded-cost-flips-to-metered; previous-window math; simulated-CLI
61
+ comparison asserting values and delta.
62
+ - Phase 1 baseline extended for additive keys `project_breakdown`,
63
+ `session_breakdown`, `period_comparison`; Phase 6 pins the final contract.
64
+
65
+ ## [0.0.4] - Report baseline + result seams
66
+
67
+ ### Added
68
+
69
+ - Tests lock JSON `--output` schema and terminal report key sections against a hermetic fixture to assert exact values.
70
+ - Added cache read and cache efficiency ratios to JSON exports (previously terminal-only).
71
+ - `AnalysisReport` encapsulates period, per-agent stats/display periods, and pricing/preferences provenance; moved JSON assembly from CLI to `render.py`.
72
+ - `UsageAnalyzer.display_period` unit tests for ranged and all-time period derivations.
73
+
74
+ ### Changed
75
+
76
+ - Terminal report, comparison summary, and JSON export now consume `AnalysisReport` instead of CLI-assembled payloads.
77
+ - Internal test-only models moved out of CLI exports; tests now import `eurysx.models` directly.
78
+
79
+ ## [0.0.3] - Incremental collection + attribution and diagnostics
80
+
81
+ ### Added
82
+
83
+ - Incremental per-source collection: collectors enumerate raw sources with stat
84
+ fingerprints and a parser version; the CLI skips unchanged sources and
85
+ transactionally replaces only sources that moved.
86
+ - Best-effort project attribution: Pi session-header `cwd`, Codex
87
+ `session_meta.cwd`, and OpenCode's `session.directory` (when present) are
88
+ stored per event as `project_id`; Claude Code aggregate rows stay unattributed.
89
+ - Failed source refreshes keep their last good events, record the error on the
90
+ source row, and `report` warns when last-good data is being shown.
91
+
92
+ ### Changed
93
+
94
+ - Default and `report` commands both read usage back from the store after
95
+ collection; legacy per-agent bulk `collector:<agent>` store rows are purged.
96
+ - Collectors propagate read errors instead of printing and returning partial
97
+ data. Pi, Codex, and OpenCode parser versions moved to 2.
98
+
99
+ ## [0.0.2] - Local store implementation + module restructure
100
+
101
+ ### Added
102
+
103
+ - Local SQLite usage storage with decimal-text recorded costs.
104
+ - `eurysx collect` and `eurysx report` workflows; stored reports do not collect
105
+ agent history.
106
+
107
+ ### Changed
108
+
109
+ - Source layout now uses the `src/eurysx` package
110
+ - CLI orchestration now delegates to focused collector, pricing, analysis, and rendering modules.
111
+
112
+ ## [0.0.1] - Core CLI baseline
113
+
114
+ ### Added
115
+
116
+ - `eurysx` CLI for Claude Code, OpenCode, Pi, and Codex local usage data.
117
+ - Token, request, turn, tool-call, model, provider, session, and pricing-source reporting.
118
+ - JSON reports, `--version`/`-v`, and explicit rolling, calendar, and ISO date selectors.
119
+ - Checkout-local pricing config/cache paths with explicit environment overrides.
120
+ - Configurable pricing resolution: recorded cost, overrides, enabled sources, cache fallback, then unknown.
121
+ - User-owned per-agent route and billing preferences with pricing-provider mapping.
122
+ - Ordered provider-aware pricing source fallbacks and a project-local cache.
123
+ - Sanitized collector fixtures, pricing regression tests, setuptools metadata, and MIT license.
124
+
125
+ ### Changed
126
+
127
+ - Reports label money as known cost and expose unknown-cost tokens and priced-token coverage.
128
+ - Selected date ranges exclude `Claude Code`'s aggregate stats-cache data and emit a scope warning.
129
+ - Source distributions include the changelog and safe pricing configuration sample.
130
+ - Empty-token coverage is `N/A`; malformed pricing configuration is reported as a diagnostic.
131
+ - `OpenCode` turn detection no longer depends on SQLite message-row order.
132
+ - All-time reports derive cost-rate periods from observed usage dates.
133
+ - Reports separate metered token coverage from subscription, credit, quota, local, and unknown usage.
134
+ - Codex preserves recorded route-provider metadata; provider-qualified prices no longer cross-match.
135
+ - Preferences now use agent defaults and provider overrides; `aws-bedrock` is
136
+ renamed to `amazon-bedrock` in pricing configuration and cache provenance.
137
+ - Configuration documentation and samples now distinguish required enabled-source
138
+ settings from optional agent and provider policies.
139
+ - OpenCode collector parity now uses a tracked, sanitized SQL fixture that builds
140
+ its temporary SQLite database during tests.
eurysx-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 openlines
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,3 @@
1
+ include CHANGELOG.md
2
+ include config/pricing.jsonc.sample
3
+ include config/preferences.jsonc.sample
eurysx-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,263 @@
1
+ Metadata-Version: 2.4
2
+ Name: eurysx
3
+ Version: 0.1.0
4
+ Summary: Local usage intelligence for AI coding agents
5
+ Author: openlines
6
+ License-Expression: MIT
7
+ Requires-Python: >=3.11
8
+ Description-Content-Type: text/markdown
9
+ License-File: LICENSE
10
+ Dynamic: license-file
11
+
12
+ # Eurysx
13
+
14
+ Local-first usage observability for Claude Code, OpenCode, Pi, and Codex.
15
+
16
+ Eurysx reads local agent history and reports tokens, requests, turns, tool calls,
17
+ estimated or recorded cost, and pricing provenance. It does not upload usage data
18
+ or persist prompts, responses, file contents, tool arguments, or tool results.
19
+
20
+ > Eurysx v0.1.0 is a local CLI, not a hosted service.
21
+
22
+ ## Install
23
+
24
+ ```bash
25
+ python3 -m pip install .
26
+ eurysx --help
27
+ ```
28
+
29
+ ## Run
30
+
31
+ ```bash
32
+ eurysx --version
33
+ eurysx
34
+ eurysx --agent codex --days 30
35
+ eurysx --agent all --month 2026-08
36
+ eurysx --agent pi --from 2026-08-01 --to 2026-08-15
37
+ eurysx --agent all --days 30 --output reports/usage.json
38
+ eurysx --refresh-pricing
39
+ eurysx collect --agent codex
40
+ eurysx report --agent codex --days 30
41
+ eurysx doctor
42
+ ```
43
+
44
+ `reports/` is ignored by Git.
45
+
46
+ `eurysx` collects current local metadata and then reports it. `collect` stores
47
+ metadata only; `report` reads the local store without collecting. `doctor` is
48
+ terminal-only and reports local harness, source, pricing-cache, and configuration
49
+ health without parsing history, refreshing prices, or deleting retained data. During Act II,
50
+ the store is `data/eurysx.db` relative to the current project directory. Set
51
+ `EURYSX_DATA_DIR` only to deliberately relocate it.
52
+
53
+ Period selectors are mutually exclusive: `--days N`, `--weeks N`,
54
+ `--from YYYY-MM-DD [--to YYYY-MM-DD]`, `--month YYYY-MM`,
55
+ `--quarter YYYY-QN`, `--year YYYY`, and `--ytd`. Rolling periods include today.
56
+
57
+ Filter selectors `--model`, `--provider`, and `--billing-mode` narrow the
58
+ analyzed rows and combine with `--agent` and the period selectors; bounded
59
+ period runs also compare against the same-length previous window. See the
60
+ [operational manual](docs/manual.md) for details.
61
+
62
+ ## Documentation
63
+
64
+ The [operational manual](docs/manual.md) is the authoritative command, output,
65
+ configuration, and diagnostics reference. Legacy [CLI](docs/cli.md) and
66
+ [output](docs/output.md) pages redirect there.
67
+
68
+ This manual is the authoritative contract for the JSONC configuration files.
69
+
70
+ ## Configuration manual
71
+
72
+ Eurysx is checkout-local during Act I. It reads and writes only these paths by
73
+ default, relative to the directory where you run `eurysx`:
74
+
75
+ ```text
76
+ eurysx/
77
+ ├── config/pricing.jsonc
78
+ ├── config/preferences.jsonc
79
+ └── cache/
80
+ ```
81
+
82
+ It does not use `~/Library/Application Support`, XDG directories, or other
83
+ system-level application folders. The local configuration and cache are ignored
84
+ by Git. Create them from the tracked templates:
85
+
86
+ ```bash
87
+ cp config/pricing.jsonc.sample config/pricing.jsonc
88
+ cp config/preferences.jsonc.sample config/preferences.jsonc
89
+ ```
90
+
91
+ Both files are JSONC: comments and trailing commas are allowed. Both are
92
+ optional. Without them, Eurysx retains recorded usage and marks unresolved cost
93
+ as unknown. Use `EURYSX_CONFIG_DIR` and `EURYSX_CACHE_DIR` only when deliberately
94
+ relocating those two directories, for example to a removable development volume.
95
+
96
+ ### `preferences.jsonc`: agent and provider policy
97
+
98
+ `preferences.jsonc` declares a schema version 2 policy. An agent-level policy
99
+ applies to every model when the collector has no provider metadata. `providers`
100
+ overrides that policy only for an exact recorded provider. There are no
101
+ model-match rules.
102
+
103
+ ```jsonc
104
+ {
105
+ "schemaVersion": 2,
106
+ "agents": {
107
+ "claude-code": {
108
+ "provider": "amazon-bedrock",
109
+ "billingMode": "metered",
110
+ "pricing": {
111
+ "source": "amazon-bedrock",
112
+ "otherSources": ["models-dev", "pi-models-store"]
113
+ }
114
+ },
115
+ "codex": {
116
+ "providers": {
117
+ "openai": { "billingMode": "subscription" },
118
+ "amazon-bedrock": {
119
+ "billingMode": "metered",
120
+ "pricing": { "source": "amazon-bedrock", "otherSources": ["models-dev"] }
121
+ },
122
+ "litellm": { "billingMode": "local" }
123
+ }
124
+ }
125
+ }
126
+ }
127
+ ```
128
+
129
+ `schemaVersion` and `agents` are the expected top-level fields. `schemaVersion`
130
+ is currently informational; Eurysx does not reject the file based on its value.
131
+ The file itself and each agent entry are optional. Omit an agent entry when you
132
+ want its usage to remain unclassified. Supported agent keys are `claude-code`,
133
+ `codex`, `opencode`, and `pi`; unknown keys are ignored.
134
+
135
+ | Policy field | Required? | Meaning |
136
+ | --- | --- | --- |
137
+ | `provider` | Optional | Effective provider when the collector does not record one. Usually needed for an agent-level metered policy. |
138
+ | `billingMode` | Optional | `metered`, `subscription`, `credit`, `quota`, `local`, or `unknown`. Omit it to let a matching provider policy decide; if no policy supplies it, Eurysx uses `unknown`. |
139
+ | `providers` | Optional | Map of exact recorded provider names to policy objects. Provider-policy fields override the agent-level fields. |
140
+ | `pricing` | Optional | Pricing lookup policy. For a config-priced metered route, include at least one valid `source` or `otherSources` entry. |
141
+ | `pricing.source` | Optional | Primary enabled source name from `pricing.jsonc`. |
142
+ | `pricing.otherSources` | Optional | Ordered enabled fallback source names from `pricing.jsonc`. |
143
+
144
+ `subscription`, `credit`, `quota`, and `local` report `N/A` incremental USD.
145
+ `metered` resolves pricing. A source name that is missing, disabled, or lacks an
146
+ exact provider/model price is skipped. Recorded harness cost always wins.
147
+
148
+ For an agent using more than one provider, omit agent-level `billingMode` rather
149
+ than setting it to `unknown` or an empty value. JSON has no useful blank value
150
+ here: `"billingMode": ""` is invalid policy data and is reported as unknown.
151
+ For example, Codex can classify its recorded OpenAI route as `subscription`, its
152
+ recorded Bedrock route as `metered`, and its recorded LiteLLM route as `local`.
153
+ If a record has no provider, or its provider is absent from `providers`, its
154
+ billing mode is `unknown` unless the agent-level policy defines one. Optional
155
+ budgets use `{"usd": 100, "period": "month"}` under an agent or exact provider;
156
+ invalid budgets disable pacing with a warning.
157
+
158
+ Billing modes describe incremental cost, not capability:
159
+
160
+ | Mode | Eurysx cost treatment |
161
+ | --- | --- |
162
+ | `metered` | Resolves per-token USD pricing. |
163
+ | `subscription`, `credit`, `quota`, `local` | Reports `N/A` incremental USD. Eurysx does not allocate fees or convert credits. |
164
+ | `unknown` | Retains usage and reports cost as unknown until you classify it or add pricing. |
165
+
166
+ Recorded harness cost always wins. If a recorded cost conflicts with a
167
+ non-metered policy, Eurysx keeps the recorded cost and warns.
168
+
169
+ ### `pricing.jsonc`: price sources and manual overrides
170
+
171
+ `pricing.jsonc` supplies per-million-token USD prices only for `metered` usage.
172
+ It has `sources`, provider-scoped `aliases`, and `overrides`. The file is
173
+ optional. Configure an enabled source before naming it in `pricing.source` or
174
+ `pricing.otherSources`.
175
+
176
+ ```jsonc
177
+ {
178
+ "schemaVersion": 2,
179
+ "sources": {
180
+ "amazon-bedrock": {
181
+ "enabled": true,
182
+ "profile": "your-aws-profile",
183
+ "region": "ap-southeast-1",
184
+ "refreshDays": 7
185
+ }
186
+ },
187
+ "aliases": {
188
+ "amazon-bedrock": {
189
+ "claude-sonnet-4-6": "global.anthropic.claude-sonnet-4-6"
190
+ }
191
+ },
192
+ "overrides": {
193
+ "amazon-bedrock/bedrock.gpt-5.6": {
194
+ "input": 0,
195
+ "output": 0,
196
+ "cacheRead": 0,
197
+ "cacheWrite": 0
198
+ }
199
+ }
200
+ }
201
+ ```
202
+
203
+ Supported sources are:
204
+
205
+ | Source | Required when enabled | Optional | Reads from |
206
+ | --- | --- | --- | --- |
207
+ | `amazon-bedrock` | `enabled: true`, `profile`, `region` | `refreshDays` | `aws pricing get-products` for Amazon Bedrock. |
208
+ | `pi-models-store` | `enabled: true` | `refreshDays` | `~/.pi/agent/models-store.json`. |
209
+ | `models-dev` | `enabled: true`, `url` | `refreshDays` | The configured models.dev-compatible URL. |
210
+
211
+ Aliases map collector model names to a source's canonical model ID without
212
+ changing billing policy. Override keys are `provider/model`; values are USD per
213
+ one million tokens. An override requires `input` and `output`; `cacheRead` and
214
+ `cacheWrite` are optional and default to zero. Never use a bare model override
215
+ to price multiple providers.
216
+
217
+ Resolution order is: recorded cost, explicit override, the route primary source,
218
+ the route's `otherSources` in order, then unknown. Eurysx never guesses a number
219
+ for an unpriced model.
220
+
221
+ ### Refreshing and inspecting pricing
222
+
223
+ Eurysx creates `cache/` in the current project directory on every run. Enabled
224
+ sources cache normalized results in `cache/pricing-<source>.json`. Use the
225
+ normal command to use a fresh cache, or force a refresh:
226
+
227
+ ```bash
228
+ eurysx --refresh-pricing
229
+ ```
230
+
231
+ If refresh fails, Eurysx uses a valid existing cache and reports a warning. If
232
+ no valid price is available, the associated metered usage remains unknown rather
233
+ than being reported as free. The cache contains pricing metadata, not prompts or
234
+ credentials. Do not add API keys or LiteLLM master keys to either configuration
235
+ file.
236
+
237
+ ## Current limits
238
+
239
+ - Claude Code's stats cache is aggregate-only. Eurysx excludes it from selected
240
+ date ranges and reports a scope warning; it remains available for all-time use.
241
+ Its single row per model is stamped with `lastComputedDate`, so all-time Claude
242
+ Code rates spread the whole aggregate over that observed span and its
243
+ day-by-day activity table stays empty (`n/a` per-active-day lines) rather than
244
+ inventing a one-day spike.
245
+ - The supported collectors are Claude Code, OpenCode, Pi, and Codex only.
246
+ - Pricing data is metadata only. Source pricing may be unavailable, in which case
247
+ the relevant cost remains unknown.
248
+ - Preferences use recorded route metadata or exact user rules. Eurysx does not
249
+ call LiteLLM or provider APIs for route discovery and never reads credentials.
250
+ - A report with usage entries but no tokens displays priced-token coverage as
251
+ `N/A`.
252
+ - Collector fixtures verify known file shapes, not every live harness release.
253
+
254
+ ## Development
255
+
256
+ ```bash
257
+ PYTHONPATH=src python3 -m unittest -v tests/test_eurysx.py
258
+ python3 -m py_compile src/eurysx/*.py
259
+ ```
260
+
261
+ Sanitized collector fixtures cover Claude Code, Codex, Pi, and OpenCode. The
262
+ OpenCode SQL fixture builds a temporary SQLite database during the test rather
263
+ than committing a binary database file.
eurysx-0.1.0/README.md ADDED
@@ -0,0 +1,252 @@
1
+ # Eurysx
2
+
3
+ Local-first usage observability for Claude Code, OpenCode, Pi, and Codex.
4
+
5
+ Eurysx reads local agent history and reports tokens, requests, turns, tool calls,
6
+ estimated or recorded cost, and pricing provenance. It does not upload usage data
7
+ or persist prompts, responses, file contents, tool arguments, or tool results.
8
+
9
+ > Eurysx v0.1.0 is a local CLI, not a hosted service.
10
+
11
+ ## Install
12
+
13
+ ```bash
14
+ python3 -m pip install .
15
+ eurysx --help
16
+ ```
17
+
18
+ ## Run
19
+
20
+ ```bash
21
+ eurysx --version
22
+ eurysx
23
+ eurysx --agent codex --days 30
24
+ eurysx --agent all --month 2026-08
25
+ eurysx --agent pi --from 2026-08-01 --to 2026-08-15
26
+ eurysx --agent all --days 30 --output reports/usage.json
27
+ eurysx --refresh-pricing
28
+ eurysx collect --agent codex
29
+ eurysx report --agent codex --days 30
30
+ eurysx doctor
31
+ ```
32
+
33
+ `reports/` is ignored by Git.
34
+
35
+ `eurysx` collects current local metadata and then reports it. `collect` stores
36
+ metadata only; `report` reads the local store without collecting. `doctor` is
37
+ terminal-only and reports local harness, source, pricing-cache, and configuration
38
+ health without parsing history, refreshing prices, or deleting retained data. During Act II,
39
+ the store is `data/eurysx.db` relative to the current project directory. Set
40
+ `EURYSX_DATA_DIR` only to deliberately relocate it.
41
+
42
+ Period selectors are mutually exclusive: `--days N`, `--weeks N`,
43
+ `--from YYYY-MM-DD [--to YYYY-MM-DD]`, `--month YYYY-MM`,
44
+ `--quarter YYYY-QN`, `--year YYYY`, and `--ytd`. Rolling periods include today.
45
+
46
+ Filter selectors `--model`, `--provider`, and `--billing-mode` narrow the
47
+ analyzed rows and combine with `--agent` and the period selectors; bounded
48
+ period runs also compare against the same-length previous window. See the
49
+ [operational manual](docs/manual.md) for details.
50
+
51
+ ## Documentation
52
+
53
+ The [operational manual](docs/manual.md) is the authoritative command, output,
54
+ configuration, and diagnostics reference. Legacy [CLI](docs/cli.md) and
55
+ [output](docs/output.md) pages redirect there.
56
+
57
+ This manual is the authoritative contract for the JSONC configuration files.
58
+
59
+ ## Configuration manual
60
+
61
+ Eurysx is checkout-local during Act I. It reads and writes only these paths by
62
+ default, relative to the directory where you run `eurysx`:
63
+
64
+ ```text
65
+ eurysx/
66
+ ├── config/pricing.jsonc
67
+ ├── config/preferences.jsonc
68
+ └── cache/
69
+ ```
70
+
71
+ It does not use `~/Library/Application Support`, XDG directories, or other
72
+ system-level application folders. The local configuration and cache are ignored
73
+ by Git. Create them from the tracked templates:
74
+
75
+ ```bash
76
+ cp config/pricing.jsonc.sample config/pricing.jsonc
77
+ cp config/preferences.jsonc.sample config/preferences.jsonc
78
+ ```
79
+
80
+ Both files are JSONC: comments and trailing commas are allowed. Both are
81
+ optional. Without them, Eurysx retains recorded usage and marks unresolved cost
82
+ as unknown. Use `EURYSX_CONFIG_DIR` and `EURYSX_CACHE_DIR` only when deliberately
83
+ relocating those two directories, for example to a removable development volume.
84
+
85
+ ### `preferences.jsonc`: agent and provider policy
86
+
87
+ `preferences.jsonc` declares a schema version 2 policy. An agent-level policy
88
+ applies to every model when the collector has no provider metadata. `providers`
89
+ overrides that policy only for an exact recorded provider. There are no
90
+ model-match rules.
91
+
92
+ ```jsonc
93
+ {
94
+ "schemaVersion": 2,
95
+ "agents": {
96
+ "claude-code": {
97
+ "provider": "amazon-bedrock",
98
+ "billingMode": "metered",
99
+ "pricing": {
100
+ "source": "amazon-bedrock",
101
+ "otherSources": ["models-dev", "pi-models-store"]
102
+ }
103
+ },
104
+ "codex": {
105
+ "providers": {
106
+ "openai": { "billingMode": "subscription" },
107
+ "amazon-bedrock": {
108
+ "billingMode": "metered",
109
+ "pricing": { "source": "amazon-bedrock", "otherSources": ["models-dev"] }
110
+ },
111
+ "litellm": { "billingMode": "local" }
112
+ }
113
+ }
114
+ }
115
+ }
116
+ ```
117
+
118
+ `schemaVersion` and `agents` are the expected top-level fields. `schemaVersion`
119
+ is currently informational; Eurysx does not reject the file based on its value.
120
+ The file itself and each agent entry are optional. Omit an agent entry when you
121
+ want its usage to remain unclassified. Supported agent keys are `claude-code`,
122
+ `codex`, `opencode`, and `pi`; unknown keys are ignored.
123
+
124
+ | Policy field | Required? | Meaning |
125
+ | --- | --- | --- |
126
+ | `provider` | Optional | Effective provider when the collector does not record one. Usually needed for an agent-level metered policy. |
127
+ | `billingMode` | Optional | `metered`, `subscription`, `credit`, `quota`, `local`, or `unknown`. Omit it to let a matching provider policy decide; if no policy supplies it, Eurysx uses `unknown`. |
128
+ | `providers` | Optional | Map of exact recorded provider names to policy objects. Provider-policy fields override the agent-level fields. |
129
+ | `pricing` | Optional | Pricing lookup policy. For a config-priced metered route, include at least one valid `source` or `otherSources` entry. |
130
+ | `pricing.source` | Optional | Primary enabled source name from `pricing.jsonc`. |
131
+ | `pricing.otherSources` | Optional | Ordered enabled fallback source names from `pricing.jsonc`. |
132
+
133
+ `subscription`, `credit`, `quota`, and `local` report `N/A` incremental USD.
134
+ `metered` resolves pricing. A source name that is missing, disabled, or lacks an
135
+ exact provider/model price is skipped. Recorded harness cost always wins.
136
+
137
+ For an agent using more than one provider, omit agent-level `billingMode` rather
138
+ than setting it to `unknown` or an empty value. JSON has no useful blank value
139
+ here: `"billingMode": ""` is invalid policy data and is reported as unknown.
140
+ For example, Codex can classify its recorded OpenAI route as `subscription`, its
141
+ recorded Bedrock route as `metered`, and its recorded LiteLLM route as `local`.
142
+ If a record has no provider, or its provider is absent from `providers`, its
143
+ billing mode is `unknown` unless the agent-level policy defines one. Optional
144
+ budgets use `{"usd": 100, "period": "month"}` under an agent or exact provider;
145
+ invalid budgets disable pacing with a warning.
146
+
147
+ Billing modes describe incremental cost, not capability:
148
+
149
+ | Mode | Eurysx cost treatment |
150
+ | --- | --- |
151
+ | `metered` | Resolves per-token USD pricing. |
152
+ | `subscription`, `credit`, `quota`, `local` | Reports `N/A` incremental USD. Eurysx does not allocate fees or convert credits. |
153
+ | `unknown` | Retains usage and reports cost as unknown until you classify it or add pricing. |
154
+
155
+ Recorded harness cost always wins. If a recorded cost conflicts with a
156
+ non-metered policy, Eurysx keeps the recorded cost and warns.
157
+
158
+ ### `pricing.jsonc`: price sources and manual overrides
159
+
160
+ `pricing.jsonc` supplies per-million-token USD prices only for `metered` usage.
161
+ It has `sources`, provider-scoped `aliases`, and `overrides`. The file is
162
+ optional. Configure an enabled source before naming it in `pricing.source` or
163
+ `pricing.otherSources`.
164
+
165
+ ```jsonc
166
+ {
167
+ "schemaVersion": 2,
168
+ "sources": {
169
+ "amazon-bedrock": {
170
+ "enabled": true,
171
+ "profile": "your-aws-profile",
172
+ "region": "ap-southeast-1",
173
+ "refreshDays": 7
174
+ }
175
+ },
176
+ "aliases": {
177
+ "amazon-bedrock": {
178
+ "claude-sonnet-4-6": "global.anthropic.claude-sonnet-4-6"
179
+ }
180
+ },
181
+ "overrides": {
182
+ "amazon-bedrock/bedrock.gpt-5.6": {
183
+ "input": 0,
184
+ "output": 0,
185
+ "cacheRead": 0,
186
+ "cacheWrite": 0
187
+ }
188
+ }
189
+ }
190
+ ```
191
+
192
+ Supported sources are:
193
+
194
+ | Source | Required when enabled | Optional | Reads from |
195
+ | --- | --- | --- | --- |
196
+ | `amazon-bedrock` | `enabled: true`, `profile`, `region` | `refreshDays` | `aws pricing get-products` for Amazon Bedrock. |
197
+ | `pi-models-store` | `enabled: true` | `refreshDays` | `~/.pi/agent/models-store.json`. |
198
+ | `models-dev` | `enabled: true`, `url` | `refreshDays` | The configured models.dev-compatible URL. |
199
+
200
+ Aliases map collector model names to a source's canonical model ID without
201
+ changing billing policy. Override keys are `provider/model`; values are USD per
202
+ one million tokens. An override requires `input` and `output`; `cacheRead` and
203
+ `cacheWrite` are optional and default to zero. Never use a bare model override
204
+ to price multiple providers.
205
+
206
+ Resolution order is: recorded cost, explicit override, the route primary source,
207
+ the route's `otherSources` in order, then unknown. Eurysx never guesses a number
208
+ for an unpriced model.
209
+
210
+ ### Refreshing and inspecting pricing
211
+
212
+ Eurysx creates `cache/` in the current project directory on every run. Enabled
213
+ sources cache normalized results in `cache/pricing-<source>.json`. Use the
214
+ normal command to use a fresh cache, or force a refresh:
215
+
216
+ ```bash
217
+ eurysx --refresh-pricing
218
+ ```
219
+
220
+ If refresh fails, Eurysx uses a valid existing cache and reports a warning. If
221
+ no valid price is available, the associated metered usage remains unknown rather
222
+ than being reported as free. The cache contains pricing metadata, not prompts or
223
+ credentials. Do not add API keys or LiteLLM master keys to either configuration
224
+ file.
225
+
226
+ ## Current limits
227
+
228
+ - Claude Code's stats cache is aggregate-only. Eurysx excludes it from selected
229
+ date ranges and reports a scope warning; it remains available for all-time use.
230
+ Its single row per model is stamped with `lastComputedDate`, so all-time Claude
231
+ Code rates spread the whole aggregate over that observed span and its
232
+ day-by-day activity table stays empty (`n/a` per-active-day lines) rather than
233
+ inventing a one-day spike.
234
+ - The supported collectors are Claude Code, OpenCode, Pi, and Codex only.
235
+ - Pricing data is metadata only. Source pricing may be unavailable, in which case
236
+ the relevant cost remains unknown.
237
+ - Preferences use recorded route metadata or exact user rules. Eurysx does not
238
+ call LiteLLM or provider APIs for route discovery and never reads credentials.
239
+ - A report with usage entries but no tokens displays priced-token coverage as
240
+ `N/A`.
241
+ - Collector fixtures verify known file shapes, not every live harness release.
242
+
243
+ ## Development
244
+
245
+ ```bash
246
+ PYTHONPATH=src python3 -m unittest -v tests/test_eurysx.py
247
+ python3 -m py_compile src/eurysx/*.py
248
+ ```
249
+
250
+ Sanitized collector fixtures cover Claude Code, Codex, Pi, and OpenCode. The
251
+ OpenCode SQL fixture builds a temporary SQLite database during the test rather
252
+ than committing a binary database file.