feat(zcode): add ZCode usage adapter - #1614
Conversation
Reads completed model requests from the ZCode desktop app's SQLite ledger (~/.zcode/cli/db/db.sqlite, model_usage joined with session) and exposes the standard daily/monthly/session reports, focused via `ccusage zcode <report>` and aggregated into the unified reports as the seventeenth built-in agent. Token semantics follow the schema's own arithmetic: input_tokens includes the cache-read slice (computed_total = input + output holds for every observed row), so the parser carves cache reads out of input to keep the reported buckets additive and priced at their own rate. Reasoning is always zero in observed rows and assumed to sit inside output; the shared total-token fallback catches a future version moving it outside. ZCode records no per-request cost, so every cost mode derives from the pricing tables, with model ids lowercased to match the case-sensitive pricing keys (GLM-5.3 -> glm-5.3). Discovery honors a non-empty ZCODE_HOME (single root or comma- separated list, kilo-style) before ~/.zcode, opens the database read-only so reports work while ZCode runs, and degrades to no entries with a --debug line when the schema does not match. Fixture tests pin the current shape: cache carve-out, status filter, missing db, unexpected schema, cross-root dedupe, and session aggregation with project paths.
Adds the guide page (data location, ZCODE_HOME, token and cost semantics, troubleshooting) with VitePress navigation, and registers ZCode in the supported-agent lists, data-location tables, env-var table, config namespaces, and README examples.
|
This PR was auto-closed. Only contributors approved with Maintainers review auto-closed issues and reopen worthwhile ones. Issues that do not meet the quality bar in CONTRIBUTING.md may not be reopened or receive a reply. If a maintainer replies See CONTRIBUTING.md. |
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: ⛔ Files ignored due to path filters (4)
📒 Files selected for processing (38)
📝 WalkthroughWalkthroughThis change adds ZCode as a supported ccusage source. It includes a SQLite adapter, daily/monthly/session CLI commands, configuration schema support, unified reporting integration, pricing and token reporting, environment variables, and documentation. ChangesZCode source support
Estimated code review effort: 4 (Complex) | ~60 minutes Possibly related PRs
Suggested labels: Suggested reviewers: Sequence Diagram(s)sequenceDiagram
participant User
participant CLIParser
participant CcusageMain
participant ZcodeLoader
participant SQLite
participant ZcodeReport
User->>CLIParser: run ccusage zcode daily
CLIParser->>CcusageMain: create Command::ZCode
CcusageMain->>ZcodeLoader: run with AgentCommandArgs
ZcodeLoader->>SQLite: read completed model_usage rows
SQLite-->>ZcodeLoader: return usage rows
ZcodeLoader->>ZcodeReport: summarize LoadedEntry values
ZcodeReport-->>User: render JSON, JQ, or usage table
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
@coderabbitai review |
@aseelye I have started the AI code review. It will take a few minutes to complete. |
|
|
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes This review covers the complete four-commit PR: the new ZCode SQLite adapter, token and pricing normalization, focused and unified report integration, CLI/config/schema wiring, tests, packaging, and documentation.
- ZCode data loading Reads completed
model_usagerows from the configured or default SQLite home, joins session directories, handles legacy session metadata, deduplicates multiple roots, and preserves source model labels. - Usage and cost semantics Normalizes cache-inclusive input tokens into additive buckets, preserves total-token fallbacks, applies Z.ai-qualified pricing and exact raw-model overrides, and keeps
displaymode at zero when the source has no recorded cost. - Report and CLI integration Wires daily, monthly, and session focused reports, unified aggregation, command parsing,
--last, configuration namespaces, agent detection, and native packaging. - Coverage and documentation Adds adapter fixtures and unit coverage for schema handling, token normalization, filtering, deduplication, pricing, and report shapes, along with the generated schema and user-facing source documentation.
@v0 or keep the SHA fresh with Dependabot | View workflow run | Using GPT Luna (free via Pullfrog for OSS) | 𝕏
There was a problem hiding this comment.
3 issues found across 42 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="rust/adapters/zcode/README.md">
<violation number="1" location="rust/adapters/zcode/README.md:56">
P3: report::report_from_rows is listed under "Public surface", but it is only `pub(crate)` in lib.rs, so it is not part of the crate's public API. Correct the docs to match the actual export (only loader::load_entries, report::summarize_entries, and run are public).</violation>
</file>
<file name="rust/crates/ccusage-adapter-all/README.md">
<violation number="1" location="rust/crates/ccusage-adapter-all/README.md:32">
P3: The Depends on list is alphabetized, but `ccusage-adapter-zcode` was inserted between `ccusage-adapter-grok` and `ccusage-adapter-hermes` rather than after `ccusage-adapter-qwen`. Move it to the end to restore the ordering, matching `ccusage-adapter-all/Cargo.toml` where zcode is listed last among adapters.</violation>
</file>
<file name="rust/adapters/zcode/src/paths.rs">
<violation number="1" location="rust/adapters/zcode/src/paths.rs:24">
P2: When an explicitly configured `ZCODE_HOME` root is missing or inaccessible, this filter silently drops it and `paths()` returns no paths, so `--debug` cannot explain missing ZCode data. Pass debug context into discovery and log rejected configured roots, or propagate a discovery failure that the loader can log.</violation>
</file>
Tip: cubic can generate docs of your entire codebase and keep them up to date. Try it here.
Re-trigger cubic
| .filter(|path| !path.is_empty()) | ||
| { | ||
| let path = PathBuf::from(raw); | ||
| if path.is_dir() && seen.insert(path.clone()) { |
There was a problem hiding this comment.
P2: When an explicitly configured ZCODE_HOME root is missing or inaccessible, this filter silently drops it and paths() returns no paths, so --debug cannot explain missing ZCode data. Pass debug context into discovery and log rejected configured roots, or propagate a discovery failure that the loader can log.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At rust/adapters/zcode/src/paths.rs, line 24:
<comment>When an explicitly configured `ZCODE_HOME` root is missing or inaccessible, this filter silently drops it and `paths()` returns no paths, so `--debug` cannot explain missing ZCode data. Pass debug context into discovery and log rejected configured roots, or propagate a discovery failure that the loader can log.</comment>
<file context>
@@ -0,0 +1,65 @@
+ .filter(|path| !path.is_empty())
+ {
+ let path = PathBuf::from(raw);
+ if path.is_dir() && seen.insert(path.clone()) {
+ paths.push(path);
+ }
</file context>
| ## Public surface | ||
|
|
||
| - `loader::load_entries` | ||
| - `report::report_from_rows` |
There was a problem hiding this comment.
P3: report::report_from_rows is listed under "Public surface", but it is only pub(crate) in lib.rs, so it is not part of the crate's public API. Correct the docs to match the actual export (only loader::load_entries, report::summarize_entries, and run are public).
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At rust/adapters/zcode/README.md, line 56:
<comment>report::report_from_rows is listed under "Public surface", but it is only `pub(crate)` in lib.rs, so it is not part of the crate's public API. Correct the docs to match the actual export (only loader::load_entries, report::summarize_entries, and run are public).</comment>
<file context>
@@ -0,0 +1,70 @@
+## Public surface
+
+- `loader::load_entries`
+- `report::report_from_rows`
+- `report::summarize_entries`
+- `run`
</file context>
| - `report::report_from_rows` | |
| - `report::report_from_rows` |
| - `ccusage-adapter-gemini` | ||
| - `ccusage-adapter-goose` | ||
| - `ccusage-adapter-grok` | ||
| - `ccusage-adapter-zcode` |
There was a problem hiding this comment.
P3: The Depends on list is alphabetized, but ccusage-adapter-zcode was inserted between ccusage-adapter-grok and ccusage-adapter-hermes rather than after ccusage-adapter-qwen. Move it to the end to restore the ordering, matching ccusage-adapter-all/Cargo.toml where zcode is listed last among adapters.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At rust/crates/ccusage-adapter-all/README.md, line 32:
<comment>The Depends on list is alphabetized, but `ccusage-adapter-zcode` was inserted between `ccusage-adapter-grok` and `ccusage-adapter-hermes` rather than after `ccusage-adapter-qwen`. Move it to the end to restore the ordering, matching `ccusage-adapter-all/Cargo.toml` where zcode is listed last among adapters.</comment>
<file context>
@@ -29,6 +29,7 @@ themselves independent of each other.
- `ccusage-adapter-gemini`
- `ccusage-adapter-goose`
- `ccusage-adapter-grok`
+- `ccusage-adapter-zcode`
- `ccusage-adapter-hermes`
- `ccusage-adapter-kilo`
</file context>

Summary
Add ZCode as a first-class ccusage data source for daily, monthly, session, and unified reports.
ZCode stores completed model usage in a local SQLite database. This adapter reads that database in read-only mode, normalizes ZCode's inclusive cache-token accounting into ccusage's additive token buckets, and estimates costs from the shared pricing tables.
What changed
$ZCODE_HOME/cli/db/db.sqlite(including multiple roots), with~/.zcodeas the defaultsession(id, directory)schema without requiring aversioncolumninput_tokens--mode displayis zero because ZCode records no per-request costValidation
cargo test -p ccusage-adapter-zcode -p ccusage-cli-parser -p ccusage-config -p ccusage-adapter-all -p ccusagecargo clippy -p ccusage-adapter-zcode --all-targets -- -D warningspnpm --dir docs buildcargo fmt --all -- --checkgit diff --checkContext
Closes #1595.
The schema/token-accounting investigation and earlier implementation in axisrow/ccusage#1 were useful prior art. This implementation targets ccusage's current per-adapter Rust architecture and adds compatibility and pricing behavior for the schemas and models reported in that thread.
Summary by CodeRabbit
New Features
ZCODE_HOME.Documentation