Skip to content

build(nix): provide cargo-hawk and gate nix flake check on it - #1497

Merged
ryoppippi merged 4 commits into
mainfrom
nix/cargo-hawk
Jul 27, 2026
Merged

ryoppippi merged 4 commits into
mainfrom
nix/cargo-hawk

Conversation

@ryoppippi

@ryoppippi ryoppippi commented Jul 27, 2026 •

Copy link
Copy Markdown
Member

Summary

just hawk landed in #1428 without the tool behind it, so the rust skill told
contributors to curl | sh an installer — an unpinned binary outside Nix, in a
repository that pins everything else. This adds nix/cargo-hawk.nix and puts it in
the dev shell, so just hawk works after direnv allow like every other recipe.

Why the published binary rather than a source build

hawk links against rustc_private. Building it from source needs the rustc-dev
component in the toolchain and RUSTC_BOOTSTRAP=1, which is a lot of machinery to
carry for a lint that no CI check gates on and that upstream calls experimental
("not intended for public consumption"). Upstream's own docs note that a prebuilt
release requires neither.

The derivation pins the release by hash for the four platforms upstream publishes
(aarch64/x86_64 × darwin/linux), marks sourceProvenance = binaryNativeCode, and
installs cargo-hawk-driver next to cargo-hawk because the binary execs the driver
from its own directory. Closure is 3.7 MB. A version bump is version plus the four
sha256 values, which upstream publishes beside each archive.

If a source build is preferred later, the rustc-dev toolchain can be materialised
inside this derivation through rust-overlay without touching the shared
rust-toolchain.toml pin — the file is the only thing that would change.

Testing

  • nix build .#cargo-hawk — both binaries land in $out/bin
  • cargo hawk check --manifest-path rust/Cargo.toml with the Nix-built binary: 0 findings on main
  • nix build .#ccusage still builds, so the dev-shell addition does not perturb the package set
  • just fmt

The skill section now describes the pinned derivation and how to bump it instead of
the installer script.


View with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is enabled.


Summary by cubic

Pins cargo-hawk in the Nix dev shell and gates CI with nix flake check so unnecessary pub fails fast. Fixes Linux linking by moving the pinned toolchain into buildInputs, making the binary work across macOS/Linux on arm64 and x86_64.

  • New Features

    • Added nix/cargo-hawk.nix to install cargo-hawk with cargo-hawk-driver.
    • Exposed as packages.cargo-hawk and included in the dev shell.
    • Added checks.<system>.ccusage-hawk to run cargo hawk check -D warnings, reusing clippy artifacts.
    • Updated .agents/skills/rust/SKILL.md with pinning and bump steps.
  • Bug Fixes

    • On Linux, moved the pinned rustToolchain into buildInputs (with stdenv.cc.cc.lib) so autoPatchelf resolves librustc_driver; macOS continues to resolve via @rpath.

Written for commit faac847. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • New Features
    • Added cargo-hawk to the development environment as a visibility lint tool.
    • Added platform-aware, reproducible packaging for cargo-hawk so it’s available consistently across systems.
  • Documentation
    • Updated guidance for the hawk/cargo-hawk workflow to reflect the Nix-pinned dev shell setup and how toolchain versioning affects results.
  • Tests
    • Extended nix flake check to run an additional cargo hawk check with warnings treated as errors.

`just hawk` needed a tool the dev shell did not provide, so the skill told
contributors to curl an installer — an unpinned binary outside Nix, in a
repository that pins everything else.

nix/cargo-hawk.nix fetches the upstream release by hash for the four platforms it
publishes and installs the driver next to the binary, which is where cargo-hawk
looks for it. A source build is deliberately not used: hawk links against
`rustc_private`, so it would need the `rustc-dev` component and
`RUSTC_BOOTSTRAP=1` for a tool no CI check gates on, while the published binary
needs neither. The closure is 3.7 MB.
Copilot AI review requested due to automatic review settings July 27, 2026 11:30

Copilot AI 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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jul 27, 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 faac847 Commit Preview URL

Branch Preview URL
Jul 27 2026, 11:55 AM

@coderabbitai

coderabbitai Bot commented Jul 27, 2026 •

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds a pinned Nix package for the prebuilt cargo-hawk binary, exports it from the flake, includes it in the development shell, adds a nix flake check analysis check, and updates Rust skill guidance for the Nix-based setup.

Changes

cargo-hawk Nix integration

Layer / File(s) Summary
Pinned cargo-hawk binary derivation
nix/cargo-hawk.nix
Selects system-specific hash-pinned archives, applies Linux runtime handling, installs both cargo-hawk binaries, and declares package metadata.
Package export and dev-shell wiring
nix/packages.nix, nix/dev-shell.nix
Defines and exports the per-system package and adds it to development shell inputs.
cargo-hawk check and Rust guidance
nix/checks.nix, .agents/skills/rust/SKILL.md
Runs cargo hawk check with warnings denied through the flake checks and documents the pinned Nix package, toolchain linkage, archive updates, and configuration guidance.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant DevShell as Nix dev shell
  participant CargoHawk as cargo-hawk
  participant RustCode as Rust code
  participant FlakeCheck as nix flake check
  DevShell->>CargoHawk: provide cargo-hawk
  FlakeCheck->>CargoHawk: run cargo hawk check -D warnings
  CargoHawk->>RustCode: analyze visibility
  CargoHawk-->>FlakeCheck: return diagnostics
Loading

Possibly related PRs

Suggested reviewers: copilot

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
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.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: adding cargo-hawk to Nix and gating nix flake check on it.
✨ 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 nix/cargo-hawk

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.

@pullfrog pullfrog 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 new issues found.

Reviewed changes — adds a hash-pinned cargo-hawk prebuilt binary to the Nix dev shell so just hawk works after direnv allow, replacing the unpinned curl-based installer with a reproducible derivation.

  • New nix/cargo-hawk.nix derivation — fetches upstream release binaries by hash for all four platforms (aarch64/x86_64 × darwin/linux), uses autoPatchelfHook on Linux, installs both cargo-hawk and cargo-hawk-driver together.
  • Wire into dev shell and packages — registers via callPackage in nix/packages.nix and adds to buildInputs in nix/dev-shell.nix.
  • Skill doc update — replaces curl-based install instructions in .agents/skills/rust/SKILL.md with a note about the pinned derivation and bump steps.

Pullfrog  | ⚠️ this action is pinned to a commit SHA, which freezes the cleanup step — switch to @v0 or keep the SHA fresh with Dependabot | View workflow run | Using DeepSeek Pro (free via Pullfrog for OSS) | 𝕏

@pkg-pr-new

pkg-pr-new Bot commented Jul 27, 2026 •

Copy link
Copy Markdown

Open in StackBlitz

ccusage

npx https://pkg.pr.new/ccusage@1497

@ccusage/ccusage-darwin-arm64

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

@ccusage/ccusage-darwin-x64

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

@ccusage/ccusage-linux-arm64

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

@ccusage/ccusage-linux-x64

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

@ccusage/ccusage-win32-x64

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

commit: faac847

@github-actions

Copy link
Copy Markdown
Contributor

ccusage performance comparison

PR SHA: cbfc4c9f50fa
Base SHA: 60f198460c7d

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

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, 2597 files), Codex /home/runner/_work/_temp/ccusage-large-codex-fixture (1.01 GiB, 2597 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 326.6ms 3.08 GiB/s 1
claude --offline --json Installed native binary 1.01 GiB 279.3ms 3.60 GiB/s 1
codex --offline --json Package wrapper 1.01 GiB 149.9ms 6.72 GiB/s 1
codex --offline --json Installed native binary 1.01 GiB 118.8ms 8.47 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 native ccusage binary 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 34.6ms 6.8ms 5.11x 55.00 MiB 12.46 MiB 0.23x 0.04 MiB/s 0.23 MiB/s
claude session --offline --json 0.00 MiB 31.0ms 4.0ms 7.83x 55.50 MiB 12.46 MiB 0.22x 0.05 MiB/s 0.39 MiB/s
codex daily --offline --json 0.00 MiB 27.7ms 2.9ms 9.64x 55.00 MiB 10.71 MiB 0.19x 0.03 MiB/s 0.30 MiB/s
codex session --offline --json 0.00 MiB 26.2ms 3.5ms 7.46x 55.00 MiB 10.70 MiB 0.19x 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, 2597 files), Codex /home/runner/_work/_temp/ccusage-large-codex-fixture (1.01 GiB, 2597 files)
Base runs the published ccusage package from pkg.pr.new, installed before measurement; PR runs the published native ccusage binary 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 340.9ms 305.5ms 1.12x 948.59 MiB 926.58 MiB 0.98x 2.95 GiB/s 3.30 GiB/s
codex --offline --json 1.01 GiB 125.1ms 105.8ms 1.18x 428.91 MiB 408.89 MiB 0.95x 8.05 GiB/s 9.52 GiB/s

Artifact size

Artifact Base PR Delta Ratio
packed ccusage-*.tgz 18.70 KiB 18.70 KiB -0.00 KiB 1.00x
installed native package binary 4201.63 KiB 4201.63 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: cbfc4c9f50fa
Base SHA: 60f198460c7d

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

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, 2597 files), Codex /home/runner/_work/_temp/ccusage-large-codex-fixture (1.01 GiB, 2597 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 357.7ms 2.81 GiB/s 1
claude --offline --json Installed native binary 1.01 GiB 314.8ms 3.20 GiB/s 1
codex --offline --json Package wrapper 1.01 GiB 121.8ms 8.26 GiB/s 1
codex --offline --json Installed native binary 1.01 GiB 97.0ms 10.38 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 28.6ms 26.6ms 1.07x 55.00 MiB 55.00 MiB 1.00x 0.05 MiB/s 0.06 MiB/s
claude session --offline --json 0.00 MiB 26.9ms 27.3ms 0.99x 55.25 MiB 55.00 MiB 1.00x 0.06 MiB/s 0.06 MiB/s
codex daily --offline --json 0.00 MiB 25.4ms 23.9ms 1.07x 55.00 MiB 55.00 MiB 1.00x 0.03 MiB/s 0.04 MiB/s
codex session --offline --json 0.00 MiB 25.5ms 23.8ms 1.07x 55.00 MiB 55.00 MiB 1.00x 0.03 MiB/s 0.04 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, 2597 files), Codex /home/runner/_work/_temp/ccusage-large-codex-fixture (1.01 GiB, 2597 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 371.0ms 364.8ms 1.02x 952.59 MiB 954.58 MiB 1.00x 2.71 GiB/s 2.76 GiB/s
codex --offline --json 1.01 GiB 119.5ms 127.5ms 0.94x 404.91 MiB 420.90 MiB 1.04x 8.43 GiB/s 7.90 GiB/s

Artifact size

Artifact Base PR Delta Ratio
packed ccusage-*.tgz 18.70 KiB 18.70 KiB -0.00 KiB 1.00x
installed native package binary 4201.63 KiB 4201.63 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.

Packaging the tool only helps if something runs it. `checks.<system>.ccusage-hawk`
runs `cargo hawk check -D warnings` over the workspace, reusing clippy's cargo
artifacts, so a new unnecessary `pub` fails the check rather than accumulating
until someone remembers to run `just hawk`.

It is a flake check rather than a treefmt formatter because hawk analyses the whole
workspace as a closed world instead of a file at a time, and because narrowing a
visibility is a semantic change, not formatting. Verified both directions: the check
passes on main and fails with hawk::unnecessary_public when a `pub(crate)` is widened
back to `pub`.
Copilot AI review requested due to automatic review settings July 27, 2026 11:39

Copilot AI 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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@ryoppippi ryoppippi changed the title build(nix): provide cargo-hawk from the dev shell build(nix): provide cargo-hawk and gate nix flake check on it Jul 27, 2026

@pullfrog pullfrog 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 new issues found.

Reviewed changes — gates nix flake check on cargo hawk check -D warnings so unnecessary pub visibility fails CI instead of accumulating, and updates the skill docs to match.

  • Add ccusage-hawk to flake checks — craneLib.mkCargoDerivation reuses the same cargoArtifacts as clippy so the cost is only the hawk analysis, not another workspace build. The check is wired into the checks set and listed alongside ccusage-clippy and ccusage-fmt.

  • Update rust/SKILL.md for the CI gate — replaces the old "no CI check runs it, so treat findings as suggestions" guidance with the new gate-aware advice: when a finding looks wrong, check whether rust/hawk.toml is missing an entry point before narrowing.

Pullfrog  | ⚠️ this action is pinned to a commit SHA, which freezes the cleanup step — switch to @v0 or keep the SHA fresh with Dependabot | View workflow run | Using DeepSeek Pro (free via Pullfrog for OSS) | 𝕏

The Linux build failed in CI with auto-patchelf unable to satisfy
librustc_driver-832cf6cfb1386559.so and libgcc_s.so.1. That dependency is the
concrete form of hawk's "only runs on the toolchain it was built against": its
driver links the compiler's shared library directly, and Darwin resolved it through
@rpath while Linux needs it on the search path.

The pinned toolchain carries the matching file because rust-overlay repackages the
same upstream release, so it goes into runtimeDependencies rather than being
vendored — verified on Darwin, where the published binary asks for
librustc_driver-e03ed1db822dfa4c and 1.97.1 ships exactly that.
Copilot AI review requested due to automatic review settings July 27, 2026 11:46

Copilot AI 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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@github-actions

Copy link
Copy Markdown
Contributor

ccusage performance comparison

PR SHA: a0dfc12cf342
Base SHA: 60f198460c7d

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

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, 2597 files), Codex /home/runner/_work/_temp/ccusage-large-codex-fixture (1.01 GiB, 2597 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 363.1ms 2.77 GiB/s 1
claude --offline --json Installed native binary 1.01 GiB 302.5ms 3.33 GiB/s 1
codex --offline --json Package wrapper 1.01 GiB 115.9ms 8.69 GiB/s 1
codex --offline --json Installed native binary 1.01 GiB 92.1ms 10.93 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 native ccusage binary 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.7ms 5.4ms 5.46x 55.00 MiB 12.45 MiB 0.23x 0.05 MiB/s 0.28 MiB/s
claude session --offline --json 0.00 MiB 23.5ms 3.2ms 7.23x 55.00 MiB 12.45 MiB 0.23x 0.07 MiB/s 0.48 MiB/s
codex daily --offline --json 0.00 MiB 24.2ms 2.4ms 9.97x 55.00 MiB 10.70 MiB 0.19x 0.04 MiB/s 0.35 MiB/s
codex session --offline --json 0.00 MiB 23.2ms 2.2ms 10.41x 55.00 MiB 10.70 MiB 0.19x 0.04 MiB/s 0.39 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, 2597 files), Codex /home/runner/_work/_temp/ccusage-large-codex-fixture (1.01 GiB, 2597 files)
Base runs the published ccusage package from pkg.pr.new, installed before measurement; PR runs the published native ccusage binary 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 366.1ms 321.2ms 1.14x 948.58 MiB 936.58 MiB 0.99x 2.75 GiB/s 3.13 GiB/s
codex --offline --json 1.01 GiB 118.4ms 98.2ms 1.21x 424.91 MiB 410.91 MiB 0.97x 8.50 GiB/s 10.26 GiB/s

Artifact size

Artifact Base PR Delta Ratio
packed ccusage-*.tgz 18.70 KiB 18.70 KiB -0.00 KiB 1.00x
installed native package binary 4201.63 KiB 4201.63 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: a0dfc12cf342
Base SHA: 60f198460c7d

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

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, 2597 files), Codex /home/runner/_work/_temp/ccusage-large-codex-fixture (1.01 GiB, 2597 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 344.4ms 2.92 GiB/s 1
claude --offline --json Installed native binary 1.01 GiB 300.5ms 3.35 GiB/s 1
codex --offline --json Package wrapper 1.01 GiB 116.1ms 8.67 GiB/s 1
codex --offline --json Installed native binary 1.01 GiB 93.8ms 10.74 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 28.1ms 29.4ms 0.96x 55.00 MiB 55.00 MiB 1.00x 0.06 MiB/s 0.05 MiB/s
claude session --offline --json 0.00 MiB 26.7ms 25.3ms 1.06x 55.00 MiB 55.25 MiB 1.00x 0.06 MiB/s 0.06 MiB/s
codex daily --offline --json 0.00 MiB 25.3ms 25.4ms 1.00x 54.75 MiB 55.00 MiB 1.00x 0.03 MiB/s 0.03 MiB/s
codex session --offline --json 0.00 MiB 24.1ms 23.3ms 1.04x 55.00 MiB 55.00 MiB 1.00x 0.04 MiB/s 0.04 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, 2597 files), Codex /home/runner/_work/_temp/ccusage-large-codex-fixture (1.01 GiB, 2597 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 356.1ms 347.5ms 1.02x 960.58 MiB 952.59 MiB 0.99x 2.83 GiB/s 2.90 GiB/s
codex --offline --json 1.01 GiB 119.4ms 119.0ms 1.00x 422.89 MiB 410.91 MiB 0.97x 8.43 GiB/s 8.46 GiB/s

Artifact size

Artifact Base PR Delta Ratio
packed ccusage-*.tgz 18.70 KiB 18.70 KiB -0.00 KiB 1.00x
installed native package binary 4201.63 KiB 4201.63 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.

@pullfrog

pullfrog Bot commented Jul 27, 2026 •

Copy link
Copy Markdown
Contributor

Diagnosis: autoPatchelfHook only searches buildInputs and nativeBuildInputs for shared libraries to satisfy NEEDED entries. runtimeDependencies only populates the RPATH — it doesn't participate in the dependency search. The rustToolchain was only listed in runtimeDependencies, so librustc_driver was never found during the auto-patch step, causing the nix flake check failure.

Fix: Added rustToolchain to buildInputs alongside the existing stdenv.cc.cc.lib. Verfied locally — nix build .#cargo-hawk succeeds and all libraries resolve correctly:

  • librustc_driver-832cf6cfb1386559.so → resolves from rust toolchain lib
  • libgcc_s.so.1 → resolves from gcc lib

Push failed: github-actions[bot] does not have push permission to this repository. The fix is committed locally at 099961fb on branch pr-1497.

Task list (7/7 completed)

Pullfrog  | ⚠️ this action is pinned to a commit SHA, which freezes the cleanup step — switch to @v0 or keep the SHA fresh with Dependabot | View workflow run | via Pullfrog | Using DeepSeek Pro (free via Pullfrog for OSS) | 𝕏

@pullfrog pullfrog 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 new issues found.

Reviewed changes — fixes Linux runtime linking for cargo-hawk so cargo-hawk-driver can resolve librustc_driver on Linux, which the prior Nix derivation inadvertently omitted.

  • Add rustToolchain as a runtime dependency on Linux — passes rustToolchain (derived from rust-toolchain.toml via pkgs.rust-bin.fromRustupToolchainFile) to the cargo-hawk derivation as runtimeDependencies so the binary can load librustc_driver at runtime.

  • Add stdenv.cc.cc.lib as a build input on Linux — lets autoPatchelfHook link against glibc symbols during the build phase.

  • Thread rustToolchain through from nix/packages.nix — already bound there at line 19 and used by every other Nix module (checks.nix, dev-shell.nix, git-hooks.nix), now passed to pkgs.callPackage for cargo-hawk.

Pullfrog  | ⚠️ this action is pinned to a commit SHA, which freezes the cleanup step — switch to @v0 or keep the SHA fresh with Dependabot | View workflow run | Using DeepSeek Pro (free via Pullfrog for OSS) | 𝕏

@github-actions

Copy link
Copy Markdown
Contributor

ccusage performance comparison

PR SHA: d937ebfe7876
Base SHA: 60f198460c7d

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

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, 2597 files), Codex /home/runner/_work/_temp/ccusage-large-codex-fixture (1.01 GiB, 2597 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 332.2ms 3.03 GiB/s 1
claude --offline --json Installed native binary 1.01 GiB 327.3ms 3.08 GiB/s 1
codex --offline --json Package wrapper 1.01 GiB 119.9ms 8.40 GiB/s 1
codex --offline --json Installed native binary 1.01 GiB 94.3ms 10.68 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 native ccusage binary 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 27.1ms 5.4ms 4.99x 55.00 MiB 12.44 MiB 0.23x 0.06 MiB/s 0.28 MiB/s
claude session --offline --json 0.00 MiB 26.0ms 2.7ms 9.47x 55.00 MiB 12.45 MiB 0.23x 0.06 MiB/s 0.56 MiB/s
codex daily --offline --json 0.00 MiB 23.6ms 3.1ms 7.63x 55.00 MiB 10.44 MiB 0.19x 0.04 MiB/s 0.28 MiB/s
codex session --offline --json 0.00 MiB 25.6ms 2.4ms 10.61x 55.00 MiB 10.44 MiB 0.19x 0.03 MiB/s 0.36 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, 2597 files), Codex /home/runner/_work/_temp/ccusage-large-codex-fixture (1.01 GiB, 2597 files)
Base runs the published ccusage package from pkg.pr.new, installed before measurement; PR runs the published native ccusage binary 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 366.7ms 343.2ms 1.07x 958.59 MiB 952.58 MiB 0.99x 2.75 GiB/s 2.93 GiB/s
codex --offline --json 1.01 GiB 121.1ms 95.6ms 1.27x 406.90 MiB 428.90 MiB 1.05x 8.31 GiB/s 10.53 GiB/s

Artifact size

Artifact Base PR Delta Ratio
packed ccusage-*.tgz 18.70 KiB 18.70 KiB +0.00 KiB 1.00x
installed native package binary 4201.63 KiB 4008.14 KiB -193.48 KiB 1.05x

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: d937ebfe7876
Base SHA: 60f198460c7d

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

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, 2597 files), Codex /home/runner/_work/_temp/ccusage-large-codex-fixture (1.01 GiB, 2597 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 340.2ms 2.96 GiB/s 1
claude --offline --json Installed native binary 1.01 GiB 308.1ms 3.27 GiB/s 1
codex --offline --json Package wrapper 1.01 GiB 122.7ms 8.20 GiB/s 1
codex --offline --json Installed native binary 1.01 GiB 110.0ms 9.15 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 25.9ms 31.0ms 0.83x 55.00 MiB 55.00 MiB 1.00x 0.06 MiB/s 0.05 MiB/s
claude session --offline --json 0.00 MiB 24.9ms 25.1ms 0.99x 55.25 MiB 55.00 MiB 1.00x 0.06 MiB/s 0.06 MiB/s
codex daily --offline --json 0.00 MiB 23.7ms 23.0ms 1.03x 55.00 MiB 55.00 MiB 1.00x 0.04 MiB/s 0.04 MiB/s
codex session --offline --json 0.00 MiB 26.6ms 24.6ms 1.08x 55.25 MiB 55.00 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, 2597 files), Codex /home/runner/_work/_temp/ccusage-large-codex-fixture (1.01 GiB, 2597 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 371.7ms 338.2ms 1.10x 952.59 MiB 952.57 MiB 1.00x 2.71 GiB/s 2.98 GiB/s
codex --offline --json 1.01 GiB 118.1ms 122.6ms 0.96x 408.91 MiB 402.89 MiB 0.99x 8.53 GiB/s 8.21 GiB/s

Artifact size

Artifact Base PR Delta Ratio
packed ccusage-*.tgz 18.70 KiB 18.70 KiB +0.00 KiB 1.00x
installed native package binary 4201.63 KiB 4008.14 KiB -193.48 KiB 1.05x

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

runtimeDependencies put the toolchain on the RUNPATH but left the dependency
reported as unsatisfied, because auto-patchelf resolves against the library set
derived from buildInputs and only writes runtimeDependencies into the RUNPATH.

The pinned toolchain does carry the exact file the published binary asks for: the
upstream rustc 1.97.1 archive for x86_64-unknown-linux-gnu ships
librustc_driver-832cf6cfb1386559.so, the name in the CI failure, so moving the
toolchain into buildInputs makes the search find it instead of ignoring it.
Copilot AI review requested due to automatic review settings July 27, 2026 11:54

Copilot AI 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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

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

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 `@nix/checks.nix`:
- Line 59: Update the nativeBuildInputs expression in the relevant checks
configuration to parenthesize the `commonArgs.nativeBuildInputs` fallback before
appending `config.packages.cargo-hawk`, ensuring the `or [ ]` default applies
only to nativeBuildInputs.
🪄 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 Plus

Run ID: 4914d58f-61ea-4d0d-9e62-abff4c00885f

📥 Commits

Reviewing files that changed from the base of the PR and between cbfc4c9 and d937ebf.

📒 Files selected for processing (4)
  • .agents/skills/rust/SKILL.md
  • nix/cargo-hawk.nix
  • nix/checks.nix
  • nix/packages.nix
🚧 Files skipped from review as they are similar to previous changes (3)
  • nix/packages.nix
  • nix/cargo-hawk.nix
  • .agents/skills/rust/SKILL.md

Comment thread nix/checks.nix
sourceRoot = "source/rust";
cargoLock = root + /rust/Cargo.lock;
inherit cargoArtifacts;
nativeBuildInputs = commonArgs.nativeBuildInputs or [ ] ++ [ config.packages.cargo-hawk ];

@coderabbitai coderabbitai Bot Jul 27, 2026 •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

direnv allow
just --list

nix eval --json --expr '
let
  commonArgs = { nativeBuildInputs = [ "existing-input" ]; };
in
  commonArgs.nativeBuildInputs or [ ] ++ [ "cargo-hawk" ]
'

nix eval --json --expr '
let
  commonArgs = { nativeBuildInputs = [ "existing-input" ]; };
in
  (commonArgs.nativeBuildInputs or [ ]) ++ [ "cargo-hawk" ]
'

Repository: ccusage/ccusage

Length of output: 197


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

echo "== files =="
git ls-files nix/

echo "== nix/checks.nix around 47-62 and 160-172 =="
cat -n nix/checks.nix | sed -n '45,70p;158,174p'

echo "== searches for ccusage-hawk / cargo-hawk native inputs =="
rg -n "cargo-hawk|ccusage-hawk|nativeBuildInputs.*or|nativeBuildInputs = commonArgs" nix .github README.md 2>/dev/null | head -120

echo "== nix parser probe if nix is available =="
if command -v nix >/dev/null 2>&1; then
  nix eval --json --expr '
let
  commonArgs = { nativeBuildInputs = [ "existing-input" ]; };
in
  commonArgs.nativeBuildInputs or [ ] ++ [ "cargo-hawk" ]
' || true

  nix eval --json --expr '
let
  commonArgs = { nativeBuildInputs = [ "existing-input" ]; };
in
  (commonArgs.nativeBuildInputs or [ ]) ++ [ "cargo-hawk" ]
' || true
else
  echo "nix not available"
fi

echo "== locate Nix evaluator for parsing if commonArgs can be omitted =="
if command -v nix >/dev/null 2>&1; then
  cat >/tmp/nix-or-probe.nix <<'NIX'
let
  commonArgs = { };
  cfg = commonArgs.nativeBuildInputs or [ ];
  inputs = cfg ++ [ "cargo-hawk" ];
in { cfg = cfg; inputs = inputs; }
NIX
  nix eval --json --file /tmp/nix-or-probe.nix || true
fi

Repository: ccusage/ccusage

Length of output: 4686


🌐 Web query:

Nix attribute selection operators precedence dot or concat list or [ ] ++ concatenation

💡 Result:

In the Nix expression language, operators follow a specific precedence order that determines how expressions are evaluated. Attribute selection and list concatenation occupy different tiers in this hierarchy, meaning attribute selection binds more tightly than list concatenation [1][2]. The precedence levels for the requested operators are as follows (where 1 is the highest precedence/strongest binding): 1. Attribute Selection (.): This operator has a precedence of 1, making it one of the highest-binding operations in the language [1][3]. It is used to select an attribute from an attribute set (e.g., attrset.attrpath) [1][4]. 2. List Concatenation (++): This operator has a precedence of 5 [1][2]. It is used to join two lists together (e.g., list1 ++ list2) [1][5]. Because attribute selection (precedence 1) binds more tightly than list concatenation (precedence 5), an expression like a.b ++ c is parsed as (a.b) ++ c [1][2]. Summary of relevant operator precedence (from strongest to weakest): - Attribute Selection (.): 1 [1][3] - Function Application: 2 [1][2] - Arithmetic Negation (-): 3 [1][6] - Has Attribute (?): 4 [1][2] - List Concatenation (++): 5 [1][4] For comprehensive details, you can refer to the official Nix language documentation regarding operators [1][2].

Citations:


🌐 Web query:

Nix syntax or operator binding associativity in attrpath fallback or syntax A or B

💡 Result:

In the Nix language, the attribute selection operator (also known as the fallback syntax when the or keyword is used) is defined as having "none" for its associativity [1][2][3]. The formal syntax for this operation is: attrset. attrpath [or expr] When the or keyword is used, it provides a fallback value if the specified attribute path (attrpath) does not exist in the attribute set (attrset). If the attribute is missing and no or expression is provided, Nix will abort evaluation [1][2][3]. Regarding associativity, the attribute selection operator's "none" designation signifies that chaining behaves in a specific way: while multiple selections can be chained (e.g., a.b.c), the or fallback expression extends as far as possible to the right [4]. This means that in an expression like a.b or c.d or e, the parser interprets the or as applying to the entire preceding selection chain [4]. Because the or clause binds to the entire preceding expression, it effectively acts as a fallback for the entire lookup operation rather than just the final segment of a chained path [4].

Citations:


🌐 Web query:

"commonArgs.nativeBuildInputs or [ ] ++" "Nix" "or []"

💡 Result:

The expression commonArgs.nativeBuildInputs or [] ++ ... is a common pattern in Nix flake configurations, particularly when using builders like crane, to safely extend an existing list of build dependencies [1][2][3]. Breakdown of the expression: 1. commonArgs.nativeBuildInputs or []: This part uses the OR operator (or). It attempts to access the nativeBuildInputs attribute from the commonArgs attribute set. If nativeBuildInputs is missing from commonArgs, it defaults to an empty list [], preventing an evaluation error [1][4]. 2. ++: This is the list concatenation operator in the Nix language. It combines the list obtained in the first step with the list on the right-hand side [1][5][6]. 3....: This represents the new dependencies you wish to add to the derivation (e.g., with pkgs; [ git cmake ]) [1][3]. Why this is used: In Nix, defining derivation arguments often involves merging attribute sets. If you simply use // to override nativeBuildInputs, you will completely replace the original list, effectively "dropping" any default dependencies (like build hooks or standard tools) that were defined in commonArgs [1]. Using (commonArgs.nativeBuildInputs or []) ++ [...] ensures that you are extending the existing list rather than overwriting it, which is crucial for maintaining necessary build tools across different parts of a project [1][4]. It is important to note the order of operations and grouping. Because the or operator has higher precedence than ++, you should generally group the first part in parentheses if you want the or to apply to the retrieval of the attribute before the concatenation occurs: (commonArgs.nativeBuildInputs or []) ++ [...] [1][4]. Without proper grouping, the expression might be parsed as commonArgs.nativeBuildInputs or ([] ++ [...]), which may not be the intended behavior.

Citations:


🌐 Web query:

"Nix language operators" "or" "None"

💡 Result:

The Nix language does not have a None type or a specific None operator. Instead, it provides a null value, which represents the absence of a value [1][2][3]. The null value is a distinct primitive type in Nix [3][4]. It can be accessed as the literal null or via the built-in attribute set as builtins.null [1][3][5]. Regarding operators, Nix features a variety of arithmetic, logical, and structural operators, such as attribute selection (.), attribute update (//), and equality tests (==,!=), but there is no None operator [6][7][8]. Notably, the attribute selection operator does support a default value mechanism using the or keyword (e.g., attrset.attrpath or default_expr), which is often used in scenarios where one might use an option or null-coalescing operator in other languages [6][7][9].

Citations:


🌐 Web query:

github nixos/nix "or" attrpath precedence "++" language/operators.md

💡 Result:

In the Nix expression language, attribute selection (.) and the ++ (list concatenation) operator have different precedence levels, which determine the order in which expressions are evaluated [1][2]. According to the official Nix reference documentation, attribute selection has the highest precedence (1), while list concatenation (++) has a lower precedence (5) [1][3]. Because lower precedence numbers indicate "stronger" binding (the operations performed first), attribute selection binds more tightly than the ++ operator [4]. Summary of precedence levels for these operators: 1. Attribute selection (attrset.attrpath): Precedence 1 [1][2]. 2. List concatenation (list ++ list): Precedence 5 [1][2]. Because of this, an expression like a.b ++ c is parsed as (a.b) ++ c rather than a.(b ++ c). In Nix, an "attribute path" is defined as a dot-separated list of attribute names (e.g., a.b.c) and is used specifically with the attribute selection operator [4][5].

Citations:


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

python3 - <<'PY'
# Read-only static probe: parse Nix attr-or syntax using a small tokenizer from the
# language/operator precedent described by the Nix manual for attribute selection vs
# list concatenation.
#
# Relevance: we do not run repository code or tools, but this mirrors deterministic
# parsing by respecting precedence/associativity facts from the referenced Nix semantics.
import re

def tokenize(s):
    state = 'start'
    i = 0
    while i < len(s):
        ch = s[i:i+1]
        if ch.isspace():
            i += 1
            continue
        if ch == '.':
            yield 'DOT'
            i += 1
        elif ch == '+':
            if s[i:i+2] == '++':
                yield 'CONCAT'
                i += 2
            else:
                raise SystemExit("unknown token ++")
        elif ch == '[':
            yield 'LBRACKET'
            i += 1
        elif ch == ']':
            yield 'RBRACKET'
        elif s[i:i+2] == 'or':
            yield 'OR'
            i += 2
        else:
            m = re.match(r'[A-Za-z0-9_-]+', s[i:])
            if not m:
                raise SystemExit(f"unexpected token at {i!r}")
            yield m.group(0)
            i += len(m.group(0))

def parse_attr_or_concat(s):
    tokens = list(tokenize(s))
    # Tokens relevant to expression `commonArgs.nativeBuildInputs or [] ++ [ cargo-hawk ]`
    # with hyphen names tokenized.
    expr = tokens

    if tokens == ['commonArgs','nativeBuildInputs','OR','LBRACKET','RBRACKET','CONCAT','LBRACKET','cargo hawk','RBRACKET']:
        # Model precedence/order: dot binds attrpath; or is part of attr-or syntax for
        # missing attrpath with fallback expression. Concat is a separate later list
        # operator with lower precedence.
        attr_path = ('commonArgs','nativeBuildInputs')
        fallback = []
        extra = ['cargo hawk']
        return {'parsed': f'attr_or(attr_path={attr_path}, fallback={fallback}) ++ extra={extra}',
                'would_concat_if_exists': True}

    attr = []
    i = 0
    if expr[0] not in ['commonArgs','nativeBuildInputs']:
        return {}
    # Parse leading attrpath with attributes.
    while i < len(expr) and expr[i].isidentifier():
        attr.append(expr[i])
        i += 1
    if i < len(expr) and expr[i] == 'DOT':
        if len(attr) < 2 or expr[i+1] != 'nativeBuildInputs':
            raise SystemExit("unexpected attrpath")
        attr.append('nativeBuildInputs')
        i += 2
    if i < len(expr) and expr[i] == 'OR':
        if len(attr) != 2 or expr[i+1:i+3] != ['LBRACKET','RBRACKET']:
            raise SystemExit("unexpected or")
        attrs = tuple(attr)
        i += 3
        result_exists = attrs == ('commonArgs','nativeBuildInputs')
        fallback = []
        if i < len(expr) and expr[i] == 'CONCAT':
            if expr[i+1:i+3] != ['LBRACKET','cargo hawk','RBRACKET']:
                raise SystemExit("unexpected concat")
            print("Parsed expression has later CONCAT after attr-or, so concat is a separate operator.")
            print("If commonArgs.nativeBuildInputs exists, eval-result = existing ++ ['cargo hawk'].")
            print("If commonArgs.nativeBuildInputs is missing, eval-result = [] ++ ['cargo hawk'].")
            raise SystemExit(0)
        else:
            raise SystemExit("missing concat after or")
    raise SystemExit("bad expression")

parse_attr_or_concat('commonArgs.nativeBuildInputs or [ ] ++ [ cargo hawk ]')
PY

Repository: ccusage/ccusage

Length of output: 145


🌐 Web query:

"commonArgs.nativeBuildInputs or [ ] ++" "Nix"

💡 Result:

In Nix, the expression commonArgs.nativeBuildInputs or [ ] is a common pattern used to safely access a list of dependencies from an attribute set (commonArgs), providing an empty list [ ] as a fallback if the attribute is missing [1][2][3]. The syntax x or y is a built-in Nix language feature used to access an attribute x from a set if it exists, otherwise returning the default value y. This pattern is frequently used in Nix derivations—particularly when building Rust projects with tools like Crane—to incrementally extend or override build arguments [1][2][4]. For example, when creating a new derivation based on a set of common arguments, you can extend the nativeBuildInputs while ensuring you do not encounter an error if the base set lacks that specific attribute: nativeBuildInputs = (commonArgs.nativeBuildInputs or [ ]) ++ [ pkgs.some-tool ]; This allows for modular and DRY (Don't Repeat Yourself) configurations, where common dependencies are defined once and then augmented as needed for specific targets or test environments [1][2]. It is particularly valuable in complex Flake configurations where arguments are passed through multiple layers of derivation overrides [4][5].

Citations:


🌐 Web query:

docs.rs nix-parser "or" operator precedence list concatenation "++"

💡 Result:

In the Nix expression language, the list concatenation operator (++) has a precedence level of 5 [1][2][3]. It is right-associative [1][2][3]. For context, this places it between the "has attribute" operator (precedence 4) and multiplication/division (precedence 6) [1][2][3]. Regarding the mention of "docs.rs nix-parser," the primary Rust-based parser for the Nix language is rnix (often referred to as rnix-parser) [4][5][6]. While it provides tools for parsing and manipulating the Nix abstract syntax tree (AST) [4][5][6], authoritative technical details regarding language-level operator precedence are defined by the official Nix reference manual [1][2][3] and implemented in the language's core source code (e.g., parser.y) [7].

Citations:


Parenthesize the fallback before appending cargo-hawk.

commonArgs.nativeBuildInputs or [ ] ++ [ config.packages.cargo-hawk ] uses precedence that can make the fallback apply to the lookup result after concatenation instead of before. Move the default list outside the or syntax instead of leaving or [ ] ++ ... as the fallback target.

Proposed fix
-          nativeBuildInputs = commonArgs.nativeBuildInputs or [ ] ++ [ config.packages.cargo-hawk ];
+          nativeBuildInputs = (commonArgs.nativeBuildInputs or [ ]) ++ [ config.packages.cargo-hawk ];
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
nativeBuildInputs = commonArgs.nativeBuildInputs or [ ] ++ [ config.packages.cargo-hawk ];
nativeBuildInputs = (commonArgs.nativeBuildInputs or [ ]) ++ [ config.packages.cargo-hawk ];
🤖 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/checks.nix` at line 59, Update the nativeBuildInputs expression in the
relevant checks configuration to parenthesize the `commonArgs.nativeBuildInputs`
fallback before appending `config.packages.cargo-hawk`, ensuring the `or [ ]`
default applies only to nativeBuildInputs.

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.

False positive: in Nix the or fallback is an expr_select and binds tighter than the lower-precedence ++, so the line already parses as (commonArgs.nativeBuildInputs or [ ]) ++ [ config.packages.cargo-hawk ]. CI confirms this — commonArgs defines nativeBuildInputs, yet the check still builds cargo-hawk, which only happens under the correct parse. The suggested parens are a no-op.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Skipped: comment is from another GitHub bot.

@github-actions

Copy link
Copy Markdown
Contributor

ccusage performance comparison

PR SHA: faac847db5d8
Base SHA: 60f198460c7d

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

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, 2597 files), Codex /home/runner/_work/_temp/ccusage-large-codex-fixture (1.01 GiB, 2597 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 348.7ms 2.89 GiB/s 1
claude --offline --json Installed native binary 1.01 GiB 313.4ms 3.21 GiB/s 1
codex --offline --json Package wrapper 1.01 GiB 116.0ms 8.68 GiB/s 1
codex --offline --json Installed native binary 1.01 GiB 93.6ms 10.76 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 native ccusage binary 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.1ms 5.3ms 5.45x 55.00 MiB 12.44 MiB 0.23x 0.05 MiB/s 0.29 MiB/s
claude session --offline --json 0.00 MiB 23.6ms 3.3ms 7.10x 55.25 MiB 12.44 MiB 0.23x 0.07 MiB/s 0.46 MiB/s
codex daily --offline --json 0.00 MiB 23.0ms 2.3ms 9.95x 55.00 MiB 10.44 MiB 0.19x 0.04 MiB/s 0.37 MiB/s
codex session --offline --json 0.00 MiB 22.9ms 2.3ms 9.85x 55.00 MiB 10.43 MiB 0.19x 0.04 MiB/s 0.37 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, 2597 files), Codex /home/runner/_work/_temp/ccusage-large-codex-fixture (1.01 GiB, 2597 files)
Base runs the published ccusage package from pkg.pr.new, installed before measurement; PR runs the published native ccusage binary 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 369.9ms 303.9ms 1.22x 952.59 MiB 972.57 MiB 1.02x 2.72 GiB/s 3.31 GiB/s
codex --offline --json 1.01 GiB 115.9ms 97.0ms 1.19x 418.90 MiB 458.90 MiB 1.10x 8.69 GiB/s 10.38 GiB/s

Artifact size

Artifact Base PR Delta Ratio
packed ccusage-*.tgz 18.70 KiB 18.70 KiB +0.00 KiB 1.00x
installed native package binary 4201.63 KiB 4008.14 KiB -193.48 KiB 1.05x

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: faac847db5d8
Base SHA: 60f198460c7d

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

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, 2597 files), Codex /home/runner/_work/_temp/ccusage-large-codex-fixture (1.01 GiB, 2597 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 369.9ms 2.72 GiB/s 1
claude --offline --json Installed native binary 1.01 GiB 377.2ms 2.67 GiB/s 1
codex --offline --json Package wrapper 1.01 GiB 134.3ms 7.49 GiB/s 1
codex --offline --json Installed native binary 1.01 GiB 107.9ms 9.33 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 28.3ms 28.5ms 0.99x 55.00 MiB 55.00 MiB 1.00x 0.05 MiB/s 0.05 MiB/s
claude session --offline --json 0.00 MiB 32.6ms 37.0ms 0.88x 55.25 MiB 55.00 MiB 1.00x 0.05 MiB/s 0.04 MiB/s
codex daily --offline --json 0.00 MiB 32.9ms 30.0ms 1.10x 55.00 MiB 55.25 MiB 1.00x 0.03 MiB/s 0.03 MiB/s
codex session --offline --json 0.00 MiB 34.3ms 30.0ms 1.14x 55.25 MiB 55.00 MiB 1.00x 0.02 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, 2597 files), Codex /home/runner/_work/_temp/ccusage-large-codex-fixture (1.01 GiB, 2597 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.0ms 399.5ms 1.24x 952.84 MiB 948.57 MiB 1.00x 2.03 GiB/s 2.52 GiB/s
codex --offline --json 1.01 GiB 135.5ms 136.6ms 0.99x 434.91 MiB 414.89 MiB 0.95x 7.43 GiB/s 7.37 GiB/s

Artifact size

Artifact Base PR Delta Ratio
packed ccusage-*.tgz 18.70 KiB 18.70 KiB +0.00 KiB 1.00x
installed native package binary 4201.63 KiB 4008.14 KiB -193.48 KiB 1.05x

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 d7d2dd7 into main Jul 27, 2026
49 of 50 checks passed
@ryoppippi
ryoppippi deleted the nix/cargo-hawk branch July 27, 2026 12:13
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.

2 participants