Skip to content

refactor(ccusage): generate config schema from Rust types#1058

Merged
ryoppippi merged 4 commits into
mainfrom
codex/rust-config-schema
May 19, 2026
Merged

refactor(ccusage): generate config schema from Rust types#1058
ryoppippi merged 4 commits into
mainfrom
codex/rust-config-schema

Conversation

@ryoppippi
Copy link
Copy Markdown
Owner

@ryoppippi ryoppippi commented May 19, 2026

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

  • Added Rust config schema types and a generate-config-schema binary.
  • Replaced the old Bun schema copy script with a direct Rust generator command.
  • Updated the pre-commit schema hook to watch Rust schema sources.
  • Added tests covering schema option sets, null-free generated schema output, --config file loading, and schema-documented config shapes.

Testing

  • pnpm --filter ccusage run generate:schema
  • pnpm run format
  • pnpm typecheck
  • pnpm run test

@coderabbitai please review this PR, especially the schema/runtime config alignment and the generated schema shape.


Summary by cubic

Generate ccusage config 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 a cargo generator that formats and syncs the schema to docs.

  • Refactors

    • Added Rust schema types and a generate-config-schema binary (draft-07, no nulls) using schemars.
    • Replaced the Bun script with pnpm run generate:schema that runs the cargo generator, formats via oxfmt, and copies to docs.
    • Updated pre-commit to watch Rust schema sources.
  • Bug Fixes

    • Preserved the schema root shape by wrapping under definitions.ccusage-config with a top-level $ref, matching the previous TypeScript generator.
    • Root commands.weekly now validates with the same WeeklyOptions used by runtime parsing.
    • Generator emits defaults for shared options, weekly startOfWeek, blocks sessionLength, statusline options, and Codex speed to restore IDE/autocomplete hints.

Written for commit 1089c1f. Summary will update on new commits. Review in cubic

Summary by CodeRabbit

  • New Features

    • Switched to a schema-driven configuration model with typed, validated options applied across all commands.
  • Tests

    • Added unit tests to verify config parsing, schema correctness, and command compatibility.
  • Chores

    • Replaced the previous schema generator with a Rust-based generator and updated pre-commit checks to use the new workflow.

Review Change Stack

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.
@ryoppippi
Copy link
Copy Markdown
Owner Author

@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.

@cloudflare-workers-and-pages
Copy link
Copy Markdown

cloudflare-workers-and-pages Bot commented May 19, 2026

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

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

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 19, 2026

📝 Walkthrough

Walkthrough

Replaces the TypeScript schema generator with a Rust generator and binary, adds a typed config_schema module that emits an enriched JSON Schema and tests, refactors runtime config application to use schema-backed option structs, and updates package scripts and pre-commit hooks.

Changes

Schema Generation Migration

Layer / File(s) Summary
Configuration Schema Model and Generation
rust/crates/ccusage/src/config_schema.rs
New module defines CcusageConfig, shared and per-agent option structs, enums, from_map constructors, generate_config_schema_json() using schemars, schema enrichment and default injection, tab-indented output, helpers, and unit tests validating schema shape and validation.
Schema Generator Binary and Integration
rust/crates/ccusage/src/main.rs, rust/crates/ccusage/Cargo.toml, rust/crates/ccusage/src/bin/generate_config_schema.rs
Adds mod config_schema;, declares [[bin]] generate-config-schema, adds schemars dependency, and implements a binary that calls generate_config_schema_json() and writes schema to stdout or specified files with error handling.
Config Application Refactoring
rust/crates/ccusage/src/config.rs
Replaces manual JSON-key parsing with schema-driven from_map option bundles (shared/daily/weekly/blocks/statusline/Codex/Pi), extracts apply_shared_options(), and uses From<Config*> conversions for enums; tests updated to assert schema-backed mappings.
Build System and Script Updates
apps/ccusage/package.json, lefthook.yml
Replaces generate:schema script to run the Rust generator (via cargo run --quiet), format with oxfmt, and copy config-schema.json to docs; updates lefthook pre-commit globs to reference apps/ccusage/package.json and Rust generator/source files instead of the removed TS generator.
Schema-Based Configuration Tests
rust/crates/ccusage/src/cli.rs
Adds tests: one ensuring --config after an agent command applies defaults and command-specific settings; another that loads a $schema-annotated config and validates parsing across multiple commands and option fields.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • ryoppippi/ccusage#1007: Modifies the TypeScript schema generator that this PR removes; likely direct overlap/conflict with the removed TS generator.
  • ryoppippi/ccusage#549: Earlier changes to the TypeScript schema generator’s behavior (change-detection/skip logic) that this PR replaces by removing the TS generator.
  • ryoppippi/ccusage#1040: Prior refactor of the TS schema generator for nested subcommands; this PR deletes/replaces that generator with the Rust implementation.

Poem

🐰 I dug a schema hole and planted typed seeds,
Enums and structs sprout where free JSON fed needs,
I run the Rust sprout, tab-indent and groom,
Oxfmt polishes leaves, docs get a new bloom,
A hopping rabbit cheers: configs find their deeds!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 23.21% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title clearly and accurately summarizes the main change: refactoring ccusage to generate config schema from Rust types instead of TypeScript/Bun.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/rust-config-schema

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@socket-security
Copy link
Copy Markdown

socket-security Bot commented May 19, 2026

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addedcargo/​schemars@​0.8.2291100100100100

View full report

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 19, 2026

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Get the PR diff and file list
gh pr view 1058 --repo ryoppippi/ccusage --json files,title,body 2>/dev/null | jq '.files[].path' 2>/dev/null || true

# List changed files
gh pr diff 1058 --repo ryoppippi/ccusage --name-only 2>/dev/null || true

Length of output: 732


🏁 Script executed:

#!/bin/bash
# Get the full diff of the PR
gh pr diff 1058 --repo ryoppippi/ccusage 2>/dev/null | head -2000

Length of output: 84233


🏁 Script executed:

#!/bin/bash
# Read all the key Rust source files
echo "=== config_schema.rs ==="
cat rust/crates/ccusage/src/config_schema.rs

echo ""
echo "=== config.rs ==="
cat rust/crates/ccusage/src/config.rs

echo ""
echo "=== cli.rs ==="
cat rust/crates/ccusage/src/cli.rs

echo ""
echo "=== generate_config_schema.rs ==="
cat rust/crates/ccusage/src/bin/generate_config_schema.rs

Length of output: 91215


@ryoppippi, here's my focused review on the two areas you asked about.


Schema ↔ Runtime Config Alignment

Overall the alignment is excellent. Every from_map helper mirrors its corresponding apply_config_to_* function field-for-field. The From<Config*> impls in config.rs are exhaustive and match the CLI enum variants in cli.rs. Here are the specific issues I found:

1. 🔴 commands.weekly.startOfWeek — schema/runtime mismatch (possible breaking change)

RootCommandsConfig.weekly is typed as Option<SharedOptions>, so the generated schema does not allow startOfWeek under commands.weekly:

// config_schema.rs
pub(crate) struct RootCommandsConfig {
    pub(crate) weekly: Option<SharedOptions>,  // ← SharedOptions, not WeeklyOptions
    ...
}

However, the runtime will happily accept it. apply_config_to_weekly_args calls WeeklySpecificOptions::from_map(options) on every map returned by option_maps(), including the raw JSON map for commands.weekly. So a user who has:

{ "commands": { "weekly": { "startOfWeek": "monday" } } }

will find it works at runtime but is flagged as invalid by JSON Schema validators (e.g. additionalProperties: false is injected by enrich_schema). This was valid in the old schema. To fix, change:

// config_schema.rs
pub(crate) struct RootCommandsConfig {
    pub(crate) weekly: Option<WeeklyOptions>,  // instead of SharedOptions
    ...
}

2. 🟡 Missing default annotations

schemars doesn't emit default from struct field values. The old schema had rich defaults throughout (e.g. "default": false, "default": 5, "default": "auto", "default": "asc"). The new schema drops all of them.

This means IDE autocomplete (e.g. VS Code with the $schema hint) no longer shows what value a field defaults to. Consider using the schemars #[schemars(default)] attribute on fields where you want to preserve default documentation, or add a post-processing step in enrich_schema to inject known defaults.

For example, SharedArgs::with_defaults() in cli.rs sets:

mode: CostMode::Auto,
debug_samples: 5,
order: SortOrder::Asc,

None of these appear as default in the generated schema.

3. 🟢 session.id intentionally not configurable

The old schema exposed claude.commands.session.id. The new schema has no SessionOptions type and there is no apply_config_to_session_args. This is a clean intentional decision (persisting a session ID in a config file doesn't make sense), but worth noting in a CHANGELOG or migration note for users who may have relied on it.

4. 🟢 SharedOptions.all — intentional no-op

all: Option<bool> is in the schema but apply_shared_options never writes to a SharedArgs.all field (which doesn't exist). The doc comment "Accepted for compatibility" makes this clear. Fine as-is.

5. 🟡 ClaudeOptions exposes statusline fields under claude.defaults

ClaudeOptions flattens StatuslineSpecificOptions, so claude.defaults.cache, claude.defaults.refreshInterval, etc. appear valid in the schema and do work at runtime (they'd be applied by apply_config_to_statusline_args when option_maps() includes claude.defaults). This is technically correct but may surprise users who don't expect statusline tuning under claude.defaults. It might be worth a doc comment on ClaudeOptions.


--config File Shape Coverage in Tests

The test coverage is thorough and the shapes in the tests do match the schema.

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.

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented May 19, 2026

Open in StackBlitz

ccusage

npx https://pkg.pr.new/ryoppippi/ccusage@1058

@ccusage/ccusage-darwin-arm64

npx https://pkg.pr.new/ryoppippi/ccusage/@ccusage/ccusage-darwin-arm64@1058

@ccusage/ccusage-darwin-x64

npx https://pkg.pr.new/ryoppippi/ccusage/@ccusage/ccusage-darwin-x64@1058

@ccusage/ccusage-linux-arm64

npx https://pkg.pr.new/ryoppippi/ccusage/@ccusage/ccusage-linux-arm64@1058

@ccusage/ccusage-linux-x64

npx https://pkg.pr.new/ryoppippi/ccusage/@ccusage/ccusage-linux-x64@1058

@ccusage/ccusage-win32-arm64

npx https://pkg.pr.new/ryoppippi/ccusage/@ccusage/ccusage-win32-arm64@1058

@ccusage/ccusage-win32-x64

npx https://pkg.pr.new/ryoppippi/ccusage/@ccusage/ccusage-win32-x64@1058

commit: 1089c1f

@github-actions
Copy link
Copy Markdown

ccusage performance comparison

PR SHA: 19fdd3c74a59
Base SHA: a2ca34a5965f

This compares the Rust PR release binary against the configured base package on the same CI runner.

Package runner startup

Execution setup measures any pre-benchmark package materialization used by the execution benchmark. Bunx temp cache measures one bunx -p <url> ccusage --version run with an empty Bun install cache. Warm reuses that cache and reports the median of repeated runs.

Package SHA Execution setup Bunx temp cache Bunx warm median Warm samples
Base pkg.pr.new a2ca34a5965f 503.4ms 465.9ms 35.6ms 3
PR pkg.pr.new 19fdd3c74a59 719.1ms 568.8ms 34.0ms 3

Cached bunx execution performance

Runs the same large fixture through bunx -p <pkg.pr.new URL> ccusage after the Bun install cache has already been populated by the startup measurement. This separates cached package-runner execution from first-fetch package materialization.

Fixtures: Claude /home/runner/work/_temp/ccusage-large-fixture (1.01 GiB, 2,597 files), Codex /home/runner/work/_temp/ccusage-large-codex-fixture (1.01 GiB, 2,597 files)
Base package: a2ca34a5965f; PR package: 19fdd3c74a59. Both run through bunx -p <pkg.pr.new URL> ccusage using the warmed Bun install cache from package runner startup, measured by hyperfine with 0 warmups and 1 runs.

Command Input Base median PR median PR vs base Base throughput PR throughput
bunx -p <pkg> ccusage claude --offline --json 1.01 GiB 684.4ms 666.9ms 1.03x 1.47 GiB/s 1.51 GiB/s
bunx -p <pkg> ccusage codex --offline --json 1.01 GiB 852.5ms 859.2ms 0.99x 1.18 GiB/s 1.17 GiB/s

Package runtime diagnostics

Compares 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 /home/runner/work/_temp/ccusage-large-fixture (1.01 GiB, 2,597 files), Codex /home/runner/work/_temp/ccusage-large-codex-fixture (1.01 GiB, 2,597 files)
All rows run --offline --json, measured by hyperfine with 0 warmups and 1 runs. This isolates wrapper overhead from the installed native optional dependency and the workspace release binary built on the runner.

Command Runtime Input Median Throughput Samples
claude --offline --json Package wrapper 1.01 GiB 656.0ms 1.53 GiB/s 1
claude --offline --json Installed native binary 1.01 GiB 633.8ms 1.59 GiB/s 1
claude --offline --json Workspace release binary 1.01 GiB 716.8ms 1.40 GiB/s 1
codex --offline --json Package wrapper 1.01 GiB 846.5ms 1.19 GiB/s 1
codex --offline --json Installed native binary 1.01 GiB 812.9ms 1.24 GiB/s 1
codex --offline --json Workspace release binary 1.01 GiB 837.5ms 1.20 GiB/s 1

Committed fixture performance

Committed small fixtures for stable PR-to-PR feedback and explicit Claude/Codex command coverage.

Fixtures: Claude apps/ccusage/test/fixtures/claude (0.00 MiB, 2 files), Codex apps/ccusage/test/fixtures/codex (0.00 MiB, 1 files)
Base runs the published ccusage package from pkg.pr.new, installed before measurement; PR runs rust/target/release/ccusage directly. Both run --offline --json, measured by hyperfine with 2 warmups and 7 runs.

Command Input Base median PR median PR vs base Base throughput PR throughput
claude daily --offline --json 0.00 MiB 30.4ms 3.9ms 7.76x 0.05 MiB/s 0.40 MiB/s
claude session --offline --json 0.00 MiB 30.5ms 4.0ms 7.67x 0.05 MiB/s 0.39 MiB/s
codex daily --offline --json 0.00 MiB 30.0ms 3.5ms 8.69x 0.03 MiB/s 0.25 MiB/s
codex session --offline --json 0.00 MiB 29.6ms 3.6ms 8.33x 0.03 MiB/s 0.24 MiB/s

Large real-world-shaped fixture performance

Generated 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 /home/runner/work/_temp/ccusage-large-fixture (1.01 GiB, 2,597 files), Codex /home/runner/work/_temp/ccusage-large-codex-fixture (1.01 GiB, 2,597 files)
Base runs the published ccusage package from pkg.pr.new, installed before measurement; PR runs rust/target/release/ccusage directly. Both run --offline --json, measured by hyperfine with 0 warmups and 1 runs.

Command Input Base median PR median PR vs base Base throughput PR throughput
claude --offline --json 1.01 GiB 670.8ms 725.5ms 0.92x 1.50 GiB/s 1.39 GiB/s
codex --offline --json 1.01 GiB 847.4ms 824.5ms 1.03x 1.19 GiB/s 1.22 GiB/s

Artifact size

Artifact Base PR Delta Ratio
packed ccusage-*.tgz 10.65 KiB 8.71 KiB -1.94 KiB 1.22x
installed native package binary 2772.96 KiB 2772.96 KiB +0.00 KiB 1.00x
Rust release binary rust/target/release/ccusage - 2699.68 KiB - -

Lower medians and smaller artifacts are better. CI runner noise still applies; use same-run ratios as directional PR feedback, not release guarantees.

@github-actions
Copy link
Copy Markdown

ccusage performance comparison

PR SHA: 19fdd3c74a59
Base SHA: a2ca34a5965f

This compares the PR package against the configured base package on the same CI runner.

Package runner startup

Execution setup measures any pre-benchmark package materialization used by the execution benchmark. Bunx temp cache measures one bunx -p <url> ccusage --version run with an empty Bun install cache. Warm reuses that cache and reports the median of repeated runs.

Package SHA Execution setup Bunx temp cache Bunx warm median Warm samples
Base pkg.pr.new a2ca34a5965f 409.7ms 456.9ms 35.2ms 3
PR pkg.pr.new 19fdd3c74a59 460.5ms 457.8ms 34.7ms 3

Cached bunx execution performance

Runs the same large fixture through bunx -p <pkg.pr.new URL> ccusage after the Bun install cache has already been populated by the startup measurement. This separates cached package-runner execution from first-fetch package materialization.

Fixtures: Claude /home/runner/work/_temp/ccusage-large-fixture (1.01 GiB, 2,597 files), Codex /home/runner/work/_temp/ccusage-large-codex-fixture (1.01 GiB, 2,597 files)
Base package: a2ca34a5965f; PR package: 19fdd3c74a59. Both run through bunx -p <pkg.pr.new URL> ccusage using the warmed Bun install cache from package runner startup, measured by hyperfine with 0 warmups and 1 runs.

Command Input Base median PR median PR vs base Base throughput PR throughput
bunx -p <pkg> ccusage claude --offline --json 1.01 GiB 691.7ms 668.2ms 1.04x 1.46 GiB/s 1.51 GiB/s
bunx -p <pkg> ccusage codex --offline --json 1.01 GiB 861.9ms 842.6ms 1.02x 1.17 GiB/s 1.19 GiB/s

Package runtime diagnostics

Compares 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 /home/runner/work/_temp/ccusage-large-fixture (1.01 GiB, 2,597 files), Codex /home/runner/work/_temp/ccusage-large-codex-fixture (1.01 GiB, 2,597 files)
All rows run --offline --json, measured by hyperfine with 0 warmups and 1 runs. This isolates wrapper overhead from the installed native optional dependency and the workspace release binary built on the runner.

Command Runtime Input Median Throughput Samples
claude --offline --json Package wrapper 1.01 GiB 659.0ms 1.53 GiB/s 1
claude --offline --json Installed native binary 1.01 GiB 633.0ms 1.59 GiB/s 1
claude --offline --json Workspace release binary 1.01 GiB 730.3ms 1.38 GiB/s 1
codex --offline --json Package wrapper 1.01 GiB 848.8ms 1.19 GiB/s 1
codex --offline --json Installed native binary 1.01 GiB 815.4ms 1.23 GiB/s 1
codex --offline --json Workspace release binary 1.01 GiB 824.8ms 1.22 GiB/s 1

Committed fixture performance

Committed small fixtures for stable PR-to-PR feedback and explicit Claude/Codex command coverage.

Fixtures: Claude apps/ccusage/test/fixtures/claude (0.00 MiB, 2 files), Codex apps/ccusage/test/fixtures/codex (0.00 MiB, 1 files)
Base runs the published ccusage package from pkg.pr.new, installed before measurement; PR runs the published ccusage package from pkg.pr.new, installed before measurement. Both run --offline --json, measured by hyperfine with 2 warmups and 7 runs.

Command Input Base median PR median PR vs base Base throughput PR throughput
claude daily --offline --json 0.00 MiB 31.1ms 31.1ms 1.00x 0.05 MiB/s 0.05 MiB/s
claude session --offline --json 0.00 MiB 31.4ms 30.7ms 1.02x 0.05 MiB/s 0.05 MiB/s
codex daily --offline --json 0.00 MiB 30.7ms 30.6ms 1.00x 0.03 MiB/s 0.03 MiB/s
codex session --offline --json 0.00 MiB 30.6ms 30.1ms 1.02x 0.03 MiB/s 0.03 MiB/s

Large real-world-shaped fixture performance

Generated 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 /home/runner/work/_temp/ccusage-large-fixture (1.01 GiB, 2,597 files), Codex /home/runner/work/_temp/ccusage-large-codex-fixture (1.01 GiB, 2,597 files)
Base runs the published ccusage package from pkg.pr.new, installed before measurement; PR runs the published ccusage package from pkg.pr.new, installed before measurement. Both run --offline --json, measured by hyperfine with 0 warmups and 1 runs.

Command Input Base median PR median PR vs base Base throughput PR throughput
claude --offline --json 1.01 GiB 698.5ms 678.9ms 1.03x 1.44 GiB/s 1.48 GiB/s
codex --offline --json 1.01 GiB 907.1ms 855.9ms 1.06x 1.11 GiB/s 1.18 GiB/s

Artifact size

Artifact Base PR Delta Ratio
packed ccusage-*.tgz 10.65 KiB 8.71 KiB -1.94 KiB 1.22x
installed native package binary 2772.96 KiB 2772.96 KiB +0.00 KiB 1.00x
Rust release binary rust/target/release/ccusage - 2699.68 KiB - -

Lower medians and smaller artifacts are better. CI runner noise still applies; use same-run ratios as directional PR feedback, not release guarantees.

ryoppippi added 2 commits May 19, 2026 11:17
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.
@ryoppippi
Copy link
Copy Markdown
Owner Author

@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.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 19, 2026

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
echo "=== config_schema.rs (latest) ==="
cat rust/crates/ccusage/src/config_schema.rs

echo ""
echo "=== Recent commits on PR branch ==="
git log --oneline -10

Length of output: 29867


🏁 Script executed:

#!/bin/bash
echo "=== Generated schema file (if present) ==="
cat apps/ccusage/config-schema.json 2>/dev/null | head -200 || echo "File not found"

Length of output: 5791


@ryoppippi, both fixes are confirmed in commit 35126e2 — great work!

Fix 1 — commands.weekly type corrected ✅

RootCommandsConfig.weekly is now Option<WeeklyOptions> (instead of Option<SharedOptions>), so startOfWeek is a valid schema property under the root commands.weekly namespace. The schema_allows_cli_config_file_shape test also now exercises this path directly:

"commands": { "weekly": { "startOfWeek": "monday" } }

Fix 2 — Default metadata injected ✅

The new add_schema_defaults / set_definition_defaults post-processing step correctly wires runtime defaults into the schema definitions — SharedOptions, WeeklyOptions, BlocksOptions, StatuslineOptions, and CodexOptions are all covered. The generated config-schema.json already reflects this (e.g. "default": 5.0 on sessionLength). The new generated_schema_exposes_cli_defaults test gives solid regression coverage across 10 distinct default values.

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.
@ryoppippi
Copy link
Copy Markdown
Owner Author

@coderabbitai I pushed one more follow-up after the schema shape concern: the generated schema now preserves the previous top-level `` to #/definitions/ccusage-config, while keeping the Rust-generated agent-specific definitions for codex, opencode, amp, and pi. Please review the latest commit again.

@ryoppippi
Copy link
Copy Markdown
Owner Author

@coderabbitai Correction to my previous note: the generated schema now preserves the previous top-level $ref to #/definitions/ccusage-config, while keeping the Rust-generated agent-specific definitions for codex, opencode, amp, and pi. Please review the latest commit again.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 19, 2026

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
echo "=== Recent commits ==="
git log --oneline -8

echo ""
echo "=== config_schema.rs - generate_config_schema_json and enrich_schema functions ==="
grep -n "fn generate_config_schema_json\|fn enrich_schema\|fn add_schema_defaults\|\$ref\|ccusage-config\|allOf\|definitions" rust/crates/ccusage/src/config_schema.rs | head -80

echo ""
echo "=== Generated config-schema.json (top-level structure) ==="
cat apps/ccusage/config-schema.json 2>/dev/null | python3 -c "
import json, sys
schema = json.load(sys.stdin)
# Print top-level keys and ref
top = {k: v for k, v in schema.items() if k != 'definitions'}
print('Top-level (minus definitions):', json.dumps(top, indent=2))
print()
print('Definition keys:', list(schema.get('definitions', {}).keys()))
" || echo "File not found or parse error"

echo ""
echo "=== Full generate_config_schema_json function ==="
awk '/^pub\(crate\) fn generate_config_schema_json/,/^}/' rust/crates/ccusage/src/config_schema.rs

Length of output: 5431


🏁 Script executed:

#!/bin/bash
echo "=== wrap_root_schema function ==="
awk '/^fn wrap_root_schema/,/^}/' rust/crates/ccusage/src/config_schema.rs

echo ""
echo "=== Test covering the $ref and ccusage-config definition ==="
grep -n "ccusage-config\|wrap_root_schema\|\$ref" rust/crates/ccusage/src/config_schema.rs

Length of output: 1611


@ryoppippi, commit 1089c1f looks great — the new wrap_root_schema function correctly implements the shape change:

$ref#/definitions/ccusage-config preserved ✅

The function lifts the root schema's structural keys (type, properties, additionalProperties, description, markdownDescription) into a named ccusage-config definition, then replaces the root with a $ref pointing at it. The generated config-schema.json confirms the top-level is exactly "$ref": "#/definitions/ccusage-config".

All Rust-generated agent definitions retained ✅

The definitions map now carries 26 typed entries — all the Rust-generated structs (AmpCommandsConfig, ClaudeConfig, CodexConfig, CodexOptions, OpenCodeConfig, PiConfig, etc.) — plus the new ccusage-config root wrapper.

Regression test in place ✅

Lines 747–752 explicitly assert both the top-level $ref value and the presence of ccusage-config in definitions, so this shape is protected going forward.

Everything looks solid. The three-phase review is complete — schema/runtime alignment, default metadata, and root schema shape are all addressed. 🐇✨

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 19, 2026

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
echo "=== Recent commits ==="
git log --oneline -10

echo ""
echo "=== config_schema.rs (generate_config_schema_json and enrich_schema) ==="
cat rust/crates/ccusage/src/config_schema.rs

echo ""
echo "=== Generated config-schema.json (full) ==="
cat apps/ccusage/config-schema.json 2>/dev/null || echo "File not found"

Length of output: 68566


@ryoppippi, the wrap_root_schema commit (1089c1f) looks correct. ✅

$ref root shape preserved ✅

The new wrap_root_schema() function correctly lifts the core schema content into definitions["ccusage-config"] and replaces the root properties with a single $ref: "#/definitions/ccusage-config" pointer, while leaving the draft-07 metadata ($schema, title, examples) at the root. The generated config-schema.json matches exactly:

{
  "$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 (CodexOptions, CodexCommandsConfig, CodexConfig, OpenCodeConfig, AmpConfig, PiOptions, PiConfig, ClaudeOptions, ClaudeCommandsConfig, etc.) remain intact in the definitions block alongside the new ccusage-config entry.

Test coverage ✅

The new generated_schema_keeps_legacy_root_definition_shape test pins both the $ref pointer and the complete property set of ccusage-config, giving solid regression protection if wrap_root_schema were accidentally removed or modified.

No issues. All three rounds of review feedback have been addressed cleanly — the schema ↔ runtime alignment, default metadata, and root shape are all correct.

🐇✨

@github-actions
Copy link
Copy Markdown

ccusage performance comparison

PR SHA: 85a2f61b1e3e
Base SHA: a2ca34a5965f

This compares the Rust PR release binary against the configured base package on the same CI runner.

Package runner startup

Execution setup measures any pre-benchmark package materialization used by the execution benchmark. Bunx temp cache measures one bunx -p <url> ccusage --version run with an empty Bun install cache. Warm reuses that cache and reports the median of repeated runs.

Package SHA Execution setup Bunx temp cache Bunx warm median Warm samples
Base pkg.pr.new a2ca34a5965f 466.4ms 462.3ms 35.6ms 3
PR pkg.pr.new 85a2f61b1e3e 845.4ms 458.1ms 36.5ms 3

Cached bunx execution performance

Runs the same large fixture through bunx -p <pkg.pr.new URL> ccusage after the Bun install cache has already been populated by the startup measurement. This separates cached package-runner execution from first-fetch package materialization.

Fixtures: Claude /home/runner/work/_temp/ccusage-large-fixture (1.01 GiB, 2,597 files), Codex /home/runner/work/_temp/ccusage-large-codex-fixture (1.01 GiB, 2,597 files)
Base package: a2ca34a5965f; PR package: 85a2f61b1e3e. Both run through bunx -p <pkg.pr.new URL> ccusage using the warmed Bun install cache from package runner startup, measured by hyperfine with 0 warmups and 1 runs.

Command Input Base median PR median PR vs base Base throughput PR throughput
bunx -p <pkg> ccusage claude --offline --json 1.01 GiB 681.9ms 681.6ms 1.00x 1.48 GiB/s 1.48 GiB/s
bunx -p <pkg> ccusage codex --offline --json 1.01 GiB 877.7ms 869.1ms 1.01x 1.15 GiB/s 1.16 GiB/s

Package runtime diagnostics

Compares 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 /home/runner/work/_temp/ccusage-large-fixture (1.01 GiB, 2,597 files), Codex /home/runner/work/_temp/ccusage-large-codex-fixture (1.01 GiB, 2,597 files)
All rows run --offline --json, measured by hyperfine with 0 warmups and 1 runs. This isolates wrapper overhead from the installed native optional dependency and the workspace release binary built on the runner.

Command Runtime Input Median Throughput Samples
claude --offline --json Package wrapper 1.01 GiB 666.1ms 1.51 GiB/s 1
claude --offline --json Installed native binary 1.01 GiB 636.4ms 1.58 GiB/s 1
claude --offline --json Workspace release binary 1.01 GiB 729.2ms 1.38 GiB/s 1
codex --offline --json Package wrapper 1.01 GiB 861.7ms 1.17 GiB/s 1
codex --offline --json Installed native binary 1.01 GiB 869.1ms 1.16 GiB/s 1
codex --offline --json Workspace release binary 1.01 GiB 839.7ms 1.20 GiB/s 1

Committed fixture performance

Committed small fixtures for stable PR-to-PR feedback and explicit Claude/Codex command coverage.

Fixtures: Claude apps/ccusage/test/fixtures/claude (0.00 MiB, 2 files), Codex apps/ccusage/test/fixtures/codex (0.00 MiB, 1 files)
Base runs the published ccusage package from pkg.pr.new, installed before measurement; PR runs rust/target/release/ccusage directly. Both run --offline --json, measured by hyperfine with 2 warmups and 7 runs.

Command Input Base median PR median PR vs base Base throughput PR throughput
claude daily --offline --json 0.00 MiB 30.6ms 4.0ms 7.67x 0.05 MiB/s 0.39 MiB/s
claude session --offline --json 0.00 MiB 31.3ms 4.0ms 7.84x 0.05 MiB/s 0.39 MiB/s
codex daily --offline --json 0.00 MiB 30.1ms 3.8ms 8.01x 0.03 MiB/s 0.23 MiB/s
codex session --offline --json 0.00 MiB 30.2ms 3.6ms 8.30x 0.03 MiB/s 0.24 MiB/s

Large real-world-shaped fixture performance

Generated 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 /home/runner/work/_temp/ccusage-large-fixture (1.01 GiB, 2,597 files), Codex /home/runner/work/_temp/ccusage-large-codex-fixture (1.01 GiB, 2,597 files)
Base runs the published ccusage package from pkg.pr.new, installed before measurement; PR runs rust/target/release/ccusage directly. Both run --offline --json, measured by hyperfine with 0 warmups and 1 runs.

Command Input Base median PR median PR vs base Base throughput PR throughput
claude --offline --json 1.01 GiB 688.3ms 738.1ms 0.93x 1.46 GiB/s 1.36 GiB/s
codex --offline --json 1.01 GiB 876.7ms 833.2ms 1.05x 1.15 GiB/s 1.21 GiB/s

Artifact size

Artifact Base PR Delta Ratio
packed ccusage-*.tgz 10.65 KiB 8.87 KiB -1.78 KiB 1.20x
installed native package binary 2772.96 KiB 2772.96 KiB +0.00 KiB 1.00x
Rust release binary rust/target/release/ccusage - 2699.68 KiB - -

Lower medians and smaller artifacts are better. CI runner noise still applies; use same-run ratios as directional PR feedback, not release guarantees.

@github-actions
Copy link
Copy Markdown

ccusage performance comparison

PR SHA: 85a2f61b1e3e
Base SHA: a2ca34a5965f

This compares the PR package against the configured base package on the same CI runner.

Package runner startup

Execution setup measures any pre-benchmark package materialization used by the execution benchmark. Bunx temp cache measures one bunx -p <url> ccusage --version run with an empty Bun install cache. Warm reuses that cache and reports the median of repeated runs.

Package SHA Execution setup Bunx temp cache Bunx warm median Warm samples
Base pkg.pr.new a2ca34a5965f 571.0ms 574.7ms 36.0ms 3
PR pkg.pr.new 85a2f61b1e3e 1.594s 498.2ms 35.2ms 3

Cached bunx execution performance

Runs the same large fixture through bunx -p <pkg.pr.new URL> ccusage after the Bun install cache has already been populated by the startup measurement. This separates cached package-runner execution from first-fetch package materialization.

Fixtures: Claude /home/runner/work/_temp/ccusage-large-fixture (1.01 GiB, 2,597 files), Codex /home/runner/work/_temp/ccusage-large-codex-fixture (1.01 GiB, 2,597 files)
Base package: a2ca34a5965f; PR package: 85a2f61b1e3e. Both run through bunx -p <pkg.pr.new URL> ccusage using the warmed Bun install cache from package runner startup, measured by hyperfine with 0 warmups and 1 runs.

Command Input Base median PR median PR vs base Base throughput PR throughput
bunx -p <pkg> ccusage claude --offline --json 1.01 GiB 685.5ms 675.6ms 1.01x 1.47 GiB/s 1.49 GiB/s
bunx -p <pkg> ccusage codex --offline --json 1.01 GiB 879.3ms 873.6ms 1.01x 1.14 GiB/s 1.15 GiB/s

Package runtime diagnostics

Compares 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 /home/runner/work/_temp/ccusage-large-fixture (1.01 GiB, 2,597 files), Codex /home/runner/work/_temp/ccusage-large-codex-fixture (1.01 GiB, 2,597 files)
All rows run --offline --json, measured by hyperfine with 0 warmups and 1 runs. This isolates wrapper overhead from the installed native optional dependency and the workspace release binary built on the runner.

Command Runtime Input Median Throughput Samples
claude --offline --json Package wrapper 1.01 GiB 675.5ms 1.49 GiB/s 1
claude --offline --json Installed native binary 1.01 GiB 651.1ms 1.55 GiB/s 1
claude --offline --json Workspace release binary 1.01 GiB 742.3ms 1.36 GiB/s 1
codex --offline --json Package wrapper 1.01 GiB 878.9ms 1.15 GiB/s 1
codex --offline --json Installed native binary 1.01 GiB 830.5ms 1.21 GiB/s 1
codex --offline --json Workspace release binary 1.01 GiB 839.2ms 1.20 GiB/s 1

Committed fixture performance

Committed small fixtures for stable PR-to-PR feedback and explicit Claude/Codex command coverage.

Fixtures: Claude apps/ccusage/test/fixtures/claude (0.00 MiB, 2 files), Codex apps/ccusage/test/fixtures/codex (0.00 MiB, 1 files)
Base runs the published ccusage package from pkg.pr.new, installed before measurement; PR runs the published ccusage package from pkg.pr.new, installed before measurement. Both run --offline --json, measured by hyperfine with 2 warmups and 7 runs.

Command Input Base median PR median PR vs base Base throughput PR throughput
claude daily --offline --json 0.00 MiB 31.0ms 30.3ms 1.02x 0.05 MiB/s 0.05 MiB/s
claude session --offline --json 0.00 MiB 29.8ms 29.6ms 1.01x 0.05 MiB/s 0.05 MiB/s
codex daily --offline --json 0.00 MiB 29.5ms 30.1ms 0.98x 0.03 MiB/s 0.03 MiB/s
codex session --offline --json 0.00 MiB 29.9ms 29.8ms 1.00x 0.03 MiB/s 0.03 MiB/s

Large real-world-shaped fixture performance

Generated 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 /home/runner/work/_temp/ccusage-large-fixture (1.01 GiB, 2,597 files), Codex /home/runner/work/_temp/ccusage-large-codex-fixture (1.01 GiB, 2,597 files)
Base runs the published ccusage package from pkg.pr.new, installed before measurement; PR runs the published ccusage package from pkg.pr.new, installed before measurement. Both run --offline --json, measured by hyperfine with 0 warmups and 1 runs.

Command Input Base median PR median PR vs base Base throughput PR throughput
claude --offline --json 1.01 GiB 683.7ms 669.8ms 1.02x 1.47 GiB/s 1.50 GiB/s
codex --offline --json 1.01 GiB 864.2ms 888.8ms 0.97x 1.16 GiB/s 1.13 GiB/s

Artifact size

Artifact Base PR Delta Ratio
packed ccusage-*.tgz 10.65 KiB 8.87 KiB -1.78 KiB 1.20x
installed native package binary 2772.96 KiB 2772.96 KiB +0.00 KiB 1.00x
Rust release binary rust/target/release/ccusage - 2699.68 KiB - -

Lower medians and smaller artifacts are better. CI runner noise still applies; use same-run ratios as directional PR feedback, not release guarantees.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

📥 Commits

Reviewing files that changed from the base of the PR and between 85a2f61 and 1089c1f.

📒 Files selected for processing (2)
  • apps/ccusage/config-schema.json
  • rust/crates/ccusage/src/config_schema.rs

Comment on lines +550 to +589
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"))]);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

🧩 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.rs

Repository: 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 -200

Repository: 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.rs

Repository: 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.rs

Repository: ryoppippi/ccusage

Length of output: 1646


🏁 Script executed:

# Look for WeeklyOptions and BlocksOptions definitions
sed -n '200,280p' rust/crates/ccusage/src/config_schema.rs

Repository: 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).

@github-actions
Copy link
Copy Markdown

ccusage performance comparison

PR SHA: 1089c1f01bb1
Base SHA: a2ca34a5965f

This compares the Rust PR release binary against the configured base package on the same CI runner.

Package runner startup

Execution setup measures any pre-benchmark package materialization used by the execution benchmark. Bunx temp cache measures one bunx -p <url> ccusage --version run with an empty Bun install cache. Warm reuses that cache and reports the median of repeated runs.

Package SHA Execution setup Bunx temp cache Bunx warm median Warm samples
Base pkg.pr.new a2ca34a5965f 378.8ms 426.0ms 32.7ms 3
PR pkg.pr.new 1089c1f01bb1 877.9ms 520.4ms 34.9ms 3

Cached bunx execution performance

Runs the same large fixture through bunx -p <pkg.pr.new URL> ccusage after the Bun install cache has already been populated by the startup measurement. This separates cached package-runner execution from first-fetch package materialization.

Fixtures: Claude /home/runner/work/_temp/ccusage-large-fixture (1.01 GiB, 2,597 files), Codex /home/runner/work/_temp/ccusage-large-codex-fixture (1.01 GiB, 2,597 files)
Base package: a2ca34a5965f; PR package: 1089c1f01bb1. Both run through bunx -p <pkg.pr.new URL> ccusage using the warmed Bun install cache from package runner startup, measured by hyperfine with 0 warmups and 1 runs.

Command Input Base median PR median PR vs base Base throughput PR throughput
bunx -p <pkg> ccusage claude --offline --json 1.01 GiB 675.8ms 740.1ms 0.91x 1.49 GiB/s 1.36 GiB/s
bunx -p <pkg> ccusage codex --offline --json 1.01 GiB 810.6ms 815.5ms 0.99x 1.24 GiB/s 1.23 GiB/s

Package runtime diagnostics

Compares 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 /home/runner/work/_temp/ccusage-large-fixture (1.01 GiB, 2,597 files), Codex /home/runner/work/_temp/ccusage-large-codex-fixture (1.01 GiB, 2,597 files)
All rows run --offline --json, measured by hyperfine with 0 warmups and 1 runs. This isolates wrapper overhead from the installed native optional dependency and the workspace release binary built on the runner.

Command Runtime Input Median Throughput Samples
claude --offline --json Package wrapper 1.01 GiB 654.2ms 1.54 GiB/s 1
claude --offline --json Installed native binary 1.01 GiB 656.4ms 1.53 GiB/s 1
claude --offline --json Workspace release binary 1.01 GiB 732.4ms 1.37 GiB/s 1
codex --offline --json Package wrapper 1.01 GiB 811.1ms 1.24 GiB/s 1
codex --offline --json Installed native binary 1.01 GiB 778.4ms 1.29 GiB/s 1
codex --offline --json Workspace release binary 1.01 GiB 788.8ms 1.28 GiB/s 1

Committed fixture performance

Committed small fixtures for stable PR-to-PR feedback and explicit Claude/Codex command coverage.

Fixtures: Claude apps/ccusage/test/fixtures/claude (0.00 MiB, 2 files), Codex apps/ccusage/test/fixtures/codex (0.00 MiB, 1 files)
Base runs the published ccusage package from pkg.pr.new, installed before measurement; PR runs rust/target/release/ccusage directly. Both run --offline --json, measured by hyperfine with 2 warmups and 7 runs.

Command Input Base median PR median PR vs base Base throughput PR throughput
claude daily --offline --json 0.00 MiB 28.8ms 3.6ms 7.95x 0.05 MiB/s 0.43 MiB/s
claude session --offline --json 0.00 MiB 29.1ms 3.6ms 8.07x 0.05 MiB/s 0.43 MiB/s
codex daily --offline --json 0.00 MiB 28.4ms 3.3ms 8.63x 0.03 MiB/s 0.26 MiB/s
codex session --offline --json 0.00 MiB 27.9ms 3.3ms 8.43x 0.03 MiB/s 0.26 MiB/s

Large real-world-shaped fixture performance

Generated 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 /home/runner/work/_temp/ccusage-large-fixture (1.01 GiB, 2,597 files), Codex /home/runner/work/_temp/ccusage-large-codex-fixture (1.01 GiB, 2,597 files)
Base runs the published ccusage package from pkg.pr.new, installed before measurement; PR runs rust/target/release/ccusage directly. Both run --offline --json, measured by hyperfine with 0 warmups and 1 runs.

Command Input Base median PR median PR vs base Base throughput PR throughput
claude --offline --json 1.01 GiB 675.0ms 713.8ms 0.95x 1.49 GiB/s 1.41 GiB/s
codex --offline --json 1.01 GiB 812.2ms 786.5ms 1.03x 1.24 GiB/s 1.28 GiB/s

Artifact size

Artifact Base PR Delta Ratio
packed ccusage-*.tgz 10.65 KiB 8.86 KiB -1.78 KiB 1.20x
installed native package binary 2772.96 KiB 2772.96 KiB +0.00 KiB 1.00x
Rust release binary rust/target/release/ccusage - 2699.68 KiB - -

Lower medians and smaller artifacts are better. CI runner noise still applies; use same-run ratios as directional PR feedback, not release guarantees.

@github-actions
Copy link
Copy Markdown

ccusage performance comparison

PR SHA: 1089c1f01bb1
Base SHA: a2ca34a5965f

This compares the PR package against the configured base package on the same CI runner.

Package runner startup

Execution setup measures any pre-benchmark package materialization used by the execution benchmark. Bunx temp cache measures one bunx -p <url> ccusage --version run with an empty Bun install cache. Warm reuses that cache and reports the median of repeated runs.

Package SHA Execution setup Bunx temp cache Bunx warm median Warm samples
Base pkg.pr.new a2ca34a5965f 425.0ms 415.8ms 32.8ms 3
PR pkg.pr.new 1089c1f01bb1 1.226s 967.4ms 32.0ms 3

Cached bunx execution performance

Runs the same large fixture through bunx -p <pkg.pr.new URL> ccusage after the Bun install cache has already been populated by the startup measurement. This separates cached package-runner execution from first-fetch package materialization.

Fixtures: Claude /home/runner/work/_temp/ccusage-large-fixture (1.01 GiB, 2,597 files), Codex /home/runner/work/_temp/ccusage-large-codex-fixture (1.01 GiB, 2,597 files)
Base package: a2ca34a5965f; PR package: 1089c1f01bb1. Both run through bunx -p <pkg.pr.new URL> ccusage using the warmed Bun install cache from package runner startup, measured by hyperfine with 0 warmups and 1 runs.

Command Input Base median PR median PR vs base Base throughput PR throughput
bunx -p <pkg> ccusage claude --offline --json 1.01 GiB 671.8ms 671.8ms 1.00x 1.50 GiB/s 1.50 GiB/s
bunx -p <pkg> ccusage codex --offline --json 1.01 GiB 807.9ms 805.8ms 1.00x 1.25 GiB/s 1.25 GiB/s

Package runtime diagnostics

Compares 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 /home/runner/work/_temp/ccusage-large-fixture (1.01 GiB, 2,597 files), Codex /home/runner/work/_temp/ccusage-large-codex-fixture (1.01 GiB, 2,597 files)
All rows run --offline --json, measured by hyperfine with 0 warmups and 1 runs. This isolates wrapper overhead from the installed native optional dependency and the workspace release binary built on the runner.

Command Runtime Input Median Throughput Samples
claude --offline --json Package wrapper 1.01 GiB 654.4ms 1.54 GiB/s 1
claude --offline --json Installed native binary 1.01 GiB 629.8ms 1.60 GiB/s 1
claude --offline --json Workspace release binary 1.01 GiB 700.1ms 1.44 GiB/s 1
codex --offline --json Package wrapper 1.01 GiB 799.7ms 1.26 GiB/s 1
codex --offline --json Installed native binary 1.01 GiB 781.1ms 1.29 GiB/s 1
codex --offline --json Workspace release binary 1.01 GiB 782.9ms 1.29 GiB/s 1

Committed fixture performance

Committed small fixtures for stable PR-to-PR feedback and explicit Claude/Codex command coverage.

Fixtures: Claude apps/ccusage/test/fixtures/claude (0.00 MiB, 2 files), Codex apps/ccusage/test/fixtures/codex (0.00 MiB, 1 files)
Base runs the published ccusage package from pkg.pr.new, installed before measurement; PR runs the published ccusage package from pkg.pr.new, installed before measurement. Both run --offline --json, measured by hyperfine with 2 warmups and 7 runs.

Command Input Base median PR median PR vs base Base throughput PR throughput
claude daily --offline --json 0.00 MiB 27.9ms 27.4ms 1.02x 0.06 MiB/s 0.06 MiB/s
claude session --offline --json 0.00 MiB 27.8ms 28.2ms 0.98x 0.06 MiB/s 0.05 MiB/s
codex daily --offline --json 0.00 MiB 28.4ms 27.5ms 1.03x 0.03 MiB/s 0.03 MiB/s
codex session --offline --json 0.00 MiB 27.6ms 27.4ms 1.01x 0.03 MiB/s 0.03 MiB/s

Large real-world-shaped fixture performance

Generated 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 /home/runner/work/_temp/ccusage-large-fixture (1.01 GiB, 2,597 files), Codex /home/runner/work/_temp/ccusage-large-codex-fixture (1.01 GiB, 2,597 files)
Base runs the published ccusage package from pkg.pr.new, installed before measurement; PR runs the published ccusage package from pkg.pr.new, installed before measurement. Both run --offline --json, measured by hyperfine with 0 warmups and 1 runs.

Command Input Base median PR median PR vs base Base throughput PR throughput
claude --offline --json 1.01 GiB 674.0ms 661.8ms 1.02x 1.49 GiB/s 1.52 GiB/s
codex --offline --json 1.01 GiB 796.7ms 796.2ms 1.00x 1.26 GiB/s 1.26 GiB/s

Artifact size

Artifact Base PR Delta Ratio
packed ccusage-*.tgz 10.65 KiB 8.86 KiB -1.78 KiB 1.20x
installed native package binary 2772.96 KiB 2772.96 KiB +0.00 KiB 1.00x
Rust release binary rust/target/release/ccusage - 2699.68 KiB - -

Lower medians and smaller artifacts are better. CI runner noise still applies; use same-run ratios as directional PR feedback, not release guarantees.

@ryoppippi ryoppippi merged commit 27047ac into main May 19, 2026
38 checks passed
@ryoppippi ryoppippi deleted the codex/rust-config-schema branch May 19, 2026 10:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant