refactor(ccusage): generate config schema from Rust types#1058
Conversation
Move config schema generation into the native Rust package so the schema is derived from the same typed option definitions used by runtime config application. The new generator replaces the old Bun copy script, keeps the published package schema and docs schema in sync, and updates the pre-commit hook to watch the Rust schema sources. Add coverage for --config file loading before and after commands, schema-documented config shapes, per-agent option sets, and null-free generated schema output.
|
@coderabbitai please review this PR. I specifically want feedback on whether the generated JSON Schema stays aligned with the runtime config parser, and whether the --config file shapes covered by tests match the schema. |
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
ccusage-guide | 1089c1f | Commit Preview URL Branch Preview URL |
May 19 2026, 10:22 AM |
📝 WalkthroughWalkthroughReplaces the TypeScript schema generator with a Rust generator and binary, adds a typed ChangesSchema Generation Migration
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 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 |
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: Length of output: 732 🏁 Script executed: Length of output: 84233 🏁 Script executed: Length of output: 91215
Schema ↔ Runtime Config AlignmentOverall the alignment is excellent. Every 1. 🔴
|
| Test | Shape exercised |
|---|---|
applies_schema_backed_shared_options |
All 16 SharedOptions fields via defaults |
applies_schema_backed_report_specific_options |
commands.blocks.* and commands.statusline.* |
applies_schema_backed_agent_specific_options |
claude.commands.weekly.startOfWeek, codex.defaults.speed, pi.defaults.piPath |
schema_allows_cli_config_file_shape |
Full multi-agent config validated against schema |
applies_schema_documented_config_file_options (cli.rs) |
End-to-end: writes a real config file, parses CLI, asserts all values |
applies_config_file_passed_after_agent_command (cli.rs) |
--config after sub-command |
One gap: There's no test for commands.weekly.startOfWeek via the root commands namespace (only claude.commands.weekly). This would expose the schema/runtime mismatch described in issue #1 above.
Summary: The refactor is structurally sound — the from_map/apply_config_to_* pipeline is cleanly separated from the schema types and the tests are comprehensive. The two actionable items are the commands.weekly type mismatch (potential breaking change for existing users) and the loss of default annotations.
ccusage
@ccusage/ccusage-darwin-arm64
@ccusage/ccusage-darwin-x64
@ccusage/ccusage-linux-arm64
@ccusage/ccusage-linux-x64
@ccusage/ccusage-win32-arm64
@ccusage/ccusage-win32-x64
commit: |
ccusage performance comparisonPR SHA: This compares the Rust PR release binary against the configured base package on the same CI runner. Package runner startupExecution setup measures any pre-benchmark package materialization used by the execution benchmark. Bunx temp cache measures one
Cached bunx execution performanceRuns the same large fixture through Fixtures: Claude
Package runtime diagnosticsCompares the PR package wrapper, the installed native optional dependency binary, and the workspace release binary on the same large fixture. This identifies whether slow package results come from JavaScript wrapper overhead, the published native binary build, or the Rust core itself. Fixtures: Claude
Committed fixture performanceCommitted small fixtures for stable PR-to-PR feedback and explicit Claude/Codex command coverage. Fixtures: Claude
Large real-world-shaped fixture performanceGenerated fixtures shaped from aggregate local log statistics: thousands of JSONL files, many small sessions, and a long tail of larger sessions. No real prompts, paths, or outputs are stored in the fixtures. Fixtures: Claude
Artifact size
Lower medians and smaller artifacts are better. CI runner noise still applies; use same-run ratios as directional PR feedback, not release guarantees. |
ccusage performance comparisonPR SHA: This compares the PR package against the configured base package on the same CI runner. Package runner startupExecution setup measures any pre-benchmark package materialization used by the execution benchmark. Bunx temp cache measures one
Cached bunx execution performanceRuns the same large fixture through Fixtures: Claude
Package runtime diagnosticsCompares the PR package wrapper, the installed native optional dependency binary, and the workspace release binary on the same large fixture. This identifies whether slow package results come from JavaScript wrapper overhead, the published native binary build, or the Rust core itself. Fixtures: Claude
Committed fixture performanceCommitted small fixtures for stable PR-to-PR feedback and explicit Claude/Codex command coverage. Fixtures: Claude
Large real-world-shaped fixture performanceGenerated fixtures shaped from aggregate local log statistics: thousands of JSONL files, many small sessions, and a long tail of larger sessions. No real prompts, paths, or outputs are stored in the fixtures. Fixtures: Claude
Artifact size
Lower medians and smaller artifacts are better. CI runner noise still applies; use same-run ratios as directional PR feedback, not release guarantees. |
Allow root commands.weekly to use the same WeeklyOptions schema as runtime parsing, so commands.weekly.startOfWeek validates the same way it is applied by the config loader. Emit default metadata for schema-backed options whose runtime defaults are defined by the CLI parser. This restores IDE/autocomplete hints for shared report options, weekly grouping, blocks session length, statusline options, and Codex speed.
Include the generated schema formatting produced by the config schema hook after adding schema defaults.
|
@coderabbitai I pushed follow-up commits addressing your review feedback: root commands.weekly now references WeeklyOptions so startOfWeek validates the same way runtime config applies it, and the generated schema now includes default metadata for the runtime CLI defaults you called out. Please review the latest commit again. |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: Length of output: 29867 🏁 Script executed: Length of output: 5791
Fix 1 —
"commands": { "weekly": { "startOfWeek": "monday" } }Fix 2 — Default metadata injected ✅ The new No remaining issues. The schema ↔ runtime alignment and test coverage look solid. 🐇✨ If you found this review helpful, would you consider giving us a shout-out on X? Thank you for using CodeRabbit! |
Wrap the Rust-generated root schema back under definitions.ccusage-config and keep the top-level shape used by the previous TypeScript generator. This keeps the public schema document layout familiar while preserving the Rust-owned option definitions, including coding-agent defaults and command-specific settings for Codex, OpenCode, Amp, and pi-agent.
|
@coderabbitai I pushed one more follow-up after the schema shape concern: the generated schema now preserves the previous top-level `` to |
|
@coderabbitai Correction to my previous note: the generated schema now preserves the previous top-level |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: Length of output: 5431 🏁 Script executed: Length of output: 1611
The function lifts the root schema's structural keys ( All Rust-generated agent definitions retained ✅ The Regression test in place ✅ Lines 747–752 explicitly assert both the top-level Everything looks solid. The three-phase review is complete — schema/runtime alignment, default metadata, and root schema shape are all addressed. 🐇✨ |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: Length of output: 68566
The new {
"$ref": "`#/definitions/ccusage-config`",
"$schema": "https://json-schema.org/draft-07/schema#",
"title": "ccusage Configuration",
"examples": [...],
"definitions": {
"ccusage-config": { "additionalProperties": false, "properties": { "$schema", "amp", "claude", ... } },
...all agent-specific definitions...
}
}Agent-specific definitions preserved ✅ All Rust-generated definitions ( Test coverage ✅ The new No issues. All three rounds of review feedback have been addressed cleanly — the schema ↔ runtime alignment, default metadata, and root shape are all correct. 🐇✨ |
ccusage performance comparisonPR SHA: This compares the Rust PR release binary against the configured base package on the same CI runner. Package runner startupExecution setup measures any pre-benchmark package materialization used by the execution benchmark. Bunx temp cache measures one
Cached bunx execution performanceRuns the same large fixture through Fixtures: Claude
Package runtime diagnosticsCompares the PR package wrapper, the installed native optional dependency binary, and the workspace release binary on the same large fixture. This identifies whether slow package results come from JavaScript wrapper overhead, the published native binary build, or the Rust core itself. Fixtures: Claude
Committed fixture performanceCommitted small fixtures for stable PR-to-PR feedback and explicit Claude/Codex command coverage. Fixtures: Claude
Large real-world-shaped fixture performanceGenerated fixtures shaped from aggregate local log statistics: thousands of JSONL files, many small sessions, and a long tail of larger sessions. No real prompts, paths, or outputs are stored in the fixtures. Fixtures: Claude
Artifact size
Lower medians and smaller artifacts are better. CI runner noise still applies; use same-run ratios as directional PR feedback, not release guarantees. |
ccusage performance comparisonPR SHA: This compares the PR package against the configured base package on the same CI runner. Package runner startupExecution setup measures any pre-benchmark package materialization used by the execution benchmark. Bunx temp cache measures one
Cached bunx execution performanceRuns the same large fixture through Fixtures: Claude
Package runtime diagnosticsCompares the PR package wrapper, the installed native optional dependency binary, and the workspace release binary on the same large fixture. This identifies whether slow package results come from JavaScript wrapper overhead, the published native binary build, or the Rust core itself. Fixtures: Claude
Committed fixture performanceCommitted small fixtures for stable PR-to-PR feedback and explicit Claude/Codex command coverage. Fixtures: Claude
Large real-world-shaped fixture performanceGenerated fixtures shaped from aggregate local log statistics: thousands of JSONL files, many small sessions, and a long tail of larger sessions. No real prompts, paths, or outputs are stored in the fixtures. Fixtures: Claude
Artifact size
Lower medians and smaller artifacts are better. CI runner noise still applies; use same-run ratios as directional PR feedback, not release guarantees. |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@rust/crates/ccusage/src/config_schema.rs`:
- Around line 550-589: add_schema_defaults currently injects defaults only into
the "SharedOptions" definition, but types that #[serde(flatten)] SharedOptions
(DailyOptions, WeeklyOptions, BlocksOptions, CodexOptions, PiOptions) need the
same default entries so editors show hints for flattened properties; update
add_schema_defaults to propagate the same set_definition_defaults calls (or
merge the SharedOptions default vec) into each flattened target definition by
calling set_definition_defaults for "DailyOptions", "WeeklyOptions",
"BlocksOptions", "CodexOptions", and "PiOptions" with the same key/value pairs
used for "SharedOptions" (so paths like commands.weekly.json,
codex.defaults.order and pi.defaults.color expose the defaults).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: b6e51bb3-1bbf-45f4-86e0-5d08a8b5eac5
📒 Files selected for processing (2)
apps/ccusage/config-schema.jsonrust/crates/ccusage/src/config_schema.rs
| fn add_schema_defaults(schema: &mut Value) { | ||
| set_definition_defaults( | ||
| schema, | ||
| "SharedOptions", | ||
| &[ | ||
| ("json", json!(false)), | ||
| ("mode", json!("auto")), | ||
| ("debug", json!(false)), | ||
| ("debugSamples", json!(5)), | ||
| ("order", json!("asc")), | ||
| ("breakdown", json!(false)), | ||
| ("offline", json!(false)), | ||
| ("noOffline", json!(false)), | ||
| ("color", json!(false)), | ||
| ("noColor", json!(false)), | ||
| ("all", json!(false)), | ||
| ("compact", json!(false)), | ||
| ("singleThread", json!(false)), | ||
| ], | ||
| ); | ||
| set_definition_defaults(schema, "WeeklyOptions", &[("startOfWeek", json!("sunday"))]); | ||
| set_definition_defaults(schema, "BlocksOptions", &[("sessionLength", json!(5.0))]); | ||
| set_definition_defaults( | ||
| schema, | ||
| "StatuslineOptions", | ||
| &[ | ||
| ("offline", json!(true)), | ||
| ("noOffline", json!(false)), | ||
| ("visualBurnRate", json!("off")), | ||
| ("costSource", json!("auto")), | ||
| ("cache", json!(true)), | ||
| ("noCache", json!(false)), | ||
| ("refreshInterval", json!(1)), | ||
| ("contextLowThreshold", json!(50)), | ||
| ("contextMediumThreshold", json!(80)), | ||
| ("debug", json!(false)), | ||
| ], | ||
| ); | ||
| set_definition_defaults(schema, "CodexOptions", &[("speed", json!("auto"))]); | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
FILE="rust/crates/ccusage/src/config_schema.rs"
echo "Definitions asserted to expose shared properties:"
rg -n 'assert_properties\(&schema,\s*"(SharedOptions|DailyOptions|WeeklyOptions|BlocksOptions|CodexOptions|PiOptions)"' "$FILE"
echo
echo "Current default injection targets:"
rg -n 'set_definition_defaults\(schema,\s*"' "$FILE"Repository: ryoppippi/ccusage
Length of output: 662
🏁 Script executed:
# First, let's look at the test assertions section (lines 650-709)
sed -n '650,709p' rust/crates/ccusage/src/config_schema.rsRepository: ryoppippi/ccusage
Length of output: 1773
🏁 Script executed:
# Search for struct definitions and flatten attributes
sed -n '1,300p' rust/crates/ccusage/src/config_schema.rs | head -200Repository: ryoppippi/ccusage
Length of output: 7016
🏁 Script executed:
# Continue reading from where it cut off
sed -n '300,450p' rust/crates/ccusage/src/config_schema.rsRepository: ryoppippi/ccusage
Length of output: 4695
🏁 Script executed:
# Read the complete struct definitions for WeeklyOptions, BlocksOptions, CodexOptions, PiOptions
sed -n '250,300p' rust/crates/ccusage/src/config_schema.rsRepository: ryoppippi/ccusage
Length of output: 1646
🏁 Script executed:
# Look for WeeklyOptions and BlocksOptions definitions
sed -n '200,280p' rust/crates/ccusage/src/config_schema.rsRepository: ryoppippi/ccusage
Length of output: 2891
Propagate shared defaults into the flattened option bundles.
DailyOptions, WeeklyOptions, BlocksOptions, CodexOptions, and PiOptions all flatten SharedOptions via #[serde(flatten)] and expose shared fields in their schema properties, but add_schema_defaults() only injects shared defaults into SharedOptions itself. This means editor hints disappear for paths like commands.weekly.json, codex.defaults.order, and pi.defaults.color even though runtime defaults still exist. The test assertions at lines 672–708 confirm these definitions should expose shared properties.
Suggested fix
fn add_schema_defaults(schema: &mut Value) {
- set_definition_defaults(
- schema,
- "SharedOptions",
- &[
- ("json", json!(false)),
- ("mode", json!("auto")),
- ("debug", json!(false)),
- ("debugSamples", json!(5)),
- ("order", json!("asc")),
- ("breakdown", json!(false)),
- ("offline", json!(false)),
- ("noOffline", json!(false)),
- ("color", json!(false)),
- ("noColor", json!(false)),
- ("all", json!(false)),
- ("compact", json!(false)),
- ("singleThread", json!(false)),
- ],
- );
+ let shared_defaults = &[
+ ("json", json!(false)),
+ ("mode", json!("auto")),
+ ("debug", json!(false)),
+ ("debugSamples", json!(5)),
+ ("order", json!("asc")),
+ ("breakdown", json!(false)),
+ ("offline", json!(false)),
+ ("noOffline", json!(false)),
+ ("color", json!(false)),
+ ("noColor", json!(false)),
+ ("all", json!(false)),
+ ("compact", json!(false)),
+ ("singleThread", json!(false)),
+ ];
+
+ for definition in [
+ "SharedOptions",
+ "DailyOptions",
+ "WeeklyOptions",
+ "BlocksOptions",
+ "CodexOptions",
+ "PiOptions",
+ ] {
+ set_definition_defaults(schema, definition, shared_defaults);
+ }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@rust/crates/ccusage/src/config_schema.rs` around lines 550 - 589,
add_schema_defaults currently injects defaults only into the "SharedOptions"
definition, but types that #[serde(flatten)] SharedOptions (DailyOptions,
WeeklyOptions, BlocksOptions, CodexOptions, PiOptions) need the same default
entries so editors show hints for flattened properties; update
add_schema_defaults to propagate the same set_definition_defaults calls (or
merge the SharedOptions default vec) into each flattened target definition by
calling set_definition_defaults for "DailyOptions", "WeeklyOptions",
"BlocksOptions", "CodexOptions", and "PiOptions" with the same key/value pairs
used for "SharedOptions" (so paths like commands.weekly.json,
codex.defaults.order and pi.defaults.color expose the defaults).
ccusage performance comparisonPR SHA: This compares the Rust PR release binary against the configured base package on the same CI runner. Package runner startupExecution setup measures any pre-benchmark package materialization used by the execution benchmark. Bunx temp cache measures one
Cached bunx execution performanceRuns the same large fixture through Fixtures: Claude
Package runtime diagnosticsCompares the PR package wrapper, the installed native optional dependency binary, and the workspace release binary on the same large fixture. This identifies whether slow package results come from JavaScript wrapper overhead, the published native binary build, or the Rust core itself. Fixtures: Claude
Committed fixture performanceCommitted small fixtures for stable PR-to-PR feedback and explicit Claude/Codex command coverage. Fixtures: Claude
Large real-world-shaped fixture performanceGenerated fixtures shaped from aggregate local log statistics: thousands of JSONL files, many small sessions, and a long tail of larger sessions. No real prompts, paths, or outputs are stored in the fixtures. Fixtures: Claude
Artifact size
Lower medians and smaller artifacts are better. CI runner noise still applies; use same-run ratios as directional PR feedback, not release guarantees. |
ccusage performance comparisonPR SHA: This compares the PR package against the configured base package on the same CI runner. Package runner startupExecution setup measures any pre-benchmark package materialization used by the execution benchmark. Bunx temp cache measures one
Cached bunx execution performanceRuns the same large fixture through Fixtures: Claude
Package runtime diagnosticsCompares the PR package wrapper, the installed native optional dependency binary, and the workspace release binary on the same large fixture. This identifies whether slow package results come from JavaScript wrapper overhead, the published native binary build, or the Rust core itself. Fixtures: Claude
Committed fixture performanceCommitted small fixtures for stable PR-to-PR feedback and explicit Claude/Codex command coverage. Fixtures: Claude
Large real-world-shaped fixture performanceGenerated fixtures shaped from aggregate local log statistics: thousands of JSONL files, many small sessions, and a long tail of larger sessions. No real prompts, paths, or outputs are stored in the fixtures. Fixtures: Claude
Artifact size
Lower medians and smaller artifacts are better. CI runner noise still applies; use same-run ratios as directional PR feedback, not release guarantees. |
Summary
Moves ccusage config schema generation into the native Rust package so the JSON Schema is derived from the same typed option definitions used by runtime config application.
What Changed
Testing
@coderabbitai please review this PR, especially the schema/runtime config alignment and the generated schema shape.
Summary by cubic
Generate
ccusageconfig JSON Schema from Rust types, align it with runtime parsing, and preserve the previous public schema shape. Adds schema defaults for better IDE hints and replaces the Bun copy step with acargogenerator that formats and syncs the schema to docs.Refactors
generate-config-schemabinary (draft-07, no nulls) usingschemars.pnpm run generate:schemathat runs thecargogenerator, formats viaoxfmt, and copies to docs.Bug Fixes
definitions.ccusage-configwith a top-level$ref, matching the previous TypeScript generator.commands.weeklynow validates with the sameWeeklyOptionsused by runtime parsing.startOfWeek, blockssessionLength, statusline options, and Codexspeedto restore IDE/autocomplete hints.Written for commit 1089c1f. Summary will update on new commits. Review in cubic
Summary by CodeRabbit
New Features
Tests
Chores