A CLI tool written in Haskell for checking your recent AtCoder AC count and the problems you solved, from the command line.
Inspired by ccusage.
It uses the AtCoder Problems API to fetch the AC history.
npx acac-cli <atcoder-username>
┌──────────────────┬────┬───────────────────────────────────────────────────┐
│ Date │ AC │ Problems │
├──────────────────┼────┼───────────────────────────────────────────────────┤
│ 2026-05-26 (Tue) │ 2 │ abc081B abc290A │
│ 2026-05-29 (Fri) │ 1 │ abc342C │
│ 2026-05-30 (Sat) │ 6 │ abc460A abc460B abc460C abc460D awc0001A awc0001B │
├──────────────────┼────┼───────────────────────────────────────────────────┤
│ week total │ 9 │ │
├──────────────────┼────┼───────────────────────────────────────────────────┤
│ 2026-05-31 (Sun) │ 1 │ abc460C │
│ 2026-06-01 (Mon) │ 1 │ abc460D │
│ 2026-06-06 (Sat) │ 3 │ abc461A abc461B abc461C │
├──────────────────┼────┼───────────────────────────────────────────────────┤
│ week total │ 5 │ │
├──────────────────┼────┼───────────────────────────────────────────────────┤
│ 2026-06-07 (Sun) │ 1 │ abc461C │
│ 2026-06-08 (Mon) │ 1 │ abc144B │
│ 2026-06-09 (Tue) │ 5 │ abc106B abc120B abc122B abc136B abc150B │
│ 2026-06-10 (Wed) │ 1 │ abc057C │
│ 2026-06-11 (Thu) │ 1 │ abc095A │
│ 2026-06-12 (Fri) │ 1 │ sumitrust2019D │
│ 2026-06-13 (Sat) │ 3 │ abc462A abc462B abc462C │
├──────────────────┼────┼───────────────────────────────────────────────────┤
│ week total │ 13 │ │
├──────────────────┼────┼───────────────────────────────────────────────────┤
│ 2026-06-15 (Mon) │ 5 │ APG4bA APG4bPythonA abc128C abc462B abc462D │
│ 2026-06-17 (Wed) │ 3 │ abc145C abc147C abc150C │
│ 2026-06-18 (Thu) │ 2 │ abc054C abc448B │
│ 2026-06-19 (Fri) │ 5 │ abc054C abc245B abc273A abc425B awc0001B │
│ 2026-06-20 (Sat) │ 6 │ abc029C abc153D abc247C abc463A abc463B abc463C │
├──────────────────┼────┼───────────────────────────────────────────────────┤
│ week total │ 21 │ │
├──────────────────┼────┼───────────────────────────────────────────────────┤
│ 2026-06-22 (Mon) │ 2 │ abc292B abc350B │
├──────────────────┼────┼───────────────────────────────────────────────────┤
│ week total │ 2 │ │
└──────────────────┴────┴───────────────────────────────────────────────────┘It displays your recent AC history as a weekly table.
npx acac-cli --help # show usage (-h)If no AC submissions are found in the last 4 weeks (e.g. a typo'd username), acac prints a message instead of an empty table:
npx acac-cli no-such-user
No AC submissions found for user no-such-user in the last 4 weeks (check the username?)The following binaries are built.
| OS | binary type | Verified on real device |
|---|---|---|
| Linux | linux-x64 | ✅ |
| Linux | linux-arm64 | |
| macOS | darwin-arm64 | ✅ |
| macOS | darwin-x64 | |
| Windows | win32-x64 | ✅ |
If you have verified acac on a real device other than the ✅ ones, please let us know via an Issue.
If you use another environment, we would appreciate a request/PR on an Issue, but you can also set it up by referring to For Developer Memo.
For supply chain transparency, the distributed artifacts are produced as follows.
- All binaries are built on GitHub Actions from the acac-cli source. Nothing is published from a local machine.
- Linux (linux-x64 / linux-arm64) is a reproducible musl static build via Nix (
nix build .#static). - macOS / Windows are built on each OS's native runner with GHC 9.12.2 + cabal.
- Linux (linux-x64 / linux-arm64) is a reproducible musl static build via Nix (
- Publishing to npm is done by CI with provenance (
--provenance, OIDC trusted publishing). Each release can be verified back to the workflow run and commit it came from. - Releases are cut from
v*.*.*tags using GitHub Immutable Releases (the release is created by the CI bot, not by hand). - Each GitHub Release binary is signed with cosign (keyless) — every
acac-<os>-<arch>ships an accompanying.sig(signature) and.pem(certificate), plus aacac.intoto.jsonlSLSA provenance attestation for the release. This is what OpenSSF Scorecard'sSigned-Releaseschecks (Immutable Releases and npm provenance alone do not satisfy it). - Platform binaries are distributed as
acac-<os>-<arch>optionalDependencypackages, so the main package has no runtime dependencies.
nix developRun it from cabal inside the nix develop shell.
cabal run acac -- <atcoder-username># runghc may be handier for debugging
runghc -isrc -iapp app/Main.hs <atcoder-username>You can also run it directly from the flake.
nix run . -- <atcoder-username>runghc -isrc test/Spec.hsFormat everything at once with treefmt (ormolu / nixfmt / mdformat).
nix fmtPushing a v*.*.* tag triggers artifact upload to a GitHub Release and npm publish.
CACHIX_AUTH_TOKEN
The CI fetches the distributable musl static binary from Cachix (acac) (because rebuilding from source takes around 60 minutes and times out).
Therefore, before cutting a tag, you must seed the current static build to Cachix.
# Set the token only the first time (not needed afterwards)
cachix authtoken <CACHIX_AUTH_TOKEN>
nix build .#static
cachix push acac ./resultRun the following; 200 means OK. If it returns 404, it is not seeded, so push it:
hash=$(basename "$(readlink -f result)" | cut -d- -f1)
curl -s -o /dev/null -w "%{http_code}\n" "https://acac.cachix.org/$hash.narinfo"Only when the .#static derivation changes. Specifically, when you change the following:
src/,app/,test/,acac.cabal(= the cabal package source)flake.lock(dependency updates)- the parts of
flake.nixthat affect.#static(dependencies,fileset, GHC version,pkgsStaticconfig, etc.)
Conversely, changes to only README, docs, npm, or the devShell/comments in flake.nix do not require re-seeding
(because the callCabal2nix source is narrowed to src/app/test/acac.cabal via fileset).
When in doubt, if the narinfo check above returns 404, push — that is reliable.
git tag v0.1.0
git push origin v0.1.0