Public record
Software health reportschema 0.27.0 · metrics 1.13.0 · 2026-07-26 22:34 UTC

drogers0 / aistat

Check Claude and Codex API usage limits from the terminal

GoMIT★ 8 stars⑂ 2 forkssince Mar 2026View on GitHub ↗

drogers0/aistat holds a health index of 55 out of 100, placing it in the Moderate band. It scores highest on Vitality (74/100) and lowest on Community & Adoption (31/100). It was last updated 10 days ago. A single contributor accounts for most of its recent work.

55
overall / 100
Moderate

Software health index

Metrics are grouped into weighted categories on one standardized 1–100 scale. Overall starts as their weighted mean; when public evidence triggers the High-Risk Jurisdiction Policy, the rating is adjusted and receives an At risk ceiling of 49. AI Readiness sits outside the overall score.

55
Excellent85-100Exemplary; meets essentially all checked criteria
Good70-84Healthy; minor gaps
Moderate50-69Acceptable with notable gaps; review recommended
At risk30-49Significant weaknesses; adoption warrants caution
Critical1-29Severe problems (abandoned, single-maintainer, no hygiene)
VitalityCommunity &AdoptionSustainability &GovernanceEngineeringQualitySecurityAI Readiness

Score profile

Each axis is a category. The shape matters more than the average — a healthy subject fills the whole shape, while a spike-and-crater profile means strength in one dimension is masking risk in another.

Ownership

David RogersPersonal account
2 followers17 public repossince Dec 2022

This repository is owned by a personal account. A single-owner project carries more continuity risk than an organization-backed one.

Package ecosystems

RegistryPackageVersionDownloads / moVersionsLast publish
Gogithub.com/drogers0/aistat/v2v2.4.0-1210 days ago

Metrics by category

Vitality

Is the project alive — is code being written and are releases shipping?

74Good · 22% of overall
How it's scored
28.8/36Push recency — last push 10 days ago
7.6/36Commit cadence — 11/52 weeks with commits
17.1/18Commit volume — 80 commits in the last year
10/10OpenSSF Scorecard: Maintained — 30 commit(s) and 13 issue activity found in the last 90 days -- score normalized to 10
Inputs used
commits_last_year80
human_commit_share1
days_since_last_push10
active_weeks_last_year11
How it's scored
27/27Ships releases — 16 releases published
36/36Release recency — latest release 10 days ago
27/27Release cadence — a release every ~5.3 days
0/10OpenSSF Scorecard: Signed-Releases — Project has not signed or included provenance with any releases.
Inputs used
releases_count16
latest_release_tagv2.4.0
releases_from_tagsno
days_since_latest_release10
mean_days_between_releases5.3

Community & Adoption

Does the project have users, downloads, attention, and a welcoming setup for contributors?

31At risk · 18% of overall
How it's scored
13.7/60Stars — 8 stars
0/25Forks — 2 forks
0/15Watchers — 1 watchers
Inputs used
forks2
stars8
watchers1
growth_stateunverified
growth_factor_pct100
growth_unverified_reasonno_history
How it's scored
22.5/22.5README
22.5/22.5License — recognized license (MIT)
0/18CONTRIBUTING guide
0/13.5Code of conduct
0/7.2Issue template
0/6.3PR template
Inputs used
has_readmeyes
has_licenseyes
has_contributingno
has_issue_templateno
has_code_of_conductno
has_pull_request_templateno

Sustainability & Governance

Will the project survive its people — bus factor, responsiveness, who backs it, and package upkeep?

50Moderate · 24% of overall
How it's scored
9/54Bus factor — 1 contributor(s) cover half of all commits
1.1/22.5Commit distribution — top contributor authored 95% of commits
2.7/13.5Contributor breadth — 2 contributors
0/10OpenSSF Scorecard: Contributors — project has 0 contributing companies or organizations -- score normalized to 0
Inputs used
bus_factor1
contributors_sampled2
top_contributor_share0.949
How it's scored
28.8/46.8Issue resolution — 62% of issues closed
34.6/38.3PR acceptance — 19/21 decided PRs merged
3/15OpenSSF Scorecard: Code-Review — Found 4/15 approved changesets -- score normalized to 2
Inputs used
merged_prs19
open_issues5
closed_issues8
issue_closed_ratio0.615
closed_unmerged_prs2
How it's scored
10/30Ownership backing — personal (user) account
0/20Verified domain — not applicable to user accounts
3.4/25Owner reach — 2 followers of drogers0
16.4/25Track record — 17 public repos, account ~3 yr old
Inputs used
followers2
owner_typeUser
is_verified
owner_logindrogers0
public_repos17
account_age_days1,325
Excluded from scoring (no data or not applicable): Verified domain. Remaining weights renormalized.
How it's scored
25/25Published & resolvable — 1 package(s) on go
35/35Publish recency — latest publish 10 days ago
20/20Version history — 12 published versions
20/20Not deprecated — active, not deprecated or yanked
Inputs used
packagesgithub.com/drogers0/aistat/v2
ecosystemsgo
any_deprecatedno
min_days_since_publish10

Engineering Quality

Are baseline engineering and documentation practices in place?

69Moderate · 20% of overall
How it's scored
24/24CI workflows — 3 workflow(s)
24/24Tests present
16/16Linter config — .golangci.yml
0/9.6Pre-commit hooks
0/6.4.editorconfig
18/20OpenSSF Scorecard: CI-Tests — 14 out of 15 merged PRs checked by a CI test -- score normalized to 9
Inputs used
has_ciyes
has_testsyes
has_editorconfigno
has_linter_configyes
has_precommit_configno

Documentation

50Moderate
How it's scored
30/30README
0/25Documentation directory
0/15Documentation / homepage site
10/10Repository description
0/10Topics
10/10Wiki
Inputs used
topics
has_wikiyes
homepage
has_readmeyes
has_docs_dirno
has_descriptionyes

Security

Are visible security and supply-chain practices strong, without unresolved high-risk jurisdiction exposure?

47At risk · 16% of overall
How it's scored
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.5License — 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
Inputs used
sourceopenssf_scorecard
checks_evaluated18
scorecard_versionv5.5.0
checks_inconclusive0
scorecard_aggregate4.7

AI Readiness

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.

69Moderate · 0% of overall
How it's scored
45/45Agent instructions — AGENTS.md, CLAUDE.md
0/15Machine-readable docs (llms.txt)
40/40Legible commit history — 77 of 80 human commits state their intent (structured subject or explanatory body)
Inputs used
has_llms_txtno
legible_history_share0.963
agent_instruction_filesAGENTS.md, CLAUDE.md
agent_instruction_max_bytes18,300
How it's scored
12.6/18One-command bootstrap — go.mod (toolchain convention, no task runner)
22/22Automated tests
11/11Lint / format config — .golangci.yml
11/11Static type checking — Go (statically typed)
0/10Reproducible environment
0/10Demonstrated agent practice — no agent-authored commits among the last 80
0/8Automated maintenance — no automated dependency updates observed
0/10OpenSSF Scorecard: Pinned-Dependencies — dependency not pinned by hash detected -- score normalized to 0
Inputs used
has_nixno
has_testsyes
lockfiles
has_dockerfileno
typed_languageyes
bootstrap_files
has_devcontainerno
has_linter_configyes
typecheck_configs
agent_commit_share0
toolchain_manifestsgo.mod
dependency_bot_commit_share0
How it's scored
45/45Type-checkable code — Go (statically typed)
54/55Manageable file sizes — 2/107 source files over 60KB
Inputs used
primary_languageGo
largest_source_bytes71,156
source_files_sampled107
oversized_source_files2
How it's scored
0/40API schema (OpenAPI/GraphQL/proto)
0/20MCP server
40/40Runnable examples — examples
Inputs used
example_dirsexamples
has_mcp_signalno
api_schema_files

Key facts

8GitHub stars
2contributors
80commits, last 12 months
10days since last push
16releases
1bus factor
5open issues
Gopackage ecosystems

Data collection 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

More detail

Star and fork history 0 ★ / 2 ⇿
0Stars
2Forks
4Releases

When each star and fork was added, collected from GitHub and bucketed by day. Cumulative growth sits directly above the daily additions it is made of, so the two read against each other: steady organic accretion looks nothing like an abrupt, short-lived burst. Where that difference is measurable, it is reported as growth authenticity.

111222212026-062026-062026-07
Major 0Minor 1Patch 1
OpenSSF Scorecard 4.7 / 10
4.7aggregate

Independent, tool-agnostic security assessment from the open-source OpenSSF Scorecard. Each check rewards a security practice, not a specific vendor's tool. Checks Scorecard could not determine are marked n/a and excluded from the security score (never counted as zero).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
All dependencies not collected

The resolved dependency set could not be collected for this report: GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository

Raw JSON report machine-readable
{
  "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"
}

Scores are signals, not warranties. They reflect publicly visible practices on GitHub — not a code audit, and not a security guarantee.

Missing data is excluded and weights renormalized, never scored as zero. Methodology is versioned and open: metrics v1.13.0, schema v0.27.0 — full methodology · metrics wiki.

How one result sits in the wider record: aggregate statisticsGo.