Публічний реєстр
Звіт про здоров'я програмного забезпеченнясхема 0.27.0 · метрики 1.13.0 · 2026-07-26 22:34 UTC

drogers0 / aistat

Check Claude and Codex API usage limits from the terminal

GoMIT★ 8 зірок⑂ 2 форкиз бер. 2026 р.Переглянути на GitHub ↗

drogers0/aistat має індекс здоров’я 55 зі 100, що відповідає смузі «Помірний». Найвищий показник — Vitality (74/100), найнижчий — Community & Adoption (31/100). Останнє оновлення було 10 днів тому. Більшість нещодавньої роботи виконує один учасник.

55
загалом / 100
Помірний

Індекс здоров'я програмного забезпечення

Метрики згруповано у зважені категорії на шкалі 1–100. Загальна оцінка починається як їхнє середнє; коли публічні дані активують Політику юрисдикцій високого ризику, рейтинг коригується й отримує верхню межу 49 («Під ризиком»). Готовність до ШІ не входить до індексу.

55
Відмінний85-100Зразковий; відповідає практично всім перевіреним критеріям
Добрий70-84Здоровий; незначні прогалини
Помірний50-69Прийнятний, але з помітними прогалинами; рекомендовано перевірку
У зоні ризику30-49Суттєві слабкі місця; впровадження потребує обережності
Критичний1-29Серйозні проблеми (покинутий, єдиний мейнтейнер, без базової гігієни)
ЖиттєздатністьСпільнота тавпровадженняСталість таврядуванняІнженернаякістьБезпекаГотовність доШІ

Профіль оцінок

Кожна вісь — окрема категорія. Форма важить більше, ніж середнє: здоровий об'єкт заповнює всю фігуру, тоді як профіль із піками та провалами означає, що сила в одному вимірі маскує ризик в іншому.

Власність

David RogersОсобистий обліковий запис
2 підписники17 публічних репозиторіївз груд. 2022 р.

Цей репозиторій належить особистому обліковому запису. Проєкт з єдиним власником несе більший ризик безперервності, ніж підтримуваний організацією.

Пакетні екосистеми

РеєстрПакетВерсіяЗавантажень / місВерсіїОстання публікація
Gogithub.com/drogers0/aistat/v2v2.4.0-1210 днів тому

Метрики за категоріями

Життєздатність

Чи живий проєкт — чи пишеться код і чи виходять релізи?

74Добрий · 22% загального індексу
Як обчислюється оцінка
28.8/36Свіжість push — останній push 10 дн. тому
7.6/36Ритм комітів — 11/52 тижнів із комітами
17.1/18Обсяг комітів — 80 комітів за останній рік
10/10OpenSSF Scorecard: Maintained — 30 commit(s) and 13 issue activity found in the last 90 days -- score normalized to 10
Використані вхідні дані
commits_last_year80
human_commit_share1
days_since_last_push10
active_weeks_last_year11
Як обчислюється оцінка
27/27Випускає релізи — опубліковано 16 релізів
36/36Свіжість релізів — останній реліз 10 дн. тому
27/27Ритм релізів — реліз кожні ~5,3 дн.
0/10OpenSSF Scorecard: Signed-Releases — Project has not signed or included provenance with any releases.
Використані вхідні дані
releases_count16
latest_release_tagv2.4.0
releases_from_tagsні
days_since_latest_release10
mean_days_between_releases5,3

Спільнота та впровадження

Чи має проєкт користувачів, завантаження, увагу та влаштовані умови для контриб’юторів?

31У зоні ризику · 18% загального індексу
Як обчислюється оцінка
13.7/60Зірки — 8 зірок
0/25Форки — 2 форків
0/15Спостерігачі — 1 спостерігачів
Використані вхідні дані
forks2
stars8
watchers1
growth_stateunverified
growth_factor_pct100
growth_unverified_reasonno_history
Як обчислюється оцінка
22.5/22.5README
22.5/22.5Ліцензія — визнана ліцензія (MIT)
0/18Настанови CONTRIBUTING
0/13.5Кодекс поведінки
0/7.2Шаблон issue
0/6.3Шаблон PR
Використані вхідні дані
has_readmeтак
has_licenseтак
has_contributingні
has_issue_templateні
has_code_of_conductні
has_pull_request_templateні

Сталість та врядування

Чи переживе проєкт своїх людей — бас-фактор, реактивність, хто за ним стоїть і як супроводжуються пакети?

50Помірний · 24% загального індексу
Як обчислюється оцінка
9/54Бас-фактор — на 1 контриб’ютор(ів) припадає половина всіх комітів
1.1/22.5Розподіл комітів — головний контриб’ютор — автор 95% комітів
2.7/13.5Широта контриб’юторів — 2 контриб’юторів
0/10OpenSSF Scorecard: Contributors — project has 0 contributing companies or organizations -- score normalized to 0
Використані вхідні дані
bus_factor1
contributors_sampled2
top_contributor_share0,949
Як обчислюється оцінка
28.8/46.8Вирішення issue — закрито 62% issue
34.6/38.3Прийняття PR — злито 19/21 вирішених PR
3/15OpenSSF Scorecard: Code-Review — Found 4/15 approved changesets -- score normalized to 2
Використані вхідні дані
merged_prs19
open_issues5
closed_issues8
issue_closed_ratio0,615
closed_unmerged_prs2

Власність та опіка

37У зоні ризику
Як обчислюється оцінка
10/30Підтримка власника — особистий (користувацький) обліковий запис
0/20Верифікований домен — не застосовно до користувацьких облікових записів
3.4/25Охоплення власника — 2 підписників у drogers0
16.4/25Послужний список — 17 публічних репозиторіїв, вік облікового запису ~3 р.
Використані вхідні дані
followers2
owner_typeUser
is_verified
owner_logindrogers0
public_repos17
account_age_days1 325
Виключено з оцінювання (немає даних або не застосовно): Верифікований домен. Залишкові ваги перенормовано.

Супровід пакетів

100Відмінний
Як обчислюється оцінка
25/25Опубліковано й доступно — 1 пакет(ів) у go
35/35Свіжість публікацій — остання публікація 10 дн. тому
20/20Історія версій — 12 опублікованих версій
20/20Не застарілий — активний, не deprecated і не yanked
Використані вхідні дані
packagesgithub.com/drogers0/aistat/v2
ecosystemsgo
any_deprecatedні
min_days_since_publish10

Інженерна якість

Чи наявні базові інженерні практики та документація?

69Помірний · 20% загального індексу
Як обчислюється оцінка
24/24Процеси CI — 3 процес(ів) CI
24/24Наявні тести
16/16Конфігурація лінтера — .golangci.yml
0/9.6Pre-commit-хуки
0/6.4.editorconfig
18/20OpenSSF Scorecard: CI-Tests — 14 out of 15 merged PRs checked by a CI test -- score normalized to 9
Використані вхідні дані
has_ciтак
has_testsтак
has_editorconfigні
has_linter_configтак
has_precommit_configні

Документація

50Помірний
Як обчислюється оцінка
30/30README
0/25Каталог документації
0/15Сайт документації / домашня сторінка
10/10Опис репозиторію
0/10Теми
10/10Wiki
Використані вхідні дані
topics
has_wikiтак
homepage
has_readmeтак
has_docs_dirні
has_descriptionтак

Безпека

Чи міцні видимі практики безпеки й ланцюга постачання, без непослабленої пов’язаності з юрисдикціями високого ризику?

47У зоні ризику · 16% загального індексу

Стан безпеки

47У зоні ризику
Як обчислюється оцінка
7.5/7.5Binary-Artifacts — no binaries found in the repo
6/7.5Branch-Protection — branch protection is not maximal on development and all release branches
2.2/2.5CI-Tests — 14 out of 15 merged PRs checked by a CI test -- score normalized to 9
0/2.5CII-Best-Practices — no effort to earn an OpenSSF best practices badge detected
1.5/7.5Code-Review — Found 4/15 approved changesets -- score normalized to 2
0/2.5Contributors — project has 0 contributing companies or organizations -- score normalized to 0
10/10Dangerous-Workflow — no dangerous workflow patterns detected
0/7.5Dependency-Update-Tool — no update tool detected
0/5Fuzzing — project is not fuzzed
2.5/2.5Ліцензія — license file detected
7.5/7.5Maintained — 30 commit(s) and 13 issue activity found in the last 90 days -- score normalized to 10
5/5Packaging — packaging workflow detected
0/5Pinned-Dependencies — dependency not pinned by hash detected -- score normalized to 0
0/5SAST — SAST tool is not run on all commits -- score normalized to 0
0/5Security-Policy — security policy file not detected
0/7.5Signed-Releases — Project has not signed or included provenance with any releases.
0/7.5Token-Permissions — detected GitHub workflow tokens with excessive permissions
7.5/7.5Vulnerabilities — 0 existing vulnerabilities detected
Використані вхідні дані
sourceopenssf_scorecard
checks_evaluated18
scorecard_versionv5.5.0
checks_inconclusive0
scorecard_aggregate4,7

Готовність до ШІ

Наскільки репозиторій оснащений для розробки та супроводу за участі ШІ-агентів? Незалежний, експериментальний бейдж — вага 0.0, тож він подається окремо і не впливає на загальний індекс здоров'я.

69Помірний · 0% загального індексу
Як обчислюється оцінка
45/45Інструкції для агентів — AGENTS.md, CLAUDE.md
0/15Машиночитана документація (llms.txt)
40/40Читабельна історія комітів — намір зазначено у 77 з 80 людських комітів (структурований заголовок або пояснювальний текст)
Використані вхідні дані
has_llms_txtні
legible_history_share0,963
agent_instruction_filesAGENTS.md, CLAUDE.md
agent_instruction_max_bytes18 300
Як обчислюється оцінка
12.6/18Розгортання однією командою — go.mod (домовленість інструментарію, без раннера задач)
22/22Автоматизовані тести
11/11Конфігурація лінтера / форматера — .golangci.yml
11/11Статична перевірка типів — Go (статично типізована)
0/10Відтворюване середовище
0/10Підтверджена практика роботи з агентами — серед останніх 80 комітів немає створених агентом
0/8Автоматизоване супроводження — автоматичних оновлень залежностей не виявлено
0/10OpenSSF Scorecard: Pinned-Dependencies — dependency not pinned by hash detected -- score normalized to 0
Використані вхідні дані
has_nixні
has_testsтак
lockfiles
has_dockerfileні
typed_languageтак
bootstrap_files
has_devcontainerні
has_linter_configтак
typecheck_configs
agent_commit_share0
toolchain_manifestsgo.mod
dependency_bot_commit_share0
Як обчислюється оцінка
45/45Типізований код — Go (статично типізована)
54/55Керовані розміри файлів — 2/107 файлів вихідного коду понад 60 КБ
Використані вхідні дані
primary_languageGo
largest_source_bytes71 156
source_files_sampled107
oversized_source_files2
Як обчислюється оцінка
0/40Схема API (OpenAPI/GraphQL/proto)
0/20Сервер MCP
40/40Придатні до запуску приклади — examples
Використані вхідні дані
example_dirsexamples
has_mcp_signalні
api_schema_files

Ключові факти

8зірок GitHub
2контриб'юторів
80комітів за останні 12 місяців
10днів від останнього пушу
16релізів
1бас-фактор
5відкритих issue
Goпакетних екосистем

Попередження щодо збору даних

  • Star history unavailable: GitHub GraphQL error: Resource not accessible by personal access token
  • GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository

Докладніше

Історія зірок і форків 0 ★ / 2 ⇿
0Зірки
2Форки
4Релізи

Коли додано кожну зірку й форк — зібрано з GitHub і згруповано за днями. Кумулятивне зростання розміщено просто над денними додаваннями, з яких воно складається, тож їх видно одне проти одного: рівномірне органічне накопичення виглядає зовсім інакше, ніж різкий короткочасний сплеск. Там, де цю різницю можна виміряти, її подано як автентичність росту.

111222212026-062026-062026-07
Мажорні 0Мінорні 1Патчі 1
OpenSSF Scorecard 4.7 / 10
4.7сукупно

Незалежна, не прив'язана до інструментів оцінка безпеки від відкритого проєкту OpenSSF Scorecard. Кожна перевірка винагороджує практику безпеки, а не інструмент конкретного постачальника. Перевірки, які Scorecard не зміг визначити, позначено н/д і виключено з оцінки безпеки (вони ніколи не зараховуються як нуль).Scorecard v5.5.0 · 2026-07-26 22:34 UTC

10Binary-Artifactsno binaries found in the repo
8Branch-Protectionbranch protection is not maximal on development and all release branches
9CI-Tests14 out of 15 merged PRs checked by a CI test -- score normalized to 9
0CII-Best-Practicesno effort to earn an OpenSSF best practices badge detected
2Code-ReviewFound 4/15 approved changesets -- score normalized to 2
0Contributorsproject has 0 contributing companies or organizations -- score normalized to 0
10Dangerous-Workflowno dangerous workflow patterns detected
0Dependency-Update-Toolno update tool detected
0Fuzzingproject is not fuzzed
10Licenselicense file detected
10Maintained30 commit(s) and 13 issue activity found in the last 90 days -- score normalized to 10
10Packagingpackaging workflow detected
0Pinned-Dependenciesdependency not pinned by hash detected -- score normalized to 0
0SASTSAST tool is not run on all commits -- score normalized to 0
0Security-Policysecurity policy file not detected
0Signed-ReleasesProject has not signed or included provenance with any releases.
0Token-Permissionsdetected GitHub workflow tokens with excessive permissions
10Vulnerabilities0 existing vulnerabilities detected
Усі залежності не зібрано

Не вдалося зібрати розв'язаний набір залежностей для цього звіту: GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository

Звіт у форматі JSON машиночитний
{
  "data": {
    "repo": {
      "topics": [],
      "is_fork": false,
      "size_kb": 597,
      "has_wiki": true,
      "homepage": null,
      "languages": {
        "Go": 779737,
        "Shell": 10017
      },
      "pushed_at": "2026-07-16T21:41:14Z",
      "created_at": "2026-03-18T01:19:48Z",
      "owner_type": "User",
      "updated_at": "2026-07-16T00:16:07Z",
      "description": "Check Claude and Codex API usage limits from the terminal",
      "is_archived": false,
      "is_disabled": false,
      "license_spdx": "MIT",
      "default_branch": "main",
      "license_spdx_raw": "MIT",
      "primary_language": "Go",
      "significant_languages": [
        "Go"
      ]
    },
    "owner": {
      "blog": null,
      "name": "David Rogers",
      "type": "User",
      "login": "drogers0",
      "company": null,
      "location": null,
      "followers": 2,
      "avatar_url": "https://avatars.githubusercontent.com/u/120214987?v=4",
      "created_at": "2022-12-09T18:51:00Z",
      "is_verified": null,
      "public_repos": 17,
      "account_age_days": 1325
    },
    "license": {
      "state": "standard",
      "spdx_id": "MIT",
      "raw_spdx": "MIT",
      "file_present": true,
      "scorecard_found": true,
      "profile_has_license": true
    },
    "activity": {
      "releases": [
        {
          "tag": "v2.4.0",
          "kind": "minor",
          "published_at": "2026-07-16T21:42:21Z"
        },
        {
          "tag": "v2.4.0-rc.2",
          "kind": "prerelease",
          "published_at": "2026-07-15T20:26:45Z"
        },
        {
          "tag": "v2.4.0-rc.1",
          "kind": "prerelease",
          "published_at": "2026-07-08T19:03:12Z"
        },
        {
          "tag": "v2.3.0",
          "kind": "minor",
          "published_at": "2026-07-08T16:19:46Z"
        },
        {
          "tag": "v2.3.0-rc.1",
          "kind": "prerelease",
          "published_at": "2026-07-07T22:05:28Z"
        },
        {
          "tag": "v2.2.1",
          "kind": "patch",
          "published_at": "2026-06-23T19:03:35Z"
        },
        {
          "tag": "v2.2.0",
          "kind": "minor",
          "published_at": "2026-06-09T18:41:12Z"
        },
        {
          "tag": "v2.1.3",
          "kind": "patch",
          "published_at": "2026-06-04T00:50:40Z"
        },
        {
          "tag": "v2.1.2",
          "kind": "patch",
          "published_at": "2026-06-01T23:14:10Z"
        },
        {
          "tag": "v2.1.1",
          "kind": "patch",
          "published_at": "2026-05-29T22:37:10Z"
        },
        {
          "tag": "v2.1.0",
          "kind": "minor",
          "published_at": "2026-05-28T21:03:54Z"
        },
        {
          "tag": "v2.0.0",
          "kind": "major",
          "published_at": "2026-05-28T00:44:36Z"
        },
        {
          "tag": "v1.0.0",
          "kind": "major",
          "published_at": "2026-05-26T19:56:53Z"
        },
        {
          "tag": "v0.0.3",
          "kind": "patch",
          "published_at": "2026-04-30T17:30:32Z"
        },
        {
          "tag": "v0.0.2",
          "kind": "patch",
          "published_at": "2026-03-26T23:56:42Z"
        },
        {
          "tag": "v0.0.1",
          "kind": "patch",
          "published_at": "2026-03-20T19:39:07Z"
        }
      ],
      "recent_commits": [
        {
          "oid": "bebce19724a665269594cc94f1d11b91ba8c5eb8",
          "body": "…3) (#34)\n\n* feat: golangci-lint migration, integer percentages, agent skill, README multi-provider refresh (#27 #29 #33)\n\n* docs(skill): drop non-standard when_to_use frontmatter key\n\nClaude Code selects skills off the description field (which already\ncarries the triggers) and ignores unknown frontmatter keys, so\nwhen_to_use was inert duplication.",
          "is_bot": false,
          "headline": "golangci-lint migration, integer percentages, agent skill (#27 #29 #3…",
          "author_name": "David Rogers",
          "author_login": "drogers0",
          "committed_at": "2026-07-16T00:16:02Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "2df934a6b1832b837864ada4ae0daa3a1d4665d8",
          "body": "…ve-*] [--watch]` (#31)\n\nRemoves the `watch` subcommand and the `--if-needed` flag (both rc.1-only) and folds them into `switch --watch` with unified threshold flags (`--if-above-5h`/`--if-above-weekly`, precedence flag > env > default). Includes the extracted conditional gate + notifier threading from the #23/#24 follow-up, plus docs/help updates.\n\nRefs #23 #24. Closes #32.",
          "is_bot": false,
          "headline": "refactor(switch): unify conditional switching under `switch [--if-abo…",
          "author_name": "David Rogers",
          "author_login": "drogers0",
          "committed_at": "2026-07-15T20:24:18Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "69b544aede03423e984fe9e7bcc27a305d05a6e2",
          "body": "* feat(switch): conditional switching with --if-needed and --notify\n\naistat switch --if-needed only rotates the live account when the active\naccount crosses a used-percent threshold (AISTAT_IF_ABOVE_5H default 85,\nAISTAT_IF_ABOVE_WEEKLY default 95; 'off' disables a window; resolved from\nprocess env,\n[…]\nthat window's alert was lost. Send first; record only on success so\nthe next tick retries. Add a regression test.\n\n---------\n\nCo-authored-by: David Rogers <120214987+drogers0@users.noreply.github.com>",
          "is_bot": false,
          "headline": "feat(watch): aistat watch daemon (in-memory notification dedup) (#24)",
          "author_name": "Stephan R.",
          "author_login": "casiusss",
          "committed_at": "2026-07-08T19:00:56Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "0eded93da7f7b748eeb59d96265014e1f925ef1a",
          "body": "* feat(switch): conditional switching with --if-needed and --notify\n\naistat switch --if-needed only rotates the live account when the active\naccount crosses a used-percent threshold (AISTAT_IF_ABOVE_5H default 85,\nAISTAT_IF_ABOVE_WEEKLY default 95; 'off' disables a window; resolved from\nprocess env,\n[…]\non\nopts.ifNeeded and return 0, mirroring the single-account branch, and\nadd a regression test for the new branch.\n\n---------\n\nCo-authored-by: David Rogers <120214987+drogers0@users.noreply.github.com>",
          "is_bot": false,
          "headline": "feat(switch): conditional switching (--if-needed + --notify) (#23)",
          "author_name": "Stephan R.",
          "author_login": "casiusss",
          "committed_at": "2026-07-08T18:40:33Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "d60f024e2c95b504515a02f7ca397d47999d2dba",
          "body": "Windows previously fell through the !darwin && !linux stubs: the binary\ncompiled but Claude was unsupported, the account store was a no-op, and the\nusage cache was disabled. This adds real Windows support with no new\nthird-party dependency.\n\n- internal/winlock: whole-file locking via kernel32!LockFi\n[…]\nPROFILE%\\.claude\\.credentials.json.\n- install.sh installs the Windows .zip under Git Bash/MSYS.\n- CI adds windows-latest; goreleaser ships a Windows .zip; .gitattributes\n  pins LF for golden fixtures.",
          "is_bot": false,
          "headline": "feat: native Windows support (Claude/Codex/Copilot usage + switch) (#28)",
          "author_name": "David Rogers",
          "author_login": "drogers0",
          "committed_at": "2026-07-08T16:18:22Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "9f0e4fba6d741130d6a8dbae16221c0e24eb688f",
          "body": "Parse Anthropic's new limits array and surface weekly_scoped entries as\nseven_day_<model> windows (e.g. seven_day_fable), rendered generically so a\nmodel rename degrades gracefully instead of showing a raw key. Informational\nonly — does not affect switch ranking or triggers.",
          "is_bot": false,
          "headline": "feat(claude): surface model-scoped weekly limits in usage (#22)",
          "author_name": "Stephan R.",
          "author_login": "casiusss",
          "committed_at": "2026-07-06T18:29:19Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "aeda7f15f20963a4f41ac931322df5eaa76dbf78",
          "body": "…ield\n\nfix(claude): tolerate non-window sibling fields in usage response",
          "is_bot": false,
          "headline": "Merge pull request #20 from casiusss/fix/claude-usage-array-sibling-f…",
          "author_name": "David Rogers",
          "author_login": "drogers0",
          "committed_at": "2026-06-23T19:02:14Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "4f0c0c264e29b3571eb8cd237b57b0af364cad6b",
          "body": "Anthropic added a top-level field to /api/oauth/usage whose value is a JSON\narray (a per-app usage breakdown). fetchLimitsFresh decoded the whole body\ninto map[string]*window, forcing every value to be a window object, so the\narray-valued field failed json.Unmarshal for the entire response -- taking\n[…]\nn unexpected shape is skipped rather than failing the whole account.\n\nAdds a regression test reproducing the exact error and extends the usage.json\nfixture with a realistic array-valued sibling field.",
          "is_bot": false,
          "headline": "fix(claude): tolerate non-window sibling fields in usage response",
          "author_name": "Stephan Rieche",
          "author_login": "casiusss",
          "committed_at": "2026-06-17T07:22:31Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "4eddc7a27681e721f9c4be0fe1753810000dfac1",
          "body": "feat(copilot): report AI-credit usage from copilot_internal/user",
          "is_bot": false,
          "headline": "Merge pull request #19 from drogers0/copilot-ai-credits-billing",
          "author_name": "David Rogers",
          "author_login": "drogers0",
          "committed_at": "2026-06-09T18:38:18Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "d87a40e946624500d59ab86cd16759d369f75fc2",
          "body": "fix(switch): rank accounts with no 5h window by real headroom",
          "is_bot": false,
          "headline": "Merge pull request #18 from drogers0/fix-switch-auto-pick-no-5h-window",
          "author_name": "David Rogers",
          "author_login": "drogers0",
          "committed_at": "2026-06-09T18:38:04Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "5ad6fbe9941a2a9d28383f753d770f27ec8aa365",
          "body": "GitHub retired premium-request billing on 2026-06-01; the legacy billing\nendpoint now returns an empty usage list, so the provider reported a false\nmonth: 0.0%. Switch to the live-quota endpoint copilot_internal/user and read\nquota_snapshots.premium_interactions, which carries the live entitlement a\n[…]\nnts automatically).\nUnlimited grants and no-allotment accounts now report cleanly as N/A (empty\nlimits). Classification delegates to httpx.DefaultClassify; a bare 404 is not\nremapped to missing-scope.",
          "is_bot": false,
          "headline": "feat(copilot): report AI-credit usage from copilot_internal/user",
          "author_name": "drogers0",
          "author_login": "drogers0",
          "committed_at": "2026-06-09T18:09:34Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "096942d1a7319ab29432f2991b54af73d9b8c7b9",
          "body": "aistat switch auto-pick ranked an absent five_hour window as worst\n(fiveHourBucket returned -1), so an account at 99% used on its 5h window\nbeat a freshly-reset account with no five_hour window at all — and switch\nreported \"already on best\". But providers omit the five_hour window\nprecisely when it \n[…]\nt (thirty_day at 0%) is never auto-picked, plus\na sustained-runway tiebreak. Windows are ordered by role, never blended,\nso 1% of a 5h window is not weighed against 1% of a weekly window.\n\nCloses #16.",
          "is_bot": false,
          "headline": "fix(switch): rank accounts with no 5h window by real headroom",
          "author_name": "drogers0",
          "author_login": "drogers0",
          "committed_at": "2026-06-04T23:02:47Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "2e6a4606a0df0328a6a951965b19ea0cd383292e",
          "body": "fix(codex): gate refresh on access-token expiry, not the id_token",
          "is_bot": false,
          "headline": "Merge pull request #17 from drogers0/fix-codex-refresh-expiry",
          "author_name": "David Rogers",
          "author_login": "drogers0",
          "committed_at": "2026-06-04T00:49:46Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "df88099be7ed82a1d396640c20b2d44e4f37f69b",
          "body": "aistat reported the active Codex account as \"stale refresh token (codex\nCLI rotated it)\" on every run even when the access token was valid for\ndays. The refresh gate read StoredExpiresAt from the short-lived OIDC\nid_token's exp (~1h) instead of the long-lived access_token (~10d), so\nonce the id_toke\n[…]\ntion is removed (Claude-only now), and rotateRawBlob preserves\nthe id_token rather than deleting it (the deletion was itself a\nworkaround for this bug). The id_token remains identity-only (sub/email).",
          "is_bot": false,
          "headline": "fix(codex): gate refresh on access-token expiry, not the id_token",
          "author_name": "drogers0",
          "author_login": "drogers0",
          "committed_at": "2026-06-04T00:46:31Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "484c0059d7de1a915ef108ef729313375722a898",
          "body": "test: adopt table-driven t.Run subtests as house convention",
          "is_bot": false,
          "headline": "Merge pull request #15 from drogers0/table-driven-tests",
          "author_name": "David Rogers",
          "author_login": "drogers0",
          "committed_at": "2026-06-01T22:51:45Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a573fe787a938d4fdf46fad23176c9f045ef516a",
          "body": "Second footprint pass on top of the table-driven migration:\n\n- testutil: add WantNoErr/WantErrIs/WantErrContains (shared error\n  assertions) and adopt across cred (-96), httpx, claude, codex,\n  copilot, usagecache, orchestrate, multiaccount, cmd/aistat; delete the\n  duplicated per-package wantNoErr/\n[…]\n~16 errors.Is sentinel checks in claude/codex move t.Errorf -> t.Fatalf\n(via the shared WantErrIs), a strictness escalation that aborts before a\nwrong-error-type cascade; no pass/fail outcome changes.",
          "is_bot": false,
          "headline": "test: dedupe assertions, externalize golden output",
          "author_name": "drogers0",
          "author_login": "drogers0",
          "committed_at": "2026-06-01T21:47:34Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "9437a129c36876344644a71c50875c113e89c601",
          "body": "Reduce the test footprint introduced by the table-driven migration by\nfactoring out repeated scaffolding. No behavior change; every assertion,\nexpected value, and error-string contract is preserved (leaf counts\nunchanged: claude 93, codex 107, copilot 33, cmd/aistat 89).\n\n- testutil: add MemStore, C\n[…]\n  CLI assertion helpers; adopt MemStore.\n- copilot: wantNoErr.\n\nNet -568 lines vs the migration commit; the suite is now +192 lines over\nthe pre-migration baseline while fully on the t.Run convention.",
          "is_bot": false,
          "headline": "test: cut table-driven boilerplate via shared helpers",
          "author_name": "drogers0",
          "author_login": "drogers0",
          "committed_at": "2026-06-01T20:58:43Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "38586b530917819f083b2bc376b4ae2737d78a85",
          "body": "Adopt table-driven tests with t.Run subtests as the house convention.\nCollapse standalone `func TestXxx_Case` functions into table-driven\nparents: data tables for homogeneous clusters, closure tables for\nheterogeneous families. Coverage is unchanged — every case is preserved\nas a subtest row (top-le\n[…]\nsserted values and verbatim\nerror-string contracts are preserved byte-for-byte. Setup stays inside\neach subtest; no t.Parallel added.\n\nDocument the convention in TESTING.md and link it from CLAUDE.md.",
          "is_bot": false,
          "headline": "test: migrate suite to table-driven t.Run subtests",
          "author_name": "drogers0",
          "author_login": "drogers0",
          "committed_at": "2026-06-01T19:47:43Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "ad5d284d453b54a51d384fddcc0f7bceb6b77df2",
          "body": "Codex multi-account support (substrate refactor + Codex provider + CLI surface)",
          "is_bot": false,
          "headline": "Merge pull request #14 from drogers0/codex-multi-account",
          "author_name": "David Rogers",
          "author_login": "drogers0",
          "committed_at": "2026-06-01T16:04:33Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e91bc6b8d75a2ad2780da69aab51fb42873fa2d9",
          "body": "T8's tightened error strings never fired against OpenAI's actual 401\nresponses, so users still saw the raw JSON body:\n\n- stale-refresh matched \"refresh_token already\" but the real body reads\n  \"Your refresh token has already been used to generate a new access token\"\n- revoked-token matched only \"tok\n[…]\npdate tests to the real bodies; add end-to-end coverage for token_invalidated\n  and for the LiveUnstored tightening path\n- correct CLAUDE.md \"Known limitations (Codex)\" to the real bodies and matchers",
          "is_bot": false,
          "headline": "fix(codex): match the real upstream OAuth bodies in tightened errors",
          "author_name": "drogers0",
          "author_login": "drogers0",
          "committed_at": "2026-06-01T15:44:09Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "aed97db9b46198f03bc28170d4d27b58fd510c91",
          "body": "Two well-known Codex OAuth failure modes get bespoke, actionable error\nstrings instead of the raw HTTP body, and `aistat switch codex` verifies\nthe just-switched-to account's tokens (in the --to path) so the user\nlearns immediately when the switch wrote a blob whose tokens were\nserver-revoked by an \n[…]\nurns the pre-switch\nresult; FetchForSwitch already excluded revoked accounts up front so\nthe post-switch verify is redundant there. The verify produces a live\nHTTP call only on the explicit --to path.",
          "is_bot": false,
          "headline": "feat(codex): tighter UX for upstream OAuth failures (T8)",
          "author_name": "drogers0",
          "author_login": "drogers0",
          "committed_at": "2026-05-31T01:47:11Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "c5ce61be0b9e5a1aa234c8b878db988a91793e31",
          "body": "CLAUDE.md\n- Rewritten CLI surface to match the provider-scoped grammar\n  (aistat switch [provider] [--to <id>], aistat accounts list [provider],\n  aistat accounts remove <id> [provider]).\n- Repo layout updated for the substrate split: internal/providers/usagecache,\n  internal/providers/multiaccount,\n[…]\n  fell through to the real platform Codex store on dev machines and\n  surfaced unrelated stored accounts as auto-pick candidates,\n  intermittently failing assertions that only stubbed the Claude side.",
          "is_bot": false,
          "headline": "docs+test: codex multi-account docs; test isolation for auto-pick (T7)",
          "author_name": "drogers0",
          "author_login": "drogers0",
          "committed_at": "2026-05-30T15:11:23Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "2b3a18ef96ae3aa47a937419865839b479ba866f",
          "body": "Mirror the existing Claude account-rendering tests for Codex:\n\n- TestText_CodexAccountsSingle (no [Plan] suffix; Codex has no\n  rate_limit_tier).\n- TestText_CodexAccountsTwo (active-first ordering; covers the\n  slot-vs-duration-correct seven_day + code_review_seven_day labels\n  T3 introduced in text\n[…]\nnder-package code changes are needed: T3 already added the codex\nentry to textLabels, the (live Codex account) email, and the codex\nProviderResult.MarshalJSON path. T5 pins those contracts with tests.",
          "is_bot": false,
          "headline": "test(render): codex multi-account parity for text + json (T5)",
          "author_name": "drogers0",
          "author_login": "drogers0",
          "committed_at": "2026-05-30T05:25:36Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "2ff4e1692a85171274e1c3559f06db3a861ced15",
          "body": "aistat switch and aistat accounts grow a provider-scoped grammar:\n\n- aistat switch                  - fan out to every provider with stored\n                                   accounts; per-provider header + result\n- aistat switch <provider>       - target one provider; auto-pick best\n- aistat switch\n[…]\nts list now emits {\"claude\": [...], \"codex\": []} when no\n  Codex accounts are stored; clients parsing \"claude\" are unaffected.\n- aistat accounts remove <id> infers Claude when only Claude has matches.",
          "is_bot": false,
          "headline": "feat: provider-scoped switch/accounts with bulk-on-omission (T4)",
          "author_name": "drogers0",
          "author_login": "drogers0",
          "committed_at": "2026-05-30T05:23:19Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "d93826ea342b63474e56f4ef8104e6e9ba4d21d1",
          "body": "Codex now mirrors Claude's multi-account model end to end:\n\n- internal/providers/codex/reconcile.go: pure decision tree (byte-match\n  -> id_token sub lookup -> live-unstored fallback). LookupID extracts\n  sub/email from the id_token JWT directly (no network endpoint).\n- internal/providers/codex/code\n[…]\n-test parity: the codex fake now returns the\n  per-account shape so --fake exercises the same renderer path that\n  Codex multi-account uses.\n\nA3 / A5 / A6 from T2 remain UNVERIFIED until T6 live test.",
          "is_bot": false,
          "headline": "feat(codex): multi-account provider w/ slot-vs-duration fix (T3)",
          "author_name": "drogers0",
          "author_login": "drogers0",
          "committed_at": "2026-05-30T04:05:34Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "f656495ac05d0b6dbeeece3269fc2d5b8651bf5e",
          "body": "Add the credential primitives codex multi-account needs:\n\n- cred.ReadCodexCredential returns a full Credential (parsed\n  access/refresh/exp + Raw bytes) mirroring ReadClaudeCredential.\n- cred.WriteCodexLiveBlob writes ~/.codex/auth.json atomically with\n  0600 perms (cross-platform; codex has no keyc\n[…]\nt Fetch path. No behavior change for Claude.\n\nA3 (refresh response id_token presence), A5 (sub vs account_id parity),\nand A6 (id_token exp vs access_token expiry) are flagged for T6 live\nverification.",
          "is_bot": false,
          "headline": "feat(codex): credential layer for multi-account (T2)",
          "author_name": "drogers0",
          "author_login": "drogers0",
          "committed_at": "2026-05-30T02:15:13Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "6d6ed9094b286936dfc2f1152a0f35cb8bdfc731",
          "body": "…che, multiaccount)\n\nPromote per-account scaffolding out of internal/providers/claude and\ninternal/accounts into provider-neutral packages so codex multi-account\ncan be added in follow-ups without duplicating Claude's machinery.\n\n- accounts.Account becomes opaque (identity + metadata + RawBlob);\n  C\n[…]\n SortAccountResults,\n  RecordFetchOutcome, RecomputeResetAfter, and Budget out of claude.\n\nUser-facing CLI surface (flags, output, error/debug strings, file paths,\nJSON shape) is unchanged for Claude.",
          "is_bot": false,
          "headline": "refactor: extract multi-account substrate (accounts.Provider, usageca…",
          "author_name": "drogers0",
          "author_login": "drogers0",
          "committed_at": "2026-05-30T01:21:58Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "89213db449696a75f0eee985157175b08591a5fc",
          "body": "…in accounts remove (#13)\n\nWriteClaudeLiveBlob now calls tmp.Sync() before close, matching the\natomic-write pattern in store_linux.go and usagecache.go. Closes a small\ncrash-durability gap on the only path that mutates the live Claude credential.\n\nrunAccountsRemove now fails closed when resolveActiv\n[…]\nnknowable\" cases (no live blob, 401/403, missing fields) to (\"\", nil),\nso a non-nil error is genuinely actionable — proceeding risked deleting\nthe active account on a transient profile lookup failure.",
          "is_bot": false,
          "headline": "fixes: fsync live cred write on linux; fail closed on resolver error …",
          "author_name": "David Rogers",
          "author_login": "drogers0",
          "committed_at": "2026-05-29T23:08:12Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "5ca1bc71f3f9e8c6b3359d6ebb912e681f70ade5",
          "body": "* installer: surface success and PATH guidance more clearly\n\nWhen the script falls back from /usr/local/bin to ~/.local/bin, the\nold output left users uncertain whether the install had succeeded:\na quiet PATH note printed before the success line, and the note told\nthem to 'add it to your shell rc' w\n[…]\nfish  → ~/.config/fish/config.fish (fish_add_path $PREFIX)\n- other → ~/.profile\n\nREADME documents the new behavior and flags.\n\n* README: trim installer overexplain\n\n* README: drop shell-rc prompt note",
          "is_bot": false,
          "headline": "installer: clearer success output + opt-in PATH edit with consent (#12)",
          "author_name": "David Rogers",
          "author_login": "drogers0",
          "committed_at": "2026-05-29T22:29:20Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "35da414ad1c3b33372baa7809907a680b2645380",
          "body": "* README: polish header, add examples and one-line installer\n\n- Centered title + badges, restructured intro and TL;DR.\n- Three runnable examples (agent-selection.md, route.sh, auto-switch.sh).\n- install.sh: downloads latest release tarball, verifies sha256, installs to /usr/local/bin (or --prefix).\n\n* README: embed demo video\n\n* README: center demo video and constrain width\n\n* README: swap demo for 16:9 padded version so it fills the player\n\n* README: caption the demo with what it's showing",
          "is_bot": false,
          "headline": "README: polish header, add examples and one-line installer (#11)",
          "author_name": "David Rogers",
          "author_login": "drogers0",
          "committed_at": "2026-05-29T22:01:28Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "3bd99cc34f540a2394f558e4699dd8a81d3e2bbf",
          "body": "…(#10)\n\nThe /api/oauth/usage endpoint aggressively throttles non-claude-code/<version>\nclients (reverse-engineering note in Maciek-roboblog/Claude-Code-Usage-Monitor#202,\nmultiple persistent-429 reports in anthropics/claude-code). Sending the\naistat/<v> User-Agent dropped us in the punitive bucket; \n[…]\nted in the doc comment.\n- TestNew_PassesUserAgentToDoer guards the New -> Doer.UserAgent passthrough;\n  combined with httpx_test.go's wire-level tests, this proves DefaultUserAgent\n  reaches the wire.",
          "is_bot": false,
          "headline": "claude: send claude-code/<v> User-Agent, bump usage cache TTL to 90s …",
          "author_name": "David Rogers",
          "author_login": "drogers0",
          "committed_at": "2026-05-29T20:56:53Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "ba00f3335d0a1dc14a7de2118e75593bf9544181",
          "body": "v2.1.0: multi-account Claude reporting + aistat switch",
          "is_bot": false,
          "headline": "Merge pull request #6 from drogers0/v2.1.0-foundation",
          "author_name": "David Rogers",
          "author_login": "drogers0",
          "committed_at": "2026-05-28T21:02:52Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e5a5574aa5c65332ec20e122bd33aeeb43d0241e",
          "body": "The previous edit dragged design rationale into user docs — paragraphs\nabout which failure mode is worse, why we accepted staleness, etc.\nThat's commit-message and CLAUDE.md content, not README content.\nReplace with one line: switch shares the cache; --refresh first if\nyou need fresh data for the decision.",
          "is_bot": false,
          "headline": "README: trim caching section justification down to user-facing facts",
          "author_name": "drogers0",
          "author_login": "drogers0",
          "committed_at": "2026-05-28T20:55:54Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "542e5c120af9fa8a70ed71fc7821f55166535331",
          "body": "…ache\n\naistat switch previously bypassed the 30 s usage cache unconditionally:\nFetchUsage (the active-account read for D13's \"already on best\" check)\nand FetchForSwitch (the auto-pick candidate loop) both called\nfetchLimitsFresh, with the rationale (plan §D7) that decision-driving\npaths shouldn't ri\n[…]\nhe-bypass-on-empty-uuid path remains for\nunstored live-credential reads where the cache has no key to use.\nREADME + CLAUDE.md updated to describe the unified read path and\nthe new trade-off rationale.",
          "is_bot": false,
          "headline": "claude: unify the switch and reporting usage-read paths through the c…",
          "author_name": "drogers0",
          "author_login": "drogers0",
          "committed_at": "2026-05-28T20:53:47Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "bcc17df06d6f758973d0bc70125576664dc37081",
          "body": "WriteClaudeLiveBlob used to call `security set-generic-password-\npartition-list -S \"apple-tool:,apple:\"` after every `security\nadd-generic-password -U` write, to restore the partition list the\nv2.1.0 plan believed `-U` was narrowing. macOS prompts the user\nfor their keychain password on EVERY partit\n[…]\nrom\nits own ACL entry that survives the value update, and the \"if you\nobserve a prompt from Claude CLI, file an issue\" wording is kept\nas a safety valve in case some macOS version behaves differently.",
          "is_bot": false,
          "headline": "cred/darwin: drop the partition-list step from WriteClaudeLiveBlob",
          "author_name": "drogers0",
          "author_login": "drogers0",
          "committed_at": "2026-05-28T20:33:50Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "cda9d904b67dff8c8cffbd841378489505e6e36e",
          "body": "Three bundled improvements on top of the multi-account foundation:\n\n1. Bounded retry in httpx.Doer (max 3 attempts, Retry-After-aware\n   capped at 10s, exponential backoff ±20% jitter otherwise,\n   sleepWithCtx skips waits that would exceed the parent deadline).\n   The orchestrator's outer single-re\n[…]\nychain bug stays fixed.\n\nAll checks clean: go vet (default + -tags=fake + GOOS=linux),\nstaticcheck same matrix, go test ./..., go test -race ./...,\ngo test -tags=fake ./cmd/aistat/..., go build ./....",
          "is_bot": false,
          "headline": "backoff + usage cache + darwin keychain index fix",
          "author_name": "drogers0",
          "author_login": "drogers0",
          "committed_at": "2026-05-28T19:51:01Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "79c83c7bdff689d0d40141ba49ccf2739178e667",
          "body": "The previous commit's `json:\"limits,omitempty\"` tag silently hid\nboth the empty-map case (successful fetch, zero windows recognized\n— e.g. Anthropic returned all `resets_at: null`) and the nil-map\ncase (per-account fetch error). Users saw an account row with no\n`limits` and no `error` and reasonably\n[…]\ny (since per-account \"limits\" strings now always appear),\nand the renamed TestJSON_AccountResultErrorOnAccountRow pins the\nnew `\"limits\": null` + `\"error\"` contract instead of asserting\nlimits absent.",
          "is_bot": false,
          "headline": "claude: keep AccountResult.Limits in JSON even when nil/empty",
          "author_name": "drogers0",
          "author_login": "drogers0",
          "committed_at": "2026-05-28T16:45:46Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "1e80677f0add3c3a6b91288e62f8faa0b2d6a6d1",
          "body": "…JSON\n\nThe Claude JSON had two forms of duplication for callers to wade\nthrough:\n\n  - The top-level \"limits\" block was always the same bytes as\n    accounts[i].limits where active=true, because it was set as a\n    \"backward-compatibility projection\" for single-account JSON\n    consumers. v2.0.0 hasn\n[…]\nhe absence of the top-level \"limits\" key.\nREADME's output-contract section rewritten to describe the single\ncanonical view.\n\nNet JSON for a single-account Claude run drops from ~60 lines to\n~30 lines.",
          "is_bot": false,
          "headline": "claude: drop the top-level limits mirror and AccountResult.uuid from …",
          "author_name": "drogers0",
          "author_login": "drogers0",
          "committed_at": "2026-05-28T16:35:35Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "d0a3092527885826f80cbaae9225347bf5277563",
          "body": "Fetch ran the same 8-line success/transient/error classification at\ntwo sites (the live-unstored fallback row and the per-stored-account\nloop). clonehunter clustered them at score=0.952. Beyond the line\ncount, the duplication carried real risk: if a third call site is\never added and forgets to bump \n[…]\ns.Is(transient) check. Refresh-failure stays\ninline because its error formatting differs (refreshErrorMessage,\nnot err.Error()) and it short-circuits with continue.\n\nNo behavior change; -14 lines net.",
          "is_bot": false,
          "headline": "claude: extract recordFetchOutcome for the D8 classification",
          "author_name": "drogers0",
          "author_login": "drogers0",
          "committed_at": "2026-05-28T16:23:21Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "f02b67e9e5c2493deb9dd5523db145f4b50b6775",
          "body": "cmd/aistat/switch.go had its own copy of the usage-endpoint call +\nwindow-to-Limit conversion that internal/providers/claude/claude.go\nalready implements as the unexported fetchLimits. clonehunter scored\nthe two copies at 1.000 with 56 duplicated lines; the in-file comment\non switchUsageWindow even \n[…]\nlines removed\nfrom switch.go (the duplicate window type, the doer construction, and\nthe inline conversion loop); 7 lines added to claude.go for the\nexported wrapper + doc comment.\n\nNo behavior change.",
          "is_bot": false,
          "headline": "claude: route switch's active-usage fetch through Client.FetchUsage",
          "author_name": "drogers0",
          "author_login": "drogers0",
          "committed_at": "2026-05-28T15:19:13Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "540000ffe8e24fe38aba14f9c040b5cc8a4220e6",
          "body": "The old guidance described the pre-v2.1.0 single-account, single-\nendpoint world. Update it to cover the multi-account Claude flow,\naistat switch's order-of-operations and its no-refresh\nFetchForSwitch contract, the new internal/accounts and\ninternal/providers/claude/{profile,refresh,reconcile}.go p\n[…]\n cmd/aistat subcommand layout, and the AISTAT_LIVE /\nAISTAT_LIVE_KEYCHAIN test gates. Also note the CI cross-platform\nsweep so future Linux-only failures get caught locally via\nGOOS=linux before push.",
          "is_bot": false,
          "headline": "CLAUDE.md: refresh for v2.1.0",
          "author_name": "drogers0",
          "author_login": "drogers0",
          "committed_at": "2026-05-28T15:08:15Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "a979896752d2a36e54fd70b2634323c0a818dfb6",
          "body": "Five sites under cmd/aistat repeated the same --help/--version\nshort-circuit (main dispatch + the post-Parse pass in each of usage,\nswitch, accounts list, accounts remove). clonehunter clustered four\nof them at score=1.0; the fifth fell out on inspection. Extract a\ntiny handleGlobals helper next to registerGlobalFlags so the\ncontract is in one place and the next subcommand can't drift.\n\nNo behavior change.",
          "is_bot": false,
          "headline": "cmd/aistat: extract handleGlobals helper",
          "author_name": "drogers0",
          "author_login": "drogers0",
          "committed_at": "2026-05-28T15:08:15Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "429b1b42917edbcfa814221cbd4b564b81608c10",
          "body": "The Linux store flocked the open fd of the data file itself, but\natomicWrite replaces that file via temp + rename. After the rename,\nthe open fd (and its lock) still references the now-orphaned old\ninode, so a second goroutine's Flock on the freshly-opened new\ninode never serialized against it. The \n[…]\n\nwithLock helper taking LOCK_SH or LOCK_EX. readAccountMap now reads\nthe data file directly (treating ENOENT as an empty map) so the\nhelper no longer needs to hand the data-file handle to its callers.",
          "is_bot": false,
          "headline": "accounts: lock on a sentinel file on Linux, not the data file",
          "author_name": "drogers0",
          "author_login": "drogers0",
          "committed_at": "2026-05-28T15:02:20Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "b75faa16b7952ce5312c8a12c4907d81f6731674",
          "body": "safeWriter is only used by the darwin store; defining it in the\nplatform-agnostic store.go made it unreachable on Linux, where\nstaticcheck flags it as U1000 unused. Move the type and its sync\nimport into store_darwin.go so non-darwin builds compile cleanly.\n\nNo behavior change; macOS still wraps the WithDebug writer in the\nmutex-guarded adapter as before.",
          "is_bot": false,
          "headline": "accounts: move safeWriter into store_darwin.go",
          "author_name": "drogers0",
          "author_login": "drogers0",
          "committed_at": "2026-05-28T14:59:09Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "9038dd1749f602a1c2171f767b0012d473092226",
          "body": "Restructures the CLI from positional `aistat claude` to subcommand\ndispatch (`aistat usage`, `aistat switch`, `aistat accounts`) and\nadds:\n\n- Multi-account Claude reporting. Every Claude account the user\n  signs into is auto-captured at run-time keyed by `account.uuid`\n  via Anthropic's `/api/oauth/\n[…]\nerves account\nrows when a provider returns a partial-failure error.\n\nModule path stays `github.com/drogers0/aistat/v2`; install\ncommand is `go install github.com/drogers0/aistat/v2/cmd/aistat@latest`.",
          "is_bot": false,
          "headline": "v2.1.0: multi-account Claude reporting + aistat switch",
          "author_name": "drogers0",
          "author_login": "drogers0",
          "committed_at": "2026-05-28T14:09:35Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "90c16072f21a9de2336c1b3506d9eb1e399a58cd",
          "body": "Required by Go's semantic import versioning rule: once a module is tagged\nv2+, the module path must include the major-version suffix. Updates the\ngo.mod declaration, every internal import path, and the README's\n`go install` command.\n\nInternal-only change; no runtime behavior is affected. After this lands\nand is re-tagged, `go install github.com/drogers0/aistat/v2/cmd/aistat@latest`\nwill work.",
          "is_bot": false,
          "headline": "go.mod: migrate module path to github.com/drogers0/aistat/v2",
          "author_name": "drogers0",
          "author_login": "drogers0",
          "committed_at": "2026-05-28T00:41:43Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "df14f18f56dcc2415b4f408a9bd475e22b4ecca4",
          "body": "v2.0.0: aistat (Go binary rewrite, hardened across 10 rounds)",
          "is_bot": false,
          "headline": "Merge pull request #5 from drogers0/v2-rewrite",
          "author_name": "David Rogers",
          "author_login": "drogers0",
          "committed_at": "2026-05-28T00:32:05Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e5708beb19783677156d9047381748623600b299",
          "body": "setup-go was interpreting `'1.22'` as \">= 1.22\" and pulling Go 1.26.3 on\nthe runners. The cached staticcheck 2024.1.1 binary fails to compile its\nown transitive deps under Go 1.26 (`invalid array length -delta * delta`\nin golang.org/x/tools/internal/tokeninternal). Pin to the 1.22.x line and\nbump staticcheck to a version that targets newer Go just in case.",
          "is_bot": false,
          "headline": "ci: pin go-version to 1.22.x and bump staticcheck to 2025.1.1",
          "author_name": "drogers0",
          "author_login": "drogers0",
          "committed_at": "2026-05-28T00:29:41Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "45dcf83764a20ddf8d5fb0ee2fd14c187b4e7134",
          "body": "The early return at the top of Text() was dead: the loop body would\nproduce zero sections in that case, and the existing len(sections) == 0\ncheck at the end of the function already returns nil cleanly.",
          "is_bot": false,
          "headline": "render/text: drop redundant empty-requested guard",
          "author_name": "drogers0",
          "author_login": "drogers0",
          "committed_at": "2026-05-28T00:23:07Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "2e274301b9132c37c7196fb1f752e0f60e2e7eb6",
          "body": "…dings\n\nAfter round 9 the surface was tight; this round addresses five small residual\nitems that round 9's review missed.\n\nChanges:\n- providers.Title is now defined once (internal/providers/types.go); the\n  duplicate copies in cmd/aistat/main.go and internal/render/text.go are\n  deleted.\n- buildProv\n[…]\nanch panics instead of returning\n  an error — programmer-error class, consistent with httpx.NewDoer's\n  nil-client panic. newFakeProvider is only called with the three known IDs.\n\nNet diff: -31 lines.",
          "is_bot": false,
          "headline": "Code-review hardening (round 10, simplicity-first): five residual fin…",
          "author_name": "drogers0",
          "author_login": "drogers0",
          "committed_at": "2026-05-28T00:18:07Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "9118a7393221a730851e82ffee47148257ddc6da",
          "body": "Drops defensive tripwires for problems that never occurred, deletes bespoke\nimplementations of stdlib behavior, removes per-provider test duplication,\nand corrects a small number of latent bugs. Net diff: -513 lines.\n\nDeletions (largest surface):\n- Codex LimitWindowSeconds tripwires (hard-failed who\n[…]\nobal wall-clock budget), #16 (Linux cred file perms).\nFindings skipped under simplicity lens: #15 (gh subprocess bound — defense\nagainst unrealistic threat), #28 (buildHelpText restructure — non-bug).",
          "is_bot": false,
          "headline": "Code-review hardening (round 9, simplicity-first): 33 REVIEW.md findings",
          "author_name": "drogers0",
          "author_login": "drogers0",
          "committed_at": "2026-05-28T00:06:55Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "8a504ce3f87b420b656967084d7e8bb244123a6a",
          "body": "Code-review hardening — 16 findings, 12 plan steps:\n\n- httpx.GetJSON gains a timeout parameter and derives the per-call child\n  ctx internally, letting it distinguish parent-cancel (bare ctx error)\n  from child-only-deadline (wrapped as ErrTransient so the orchestrator's\n  one retry runs against a f\n[…]\nixture UA literals and prose comments updated.\n\nGitHub-side repo rename (drogers0/llm-usage -> drogers0/aistat) is\nleft for the maintainer; GitHub auto-redirects old URLs and preserves\nthe v1.0.0 tag.",
          "is_bot": false,
          "headline": "Code-review hardening (round 8) + rename to aistat",
          "author_name": "drogers0",
          "author_login": "drogers0",
          "committed_at": "2026-05-27T22:23:32Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "1ab989ab23b2faaea69a6ab339443049d826afb1",
          "body": "…t findings\n\n- cred/github: preserve ctx.Err() before wrapping; fixes Ctrl-C / deadline\n  being reported as \"github token unavailable\"; rewrite test that locked\n  in misclassification; add deadline-kill regression test\n- cmd/usage-check: reject single-dash long-form flags (-debug, -help, etc.)\n  via\n[…]\n string in TestFetch_RequestShape\n  via WithNow-injected clock\n- cred/codex: add direct unit coverage (happy/missing/malformed/empty);\n  previously only exercised via provider tests stubbing readToken",
          "is_bot": false,
          "headline": "Code-review hardening (round 7): ctx-cancel fix + flag grammar + eigh…",
          "author_name": "drogers0",
          "author_login": "drogers0",
          "committed_at": "2026-05-27T21:13:48Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "970eb63a013ca8387b1cda2987e3a163e4896a9d",
          "body": "Splits exit 1 (runtime failures) from exit 2 (usage/contract errors),\nenforces UTC at the JSON boundary, hoists codex's ResetAt>0 guard into\ntoLimit so primary/secondary/code-review are skipped uniformly, swaps\ncopilot's 404 substring match for JSON shape detection, adds clock\ninjection (WithNow) to\n[…]\nthe\ncopilot package so the SetURLsForTest / SetReadTokenForTest leaks\ndisappear from the public API. README documents the new exit-code\ncontract; --fake-fail=<csv> drives the runtime-failure CLI test.",
          "is_bot": false,
          "headline": "Code-review hardening (round 6): exit-code split + ten findings",
          "author_name": "drogers0",
          "author_login": "drogers0",
          "committed_at": "2026-05-27T20:05:20Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "8136765baeb4ab52a4a5d7de23682c7eb8b73c21",
          "body": "- copilot: truncate now to seconds (matches claude/codex), removing the\n  up-to-1s low bias in reset_after_seconds; add WithNow option mirroring\n  WithWarn for deterministic test clock injection.\n- copilot: install classifyCopilot only on the billing call; switch /user\n  to httpx.DefaultClassify so \n[…]\nremoved from KnownWindows are caught.\n- httpx: inline the maxBodyBytes rationale (drop the REVIEW_RESOLUTION_PLAN.md\n  citation); use http.StatusOK instead of the literal 200 at the happy-path\n  gate.",
          "is_bot": false,
          "headline": "Code-review hardening (round 5): copilot truncation + classifier split",
          "author_name": "drogers0",
          "author_login": "drogers0",
          "committed_at": "2026-05-27T18:34:32Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "8c5d1bc8a8e016b9b726956dd61c60aab90a2bf0",
          "body": "Replace the hardcoded GitHub URL in userAgent() with a reference to a\nnew providers.ProjectURL constant. IssueTrackerURL now derives from it\nvia constant concatenation.\n\nSingle source of truth if the repo is renamed or forked.",
          "is_bot": false,
          "headline": "providers: extract ProjectURL constant",
          "author_name": "drogers0",
          "author_login": "drogers0",
          "committed_at": "2026-05-27T17:43:35Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "6cf1528a817102197bd116cedd47fb8fdbfb3b00",
          "body": "If every requested provider misses the report, sections stays nil and\nstrings.Join(nil, \"\\n\\n\")+\"\\n\" writes a stray newline. Return early\nwith no output when there's nothing to render.\n\nCurrently unreachable in production (orchestrate.Run populates every\nrequested known provider) but the exported contract should match.",
          "is_bot": false,
          "headline": "render: short-circuit Text on empty section list",
          "author_name": "drogers0",
          "author_login": "drogers0",
          "committed_at": "2026-05-27T17:42:22Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b95beed7dbe860afd8d7c7e4ca7ea9ffdcf6f2fb",
          "body": "Type realProviders and buildProviders's safeStderr parameter as\n*httpx.ConcurrencySafeWriter instead of io.Writer. The contract\n(caller must wrap stderr in a mutex) is now compiler-enforced.\n\ncoverage_test.go wraps io.Discard accordingly.",
          "is_bot": false,
          "headline": "cmd/usage-check: tighten safeStderr parameter type",
          "author_name": "drogers0",
          "author_login": "drogers0",
          "committed_at": "2026-05-27T17:41:58Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c64e213347c272cf22303f6550c1cc60bd3f4f83",
          "body": "Drop Client.Timeout from Claude and Codex; wrap each Fetch with\ncontext.WithTimeout so all three providers share one cancellation\nmechanism. Equivalent behavior for the single-call providers.\n\nAdd TestFetch_EmittedKeysMatchKnownWindows in codex_test.go to bind the\nexported KnownWindows slice to Fetch's emitted set — catches the drift\ndirection where a new window is added to Fetch without updating\nKnownWindows.",
          "is_bot": false,
          "headline": "providers: unify on ctx-based timeouts; codex KnownWindows tripwire",
          "author_name": "drogers0",
          "author_login": "drogers0",
          "committed_at": "2026-05-27T17:41:05Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "5b6b3ccfa4daa29a10a7dc30f1e43de1f20e9b85",
          "body": "Doer.GetJSON now silently drops any ExtraHeaders entry whose\ncanonicalized key matches Authorization or User-Agent, so a\nmisconfigured provider cannot accidentally clobber the bearer token or\nuser-agent. Uses http.CanonicalHeaderKey so lowercase variants are also\ncaught.\n\nNo provider sets either key in ExtraHeaders today; this is defensive.",
          "is_bot": false,
          "headline": "httpx: reserve Authorization and User-Agent from ExtraHeaders",
          "author_name": "drogers0",
          "author_login": "drogers0",
          "committed_at": "2026-05-27T17:40:12Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "dcb72217e6d0dc80629a00cc15bfa55af25c847d",
          "body": "usage-check is a read-only observer of ~/.claude/.credentials.json;\nfile permissions are the Claude Code CLI's responsibility. Drops the\npermission warning that bypassed the ConcurrencySafeWriter pipeline.\n\nWindows/BSD ReadClaudeToken now wraps ErrClaudeTokenNotFound so the\norchestrator classifies it as auth-missing — default usage-check no\nlonger exits 2 when Codex and Copilot succeed on those platforms.\n\nAdds a build-tagged test pinning the wrap on unsupported platforms.",
          "is_bot": false,
          "headline": "cred: drop linux perm check; wrap unsupported-platform error",
          "author_name": "drogers0",
          "author_login": "drogers0",
          "committed_at": "2026-05-27T17:39:33Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f7281e9101b371a05a96aac7205379182e9f4c4a",
          "body": "Update the requirements line to reflect that all three providers now\nwork on macOS and Linux. The Claude provider's storage location is\ndocumented per platform.\n\nNew \"Diagnostics on stderr\" section enumerates the always-on warnings\na user may see without --debug:\n- Copilot SKU-mismatch tripwire\n- Li\n[…]\nare\nnot disrupted but operators are informed.\n\nAuthentication section updated to mention the unknown-plan-slug\nfail-closed behavior introduced in the prior commit.\n\nResolves finding #3 from REVIEW.md.",
          "is_bot": false,
          "headline": "docs: stderr diagnostics + Linux Claude support",
          "author_name": "drogers0",
          "author_login": "drogers0",
          "committed_at": "2026-05-27T16:53:26Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "9659f5ecef9dfd99e410fc05158bbaac545a1fd1",
          "body": "Two new tripwires for behaviors that previously had no regression net:\n\n1. warn_wiring_test.go in cmd/usage-check verifies that the warn\n   callback installed by realProviders correctly prefixes lines with\n   \"usage-check: \" by the time they reach stderr. Uses two new\n   test-only setters on *copilo\n[…]\ning a new window to a provider but\n   forgetting the corresponding label entry gets a test failure\n   instead of a silently missing line in human output.\n\nResolves findings #11 and #13 from REVIEW.md.",
          "is_bot": false,
          "headline": "tests: warn-wiring + textLabels drift tripwires",
          "author_name": "drogers0",
          "author_login": "drogers0",
          "committed_at": "2026-05-27T16:53:19Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "67cec56fa31ae2341097d0efff63444bdbc43162",
          "body": "Drop defaultQuota and the silent fallback. An unknown plan slug now\nreturns an error naming the slug and pointing at the issue tracker\nrather than emitting a confidently-wrong used_percent (was: Enterprise\nusers at 200/1000 requests reading as 66.7% instead of 20%).\n\nThe error is a plain fmt.Errorf \n[…]\ned to planQuota. The error message tells the user exactly what\nto file; scoping to `usage-check claude codex` still works for partial\ndata while the issue is open.\n\nResolves finding #4 from REVIEW.md.",
          "is_bot": false,
          "headline": "copilot: fail closed on unknown plan slug",
          "author_name": "drogers0",
          "author_login": "drogers0",
          "committed_at": "2026-05-27T16:52:36Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "24a74ac62bcf95a8360b2d992fc3a4bed11d6f64",
          "body": "… MiB\n\nNew providers.IssueTrackerURL constant replaces three inlined GitHub\nissues URLs across codex.go and copilot.go. Fork-friendly and DRY.\n\nhttpx now wraps resp.Body with io.LimitReader at 1 MiB + 1 byte and\nfails closed on the success path if the actual body exceeds the cap.\nNon-200 oversized r\n[…]\npath.\n\nDrops the date-stamped \"verified\" line from the planQuota source comment\n— a maintenance lie waiting to happen with no automated check behind it.\n\nResolves findings #5, #12, #14 from REVIEW.md.",
          "is_bot": false,
          "headline": "providers, httpx: shared issue URL constant; limit response body to 1…",
          "author_name": "drogers0",
          "author_login": "drogers0",
          "committed_at": "2026-05-27T16:51:58Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "581212648c098d1a82d3a06d8ccf776bc8661095",
          "body": "realProviders changes from (debug, stderr io.Writer) ([]Provider, io.Writer)\nto (safeStderr io.Writer, includeDebug bool) []Provider. main now owns the\nsingle *httpx.ConcurrencySafeWriter construction and threads it where\nneeded; the writer no longer round-trips through realProviders.\n\nA new buildPr\n[…]\nng tests.\n\ndebug local flag renamed to debugFlag to unshadow the runtime/debug\npackage import. safeDebug renamed to debugSink for clearer intent.\n\nResolves findings #6, #7, #8, #9, #10 from REVIEW.md.",
          "is_bot": false,
          "headline": "cmd/usage-check: extract buildProviders; tighten realProviders signature",
          "author_name": "drogers0",
          "author_login": "drogers0",
          "committed_at": "2026-05-27T16:50:27Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "9d5cbf7b093fbeac7ded54da9203f9072173ec3b",
          "body": "On Linux, ReadClaudeToken reads ~/.claude/.credentials.json (the file\n`claude /login` writes), which uses the same JSON shape as the macOS\nKeychain item. A new shared internal/cred/claude.go holds the constant,\nsentinel, and unexported parseClaudeCred helper used by both platform\nreaders, eliminatin\n[…]\ngo and its build\ntag narrows to !darwin && !linux, leaving an explanatory error for\nWindows/BSD.\n\nResolves findings #1 (duplicated constants) and #2 (cross-platform\nexit-code surprise) from REVIEW.md.",
          "is_bot": false,
          "headline": "cred: support Claude on Linux; share parser between platforms",
          "author_name": "drogers0",
          "author_login": "drogers0",
          "committed_at": "2026-05-27T16:50:19Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "ab8e666bc78a786324076c599ee4296d46bc8bb5",
          "body": "…eal UA, dedupe\n\n- Copilot tripwires (unknown-plan and SKU-mismatch) now print to stderr on\n  every invocation, not only with --debug. SKU-mismatch trigger tightened from\n  `gross == 0` to `!sawPremiumSku` to avoid false-positives for users with\n  legitimate zero premium-request usage.\n- `--fake` an\n[…]\naticcheck and go test in both build configurations.\n- Shared ConcurrencySafeWriter wraps stderr so Doer debug, orchestrator\n  debug, and the new always-on warn channel all serialize through one mutex.",
          "is_bot": false,
          "headline": "Code-review hardening (round 2): always-on warns, --fake build tag, r…",
          "author_name": "drogers0",
          "author_login": "drogers0",
          "committed_at": "2026-05-27T05:51:33Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "277efc427a7255c54bdb3ee17ed215f42e8de0be",
          "body": "- Add internal/httpx package: shared HTTP pipeline (Doer, Classifier,\n  DefaultClassify, Snip, ConcurrencySafeWriter) absorbing per-provider\n  request setup, status classification, body read, debug logging, and\n  JSON unmarshal. Each provider's Client now holds *httpx.Doer.\n- Strict CLI grammar: pro\n[…]\n.1, go test -race).\n- .github/workflows/release.yml: goreleaser on v* tag push.\n- .goreleaser.yaml: linux/darwin × amd64/arm64 tar.gz with SHA256\n  checksums; release block targets drogers0/llm-usage.",
          "is_bot": false,
          "headline": "Code-review hardening: shared httpx, strict CLI grammar, CI/release",
          "author_name": "drogers0",
          "author_login": "drogers0",
          "committed_at": "2026-05-27T00:00:55Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "abd4e4dbdeb764ae3127a1b5977d676e2dc367e7",
          "body": "Replaces the v1.0.0 TypeScript + Chrome extension + native-messaging-host\narchitecture with a Go binary that reads each provider's existing\ncredential and hits its usage endpoint directly.\n\nSurface changes\n- JSON is now the default; -h/--human opts into text rendering\n- --json flag removed (use bare\n[…]\n (needs user scope)\n           -> api.github.com/users/{login}/settings/billing/premium_request/usage\n\nThe v1 sources are preserved at the v1.0.0 tag and the\nlegacy/typescript-chrome-extension branch.",
          "is_bot": false,
          "headline": "v2.0.0: rewrite as a single static Go binary",
          "author_name": "drogers0",
          "author_login": "drogers0",
          "committed_at": "2026-05-26T22:21:40Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "7ab3d6f8b7306aeabb99d36c939a1e6cc45ed094",
          "body": null,
          "is_bot": false,
          "headline": "Release v0.0.3",
          "author_name": "drogers0",
          "author_login": "drogers0",
          "committed_at": "2026-04-30T17:30:19Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "086e2c890fdacb29c9a89f01e30c044e80d12b7e",
          "body": "Fix usage-check crash on macOS Bash 3.2 when no renderer args",
          "is_bot": false,
          "headline": "Merge pull request #4 from drogers0/fix/bash32-empty-array-unbound",
          "author_name": "David Rogers",
          "author_login": "drogers0",
          "committed_at": "2026-03-30T16:16:49Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f99aa2cdcadbb27b2b3bfb916b2e3475ca42af3a",
          "body": null,
          "is_bot": false,
          "headline": "fix: handle empty renderer args in usage-check on bash 3.2",
          "author_name": "drogers0",
          "author_login": "drogers0",
          "committed_at": "2026-03-30T16:09:32Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "45bc49784d0bd609125a520a409e5d14db21c229",
          "body": null,
          "is_bot": false,
          "headline": "Update README install URL to v0.0.2",
          "author_name": "drogers0",
          "author_login": null,
          "committed_at": "2026-03-26T22:38:02Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "6ac3a7718ffca78373937cb950ecd708b88e8378",
          "body": "Show (X% remaining for Yd Zh) next to each usage line in non-JSON mode.",
          "is_bot": false,
          "headline": "Add remaining % and reset duration to text output",
          "author_name": "drogers0",
          "author_login": null,
          "committed_at": "2026-03-26T22:37:18Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "14c173c972616a0c678f89216d246afe91ff1dbe",
          "body": "- Add bin field for usage-check and usage-check-setup commands\n- Commit dist/ so npm install from git works without a build step\n- Resolve symlinks in bin scripts so paths work when globally installed\n- Replace all jq calls with node -e equivalents\n- Make install.sh interactive when called without arguments\n- Simplify README to two-command setup flow\n- Remove manual PATH editing (npm handles it)",
          "is_bot": false,
          "headline": "Package as installable npm CLI and remove jq dependency",
          "author_name": "DAVID ROGERS",
          "author_login": "drogers0",
          "committed_at": "2026-03-20T19:47:02Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "247e339d0468071406b1a3669956ccc4d443a220",
          "body": "- Introduce ESM + esbuild + vitest toolchain\\n- Split extension provider logic into typed modules with abstract base class\\n- Split CLI provider normalization/rendering into typed modules\\n- Adopt unified provider output model and remove duplicate provider field\\n- Keep bash-first orchestration with structured debug diagnostics\\n- Add shared typed errors/time utilities and fixture-based unit tests\\n- Update docs and gitignore for Node/dist artifacts",
          "is_bot": false,
          "headline": "Refactor to TypeScript provider architecture",
          "author_name": "DAVID ROGERS",
          "author_login": "drogers0",
          "committed_at": "2026-03-20T18:30:46Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "8a0f80939310c78550a1e2d6d0d900d1393fabf4",
          "body": "- Add copilot service support to CLI, extension, and cache flow\\n- Fetch Copilot usage from authenticated GitHub settings page\\n- Normalize Copilot output to month window with resets_at/reset_after_seconds\\n- Extend debug and timeout diagnostics for copilot cache updates\\n- Update manifest permissions and README examples",
          "is_bot": false,
          "headline": "Add Copilot usage reporting with uniform month window",
          "author_name": "DAVID ROGERS",
          "author_login": "drogers0",
          "committed_at": "2026-03-20T17:26:29Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "3e0dd712abff023d0f84747870a94c7fe7158c17",
          "body": "- Register native host via stable launcher script with absolute python path\\n- Add extension fetch status reporting for success/failure details\\n- Surface actionable errors in shell instead of generic timeout\\n- Add --debug mode to usage-check for cache/status/host-log diagnostics\\n- Reduce noisy native-host BrokenPipe traces and document debug usage",
          "is_bot": false,
          "headline": "Improve usage-check reliability and add actionable debug diagnostics",
          "author_name": "DAVID ROGERS",
          "author_login": "drogers0",
          "committed_at": "2026-03-20T17:00:54Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b0f36d41a14deae6c371894d6d63122a200f3005",
          "body": "CLI tool for checking Claude and Codex API usage limits via a Chrome\nextension that fetches data from authenticated browser sessions.",
          "is_bot": false,
          "headline": "Initial commit",
          "author_name": "DAVID ROGERS",
          "author_login": "drogers0",
          "committed_at": "2026-03-18T01:24:17Z",
          "body_truncated": false,
          "is_coding_agent": false
        }
      ],
      "releases_count": 16,
      "commits_last_year": 80,
      "latest_release_at": "2026-07-16T21:42:21Z",
      "latest_release_tag": "v2.4.0",
      "releases_from_tags": false,
      "days_since_last_push": 10,
      "active_weeks_last_year": 11,
      "days_since_latest_release": 10,
      "mean_days_between_releases": 5.3
    },
    "community": {
      "has_readme": true,
      "has_license": true,
      "has_description": true,
      "has_contributing": false,
      "health_percentage": 42,
      "has_issue_template": false,
      "has_code_of_conduct": false,
      "has_pull_request_template": false
    },
    "ecosystem": {
      "packages": [
        {
          "name": "github.com/drogers0/aistat/v2",
          "exists": true,
          "license": null,
          "keywords": [],
          "ecosystem": "go",
          "matches_repo": true,
          "registry_url": "https://pkg.go.dev/github.com/drogers0/aistat/v2",
          "is_deprecated": false,
          "latest_version": "v2.4.0",
          "repository_url": "https://github.com/drogers0/aistat",
          "versions_count": 12,
          "total_downloads": null,
          "dependents_count": null,
          "deprecation_note": null,
          "maintainers_count": null,
          "monthly_downloads": null,
          "first_published_at": null,
          "latest_published_at": "2026-07-16T00:16:02Z",
          "latest_version_yanked": null,
          "days_since_latest_publish": 10
        }
      ]
    },
    "popularity": {
      "forks": 2,
      "stars": 8,
      "watchers": 1,
      "fork_history": {
        "days": [
          {
            "date": "2026-06-17",
            "count": 1
          },
          {
            "date": "2026-07-13",
            "count": 1
          }
        ],
        "complete": true,
        "collected": 2,
        "total_forks": 2
      },
      "star_history": null,
      "open_issues_and_prs": 5
    },
    "ai_readiness": {
      "has_nix": false,
      "example_dirs": [
        "examples"
      ],
      "has_llms_txt": false,
      "has_dockerfile": false,
      "has_mcp_signal": false,
      "bootstrap_files": [],
      "api_schema_files": [],
      "has_devcontainer": false,
      "typecheck_configs": [],
      "toolchain_manifests": [
        "go.mod"
      ],
      "largest_source_bytes": 71156,
      "source_files_sampled": 107,
      "oversized_source_files": 2,
      "agent_instruction_files": [
        "AGENTS.md",
        "CLAUDE.md"
      ],
      "agent_instruction_max_bytes": 18300
    },
    "dependencies": {
      "manifests": [
        "go.mod"
      ],
      "advisories": {
        "error": null,
        "scope": null,
        "source": null,
        "findings": [],
        "collected": false,
        "malicious": [],
        "truncated": false,
        "by_severity": {},
        "advisory_count": 0,
        "affected_count": 0,
        "assessed_count": 0,
        "malicious_count": 0,
        "assessed_package": null,
        "unassessed_count": 0,
        "direct_affected_count": 0
      },
      "ecosystems": [
        "go"
      ],
      "dependencies": [],
      "all_dependencies": {
        "error": "GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository",
        "source": null,
        "packages": [],
        "collected": false,
        "truncated": false,
        "total_count": null,
        "direct_count": null,
        "indirect_count": null
      }
    },
    "maintainership": {
      "issues": {
        "open_prs": 0,
        "merged_prs": 19,
        "open_issues": 5,
        "closed_ratio": 0.615,
        "closed_issues": 8,
        "closed_unmerged_prs": 2
      },
      "bus_factor": 1,
      "bot_contributors": 0,
      "top_contributors": [
        {
          "type": "User",
          "login": "drogers0",
          "commits": 74,
          "avatar_url": "https://avatars.githubusercontent.com/u/120214987?v=4"
        },
        {
          "type": "User",
          "login": "casiusss",
          "commits": 4,
          "avatar_url": "https://avatars.githubusercontent.com/u/4124015?v=4"
        }
      ],
      "contributors_sampled": 2,
      "top_contributor_share": 0.949
    },
    "quality_signals": {
      "has_ci": true,
      "has_tests": true,
      "ci_workflows": [
        "ci.yml",
        "lint.yml",
        "release.yml"
      ],
      "has_docs_dir": false,
      "linter_configs": [
        ".golangci.yml"
      ],
      "has_editorconfig": false,
      "has_linter_config": true,
      "has_precommit_config": false
    },
    "security_signals": {
      "lockfiles": [],
      "scorecard": {
        "checks": [
          {
            "name": "Binary-Artifacts",
            "score": 10,
            "reason": "no binaries found in the repo",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#binary-artifacts"
          },
          {
            "name": "Branch-Protection",
            "score": 8,
            "reason": "branch protection is not maximal on development and all release branches",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#branch-protection"
          },
          {
            "name": "CI-Tests",
            "score": 9,
            "reason": "14 out of 15 merged PRs checked by a CI test -- score normalized to 9",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#ci-tests"
          },
          {
            "name": "CII-Best-Practices",
            "score": 0,
            "reason": "no effort to earn an OpenSSF best practices badge detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#cii-best-practices"
          },
          {
            "name": "Code-Review",
            "score": 2,
            "reason": "Found 4/15 approved changesets -- score normalized to 2",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#code-review"
          },
          {
            "name": "Contributors",
            "score": 0,
            "reason": "project has 0 contributing companies or organizations -- score normalized to 0",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#contributors"
          },
          {
            "name": "Dangerous-Workflow",
            "score": 10,
            "reason": "no dangerous workflow patterns detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dangerous-workflow"
          },
          {
            "name": "Dependency-Update-Tool",
            "score": 0,
            "reason": "no update tool detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dependency-update-tool"
          },
          {
            "name": "Fuzzing",
            "score": 0,
            "reason": "project is not fuzzed",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#fuzzing"
          },
          {
            "name": "License",
            "score": 10,
            "reason": "license file detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#license"
          },
          {
            "name": "Maintained",
            "score": 10,
            "reason": "30 commit(s) and 13 issue activity found in the last 90 days -- score normalized to 10",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#maintained"
          },
          {
            "name": "Packaging",
            "score": 10,
            "reason": "packaging workflow detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#packaging"
          },
          {
            "name": "Pinned-Dependencies",
            "score": 0,
            "reason": "dependency not pinned by hash detected -- score normalized to 0",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#pinned-dependencies"
          },
          {
            "name": "SAST",
            "score": 0,
            "reason": "SAST tool is not run on all commits -- score normalized to 0",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#sast"
          },
          {
            "name": "Security-Policy",
            "score": 0,
            "reason": "security policy file not detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#security-policy"
          },
          {
            "name": "Signed-Releases",
            "score": 0,
            "reason": "Project has not signed or included provenance with any releases.",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#signed-releases"
          },
          {
            "name": "Token-Permissions",
            "score": 0,
            "reason": "detected GitHub workflow tokens with excessive permissions",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#token-permissions"
          },
          {
            "name": "Vulnerabilities",
            "score": 10,
            "reason": "0 existing vulnerabilities detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#vulnerabilities"
          }
        ],
        "commit": "bebce19724a665269594cc94f1d11b91ba8c5eb8",
        "ran_at": "2026-07-26T22:34:39Z",
        "aggregate_score": 4.7,
        "scorecard_version": "v5.5.0"
      },
      "has_codeql_workflow": false,
      "has_security_policy": false,
      "has_dependabot_config": false
    },
    "contribution_flow": {
      "collected": true,
      "ci_last_run_at": "2026-07-16T21:42:25Z",
      "oldest_open_prs": [],
      "last_merged_pr_at": "2026-07-16T00:16:03Z",
      "ci_last_conclusion": "SUCCESS",
      "oldest_open_issues": [
        {
          "number": 7,
          "created_at": "2026-05-28T21:31:51Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 8,
          "created_at": "2026-05-29T16:41:25Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 9,
          "created_at": "2026-05-29T16:41:47Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 25,
          "created_at": "2026-07-06T18:23:29Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 30,
          "created_at": "2026-07-08T20:48:21Z",
          "last_comment_at": null,
          "last_comment_author": null
        }
      ]
    }
  },
  "config": {
    "disabled_metrics": [],
    "disabled_categories": [],
    "disabled_components": {}
  },
  "source": {
    "url": "https://github.com/drogers0/aistat",
    "host": "github.com",
    "name": "aistat",
    "owner": "drogers0"
  },
  "metrics": {
    "overall": {
      "key": "overall",
      "band": "moderate",
      "name": "Overall health",
      "note": null,
      "notes": [],
      "value": 55,
      "inputs": {
        "security": 47,
        "vitality": 74,
        "community": 31,
        "governance": 50,
        "engineering": 69
      },
      "components": []
    },
    "categories": [
      {
        "key": "vitality",
        "band": "good",
        "name": "Vitality",
        "value": 74,
        "weight": 0.22,
        "metrics": [
          {
            "key": "development_activity",
            "band": "moderate",
            "name": "Development activity",
            "note": null,
            "notes": [],
            "value": 64,
            "inputs": {
              "commits_last_year": 80,
              "human_commit_share": 1,
              "days_since_last_push": 10,
              "active_weeks_last_year": 11
            },
            "components": [
              {
                "key": "push_recency",
                "name": "Push recency",
                "detail": "last push 10 days ago",
                "points": 28.8,
                "status": "partial",
                "details": [
                  {
                    "code": "push_recency",
                    "params": {
                      "days": 10
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_cadence",
                "name": "Commit cadence",
                "detail": "11/52 weeks with commits",
                "points": 7.6,
                "status": "partial",
                "details": [
                  {
                    "code": "commit_cadence_weeks",
                    "params": {
                      "weeks": 11
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_volume",
                "name": "Commit volume",
                "detail": "80 commits in the last year",
                "points": 17.1,
                "status": "partial",
                "details": [
                  {
                    "code": "commits_last_year",
                    "params": {
                      "count": 80
                    }
                  }
                ],
                "max_points": 18
              },
              {
                "key": "openssf_scorecard_maintained",
                "name": "OpenSSF Scorecard: Maintained",
                "detail": "30 commit(s) and 13 issue activity found in the last 90 days -- score normalized to 10",
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "release_discipline",
            "band": "excellent",
            "name": "Release discipline",
            "note": null,
            "notes": [],
            "value": 90,
            "inputs": {
              "releases_count": 16,
              "latest_release_tag": "v2.4.0",
              "releases_from_tags": false,
              "days_since_latest_release": 10,
              "mean_days_between_releases": 5.3
            },
            "components": [
              {
                "key": "ships_releases",
                "name": "Ships releases",
                "detail": "16 releases published",
                "points": 27,
                "status": "met",
                "details": [
                  {
                    "code": "releases_published",
                    "params": {
                      "count": 16
                    }
                  }
                ],
                "max_points": 27
              },
              {
                "key": "release_recency",
                "name": "Release recency",
                "detail": "latest release 10 days ago",
                "points": 36,
                "status": "met",
                "details": [
                  {
                    "code": "release_recency",
                    "params": {
                      "days": 10
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "release_cadence",
                "name": "Release cadence",
                "detail": "a release every ~5.3 days",
                "points": 27,
                "status": "met",
                "details": [
                  {
                    "code": "release_cadence",
                    "params": {
                      "gap": 5.3
                    }
                  }
                ],
                "max_points": 27
              },
              {
                "key": "openssf_scorecard_signed_releases",
                "name": "OpenSSF Scorecard: Signed-Releases",
                "detail": "Project has not signed or included provenance with any releases.",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "abandonment",
            "band": "excellent",
            "name": "Abandonment",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "cap": null,
              "state": "unverified",
              "guards": [],
              "signals": [],
              "red_flag": false,
              "multiplier_pct": 100,
              "declared_reason": null,
              "unverified_reason": "repository_too_young",
              "unanswered_open_prs": null,
              "unanswered_open_issues": null,
              "days_since_last_merged_pr": null,
              "days_since_last_human_commit": null,
              "days_since_last_human_commit_is_floor": false
            },
            "components": [
              {
                "key": "project_is_still_maintained",
                "name": "Project is still maintained",
                "detail": "maintenance record not established from the collected data",
                "points": 100,
                "status": "met",
                "details": [
                  {
                    "code": "abandonment_unverified",
                    "params": {}
                  }
                ],
                "max_points": 100
              }
            ]
          }
        ],
        "description": "Is the project alive — is code being written and are releases shipping?"
      },
      {
        "key": "community",
        "band": "at_risk",
        "name": "Community & Adoption",
        "value": 31,
        "weight": 0.18,
        "metrics": [
          {
            "key": "popularity",
            "band": "critical",
            "name": "Popularity & adoption",
            "note": null,
            "notes": [],
            "value": 14,
            "inputs": {
              "forks": 2,
              "stars": 8,
              "watchers": 1,
              "growth_state": "unverified",
              "growth_factor_pct": 100,
              "growth_unverified_reason": "no_history"
            },
            "components": [
              {
                "key": "stars",
                "name": "Stars",
                "detail": "8 stars",
                "points": 13.7,
                "status": "partial",
                "details": [
                  {
                    "code": "stars",
                    "params": {
                      "count": 8
                    }
                  }
                ],
                "max_points": 60
              },
              {
                "key": "forks",
                "name": "Forks",
                "detail": "2 forks",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "forks",
                    "params": {
                      "count": 2
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "watchers",
                "name": "Watchers",
                "detail": "1 watchers",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "watchers",
                    "params": {
                      "count": 1
                    }
                  }
                ],
                "max_points": 15
              }
            ]
          },
          {
            "key": "community_health",
            "band": "moderate",
            "name": "Community health",
            "note": null,
            "notes": [],
            "value": 50,
            "inputs": {
              "has_readme": true,
              "has_license": true,
              "has_contributing": false,
              "has_issue_template": false,
              "has_code_of_conduct": false,
              "has_pull_request_template": false
            },
            "components": [
              {
                "key": "readme",
                "name": "README",
                "detail": null,
                "points": 22.5,
                "status": "met",
                "details": [],
                "max_points": 22.5
              },
              {
                "key": "license",
                "name": "License",
                "detail": "recognized license (MIT)",
                "points": 22.5,
                "status": "met",
                "details": [
                  {
                    "code": "license_standard",
                    "params": {}
                  },
                  {
                    "code": "license_spdx",
                    "params": {
                      "spdx": "MIT"
                    }
                  }
                ],
                "max_points": 22.5
              },
              {
                "key": "contributing_guide",
                "name": "CONTRIBUTING guide",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 18
              },
              {
                "key": "code_of_conduct",
                "name": "Code of conduct",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 13.5
              },
              {
                "key": "issue_template",
                "name": "Issue template",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.2
              },
              {
                "key": "pr_template",
                "name": "PR template",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 6.3
              }
            ]
          }
        ],
        "description": "Does the project have users, downloads, attention, and a welcoming setup for contributors?"
      },
      {
        "key": "governance",
        "band": "moderate",
        "name": "Sustainability & Governance",
        "value": 50,
        "weight": 0.24,
        "metrics": [
          {
            "key": "maintainer_resilience",
            "band": "critical",
            "name": "Maintainer resilience (bus factor)",
            "note": null,
            "notes": [],
            "value": 13,
            "inputs": {
              "bus_factor": 1,
              "contributors_sampled": 2,
              "top_contributor_share": 0.949
            },
            "components": [
              {
                "key": "bus_factor",
                "name": "Bus factor",
                "detail": "1 contributor(s) cover half of all commits",
                "points": 9,
                "status": "partial",
                "details": [
                  {
                    "code": "bus_factor",
                    "params": {
                      "count": 1
                    }
                  }
                ],
                "max_points": 54
              },
              {
                "key": "commit_distribution",
                "name": "Commit distribution",
                "detail": "top contributor authored 95% of commits",
                "points": 1.1,
                "status": "partial",
                "details": [
                  {
                    "code": "top_contributor_share",
                    "params": {
                      "share": 95
                    }
                  }
                ],
                "max_points": 22.5
              },
              {
                "key": "contributor_breadth",
                "name": "Contributor breadth",
                "detail": "2 contributors",
                "points": 2.7,
                "status": "partial",
                "details": [
                  {
                    "code": "contributors_sampled",
                    "params": {
                      "count": 2
                    }
                  }
                ],
                "max_points": 13.5
              },
              {
                "key": "openssf_scorecard_contributors",
                "name": "OpenSSF Scorecard: Contributors",
                "detail": "project has 0 contributing companies or organizations -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "responsiveness",
            "band": "moderate",
            "name": "Issue & PR responsiveness",
            "note": null,
            "notes": [],
            "value": 66,
            "inputs": {
              "merged_prs": 19,
              "open_issues": 5,
              "closed_issues": 8,
              "issue_closed_ratio": 0.615,
              "closed_unmerged_prs": 2
            },
            "components": [
              {
                "key": "issue_resolution",
                "name": "Issue resolution",
                "detail": "62% of issues closed",
                "points": 28.8,
                "status": "partial",
                "details": [
                  {
                    "code": "issues_closed_share",
                    "params": {
                      "share": 62
                    }
                  }
                ],
                "max_points": 46.75
              },
              {
                "key": "pr_acceptance",
                "name": "PR acceptance",
                "detail": "19/21 decided PRs merged",
                "points": 34.6,
                "status": "partial",
                "details": [
                  {
                    "code": "decided_prs_merged",
                    "params": {
                      "merged": 19,
                      "decided": 21
                    }
                  }
                ],
                "max_points": 38.25
              },
              {
                "key": "openssf_scorecard_code_review",
                "name": "OpenSSF Scorecard: Code-Review",
                "detail": "Found 4/15 approved changesets -- score normalized to 2",
                "points": 3,
                "status": "partial",
                "details": [],
                "max_points": 15
              }
            ]
          },
          {
            "key": "stewardship",
            "band": "at_risk",
            "name": "Ownership & stewardship",
            "note": "Excluded from scoring (no data or not applicable): Verified domain. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "verified_domain"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 37,
            "inputs": {
              "followers": 2,
              "owner_type": "User",
              "is_verified": null,
              "owner_login": "drogers0",
              "public_repos": 17,
              "account_age_days": 1325
            },
            "components": [
              {
                "key": "ownership_backing",
                "name": "Ownership backing",
                "detail": "personal (user) account",
                "points": 10,
                "status": "partial",
                "details": [
                  {
                    "code": "owner_personal",
                    "params": {}
                  }
                ],
                "max_points": 30
              },
              {
                "key": "verified_domain",
                "name": "Verified domain",
                "detail": "not applicable to user accounts",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "not_applicable_to_user_accounts",
                    "params": {}
                  }
                ],
                "max_points": 20
              },
              {
                "key": "owner_reach",
                "name": "Owner reach",
                "detail": "2 followers of drogers0",
                "points": 3.4,
                "status": "partial",
                "details": [
                  {
                    "code": "owner_followers",
                    "params": {
                      "count": 2,
                      "login": "drogers0"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "track_record",
                "name": "Track record",
                "detail": "17 public repos, account ~3 yr old",
                "points": 16.4,
                "status": "partial",
                "details": [
                  {
                    "code": "public_repos",
                    "params": {
                      "count": 17
                    }
                  },
                  {
                    "code": "account_age_years",
                    "params": {
                      "years": 3
                    }
                  }
                ],
                "max_points": 25
              }
            ]
          },
          {
            "key": "package_maintenance",
            "band": "excellent",
            "name": "Package maintenance",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "packages": [
                "github.com/drogers0/aistat/v2"
              ],
              "ecosystems": "go",
              "any_deprecated": false,
              "min_days_since_publish": 10
            },
            "components": [
              {
                "key": "published_resolvable",
                "name": "Published & resolvable",
                "detail": "1 package(s) on go",
                "points": 25,
                "status": "met",
                "details": [
                  {
                    "code": "packages_published",
                    "params": {
                      "count": 1,
                      "ecosystems": "go"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "publish_recency",
                "name": "Publish recency",
                "detail": "latest publish 10 days ago",
                "points": 35,
                "status": "met",
                "details": [
                  {
                    "code": "publish_recency",
                    "params": {
                      "days": 10
                    }
                  }
                ],
                "max_points": 35
              },
              {
                "key": "version_history",
                "name": "Version history",
                "detail": "12 published versions",
                "points": 20,
                "status": "met",
                "details": [
                  {
                    "code": "published_versions",
                    "params": {
                      "count": 12
                    }
                  }
                ],
                "max_points": 20
              },
              {
                "key": "not_deprecated",
                "name": "Not deprecated",
                "detail": "active, not deprecated or yanked",
                "points": 20,
                "status": "met",
                "details": [
                  {
                    "code": "package_not_deprecated",
                    "params": {}
                  }
                ],
                "max_points": 20
              }
            ]
          }
        ],
        "description": "Will the project survive its people — bus factor, responsiveness, who backs it, and package upkeep?"
      },
      {
        "key": "engineering",
        "band": "moderate",
        "name": "Engineering Quality",
        "value": 69,
        "weight": 0.2,
        "metrics": [
          {
            "key": "engineering_practices",
            "band": "good",
            "name": "Engineering practices",
            "note": null,
            "notes": [],
            "value": 82,
            "inputs": {
              "has_ci": true,
              "has_tests": true,
              "has_editorconfig": false,
              "has_linter_config": true,
              "has_precommit_config": false
            },
            "components": [
              {
                "key": "ci_workflows",
                "name": "CI workflows",
                "detail": "3 workflow(s)",
                "points": 24,
                "status": "met",
                "details": [
                  {
                    "code": "ci_workflows",
                    "params": {
                      "count": 3
                    }
                  }
                ],
                "max_points": 24
              },
              {
                "key": "tests_present",
                "name": "Tests present",
                "detail": null,
                "points": 24,
                "status": "met",
                "details": [],
                "max_points": 24
              },
              {
                "key": "linter_config",
                "name": "Linter config",
                "detail": ".golangci.yml",
                "points": 16,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": ".golangci.yml"
                    }
                  }
                ],
                "max_points": 16
              },
              {
                "key": "pre_commit_hooks",
                "name": "Pre-commit hooks",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 9.6
              },
              {
                "key": "editorconfig",
                "name": ".editorconfig",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 6.4
              },
              {
                "key": "openssf_scorecard_ci_tests",
                "name": "OpenSSF Scorecard: CI-Tests",
                "detail": "14 out of 15 merged PRs checked by a CI test -- score normalized to 9",
                "points": 18,
                "status": "partial",
                "details": [],
                "max_points": 20
              }
            ]
          },
          {
            "key": "documentation",
            "band": "moderate",
            "name": "Documentation",
            "note": null,
            "notes": [],
            "value": 50,
            "inputs": {
              "topics": [],
              "has_wiki": true,
              "homepage": null,
              "has_readme": true,
              "has_docs_dir": false,
              "has_description": true
            },
            "components": [
              {
                "key": "readme",
                "name": "README",
                "detail": null,
                "points": 30,
                "status": "met",
                "details": [],
                "max_points": 30
              },
              {
                "key": "documentation_directory",
                "name": "Documentation directory",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 25
              },
              {
                "key": "documentation_homepage_site",
                "name": "Documentation / homepage site",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              },
              {
                "key": "repository_description",
                "name": "Repository description",
                "detail": null,
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              },
              {
                "key": "topics",
                "name": "Topics",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              },
              {
                "key": "wiki",
                "name": "Wiki",
                "detail": null,
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              }
            ]
          }
        ],
        "description": "Are baseline engineering and documentation practices in place?"
      },
      {
        "key": "security",
        "band": "at_risk",
        "name": "Security",
        "value": 47,
        "weight": 0.16,
        "metrics": [
          {
            "key": "security_posture",
            "band": "at_risk",
            "name": "Security posture",
            "note": null,
            "notes": [],
            "value": 47,
            "inputs": {
              "source": "openssf_scorecard",
              "checks_evaluated": 18,
              "scorecard_version": "v5.5.0",
              "checks_inconclusive": 0,
              "scorecard_aggregate": 4.7
            },
            "components": [
              {
                "key": "binary_artifacts",
                "name": "Binary-Artifacts",
                "detail": "no binaries found in the repo",
                "points": 7.5,
                "status": "met",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "branch_protection",
                "name": "Branch-Protection",
                "detail": "branch protection is not maximal on development and all release branches",
                "points": 6,
                "status": "partial",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "ci_tests",
                "name": "CI-Tests",
                "detail": "14 out of 15 merged PRs checked by a CI test -- score normalized to 9",
                "points": 2.2,
                "status": "partial",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "cii_best_practices",
                "name": "CII-Best-Practices",
                "detail": "no effort to earn an OpenSSF best practices badge detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "code_review",
                "name": "Code-Review",
                "detail": "Found 4/15 approved changesets -- score normalized to 2",
                "points": 1.5,
                "status": "partial",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "contributors",
                "name": "Contributors",
                "detail": "project has 0 contributing companies or organizations -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "dangerous_workflow",
                "name": "Dangerous-Workflow",
                "detail": "no dangerous workflow patterns detected",
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              },
              {
                "key": "dependency_update_tool",
                "name": "Dependency-Update-Tool",
                "detail": "no update tool detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "fuzzing",
                "name": "Fuzzing",
                "detail": "project is not fuzzed",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "license",
                "name": "License",
                "detail": "license file detected",
                "points": 2.5,
                "status": "met",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "maintained",
                "name": "Maintained",
                "detail": "30 commit(s) and 13 issue activity found in the last 90 days -- score normalized to 10",
                "points": 7.5,
                "status": "met",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "packaging",
                "name": "Packaging",
                "detail": "packaging workflow detected",
                "points": 5,
                "status": "met",
                "details": [],
                "max_points": 5
              },
              {
                "key": "pinned_dependencies",
                "name": "Pinned-Dependencies",
                "detail": "dependency not pinned by hash detected -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "sast",
                "name": "SAST",
                "detail": "SAST tool is not run on all commits -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "security_policy",
                "name": "Security-Policy",
                "detail": "security policy file not detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "signed_releases",
                "name": "Signed-Releases",
                "detail": "Project has not signed or included provenance with any releases.",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "token_permissions",
                "name": "Token-Permissions",
                "detail": "detected GitHub workflow tokens with excessive permissions",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "vulnerabilities",
                "name": "Vulnerabilities",
                "detail": "0 existing vulnerabilities detected",
                "points": 7.5,
                "status": "met",
                "details": [],
                "max_points": 7.5
              }
            ]
          }
        ],
        "description": "Are visible security and supply-chain practices strong, with no malicious dependency and no unresolved high-risk jurisdiction exposure?"
      },
      {
        "key": "ai_readiness",
        "band": "moderate",
        "name": "AI Readiness",
        "value": 69,
        "weight": 0,
        "metrics": [
          {
            "key": "ai_agent_context",
            "band": "excellent",
            "name": "Agent context & guidance",
            "note": null,
            "notes": [],
            "value": 85,
            "inputs": {
              "has_llms_txt": false,
              "legible_history_share": 0.963,
              "agent_instruction_files": [
                "AGENTS.md",
                "CLAUDE.md"
              ],
              "agent_instruction_max_bytes": 18300
            },
            "components": [
              {
                "key": "agent_instructions",
                "name": "Agent instructions",
                "detail": "AGENTS.md, CLAUDE.md",
                "points": 45,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "AGENTS.md, CLAUDE.md"
                    }
                  }
                ],
                "max_points": 45
              },
              {
                "key": "machine_readable_docs_llms_txt",
                "name": "Machine-readable docs (llms.txt)",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              },
              {
                "key": "legible_commit_history",
                "name": "Legible commit history",
                "detail": "77 of 80 human commits state their intent (structured subject or explanatory body)",
                "points": 40,
                "status": "met",
                "details": [
                  {
                    "code": "legible_history",
                    "params": {
                      "legible": 77,
                      "sampled": 80
                    }
                  }
                ],
                "max_points": 40
              }
            ]
          },
          {
            "key": "ai_verify_loop",
            "band": "moderate",
            "name": "Verify loop (build / test / typecheck)",
            "note": null,
            "notes": [],
            "value": 57,
            "inputs": {
              "has_nix": false,
              "has_tests": true,
              "lockfiles": [],
              "has_dockerfile": false,
              "typed_language": true,
              "bootstrap_files": [],
              "has_devcontainer": false,
              "has_linter_config": true,
              "typecheck_configs": [],
              "agent_commit_share": 0,
              "toolchain_manifests": [
                "go.mod"
              ],
              "dependency_bot_commit_share": 0
            },
            "components": [
              {
                "key": "one_command_bootstrap",
                "name": "One-command bootstrap",
                "detail": "go.mod (toolchain convention, no task runner)",
                "points": 12.6,
                "status": "partial",
                "details": [
                  {
                    "code": "toolchain_convention",
                    "params": {
                      "files": "go.mod"
                    }
                  }
                ],
                "max_points": 18
              },
              {
                "key": "automated_tests",
                "name": "Automated tests",
                "detail": null,
                "points": 22,
                "status": "met",
                "details": [],
                "max_points": 22
              },
              {
                "key": "lint_format_config",
                "name": "Lint / format config",
                "detail": ".golangci.yml",
                "points": 11,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": ".golangci.yml"
                    }
                  }
                ],
                "max_points": 11
              },
              {
                "key": "static_type_checking",
                "name": "Static type checking",
                "detail": "Go (statically typed)",
                "points": 11,
                "status": "met",
                "details": [
                  {
                    "code": "statically_typed_language",
                    "params": {
                      "language": "Go"
                    }
                  }
                ],
                "max_points": 11
              },
              {
                "key": "reproducible_environment",
                "name": "Reproducible environment",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              },
              {
                "key": "demonstrated_agent_practice",
                "name": "Demonstrated agent practice",
                "detail": "no agent-authored commits among the last 80",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "no_agent_authored_commits",
                    "params": {
                      "sampled": 80
                    }
                  }
                ],
                "max_points": 10
              },
              {
                "key": "automated_maintenance",
                "name": "Automated maintenance",
                "detail": "no automated dependency updates observed",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "no_dependency_automation",
                    "params": {}
                  }
                ],
                "max_points": 8
              },
              {
                "key": "openssf_scorecard_pinned_dependencies",
                "name": "OpenSSF Scorecard: Pinned-Dependencies",
                "detail": "dependency not pinned by hash detected -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "ai_code_legibility",
            "band": "excellent",
            "name": "Code legibility for models",
            "note": null,
            "notes": [],
            "value": 99,
            "inputs": {
              "primary_language": "Go",
              "largest_source_bytes": 71156,
              "source_files_sampled": 107,
              "oversized_source_files": 2
            },
            "components": [
              {
                "key": "type_checkable_code",
                "name": "Type-checkable code",
                "detail": "Go (statically typed)",
                "points": 45,
                "status": "met",
                "details": [
                  {
                    "code": "statically_typed_language",
                    "params": {
                      "language": "Go"
                    }
                  }
                ],
                "max_points": 45
              },
              {
                "key": "manageable_file_sizes",
                "name": "Manageable file sizes",
                "detail": "2/107 source files over 60KB",
                "points": 54,
                "status": "partial",
                "details": [
                  {
                    "code": "oversized_source_files",
                    "params": {
                      "kb": 60,
                      "sampled": 107,
                      "oversized": 2
                    }
                  }
                ],
                "max_points": 55
              }
            ]
          },
          {
            "key": "ai_interfaces",
            "band": "at_risk",
            "name": "Machine-readable interfaces",
            "note": null,
            "notes": [],
            "value": 40,
            "inputs": {
              "example_dirs": [
                "examples"
              ],
              "has_mcp_signal": false,
              "api_schema_files": []
            },
            "components": [
              {
                "key": "api_schema_openapi_graphql_proto",
                "name": "API schema (OpenAPI/GraphQL/proto)",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 40
              },
              {
                "key": "mcp_server",
                "name": "MCP server",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 20
              },
              {
                "key": "runnable_examples",
                "name": "Runnable examples",
                "detail": "examples",
                "points": 40,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "examples"
                    }
                  }
                ],
                "max_points": 40
              }
            ]
          }
        ],
        "description": "How well is the repo equipped to be developed and maintained with AI coding agents? An independent, experimental badge — weight 0.0, so it is surfaced on its own and does not affect the overall health score."
      }
    ],
    "metrics_version": "1.13.0"
  },
  "warnings": [
    "Star history unavailable: GitHub GraphQL error: Resource not accessible by personal access token",
    "GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository"
  ],
  "report_type": "repository",
  "generated_at": "2026-07-26T22:34:53.344957Z",
  "schema_version": "0.27.0",
  "badge_url": "https://raw.githubusercontent.com/inspect-software/badges/main/v1/d/drogers0/aistat.svg",
  "full_name": "drogers0/aistat",
  "license_state": "standard",
  "license_spdx": "MIT"
}

Оцінки — це сигнали, а не гарантії. Вони відображають публічно видимі практики на GitHub — це не аудит коду й не гарантія безпеки.

Відсутні дані виключаються, а ваги перенормовуються — нуль за відсутність ніколи не ставиться. Методологія версіонована й відкрита: метрики v1.13.0, схема v0.27.0 — повна методологія · вікі метрик.

Як окремий результат виглядає на тлі всього реєстру: сукупна статистикаGo.