Skip to content

chore(nix): modularize tooling and migrate hooks - #1139

Merged
ryoppippi merged 5 commits into
mainfrom
codex/migrate-git-hooks-nix
May 23, 2026
Merged

ryoppippi merged 5 commits into
mainfrom
codex/migrate-git-hooks-nix

Conversation

@ryoppippi

@ryoppippi ryoppippi commented May 23, 2026 •

Copy link
Copy Markdown
Member

Summary

  • replace lefthook with git-hooks.nix using prek
  • split Nix configuration into flake-parts modules under nix/
  • add treefmt-nix formatting checks and Nix-managed hook tools
  • manage repo-local Claude skills as a local-only agent-skills-nix bundle linked from the Nix dev shell
  • use nix-filter for local skill sources and Nix check source filtering
  • require Nix + nix-direnv for contributor setup

Validation

  • nix flake check --no-build
  • nix build .#checks.aarch64-darwin.agent-skills .#checks.aarch64-darwin.treefmt .#checks.aarch64-darwin.oxlint .#checks.aarch64-darwin.gitleaks
  • direnv exec . prek validate-config .pre-commit-config.yaml
  • direnv exec . prek run config-schema --files rust/crates/ccusage/src/config_schema.rs
  • direnv exec . pnpm run format
  • direnv exec . pnpm typecheck
  • direnv exec . pnpm run test

Summary by CodeRabbit

  • New Features

    • Linux static binary builds for the main tool.
    • Local skill sync/install command for managed agent skills.
  • Chores

    • Refactored flake/packaging and dev-shell setup for a smoother developer workflow.
    • Centralized checks (formatting, linters, Rust checks) into reusable modules.
    • Removed legacy generated skill artifacts and unused sync scripts.
  • Documentation

    • Updated contributor and CLI docs to reflect the new Nix-based workflow and sync process.

Review Change Stack

Replace the lefthook configuration with git-hooks.nix using prek as the runner so hook installation and tool resolution come from the Nix dev shell instead of ad hoc shell setup.

Split the flake into flake-parts modules under nix/, add treefmt-nix formatting checks, and keep the package derivation in root package.nix/default.nix so package construction is separate from flake outputs.

Move hook-only checks for config schema and skill syncing into Nix-generated scripts. These checks report stale generated files instead of staging fixes automatically, and the Claude skill symlinks are synced to match .agents/skills.
@ryoppippi

Copy link
Copy Markdown
Member Author

@coderabbitai please review this PR.

@coderabbitai

coderabbitai Bot commented May 23, 2026 •

Copy link
Copy Markdown

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 922da348-24e3-4d52-aebf-051aab9af53d

📥 Commits

Reviewing files that changed from the base of the PR and between 00cc77f and f1ccccd.

📒 Files selected for processing (6)
  • .agents/skills/ccusage-development/SKILL.md
  • .agents/skills/skill-creator/SKILL.md
  • .claude/CLAUDE.md
  • .gitignore
  • CLAUDE.md
  • nix/agent-skills.nix
✅ Files skipped from review due to trivial changes (3)
  • CLAUDE.md
  • .agents/skills/ccusage-development/SKILL.md
  • .agents/skills/skill-creator/SKILL.md

📝 Walkthrough

Walkthrough

This PR refactors the project's Nix flake architecture to use flake-parts for modular per-system outputs, splits monolithic flake.nix logic into dedicated nix/*.nix modules (packages, dev-shell, checks, treefmt, git-hooks, agent-skills), introduces package.nix and default.nix for Rust crane-based builds, and migrates Git hook and skill-sync management from lefthook.yml and package.json scripts into Nix-managed modules.

Changes

Nix Flake-Parts Refactoring and Modular Tooling Architecture

Layer / File(s) Summary
Flake inputs and outputs migration to flake-parts
flake.nix
Expands inputs to include flake-parts, agent-skills, git-hooks, treefmt-nix, and nix-filter; replaces inline outputs definition with flake-parts.lib.mkFlake delegating per-system logic to imported ./nix/* modules.
Rust package build infrastructure
default.nix, package.nix
default.nix provides a curried entrypoint; package.nix defines the complete Rust derivation using crane: version extraction, source filtering via nix-filter, buildDepsOnly, buildPackage, environment variable setup for pricing data, and Darwin SDK/libiconv conditional inputs.
Package and app outputs wiring
nix/packages.nix, nix/static-package.nix
nix/packages.nix imports the ccusage derivation and exposes it as both apps and packages per-system; nix/static-package.nix adds Linux-only musl cross-compilation for static ccusage-static binary.
Development shell with auto-sync
nix/dev-shell.nix
Defines devShells.default with curated developer tooling, Darwin SDK conditional inclusion, lazy pnpm install via shellHook, and automatic agent skills sync via config.packages.syncAgentSkills.
Code quality checks and formatting
nix/checks.nix, nix/treefmt.nix
nix/checks.nix configures Rust workspace checks (clippy, cargo fmt) and repo checks (oxlint, gitleaks) via crane and mkRepoCheck helper; nix/treefmt.nix configures multi-formatter pipeline (deadnix, oxfmt, oxlint, statix, nixfmt, typos) with priorities.
Agent skills discovery and bundling
nix/agent-skills.nix
Discovers agent skills from .agents/skills via nix-filter, builds bundle, defines claude install target with copy-tree structure, generates install script, and wraps as sync-agent-skills app.
Git hooks orchestration
nix/git-hooks.nix
Configures pre-commit and pre-push hook stages with schema validation, treefmt, gitleaks, rustfmt, oxlint, clippy, vitest-related, and cargo test; wires SDK environment variables for macOS Rust builds.
Claude skill routing and documentation
.claude/CLAUDE.md, .agents/skills/*/SKILL.md, .claude/skills/* removals
Documents generated .claude/skills relationship to .agents/skills; clarifies that .claude/skills are auto-generated and must not be edited; removes pr-ai-review-workflow pointer.
Contributor setup and script updates
apps/ccusage/README.md, scripts/sync-skills.ts, package.json
Updates README to reflect Nix+direnv contributor workflow; adds nix shebang to sync-skills.ts; corrects check-mode error message; removes sync:skills and sync:skills:check from package.json.
Repository configuration cleanup
.gitignore
Adds .pre-commit-config.yaml to ignore list (now Nix-managed).

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • ryoppippi/ccusage#753: Earlier flake-parts refactoring PR that restructures flake.nix outputs away from flake-utils to flake-parts.lib.mkFlake.
  • ryoppippi/ccusage#1079: Overlaps on lint/format plumbing and hook definitions; both PRs touch git-hook/format/check orchestration.
  • ryoppippi/ccusage#1077: Related contributor docs updates to apps/ccusage/README.md about Nix direnv workflows.

Poem

🐰 A flake once compact, now split with care,

modules hum softly, builds breathe cleaner air.
Skills link by Nix, hooks find their new home,
dev shells wake gently — no more roam.
Hop on, little rabbit, the repo's a poem.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title "chore(nix): modularize tooling and migrate hooks" accurately describes the main changes: refactoring Nix configuration into modular flake-parts modules and migrating from lefthook to Nix-based git hooks.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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 unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/migrate-git-hooks-nix

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.

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented May 23, 2026 •

Copy link
Copy Markdown

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 f1ccccd Commit Preview URL

Branch Preview URL
May 23 2026, 09:59 PM

@coderabbitai

coderabbitai Bot commented May 23, 2026

Copy link
Copy Markdown
🧩 Analysis chain

Let me gather the PR details first.


🏁 Script executed:

#!/bin/bash
# Get PR details
gh pr view 1139 --repo ryoppippi/ccusage --json title,body,files,additions,deletions,changedFiles

# Get the list of changed files
gh pr diff 1139 --repo ryoppippi/ccusage --name-only

Length of output: 2543


🏁 Script executed:

#!/bin/bash
# Get full diff
gh pr diff 1139 --repo ryoppippi/ccusage

Length of output: 37285


@ryoppippi I'll review this PR now.


Review: chore(nix): migrate hooks to git-hooks.nix

This is a well-structured migration from lefthook to git-hooks.nix via prek, with a clean modularization of the flake into flake-parts. Here's my analysis:


✅ Strengths

  • Clean flake.nix simplification: The monolithic 224-line flake is reduced to 47 lines by delegating to flake-parts modules. Very readable.
  • passthru pattern in package.nix: Exposing { cargoArtifacts, commonArgs, version } via passthru allows nix/checks.nix and nix/static-package.nix to reuse build artifacts without duplicating logic. Good design.
  • default.nix for non-flake users: Adding default.nix (pointing to package.nix via callPackage) enables nix-build / niv users, which is a nice addition.
  • Nix shebang in scripts/sync-skills.ts: Allows running the script directly with nix + bun without a pre-installed global bun.
  • shopt -s nullglob in nix/sync-skills.nix: Correctly handles empty directories; broken-symlink detection via [ -L "$dst" ] is also robust.

🔍 Observations & Questions

1. check.enable = false in nix/git-hooks.nix

pre-commit = {
  check.enable = false;  # ← disables the check derivation
  ...
};

This intentionally prevents nix flake check from generating a derivation that validates the hooks config. The PR validation uses nix flake check --no-build which is consistent. Just confirming this is intentional and not accidentally suppressing a useful build check.


2. renovate in hook runtime inputs → devShell via enabledPackages

renovate-config-validator = {
  enable = true;
  entry = "${lib.getExe pkgs.renovate} --strict config-validator";
  ...
};

pkgs.renovate has a very large closure (~500 MB+). Since config.pre-commit.settings.enabledPackages is added to devShells.default.buildInputs in nix/dev-shell.nix, this pulls renovate into every developer's shell. Is this intentional? You might want to consider whether a lighter validator or a conditional tool would be preferable here.


3. Repeated pkgs instantiation across modules

Every module under nix/ independently instantiates:

pkgs = import inputs.nixpkgs {
  inherit system;
  overlays = [ inputs.rust-overlay.overlays.default ];
};

This is a known-acceptable pattern in flake-parts (Nix laziness prevents repeated evaluation), but it means the overlay is applied 6 times in isolation. The idiomatic alternative is a shared nixpkgs flake-parts module (e.g., via perSystem.pkgs). Not a bug, just worth noting for future maintenance.


4. nix/checks.nix — typos and oxfmt checks removed from flake check outputs

The old flake.nix exposed explicit checks.typos and checks.oxfmt in the flake outputs. These are now handled by treefmt-nix (which exposes checks.treefmt). Confirmed by the PR validation command:

nix build .#checks.aarch64-darwin.treefmt

This is the right approach. Just noting the change in surface area for nix flake check consumers.


5. nix/git-hooks.nix — ccusage-treefmt hook pass_filenames defaults to true

ccusage-treefmt = {
  entry = lib.getExe config.treefmt.build.wrapper;
  files = ".*";
  stages = [ "pre-commit" ];
  # pass_filenames not set → defaults to true
};

ccusage-treefmt-check explicitly sets pass_filenames = false. For consistency and clarity, it might be worth being explicit here too (even if treefmt does accept file arguments):

ccusage-treefmt = {
  entry = lib.getExe config.treefmt.build.wrapper;
  files = ".*";
  pass_filenames = false; # run treefmt on everything, not just staged files
  stages = [ "pre-commit" ];
  priority = 10;
};

6. Minor: import ./../default.nix in nix/packages.nix

ccusage = import ./../default.nix {

./../ is equivalent to ../ — the leading ./ is redundant. Not a bug, but ../default.nix is more conventional.


📋 Summary

Area Status
flake-parts migration ✅ Clean
passthru sharing pattern ✅ Well-designed
Hook coverage parity with lefthook.yml ✅ Complete
nix/sync-skills.nix shell script ✅ Correct
scripts/sync-skills.ts fix ✅ Correct
.gitignore update for .pre-commit-config.yaml ✅ Necessary
renovate in devShell via enabledPackages ⚠️ Large closure
check.enable = false ❓ Intentional?
ccusage-treefmt pass_filenames 💡 Consider being explicit
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Make the treefmt hook filename behavior explicit and use the conventional parent path when importing the root package wrapper.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
nix/dev-shell.nix (1)

62-65: ⚡ Quick win

Consider making shellHook paths more robust.

The file tests use relative paths (pnpm-lock.yaml, node_modules/.pnpm/lock.yaml) which assume the current directory is the repository root. While typical Nix workflows (direnv, nix develop) activate from the repo root, this could fail if the shell is entered from a subdirectory.

Consider adding a safety check or changing to absolute paths to ensure the pnpm install logic works correctly regardless of the initial directory.

🛡️ Suggested improvement
 shellHook = ''
+  # Ensure we're in the project root for pnpm operations
+  if [ -f "flake.nix" ]; then
     # Install dependencies only if node_modules/.pnpm/lock.yaml is older than pnpm-lock.yaml
     if [ ! -f node_modules/.pnpm/lock.yaml ] || [ pnpm-lock.yaml -nt node_modules/.pnpm/lock.yaml ]; then
       echo "📦 Installing dependencies..."
       pnpm install --frozen-lockfile
     fi
+  fi
   ${config.pre-commit.shellHook}
 '';

Alternatively, store the project root path and use it explicitly:

shellHook = 
  let
    # Note: This approach requires the project source to be available
    projectRoot = toString root;
  in
  ''
    cd "${projectRoot}" || exit 1
    # Install dependencies only if node_modules/.pnpm/lock.yaml is older than pnpm-lock.yaml
    if [ ! -f node_modules/.pnpm/lock.yaml ] || [ pnpm-lock.yaml -nt node_modules/.pnpm/lock.yaml ]; then
      echo "📦 Installing dependencies..."
      pnpm install --frozen-lockfile
    fi
    ${config.pre-commit.shellHook}
  '';
🤖 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 `@nix/dev-shell.nix` around lines 62 - 65, The shellHook currently uses
relative paths (pnpm-lock.yaml, node_modules/.pnpm/lock.yaml) which can break if
the shell is opened from a subdirectory; modify the shellHook to derive the repo
root (use the existing root variable, e.g. projectRoot = toString root) and
either cd into that directory at the start of the shellHook or use absolute
paths based on projectRoot when testing files and running pnpm install, and
ensure you still append ${config.pre-commit.shellHook} after those commands so
the pre-commit hook runs.
🤖 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.

Nitpick comments:
In `@nix/dev-shell.nix`:
- Around line 62-65: The shellHook currently uses relative paths
(pnpm-lock.yaml, node_modules/.pnpm/lock.yaml) which can break if the shell is
opened from a subdirectory; modify the shellHook to derive the repo root (use
the existing root variable, e.g. projectRoot = toString root) and either cd into
that directory at the start of the shellHook or use absolute paths based on
projectRoot when testing files and running pnpm install, and ensure you still
append ${config.pre-commit.shellHook} after those commands so the pre-commit
hook runs.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: bffbd0fc-4e0c-4443-b326-41119d3e586c

📥 Commits

Reviewing files that changed from the base of the PR and between 3e91226 and d6f6ad0.

⛔ Files ignored due to path filters (1)
  • flake.lock is excluded by !**/*.lock
📒 Files selected for processing (16)
  • .claude/skills/create-pr
  • .claude/skills/fs-fixture
  • .claude/skills/pr-ai-review-workflow
  • .gitignore
  • default.nix
  • flake.nix
  • lefthook.yml
  • nix/checks.nix
  • nix/dev-shell.nix
  • nix/git-hooks.nix
  • nix/packages.nix
  • nix/static-package.nix
  • nix/sync-skills.nix
  • nix/treefmt.nix
  • package.nix
  • scripts/sync-skills.ts
💤 Files with no reviewable changes (3)
  • .claude/skills/fs-fixture
  • lefthook.yml
  • .claude/skills/pr-ai-review-workflow

@ryoppippi ryoppippi changed the title chore(nix): migrate hooks to git-hooks.nix chore(nix): modularize flake and migrate hooks May 23, 2026
@ryoppippi

Copy link
Copy Markdown
Member Author

@coderabbitai I pushed a follow-up that makes the treefmt hook filename behavior explicit and cleans up the package import path. Please review the latest commit.

@ryoppippi

ryoppippi commented May 23, 2026 •

Copy link
Copy Markdown
Member Author

@cubic-dev-ai please review the latest commit as well.

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

1 issue found across 17 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread nix/checks.nix Outdated
@cubic-dev-ai

cubic-dev-ai Bot commented May 23, 2026 •

Copy link
Copy Markdown
Contributor

@cubic-dev-ai please review the latest commit as well.

@ryoppippi I have started the AI code review. It will take a few minutes to complete.

@coderabbitai

coderabbitai Bot commented May 23, 2026

Copy link
Copy Markdown

Tip

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Get the latest commit on the PR branch
gh pr view 1139 --repo ryoppippi/ccusage --json headRefName,headRefOid

# Get the diff of the latest commit
gh api repos/ryoppippi/ccusage/commits/$(gh pr view 1139 --repo ryoppippi/ccusage --json headRefOid --jq '.headRefOid') --jq '.files[] | {filename: .filename, patch: .patch}'

Length of output: 822


@ryoppippi Both changes look good in commit 3bc54ac:

  1. nix/git-hooks.nix — pass_filenames = true is now explicit on ccusage-treefmt. The value makes sense semantically: the format hook only processes staged files, while ccusage-treefmt-check keeps pass_filenames = false to check the full tree. That's a clean and intentional distinction between the two hooks. ✅

  2. nix/packages.nix — ./../default.nix → ../default.nix. Clean. ✅

Both follow-up items are resolved. The PR looks good overall! 🐇


If you found this review helpful, would you consider giving us a shout-out on X?

Thank you for using CodeRabbit!

@pkg-pr-new

pkg-pr-new Bot commented May 23, 2026 •

Copy link
Copy Markdown

Open in StackBlitz

ccusage

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

@ccusage/ccusage-darwin-arm64

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

@ccusage/ccusage-darwin-x64

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

@ccusage/ccusage-linux-arm64

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

@ccusage/ccusage-linux-x64

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

@ccusage/ccusage-win32-arm64

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

@ccusage/ccusage-win32-x64

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

commit: 00cc77f

Update the Nix check source filter to ignore build and cache directory names anywhere in the repository tree, not only at the repository root.

This prevents nested outputs such as rust/target, package dist directories, and coverage directories from being copied into check derivations.
@ryoppippi

Copy link
Copy Markdown
Member Author

@coderabbitai @cubic-dev-ai I pushed a follow-up fix for the nested build-output filtering issue in the Nix checks. Please review the latest commit.

@cubic-dev-ai

cubic-dev-ai Bot commented May 23, 2026

Copy link
Copy Markdown
Contributor

@coderabbitai @cubic-dev-ai I pushed a follow-up fix for the nested build-output filtering issue in the Nix checks. Please review the latest commit.

@ryoppippi I have started the AI code review. It will take a few minutes to complete.

@coderabbitai

coderabbitai Bot commented May 23, 2026

Copy link
Copy Markdown

Tip

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Get the latest commit SHA on the PR branch
LATEST_SHA=$(gh pr view 1139 --repo ryoppippi/ccusage --json headRefOid --jq '.headRefOid')
echo "Latest commit: $LATEST_SHA"

# Get the diff of the latest commit
gh api "repos/ryoppippi/ccusage/commits/$LATEST_SHA" --jq '.files[] | {filename: .filename, patch: .patch}'

Length of output: 877


@ryoppippi The fix in commit c289636 looks correct and addresses the issue cleanly.

nix/checks.nix — nested build-output filtering

Before After
hasPrefix "target/" rel builtins.elem dir pathParts where pathParts = splitString "/" rel

The old hasPrefix-based approach only excluded top-level occurrences — a path like rust/crates/ccusage/target/release/foo would not have been filtered since it doesn't start with "target/". The new approach splits the path into segments and checks whether any segment exactly matches an ignored directory name, so nested build outputs at any depth are now correctly excluded. ✅

A couple of small notes (non-blocking):

  1. Exact segment matching is correct here — a path like dist-utils/foo.ts splits into ["dist-utils", "foo.ts"] and builtins.elem "dist" [...] returns false, so there are no false positives from similarly-named directories. 👍
  2. Files named dist, target, etc. (as bare files, not directories) would technically be excluded too, but that's an unlikely edge case and an acceptable trade-off.

The fix is solid. PR looks good overall! 🐇

@github-actions

Copy link
Copy Markdown
Contributor

ccusage performance comparison

PR SHA: d6f6ad0afc68
Base SHA: 3e912262be1d

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 3e912262be1d 783.5ms 644.1ms 32.5ms 3
PR pkg.pr.new d6f6ad0afc68 771.8ms 800.6ms 32.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: 3e912262be1d; PR package: d6f6ad0afc68. 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.
Peak RSS is measured separately with /usr/bin/time using 1 runs. Lower RSS ratios are better.

Command Input Base median PR median PR vs base Base peak RSS PR peak RSS PR/base RSS Base throughput PR throughput
bunx -p <pkg> ccusage claude --offline --json 1.01 GiB 489.5ms 490.6ms 1.00x 258.33 MiB 257.58 MiB 1.00x 2.06 GiB/s 2.05 GiB/s
bunx -p <pkg> ccusage codex --offline --json 1.01 GiB 365.1ms 365.1ms 1.00x 51.58 MiB 65.45 MiB 1.27x 2.76 GiB/s 2.76 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 482.6ms 2.09 GiB/s 1
claude --offline --json Installed native binary 1.01 GiB 458.0ms 2.20 GiB/s 1
codex --offline --json Package wrapper 1.01 GiB 364.0ms 2.77 GiB/s 1
codex --offline --json Installed native binary 1.01 GiB 333.8ms 3.02 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.
Peak RSS is measured separately with /usr/bin/time using 1 runs. Lower RSS ratios are better.

Command Input Base median PR median PR vs base Base peak RSS PR peak RSS PR/base RSS Base throughput PR throughput
claude daily --offline --json 0.00 MiB 30.4ms 3.9ms 7.81x 43.61 MiB 2.83 MiB 0.06x 0.05 MiB/s 0.40 MiB/s
claude session --offline --json 0.00 MiB 29.5ms 3.9ms 7.55x 43.48 MiB 2.83 MiB 0.07x 0.05 MiB/s 0.40 MiB/s
codex daily --offline --json 0.00 MiB 29.1ms 3.7ms 7.81x 43.61 MiB 2.83 MiB 0.06x 0.03 MiB/s 0.23 MiB/s
codex session --offline --json 0.00 MiB 28.8ms 3.6ms 7.89x 43.61 MiB 2.83 MiB 0.06x 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.
Peak RSS is measured separately with /usr/bin/time using 1 runs. Lower RSS ratios are better.

Command Input Base median PR median PR vs base Base peak RSS PR peak RSS PR/base RSS Base throughput PR throughput
claude --offline --json 1.01 GiB 478.9ms 453.9ms 1.06x 262.08 MiB 261.33 MiB 1.00x 2.10 GiB/s 2.22 GiB/s
codex --offline --json 1.01 GiB 353.6ms 329.2ms 1.07x 66.95 MiB 58.33 MiB 0.87x 2.85 GiB/s 3.06 GiB/s

Artifact size

Artifact Base PR Delta Ratio
packed ccusage-*.tgz 14.25 KiB 14.25 KiB -0.00 KiB 1.00x
installed native package binary 3225.49 KiB 3225.49 KiB +0.00 KiB 1.00x

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
Contributor

ccusage performance comparison

PR SHA: d6f6ad0afc68
Base SHA: 3e912262be1d

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 3e912262be1d 481.1ms 474.4ms 33.6ms 3
PR pkg.pr.new d6f6ad0afc68 534.0ms 454.2ms 34.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: 3e912262be1d; PR package: d6f6ad0afc68. 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.
Peak RSS is measured separately with /usr/bin/time using 1 runs. Lower RSS ratios are better.

Command Input Base median PR median PR vs base Base peak RSS PR peak RSS PR/base RSS Base throughput PR throughput
bunx -p <pkg> ccusage claude --offline --json 1.01 GiB 498.9ms 498.3ms 1.00x 265.70 MiB 261.33 MiB 0.98x 2.02 GiB/s 2.02 GiB/s
bunx -p <pkg> ccusage codex --offline --json 1.01 GiB 372.7ms 413.0ms 0.90x 67.08 MiB 64.95 MiB 0.97x 2.70 GiB/s 2.44 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 494.0ms 2.04 GiB/s 1
claude --offline --json Installed native binary 1.01 GiB 457.0ms 2.20 GiB/s 1
codex --offline --json Package wrapper 1.01 GiB 363.5ms 2.77 GiB/s 1
codex --offline --json Installed native binary 1.01 GiB 334.5ms 3.01 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.
Peak RSS is measured separately with /usr/bin/time using 1 runs. Lower RSS ratios are better.

Command Input Base median PR median PR vs base Base peak RSS PR peak RSS PR/base RSS Base throughput PR throughput
claude daily --offline --json 0.00 MiB 30.4ms 30.5ms 1.00x 43.73 MiB 43.61 MiB 1.00x 0.05 MiB/s 0.05 MiB/s
claude session --offline --json 0.00 MiB 31.0ms 31.5ms 0.98x - 43.61 MiB - 0.05 MiB/s 0.05 MiB/s
codex daily --offline --json 0.00 MiB 30.7ms 29.8ms 1.03x 43.48 MiB - - 0.03 MiB/s 0.03 MiB/s
codex session --offline --json 0.00 MiB 31.0ms 31.3ms 0.99x 43.48 MiB 43.48 MiB 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.
Peak RSS is measured separately with /usr/bin/time using 1 runs. Lower RSS ratios are better.

Command Input Base median PR median PR vs base Base peak RSS PR peak RSS PR/base RSS Base throughput PR throughput
claude --offline --json 1.01 GiB 491.4ms 494.4ms 0.99x 269.45 MiB 286.70 MiB 1.06x 2.05 GiB/s 2.04 GiB/s
codex --offline --json 1.01 GiB 358.7ms 356.5ms 1.01x 63.95 MiB - - 2.81 GiB/s 2.82 GiB/s

Artifact size

Artifact Base PR Delta Ratio
packed ccusage-*.tgz 14.25 KiB 14.25 KiB -0.00 KiB 1.00x
installed native package binary 3225.49 KiB 3225.49 KiB +0.00 KiB 1.00x

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

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

No issues found across 17 files

Re-trigger cubic

@github-actions

Copy link
Copy Markdown
Contributor

ccusage performance comparison

PR SHA: 3bc54ac3a328
Base SHA: 3e912262be1d

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 3e912262be1d 557.5ms 799.0ms 33.8ms 3
PR pkg.pr.new 3bc54ac3a328 747.4ms 611.5ms 33.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: 3e912262be1d; PR package: 3bc54ac3a328. 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.
Peak RSS is measured separately with /usr/bin/time using 1 runs. Lower RSS ratios are better.

Command Input Base median PR median PR vs base Base peak RSS PR peak RSS PR/base RSS Base throughput PR throughput
bunx -p <pkg> ccusage claude --offline --json 1.01 GiB 495.4ms 495.1ms 1.00x 268.33 MiB 270.08 MiB 1.01x 2.03 GiB/s 2.03 GiB/s
bunx -p <pkg> ccusage codex --offline --json 1.01 GiB 370.0ms 363.4ms 1.02x 62.33 MiB 58.83 MiB 0.94x 2.72 GiB/s 2.77 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 490.1ms 2.05 GiB/s 1
claude --offline --json Installed native binary 1.01 GiB 478.3ms 2.11 GiB/s 1
codex --offline --json Package wrapper 1.01 GiB 369.8ms 2.72 GiB/s 1
codex --offline --json Installed native binary 1.01 GiB 339.1ms 2.97 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.
Peak RSS is measured separately with /usr/bin/time using 1 runs. Lower RSS ratios are better.

Command Input Base median PR median PR vs base Base peak RSS PR peak RSS PR/base RSS Base throughput PR throughput
claude daily --offline --json 0.00 MiB 30.7ms 4.1ms 7.43x 43.48 MiB 2.83 MiB 0.07x 0.05 MiB/s 0.37 MiB/s
claude session --offline --json 0.00 MiB 30.9ms 4.0ms 7.64x 43.73 MiB 2.83 MiB 0.06x 0.05 MiB/s 0.38 MiB/s
codex daily --offline --json 0.00 MiB 29.7ms 3.8ms 7.73x 43.61 MiB 2.83 MiB 0.06x 0.03 MiB/s 0.22 MiB/s
codex session --offline --json 0.00 MiB 29.9ms 3.7ms 8.15x 43.61 MiB 2.83 MiB 0.06x 0.03 MiB/s 0.23 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.
Peak RSS is measured separately with /usr/bin/time using 1 runs. Lower RSS ratios are better.

Command Input Base median PR median PR vs base Base peak RSS PR peak RSS PR/base RSS Base throughput PR throughput
claude --offline --json 1.01 GiB 486.0ms 464.4ms 1.05x 264.33 MiB 261.20 MiB 0.99x 2.07 GiB/s 2.17 GiB/s
codex --offline --json 1.01 GiB 349.6ms 322.6ms 1.08x 62.45 MiB 65.58 MiB 1.05x 2.88 GiB/s 3.12 GiB/s

Artifact size

Artifact Base PR Delta Ratio
packed ccusage-*.tgz 14.25 KiB 14.25 KiB -0.00 KiB 1.00x
installed native package binary 3225.49 KiB 3225.49 KiB +0.00 KiB 1.00x

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
Contributor

ccusage performance comparison

PR SHA: 3bc54ac3a328
Base SHA: 3e912262be1d

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 3e912262be1d 1.177s 731.3ms 38.1ms 3
PR pkg.pr.new 3bc54ac3a328 442.7ms 511.6ms 35.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: 3e912262be1d; PR package: 3bc54ac3a328. 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.
Peak RSS is measured separately with /usr/bin/time using 1 runs. Lower RSS ratios are better.

Command Input Base median PR median PR vs base Base peak RSS PR peak RSS PR/base RSS Base throughput PR throughput
bunx -p <pkg> ccusage claude --offline --json 1.01 GiB 495.6ms 501.5ms 0.99x 241.58 MiB 259.83 MiB 1.08x 2.03 GiB/s 2.01 GiB/s
bunx -p <pkg> ccusage codex --offline --json 1.01 GiB 372.3ms 376.3ms 0.99x 56.70 MiB 57.45 MiB 1.01x 2.70 GiB/s 2.68 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 488.1ms 2.06 GiB/s 1
claude --offline --json Installed native binary 1.01 GiB 468.9ms 2.15 GiB/s 1
codex --offline --json Package wrapper 1.01 GiB 369.9ms 2.72 GiB/s 1
codex --offline --json Installed native binary 1.01 GiB 348.7ms 2.89 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.
Peak RSS is measured separately with /usr/bin/time using 1 runs. Lower RSS ratios are better.

Command Input Base median PR median PR vs base Base peak RSS PR peak RSS PR/base RSS Base throughput PR throughput
claude daily --offline --json 0.00 MiB 31.4ms 31.7ms 0.99x 43.73 MiB 43.48 MiB 0.99x 0.05 MiB/s 0.05 MiB/s
claude session --offline --json 0.00 MiB 32.4ms 31.9ms 1.01x 43.48 MiB 43.61 MiB 1.00x 0.05 MiB/s 0.05 MiB/s
codex daily --offline --json 0.00 MiB 31.9ms 31.8ms 1.00x 43.48 MiB 43.61 MiB 1.00x 0.03 MiB/s 0.03 MiB/s
codex session --offline --json 0.00 MiB 31.9ms 31.7ms 1.01x 43.48 MiB 43.48 MiB 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.
Peak RSS is measured separately with /usr/bin/time using 1 runs. Lower RSS ratios are better.

Command Input Base median PR median PR vs base Base peak RSS PR peak RSS PR/base RSS Base throughput PR throughput
claude --offline --json 1.01 GiB 493.5ms 491.5ms 1.00x 258.83 MiB - - 2.04 GiB/s 2.05 GiB/s
codex --offline --json 1.01 GiB 360.6ms 358.1ms 1.01x - 66.95 MiB - 2.79 GiB/s 2.81 GiB/s

Artifact size

Artifact Base PR Delta Ratio
packed ccusage-*.tgz 14.25 KiB 14.25 KiB -0.00 KiB 1.00x
installed native package binary 3225.49 KiB 3225.49 KiB +0.00 KiB 1.00x

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
Contributor

ccusage performance comparison

PR SHA: c289636057c8
Base SHA: 3e912262be1d

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 3e912262be1d 432.4ms 650.0ms 33.1ms 3
PR pkg.pr.new c289636057c8 608.5ms 449.8ms 32.8ms 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: 3e912262be1d; PR package: c289636057c8. 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.
Peak RSS is measured separately with /usr/bin/time using 1 runs. Lower RSS ratios are better.

Command Input Base median PR median PR vs base Base peak RSS PR peak RSS PR/base RSS Base throughput PR throughput
bunx -p <pkg> ccusage claude --offline --json 1.01 GiB 495.3ms 508.1ms 0.97x 262.20 MiB 242.20 MiB 0.92x 2.03 GiB/s 1.98 GiB/s
bunx -p <pkg> ccusage codex --offline --json 1.01 GiB 361.3ms 363.7ms 0.99x 59.45 MiB 58.33 MiB 0.98x 2.79 GiB/s 2.77 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 505.4ms 1.99 GiB/s 1
claude --offline --json Installed native binary 1.01 GiB 463.7ms 2.17 GiB/s 1
codex --offline --json Package wrapper 1.01 GiB 364.5ms 2.76 GiB/s 1
codex --offline --json Installed native binary 1.01 GiB 329.2ms 3.06 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.
Peak RSS is measured separately with /usr/bin/time using 1 runs. Lower RSS ratios are better.

Command Input Base median PR median PR vs base Base peak RSS PR peak RSS PR/base RSS Base throughput PR throughput
claude daily --offline --json 0.00 MiB 29.8ms 30.5ms 0.98x 43.61 MiB 43.48 MiB 1.00x 0.05 MiB/s 0.05 MiB/s
claude session --offline --json 0.00 MiB 30.2ms 30.6ms 0.99x 43.48 MiB - - 0.05 MiB/s 0.05 MiB/s
codex daily --offline --json 0.00 MiB 29.9ms 29.4ms 1.02x - 43.48 MiB - 0.03 MiB/s 0.03 MiB/s
codex session --offline --json 0.00 MiB 29.8ms 30.2ms 0.99x 43.48 MiB - - 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.
Peak RSS is measured separately with /usr/bin/time using 1 runs. Lower RSS ratios are better.

Command Input Base median PR median PR vs base Base peak RSS PR peak RSS PR/base RSS Base throughput PR throughput
claude --offline --json 1.01 GiB 489.4ms 484.5ms 1.01x 255.58 MiB - - 2.06 GiB/s 2.08 GiB/s
codex --offline --json 1.01 GiB 356.7ms 355.1ms 1.00x 65.33 MiB 66.83 MiB 1.02x 2.82 GiB/s 2.84 GiB/s

Artifact size

Artifact Base PR Delta Ratio
packed ccusage-*.tgz 14.25 KiB 14.25 KiB +0.00 KiB 1.00x
installed native package binary 3225.49 KiB 3225.49 KiB +0.00 KiB 1.00x

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
Contributor

ccusage performance comparison

PR SHA: c289636057c8
Base SHA: 3e912262be1d

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 3e912262be1d 447.6ms 355.4ms 34.2ms 3
PR pkg.pr.new c289636057c8 421.2ms 364.9ms 34.8ms 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: 3e912262be1d; PR package: c289636057c8. 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.
Peak RSS is measured separately with /usr/bin/time using 1 runs. Lower RSS ratios are better.

Command Input Base median PR median PR vs base Base peak RSS PR peak RSS PR/base RSS Base throughput PR throughput
bunx -p <pkg> ccusage claude --offline --json 1.01 GiB 494.0ms 501.9ms 0.98x 265.70 MiB 262.58 MiB 0.99x 2.04 GiB/s 2.01 GiB/s
bunx -p <pkg> ccusage codex --offline --json 1.01 GiB 368.2ms 376.0ms 0.98x 66.95 MiB 60.95 MiB 0.91x 2.73 GiB/s 2.68 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 494.1ms 2.04 GiB/s 1
claude --offline --json Installed native binary 1.01 GiB 464.2ms 2.17 GiB/s 1
codex --offline --json Package wrapper 1.01 GiB 360.3ms 2.79 GiB/s 1
codex --offline --json Installed native binary 1.01 GiB 333.5ms 3.02 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.
Peak RSS is measured separately with /usr/bin/time using 1 runs. Lower RSS ratios are better.

Command Input Base median PR median PR vs base Base peak RSS PR peak RSS PR/base RSS Base throughput PR throughput
claude daily --offline --json 0.00 MiB 31.1ms 4.1ms 7.50x 43.48 MiB 2.83 MiB 0.07x 0.05 MiB/s 0.37 MiB/s
claude session --offline --json 0.00 MiB 30.7ms 4.0ms 7.70x 43.61 MiB 2.83 MiB 0.06x 0.05 MiB/s 0.39 MiB/s
codex daily --offline --json 0.00 MiB 30.5ms 3.8ms 8.08x 43.48 MiB 2.83 MiB 0.07x 0.03 MiB/s 0.23 MiB/s
codex session --offline --json 0.00 MiB 31.2ms 3.9ms 7.97x 43.61 MiB 2.83 MiB 0.06x 0.03 MiB/s 0.22 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.
Peak RSS is measured separately with /usr/bin/time using 1 runs. Lower RSS ratios are better.

Command Input Base median PR median PR vs base Base peak RSS PR peak RSS PR/base RSS Base throughput PR throughput
claude --offline --json 1.01 GiB 494.1ms 457.1ms 1.08x 267.83 MiB 272.33 MiB 1.02x 2.04 GiB/s 2.20 GiB/s
codex --offline --json 1.01 GiB 356.0ms 329.6ms 1.08x 61.70 MiB 61.20 MiB 0.99x 2.83 GiB/s 3.05 GiB/s

Artifact size

Artifact Base PR Delta Ratio
packed ccusage-*.tgz 14.25 KiB 14.25 KiB +0.00 KiB 1.00x
installed native package binary 3225.49 KiB 3225.49 KiB +0.00 KiB 1.00x

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

Replace the hand-written skill sync scripts with an agent-skills-nix based local sync app.

The Nix dev shell now generates .claude/skills from .agents/skills, while .claude/skills is ignored and .claude/CLAUDE.md documents the local workflow. The git hooks no longer run skill sync checks because generated skills are not committed.

Use nix-filter for the local skill source and for repository check source filtering so generated and build output directories stay out of Nix sources.
@ryoppippi ryoppippi changed the title chore(nix): modularize flake and migrate hooks chore(nix): modularize tooling and migrate hooks May 23, 2026
@ryoppippi

Copy link
Copy Markdown
Member Author

@coderabbitai @cubic-dev-ai I pushed a follow-up that moves repo-local skill generation to agent-skills-nix, keeps it local-only via the Nix dev shell, ignores generated .claude/skills, and updates the PR description. Please review the latest commit.

@cubic-dev-ai

cubic-dev-ai Bot commented May 23, 2026

Copy link
Copy Markdown
Contributor

@coderabbitai @cubic-dev-ai I pushed a follow-up that moves repo-local skill generation to agent-skills-nix, keeps it local-only via the Nix dev shell, ignores generated .claude/skills, and updates the PR description. Please review the latest commit.

@ryoppippi I have started the AI code review. It will take a few minutes to complete.

@coderabbitai

coderabbitai Bot commented May 23, 2026

Copy link
Copy Markdown

Tip

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Get the latest commit SHA on the PR branch
LATEST_SHA=$(gh pr view 1139 --repo ryoppippi/ccusage --json headRefOid --jq '.headRefOid')
echo "Latest commit: $LATEST_SHA"

# Get the diff of the latest commit
gh api "repos/ryoppippi/ccusage/commits/$LATEST_SHA" --jq '.files[] | {filename: .filename, patch: .patch}'

Length of output: 23031


@ryoppippi Commit 00cc77f looks great — this is a clean, well-motivated simplification.


✅ What's improved

  • Custom sync code eliminated: nix/sync-skills.nix (90 lines), scripts/sync-skills.ts (108 lines), two git hooks, and two package.json scripts are all gone. Replaced by the 60-line nix/agent-skills.nix delegating to the upstream agent-skills-nix library. Net reduction ~200 lines of bespoke maintenance burden.
  • nix/checks.nix — nix-filter upgrade: The previous commit's custom cleanSourceWith + builtins.elem path-segment filter is replaced with the idiomatic nixFilter.matchName predicates. Cleaner and more readable. ✅
  • .claude/skills/ now gitignored and generated locally: The 20 tracked symlink files are removed, .gitignore updated, and .claude/CLAUDE.md documents the new model clearly. ✅
  • checks.agent-skills = bundle: CI now verifies the bundle builds cleanly. ✅

🔍 Two minor observations (non-blocking)

1. home-manager as a transitive dependency

agent-skills-nix follows nixpkgs but brings in home-manager as a transitive input (visible in flake.lock). This is a non-trivial closure addition. It won't affect runtime behavior but is worth keeping in mind if you ever see a heavier-than-expected nix flake lock or shell startup. Nothing to change, just good to know.

2. syncAgentSkills runs on every shell entry

${lib.getExe config.packages.syncAgentSkills}
${config.pre-commit.shellHook}

Since syncAgentSkills runs unconditionally in the shellHook, it fires on every nix develop / direnv reload. If agent-skills-nix's install script is fast (idempotent copy with early-exit), this is fine. If it becomes noticeable, a lockfile stamp approach (similar to the existing pnpm-lock.yaml check above it) could gate the sync. Not an issue now, just worth revisiting if shell startup feels sluggish later.


📋 Summary

Area Status
Custom sync code removal ✅ Clean
nix-filter in checks.nix ✅ Idiomatic improvement
.claude/skills/ gitignored & documented ✅
checks.agent-skills for CI coverage ✅
home-manager transitive dep ℹ️ Noted, no action needed
syncAgentSkills in shellHook ℹ️ Watch for shell startup perf

PR looks good overall. 🐇

Switch the project-local Claude skills target from a copied tree to a symlinked Nix bundle, matching the dotfiles setup and making .claude/skills clearly generated.

The sync wrapper now refuses to overwrite an existing directory, so users explicitly remove old generated copies before switching to the Nix-managed symlink. Also relax always-on validation guidance to rely on git hooks and CI for covered checks.
@ryoppippi

Copy link
Copy Markdown
Member Author

@coderabbitai @cubic-dev-ai I pushed a follow-up that switches repo-local skill sync to a local-only symlinked agent-skills-nix bundle and updates the validation guidance to rely on hooks/CI for covered checks. Please review the latest commit.

@cubic-dev-ai

cubic-dev-ai Bot commented May 23, 2026

Copy link
Copy Markdown
Contributor

@coderabbitai @cubic-dev-ai I pushed a follow-up that switches repo-local skill sync to a local-only symlinked agent-skills-nix bundle and updates the validation guidance to rely on hooks/CI for covered checks. Please review the latest commit.

@ryoppippi I have started the AI code review. It will take a few minutes to complete.

@coderabbitai

coderabbitai Bot commented May 23, 2026

Copy link
Copy Markdown

Tip

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Get the latest commit SHA on the PR branch
LATEST_SHA=$(gh pr view 1139 --repo ryoppippi/ccusage --json headRefOid --jq '.headRefOid')
echo "Latest commit: $LATEST_SHA"

# Get the diff of the latest commit
gh api "repos/ryoppippi/ccusage/commits/$LATEST_SHA" --jq '.files[] | {filename: .filename, patch: .patch}'

Length of output: 4691


@ryoppippi Commit f1ccccd looks solid. Here's the breakdown:


✅ nix/agent-skills.nix — "copy-tree" → "link"

Switching structure to "link" means .claude/skills becomes a single directory symlink into the Nix store, rather than a tree of copied files. This is simpler, lighter, and automatically stays in sync — no risk of stale copies. ✅

The new guard:

if [ -d "$target" ] && [ ! -L "$target" ]; then
  echo "$target already exists as a directory." >&2
  echo "Remove it before syncing Nix-managed agent skills." >&2
  exit 1
fi

is exactly right for the migration path. [ -d ] && [ ! -L ] correctly identifies a plain directory (not a symlink), fails fast with an actionable message, and won't trip on an existing symlink from a previous run. ✅

The ${AGENT_SKILLS_ROOT:-$PWD} env override is a nice flexibility touch for non-standard root setups. ✅


✅ .gitignore — trailing slash removed

.claude/skills/ → .claude/skills

This is important for correctness: git's handling of trailing-slash patterns for symlinks-to-directories is inconsistent across versions. The no-slash form reliably matches both the symlink entry and any directory at that path. ✅


✅ Documentation updates

  • .claude/CLAUDE.md correctly drops the nix run .#sync-agent-skills command (hook handles it now) and points to nix/agent-skills.nix for wiring details.
  • CLAUDE.md validation guidance appropriately relaxed — "run format when formatting may apply, rely on hooks/CI, run typecheck/test manually for behavior changes" is a realistic and accurate model.
  • Skill creator and development skill docs are consistent with the new model. ✅

📋 Summary

Change Status
structure = "link" (single symlink) ✅ Simpler and correct
Migration guard for existing plain dir ✅ Well-written
AGENT_SKILLS_ROOT env override ✅ Good flexibility
.gitignore symlink handling fix ✅ Necessary
Documentation aligned to new model ✅ Clean

PR looks good! 🐇

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

No issues found across 39 files

Re-trigger cubic

@github-actions

Copy link
Copy Markdown
Contributor

ccusage performance comparison

PR SHA: 00cc77f1b12d
Base SHA: 3e912262be1d

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 3e912262be1d 557.4ms 467.6ms 34.4ms 3
PR pkg.pr.new 00cc77f1b12d 430.8ms 638.4ms 34.1ms 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: 3e912262be1d; PR package: 00cc77f1b12d. 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.
Peak RSS is measured separately with /usr/bin/time using 1 runs. Lower RSS ratios are better.

Command Input Base median PR median PR vs base Base peak RSS PR peak RSS PR/base RSS Base throughput PR throughput
bunx -p <pkg> ccusage claude --offline --json 1.01 GiB 489.0ms 502.9ms 0.97x 280.58 MiB 264.70 MiB 0.94x 2.06 GiB/s 2.00 GiB/s
bunx -p <pkg> ccusage codex --offline --json 1.01 GiB 382.0ms 377.4ms 1.01x 57.33 MiB 51.33 MiB 0.90x 2.64 GiB/s 2.67 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 493.2ms 2.04 GiB/s 1
claude --offline --json Installed native binary 1.01 GiB 465.1ms 2.16 GiB/s 1
codex --offline --json Package wrapper 1.01 GiB 367.8ms 2.74 GiB/s 1
codex --offline --json Installed native binary 1.01 GiB 337.7ms 2.98 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.
Peak RSS is measured separately with /usr/bin/time using 1 runs. Lower RSS ratios are better.

Command Input Base median PR median PR vs base Base peak RSS PR peak RSS PR/base RSS Base throughput PR throughput
claude daily --offline --json 0.00 MiB 32.1ms 4.3ms 7.40x 43.61 MiB 2.83 MiB 0.06x 0.05 MiB/s 0.36 MiB/s
claude session --offline --json 0.00 MiB 31.6ms 4.2ms 7.47x 43.73 MiB 2.83 MiB 0.06x 0.05 MiB/s 0.36 MiB/s
codex daily --offline --json 0.00 MiB 31.8ms 4.0ms 7.93x 43.48 MiB 2.83 MiB 0.07x 0.03 MiB/s 0.21 MiB/s
codex session --offline --json 0.00 MiB 31.7ms 4.0ms 8.00x 43.48 MiB 2.83 MiB 0.07x 0.03 MiB/s 0.22 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.
Peak RSS is measured separately with /usr/bin/time using 1 runs. Lower RSS ratios are better.

Command Input Base median PR median PR vs base Base peak RSS PR peak RSS PR/base RSS Base throughput PR throughput
claude --offline --json 1.01 GiB 505.2ms 468.4ms 1.08x 266.70 MiB 266.20 MiB 1.00x 1.99 GiB/s 2.15 GiB/s
codex --offline --json 1.01 GiB 363.5ms 330.3ms 1.10x 59.58 MiB 51.20 MiB 0.86x 2.77 GiB/s 3.05 GiB/s

Artifact size

Artifact Base PR Delta Ratio
packed ccusage-*.tgz 14.25 KiB 14.25 KiB -0.00 KiB 1.00x
installed native package binary 3225.49 KiB 3225.49 KiB +0.00 KiB 1.00x

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
Contributor

ccusage performance comparison

PR SHA: 00cc77f1b12d
Base SHA: 3e912262be1d

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 3e912262be1d 393.2ms 515.8ms 33.7ms 3
PR pkg.pr.new 00cc77f1b12d 677.8ms 501.2ms 33.8ms 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: 3e912262be1d; PR package: 00cc77f1b12d. 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.
Peak RSS is measured separately with /usr/bin/time using 1 runs. Lower RSS ratios are better.

Command Input Base median PR median PR vs base Base peak RSS PR peak RSS PR/base RSS Base throughput PR throughput
bunx -p <pkg> ccusage claude --offline --json 1.01 GiB 488.6ms 490.2ms 1.00x 261.33 MiB 267.45 MiB 1.02x 2.06 GiB/s 2.05 GiB/s
bunx -p <pkg> ccusage codex --offline --json 1.01 GiB 366.5ms 372.8ms 0.98x 57.20 MiB 60.08 MiB 1.05x 2.75 GiB/s 2.70 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 504.1ms 2.00 GiB/s 1
claude --offline --json Installed native binary 1.01 GiB 462.5ms 2.18 GiB/s 1
codex --offline --json Package wrapper 1.01 GiB 360.0ms 2.80 GiB/s 1
codex --offline --json Installed native binary 1.01 GiB 334.4ms 3.01 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.
Peak RSS is measured separately with /usr/bin/time using 1 runs. Lower RSS ratios are better.

Command Input Base median PR median PR vs base Base peak RSS PR peak RSS PR/base RSS Base throughput PR throughput
claude daily --offline --json 0.00 MiB 31.0ms 30.1ms 1.03x 43.73 MiB 43.61 MiB 1.00x 0.05 MiB/s 0.05 MiB/s
claude session --offline --json 0.00 MiB 29.9ms 30.7ms 0.97x 43.48 MiB 43.48 MiB 1.00x 0.05 MiB/s 0.05 MiB/s
codex daily --offline --json 0.00 MiB 30.6ms 30.0ms 1.02x 43.73 MiB 43.48 MiB 0.99x 0.03 MiB/s 0.03 MiB/s
codex session --offline --json 0.00 MiB 30.5ms 30.6ms 1.00x 43.48 MiB 43.48 MiB 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.
Peak RSS is measured separately with /usr/bin/time using 1 runs. Lower RSS ratios are better.

Command Input Base median PR median PR vs base Base peak RSS PR peak RSS PR/base RSS Base throughput PR throughput
claude --offline --json 1.01 GiB 501.4ms 488.8ms 1.03x - 254.70 MiB - 2.01 GiB/s 2.06 GiB/s
codex --offline --json 1.01 GiB 359.5ms 358.7ms 1.00x 63.20 MiB 51.58 MiB 0.82x 2.80 GiB/s 2.81 GiB/s

Artifact size

Artifact Base PR Delta Ratio
packed ccusage-*.tgz 14.25 KiB 14.25 KiB -0.00 KiB 1.00x
installed native package binary 3225.49 KiB 3225.49 KiB +0.00 KiB 1.00x

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 e2f3ef6 into main May 23, 2026
29 checks passed
@ryoppippi
ryoppippi deleted the codex/migrate-git-hooks-nix branch May 23, 2026 22:07
@github-actions

Copy link
Copy Markdown
Contributor

ccusage performance comparison

PR SHA: f1ccccddc9b3
Base SHA: 3e912262be1d

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 3e912262be1d 583.1ms 569.9ms 35.5ms 3
PR pkg.pr.new f1ccccddc9b3 471.5ms 732.4ms 34.1ms 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: 3e912262be1d; PR package: f1ccccddc9b3. 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.
Peak RSS is measured separately with /usr/bin/time using 1 runs. Lower RSS ratios are better.

Command Input Base median PR median PR vs base Base peak RSS PR peak RSS PR/base RSS Base throughput PR throughput
bunx -p <pkg> ccusage claude --offline --json 1.01 GiB 488.8ms 494.5ms 0.99x 248.20 MiB 252.08 MiB 1.02x 2.06 GiB/s 2.04 GiB/s
bunx -p <pkg> ccusage codex --offline --json 1.01 GiB 374.9ms 387.3ms 0.97x 55.45 MiB 57.58 MiB 1.04x 2.69 GiB/s 2.60 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 490.2ms 2.05 GiB/s 1
claude --offline --json Installed native binary 1.01 GiB 461.0ms 2.18 GiB/s 1
codex --offline --json Package wrapper 1.01 GiB 366.6ms 2.75 GiB/s 1
codex --offline --json Installed native binary 1.01 GiB 345.2ms 2.92 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.
Peak RSS is measured separately with /usr/bin/time using 1 runs. Lower RSS ratios are better.

Command Input Base median PR median PR vs base Base peak RSS PR peak RSS PR/base RSS Base throughput PR throughput
claude daily --offline --json 0.00 MiB 31.5ms 31.7ms 0.99x 43.61 MiB - - 0.05 MiB/s 0.05 MiB/s
claude session --offline --json 0.00 MiB 32.7ms 31.7ms 1.03x 43.48 MiB 43.48 MiB 1.00x 0.05 MiB/s 0.05 MiB/s
codex daily --offline --json 0.00 MiB 31.3ms 31.2ms 1.00x 43.61 MiB 43.48 MiB 1.00x 0.03 MiB/s 0.03 MiB/s
codex session --offline --json 0.00 MiB 31.1ms 32.1ms 0.97x 43.48 MiB 43.54 MiB 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.
Peak RSS is measured separately with /usr/bin/time using 1 runs. Lower RSS ratios are better.

Command Input Base median PR median PR vs base Base peak RSS PR peak RSS PR/base RSS Base throughput PR throughput
claude --offline --json 1.01 GiB 497.3ms 498.2ms 1.00x 251.58 MiB 260.45 MiB 1.04x 2.02 GiB/s 2.02 GiB/s
codex --offline --json 1.01 GiB 374.7ms 361.9ms 1.04x 62.95 MiB 51.45 MiB 0.82x 2.69 GiB/s 2.78 GiB/s

Artifact size

Artifact Base PR Delta Ratio
packed ccusage-*.tgz 14.25 KiB 14.25 KiB -0.00 KiB 1.00x
installed native package binary 3225.49 KiB 3225.49 KiB +0.00 KiB 1.00x

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
Contributor

ccusage performance comparison

PR SHA: f1ccccddc9b3
Base SHA: 3e912262be1d

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 3e912262be1d 443.1ms 448.9ms 32.5ms 3
PR pkg.pr.new f1ccccddc9b3 584.8ms 559.7ms 33.4ms 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: 3e912262be1d; PR package: f1ccccddc9b3. 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.
Peak RSS is measured separately with /usr/bin/time using 1 runs. Lower RSS ratios are better.

Command Input Base median PR median PR vs base Base peak RSS PR peak RSS PR/base RSS Base throughput PR throughput
bunx -p <pkg> ccusage claude --offline --json 1.01 GiB 484.3ms 483.4ms 1.00x 268.58 MiB 261.58 MiB 0.97x 2.08 GiB/s 2.08 GiB/s
bunx -p <pkg> ccusage codex --offline --json 1.01 GiB 357.9ms 353.2ms 1.01x 58.70 MiB 66.45 MiB 1.13x 2.81 GiB/s 2.85 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 481.1ms 2.09 GiB/s 1
claude --offline --json Installed native binary 1.01 GiB 461.0ms 2.18 GiB/s 1
codex --offline --json Package wrapper 1.01 GiB 357.3ms 2.82 GiB/s 1
codex --offline --json Installed native binary 1.01 GiB 328.1ms 3.07 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.
Peak RSS is measured separately with /usr/bin/time using 1 runs. Lower RSS ratios are better.

Command Input Base median PR median PR vs base Base peak RSS PR peak RSS PR/base RSS Base throughput PR throughput
claude daily --offline --json 0.00 MiB 30.3ms 3.9ms 7.71x 43.48 MiB 2.83 MiB 0.07x 0.05 MiB/s 0.39 MiB/s
claude session --offline --json 0.00 MiB 31.3ms 4.1ms 7.63x 43.48 MiB 2.83 MiB 0.07x 0.05 MiB/s 0.38 MiB/s
codex daily --offline --json 0.00 MiB 30.6ms 3.9ms 7.93x 43.48 MiB 2.83 MiB 0.07x 0.03 MiB/s 0.22 MiB/s
codex session --offline --json 0.00 MiB 29.8ms 3.8ms 7.93x 43.48 MiB 2.83 MiB 0.07x 0.03 MiB/s 0.23 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.
Peak RSS is measured separately with /usr/bin/time using 1 runs. Lower RSS ratios are better.

Command Input Base median PR median PR vs base Base peak RSS PR peak RSS PR/base RSS Base throughput PR throughput
claude --offline --json 1.01 GiB 494.9ms 463.4ms 1.07x 259.95 MiB 283.58 MiB 1.09x 2.03 GiB/s 2.17 GiB/s
codex --offline --json 1.01 GiB 355.4ms 325.7ms 1.09x 64.95 MiB 51.20 MiB 0.79x 2.83 GiB/s 3.09 GiB/s

Artifact size

Artifact Base PR Delta Ratio
packed ccusage-*.tgz 14.25 KiB 14.25 KiB -0.00 KiB 1.00x
installed native package binary 3225.49 KiB 3225.49 KiB +0.00 KiB 1.00x

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

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