Звіт у форматі JSON машиночитний
{
"data": {
"repo": {
"topics": [],
"is_fork": false,
"size_kb": 321,
"has_wiki": true,
"homepage": null,
"languages": {
"Go": 327162,
"Nix": 2007,
"Shell": 8093,
"Makefile": 1132
},
"pushed_at": "2026-07-26T18:34:23Z",
"created_at": "2026-04-05T18:21:04Z",
"owner_type": "User",
"updated_at": "2026-07-26T18:34:27Z",
"description": "Multi-account switcher and usage monitor for Claude Code",
"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": "Zachary Taylor",
"type": "User",
"login": "zach-source",
"company": "Ripple",
"location": null,
"followers": 12,
"avatar_url": "https://avatars.githubusercontent.com/u/61884887?v=4",
"created_at": "2020-03-06T18:12:56Z",
"is_verified": null,
"public_repos": 90,
"account_age_days": 2336
},
"license": {
"state": "standard",
"spdx_id": "MIT",
"raw_spdx": "MIT",
"file_present": true,
"scorecard_found": true,
"profile_has_license": true
},
"activity": {
"releases": [
{
"tag": "v2.8.0",
"kind": "minor",
"published_at": "2026-07-26T18:34:30Z"
}
],
"recent_commits": [
{
"oid": "4406b5ab832cd4c29b6e1a655cd2269a3ce13a80",
"body": null,
"is_bot": false,
"headline": "release: v2.8.0 — browser-free login (login --manual)",
"author_name": "Zach Taylor",
"author_login": "zach-source",
"committed_at": "2026-07-26T18:34:12Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "027c7ad00f24bd87e62df5f166476efc2ab88dca",
"body": "login: add --manual, browser-free login (start/finish, returns immediately)",
"is_bot": false,
"headline": "Merge pull request #15 from zach-source/manual-login",
"author_name": "Zachary Taylor",
"author_login": "zach-source",
"committed_at": "2026-07-26T18:29:57Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "7438a74bf34508d65e321d7a7d7c600f3ea96886",
"body": "Replaces the single blocking ManualLogin call with ManualLoginStart\n(prints the URL, returns right away) and ManualLoginFinish (delivers\nthe pasted code, possibly from an entirely separate `ccswitch`\ninvocation/process later on):\n\n ccswitch login --only <id> --manual # start\n ccswit\n[…]\n2.1.220 CLI: start returns\nin under a second with the real URL, and finish (given a deliberately\nwrong code, so no real login ever completes) correctly delivers it and\nsurfaces claude's own rejection.",
"is_bot": false,
"headline": "login --manual: split into start/finish so start returns immediately",
"author_name": "Zach Taylor",
"author_login": "zach-source",
"committed_at": "2026-07-26T18:14:16Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "b799845b861a7883514dd8df818a1a25fe323e0b",
"body": "Adds a headless login path that never launches a local browser: it\nprints the OAuth authorize URL for the operator to open on any device\n(phone, another machine, ...) and completes the exchange from the\nresulting \"code#state\" response, supplied either interactively (typed\nor piped on stdin) or non-i\n[…]\nrowser/noopener.go - InstallNoOpener shim + test\n internal/refresh/manual.go - ManualLogin + test (fake-claude harness)\n internal/cli/refresh.go - `login --manual`/`--code` flags + test",
"is_bot": false,
"headline": "login: add --manual, browser-free login (present URL, paste response)",
"author_name": "Zach Taylor",
"author_login": "zach-source",
"committed_at": "2026-07-26T14:11:15Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "e9f1633842d53e65f68cece26d7ad334cab2f3c6",
"body": "The CLI backend stores credentials as op documents; the Connect backend's\nRead only understands secure-note 'credentials' fields and returns\nErrNotFound for documents. usage-all reads non-active accounts through the\nConnect store, so all of them showed 'no token'. Extend the fallback\n(renamed WriteFallback -> CLIFallback) to retry reads via the op CLI on\nErrNotFound. Connect is still tried first, so the op session is prompted at\nmost once per run and only when needed.",
"is_bot": false,
"headline": "onepassword: also fall back reads to op CLI on ErrNotFound (#13)",
"author_name": "Zachary Taylor",
"author_login": "zach-source",
"committed_at": "2026-07-17T19:05:16Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "44299a77960d3912b9c2d220bdd80cb9afff1192",
"body": "Connect access tokens have their vault read/write scope fixed at creation.\nA read-only token 403s on login's credential write (HTTP PUT). Wrap the\nConnect backend so Write/Delete retry through the user's full-permission\nop CLI session on a 403; reads stay on Connect. No-op when op is absent.",
"is_bot": false,
"headline": "onepassword: fall back to op CLI for writes on Connect 403 (#11)",
"author_name": "Zachary Taylor",
"author_login": "zach-source",
"committed_at": "2026-07-17T18:52:36Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "2378e59e1d62e6377ea9c9e7a8a0c7052280a8ae",
"body": "Nix builds ccswitch ad-hoc/linker-signed with no stable code identity, so\nmacOS can never persist a keychain 'Always Allow' grant to the binary —\nevery direct Security.framework read re-prompts for the login-keychain\npassword, worse on every rebuild (new store path). Route reads through the\nApple-si\n[…]\n/security instead: one 'Always Allow' for it sticks\nacross ccswitch updates. Secret returns on stdout, never argv, preserving\nthe argv-exposure protection that motivated go-keychain. Writes unchanged.",
"is_bot": false,
"headline": "fix(keychain): read via /usr/bin/security so 'Always Allow' persists",
"author_name": "Zach Taylor",
"author_login": "zach-source",
"committed_at": "2026-07-13T01:27:36Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "f1b07aaa06def1ba21c0bf560efc433e2ef104e3",
"body": "- claudelock.go: proper-lockfile-compatible directory locking on\n ~/.claude.lock and <claude.json>.lock, matching the mkdir/mtime-staleness\n protocol Claude Code itself uses when refreshing OAuth tokens. performSwitch\n now holds both locks around the mutation steps (snapshot prior creds, save\n s\n[…]\na pure, table-tested function\n (decideAutoSwitch) with no I/O.\n\nAll new logic is covered by table-driven tests (claudelock_test.go,\nautoswitch_test.go). gofmt, go vet, go build, and go test all pass.",
"is_bot": false,
"headline": "feat: lockfile-safe swaps, --skip-limited, and autoswitch engine",
"author_name": "Zach Taylor",
"author_login": "zach-source",
"committed_at": "2026-07-13T01:07:53Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "4a74b4a16d375001b27c7fea21d6ce6f15dc09c1",
"body": "…ually swaps (#10)\n\n`performSwitch` only swapped the OAuth token (Keychain `Claude Code-credentials`),\nleaving `~/.claude.json.oauthAccount` pointing at the previous account. Since\nClaude Code reads its displayed identity from that JSON file and the token\nfrom the Keychain, the two halves disagreed \n[…]\n into that account.\n\nTests cover the happy path (verifies oauthAccount is replaced AND unrelated\ntop-level keys survive the merge), the legacy-snapshot fallback path, and\nthe no-identity warning path.",
"is_bot": false,
"headline": "fix(switch): pair identity with credentials so the active account act…",
"author_name": "Zachary Taylor",
"author_login": "zach-source",
"committed_at": "2026-05-27T20:27:41Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "8043c68295f88e1abd3498225b2d65db2e7a3bb8",
"body": "fix(refresh): stop orphaning a keychain record on every login",
"is_bot": false,
"headline": "Merge pull request #9 from zach-source/fix/login-hashed-slot-orphans",
"author_name": "Zachary Taylor",
"author_login": "zach-source",
"committed_at": "2026-05-20T13:39:58Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "b8b99ce96e89a1428b9632625bd979a795c4a71a",
"body": "`ccswitch login`/`refresh` run `claude auth login` with CLAUDE_CONFIG_DIR\npointed at a fresh `os.MkdirTemp` dir each time. claude 2.x on macOS\nwrites the captured credential to a per-config hashed keychain service,\n\"Claude Code-credentials-<8hex>\", whose suffix is opaque and effectively\nunique per r\n[…]\n green.\n\nInterface change rippled to the non-darwin stub and the keychain test;\nnew internal/refresh/capture_test.go pins the \"capture returns the hashed\nservice name\" contract the cleanup depends on.",
"is_bot": false,
"headline": "fix(refresh): stop orphaning a keychain record on every login",
"author_name": "Zach Taylor",
"author_login": "zach-source",
"committed_at": "2026-05-20T13:39:27Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "bb127376ba019b6a02e438067b6fcba6fc99d9f7",
"body": "fix(cli): read backups from configured store, active slot from local",
"is_bot": false,
"headline": "Merge pull request #8 from zach-source/fix/store-vs-local-backend-split",
"author_name": "Zachary Taylor",
"author_login": "zach-source",
"committed_at": "2026-05-20T07:38:32Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "c033284d876295e5fd87f1d5110a8c1b1495409c",
"body": "Making 1password-cli the default backend exposed a latent conflation of\ntwo backend roles that were identical when the default was keychain:\n\n - the ACTIVE slot (ActiveCredKey) lives in the local store — the\n keychain on macOS, which is what `claude` actually reads;\n - per-account BACKUPS (Back\n[…]\nause it used one backend for both roles.\n\nVerified against the real 1Password vault: usage-all shows all three\naccounts with live utilization; switch-to succeeds. make conformance\ngreen; nix build OK.",
"is_bot": false,
"headline": "fix(cli): read backups from the configured store, active slot from local",
"author_name": "Zach Taylor",
"author_login": "zach-source",
"committed_at": "2026-05-20T07:38:17Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "dd55ecbef610be2037fdcf3d1a8f50fd74db973a",
"body": "feat(1password-cli): cache the op session, one biometric prompt per run",
"is_bot": false,
"headline": "Merge pull request #7 from zach-source/feat/op-cli-session-cache",
"author_name": "Zachary Taylor",
"author_login": "zach-source",
"committed_at": "2026-05-20T06:50:11Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "d19697a9661a814f06bb9341e57f0e2a2874af64",
"body": "…cswitch run\n\nBefore: every Read/Write/Delete invoked `op` afresh, and every `op` call\ntriggered a biometric / desktop-app prompt — `ccswitch login` against\nthree accounts could fire half a dozen approvals in a row.\n\nNow: the CLIBackend runs `op signin --raw` lazily on the first sub-call\nand stashes\n[…]\nvery credential — all one tap.\n\nTest: TestCLIBackend_AccountShorthand pins the URL parsing across the\nformats users actually configure.\n\nmake conformance green: vet + Go tests + 22 bats; nix build OK.",
"is_bot": false,
"headline": "feat(1password-cli): cache the op session, one biometric prompt per c…",
"author_name": "Zach Taylor",
"author_login": "zach-source",
"committed_at": "2026-05-20T06:49:54Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "0b0235eae25fc9284ac5284f9a9e91c7dbdbb623",
"body": "feat(backend): add 1password-cli backend (writes via op CLI)",
"is_bot": false,
"headline": "Merge pull request #6 from zach-source/feat/op-cli-backend",
"author_name": "Zachary Taylor",
"author_login": "zach-source",
"committed_at": "2026-05-20T04:52:04Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "2c7c4c8722f755cc1dca9bdcb1d8d5e0967bb960",
"body": "…g Connect token perms)\n\nThe Connect HTTP backend's bearer token has read access but lacks\ncreate/update permission on the target vault, so ccswitch login captures\ncredentials correctly and then 1Password returns 403 on the write. Fixing\nthe token's permissions requires admin work in the 1Password U\n[…]\nplied by the 1Password desktop app's\nbiometric integration; if that is not available (headless server),\nkeep using the Connect backend.\n\nmake conformance green: vet + Go tests + 22 bats; nix build OK.",
"is_bot": false,
"headline": "feat(backend): add 1password-cli backend (writes via op CLI, bypassin…",
"author_name": "Zach Taylor",
"author_login": "zach-source",
"committed_at": "2026-05-20T04:51:44Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "06f47b627cf11e035038b6cbf402bf5678a0dce1",
"body": "fix(security): store 1Password Connect secrets in 0600 files, not the keychain",
"is_bot": false,
"headline": "Merge pull request #5 from zach-source/fix/op-secrets-to-files",
"author_name": "Zachary Taylor",
"author_login": "zach-source",
"committed_at": "2026-05-19T23:54:10Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "f36d35a9e9889aa182c3b5178134cf11cb3b74a9",
"body": "… keychain\n\nThe keychain-backed storage of the three Connect/CF Access secrets\nintroduced in the C1 security fix had a structural problem on macOS:\nkeychain ACLs match the calling binary's code identity, and Nix builds\nccswitch into a fresh /nix/store/<hash>/ path on every rebuild. Every\nrebuild mad\n[…]\nrity delete-generic-password -s ccswitch-op-connect-token`\n(and the cf-access-client-{id,secret} variants) if you want a tidy\nkeychain.\n\nmake conformance green: vet + Go tests + 22 bats; nix build OK.",
"is_bot": false,
"headline": "fix(security): store 1Password Connect secrets in 0600 files, not the…",
"author_name": "Zach Taylor",
"author_login": "zach-source",
"committed_at": "2026-05-19T23:53:44Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "94cdc2defcb802d45c35beef6053ce227b75795d",
"body": "feat(login): route OAuth URL into the Chrome profile signed in to the account",
"is_bot": false,
"headline": "Merge pull request #4 from zach-source/feat/chrome-profile-router",
"author_name": "Zachary Taylor",
"author_login": "zach-source",
"committed_at": "2026-05-19T23:34:46Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "22e3eaca38ce2fa6c4ffdef4523a2bc481784406",
"body": "… account\n\nMulti-account login flows used to require the user to manually switch\nChrome profiles between iterations: claude opens the OAuth URL in\nwhichever Chrome profile happens to be active, which is rarely the one\nsigned in to the account being authorized.\n\nThis adds automatic Chrome-profile rou\n[…]\nn error.\n- renderOpenerScript carries the Chrome binary, --profile-directory\n flag, both URL patterns, and the system-opener fallback.\n\nmake conformance green: vet + Go tests + 22 bats; nix build OK.",
"is_bot": false,
"headline": "feat(login): route OAuth URL into the Chrome profile signed in to the…",
"author_name": "Zach Taylor",
"author_login": "zach-source",
"committed_at": "2026-05-19T23:34:20Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "7fc469a56b767252855cb1c36bd0d57c5bc06ff5",
"body": "fix(refresh): capture claude 2.x's per-CLAUDE_CONFIG_DIR hashed keychain slot",
"is_bot": false,
"headline": "Merge pull request #3 from zach-source/fix/claude-hashed-keychain-slot",
"author_name": "Zachary Taylor",
"author_login": "zach-source",
"committed_at": "2026-05-19T23:09:01Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "186abf908f3b9e0e666018acc015252f0566bab5",
"body": "…ain slot\n\nFollow-up to the previous fix. Empirical inspection of the user's\nkeychain after `ccswitch login` revealed that claude 2.x, when\nCLAUDE_CONFIG_DIR is set, writes credentials to a *hashed* service slot\nnamed \"Claude Code-credentials-<8hex>\" where the suffix is an opaque\nfunction of the CON\n[…]\nnd_LookupHashedActiveSlot — writes a test slot, asserts\nLookupHashedActiveSlot finds it within the `since` window and skips it\noutside.\n\nmake conformance green: vet + Go tests + 22 bats; nix build OK.",
"is_bot": false,
"headline": "fix(refresh): capture claude 2.x's per-CLAUDE_CONFIG_DIR hashed keych…",
"author_name": "Zach Taylor",
"author_login": "zach-source",
"committed_at": "2026-05-19T23:08:32Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "81617373abc54e4d1ed5473dbe604ce02cf91e55",
"body": "fix(refresh): capture claude 2.x credentials from the keychain on macOS",
"is_bot": false,
"headline": "Merge pull request #2 from zach-source/fix/claude-keychain-capture",
"author_name": "Zachary Taylor",
"author_login": "zach-source",
"committed_at": "2026-05-19T21:32:00Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "fe9a0235be5abcf4ec31c183a26b1808052cc08d",
"body": "Bug report: `ccswitch login` against 3 accounts returned\n\"Interactive login complete: 0/3 accounts refreshed\", logging\n\"no credentials file after claude exit\".\n\nRoot cause: claude 2.x on macOS writes the credential blob directly to\nthe login keychain (\"Claude Code-credentials\") and ignores\nCLAUDE_CO\n[…]\nged; nothing is stored.\n- TestRefreshAll_CapturesFromLocalActiveSlot — same, with an unmodeled\n field as a raw-bytes regression guard.\n\nmake conformance green: vet + Go tests + 22 bats; nix build OK.",
"is_bot": false,
"headline": "fix(refresh): capture claude 2.x credentials from the keychain on macOS",
"author_name": "Zach Taylor",
"author_login": "zach-source",
"committed_at": "2026-05-19T21:31:37Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "df2f3bfa9f9c3854dc9f1659d963d3ae78ff1649",
"body": "Complete the Go port of ccswitch (v2.0.0)",
"is_bot": false,
"headline": "Merge pull request #1 from zach-source/go-port",
"author_name": "Zachary Taylor",
"author_login": "zach-source",
"committed_at": "2026-05-19T20:19:02Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "e65e7bf11ab4c9e1d7e4ae93ee17acd359fd4242",
"body": "The commands that shell out — login, refresh-all, usage, usage-all,\nuse-zai — were the last untested gap. They resolve claude/ccusage/op by\nname through PATH, so a temp dir of fake executables prepended to PATH\nexercises them with no real tools, network, or browser login.\n\ninternal/cli/external_test\n[…]\ncli/usage.go: the OAuth usage endpoint is now the package var\nanthropicUsageURL purely so the test can point it at httptest.\n\ncli coverage 33% -> 49%. make conformance green: vet + Go tests + 22 bats.",
"is_bot": false,
"headline": "test: cover the external-dependency commands with mocked tools",
"author_name": "Zach Taylor",
"author_login": "zach-source",
"committed_at": "2026-05-19T20:12:13Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "7e212881840887b0f81c5373d4021103d16289f7",
"body": "The CLI command layer was only 15% covered — no end-to-end test existed\nfor the credential-mutating commands, exactly where a regression silently\nloses user data. This adds a real regression gate.\n\ninternal/cli/command_test.go (new): 15 hermetic command tests. Each runs\na whole command via Root().Ex\n[…]\n bats\nis absent.\n\nflake.nix: devShells.default provides go + bats so `nix develop -c make\nconformance` works out of the box.\n\nVerified: make conformance green (vet + Go tests + 22 bats); nix build OK.",
"is_bot": false,
"headline": "test: build a hermetic conformance suite for the CLI layer",
"author_name": "Zach Taylor",
"author_login": "zach-source",
"committed_at": "2026-05-19T20:01:31Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "8c14051d483f809f3032c475e85f5edcc59c401f",
"body": "Resolves the three lower-severity security items left noted-but-unfixed\nafter the previous audit-fix pass.\n\n- L1: fetchZaiToken dropped its os.Stat + executable-bit precheck before\n running ~/.claude/scripts/mcp-secret-cache.sh — that stat-then-exec was\n a TOCTOU. A missing or non-executable helpe\n[…]\nd for\nCLI tools and not a defect\"; a hardcoded allowlist would break Nix/\nHomebrew installs for no real gain on a personal tool.\n\ngofmt/vet clean; Go unit tests + 15 bats smoke tests + nix build pass.",
"is_bot": false,
"headline": "fix(security): close out the remaining low-severity audit findings",
"author_name": "Zach Taylor",
"author_login": "zach-source",
"committed_at": "2026-05-19T19:42:46Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "51be7363ddf5f9bc7b1831b1ec1d9151ad45248f",
"body": "Aggregated fixes from a code-quality review and a security audit of the\ngo-port branch.\n\nSECURITY\n\n- CRITICAL: setup-op-connect no longer shells out to `security\n add-generic-password -w <secret>`, which exposed the 1Password Connect\n bearer token and CF Access secrets in argv (visible to any loca\n[…]\n it queries sequentially; context flows from cmd.Context() in save /\n env / remove-account instead of context.Background().\n\nAll gofmt/vet clean; Go unit tests + 15 bats smoke tests + nix build\npass.",
"is_bot": false,
"headline": "fix(security,quality): address audit findings on the Go port",
"author_name": "Zach Taylor",
"author_login": "zach-source",
"committed_at": "2026-05-19T19:17:52Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "fa104a54b88bd8a67253b4f6708a08e61e9dc1d0",
"body": "credentials.Credentials is a typed inspection lens, not a faithful mirror\nof .credentials.json — json.Unmarshal into it drops any field the struct\ndoes not model. RefreshAll and usage-all's auto-refresh persisted\nnewCred.Marshal() output, so any field Claude Code adds to the credential\nfile in futur\n[…]\n blob with an\n unmodeled field loses it across Parse->Marshal.\n- sync.TestSync_PreservesRawCredentialBytes proves a full sync pass\n stores a credential blob (incl. an unmodeled field) byte-for-byte.",
"is_bot": false,
"headline": "fix(refresh): store raw credential bytes, never a re-marshaled struct",
"author_name": "Zach Taylor",
"author_login": "zach-source",
"committed_at": "2026-05-19T18:26:58Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "29dac2eac1f80326d981d87c4a52e331cfaf261f",
"body": "… bash\n\nThe go-port branch had 15 of 23 subcommands. This finishes the port: all\ncommands are now native Go, the flake builds the Go binary, and ccswitch.sh\nis removed.\n\nNew subcommands\n - login / refresh-all wire up the existing internal/refresh package\n - use-zai / use-anthropic / api-status \n[…]\ntests/cli.bats: 15 end-to-end smoke tests in an isolated $HOME,\n including regression coverage for the stale-active-account bug.\n\nRemoved\n - ccswitch.sh (3269 lines) and tests/integration_test.sh.",
"is_bot": false,
"headline": "feat(go): complete the Go port — port remaining 8 subcommands, retire…",
"author_name": "Zach Taylor",
"author_login": "zach-source",
"committed_at": "2026-05-19T07:59:50Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "cada59ce39cd773c75b31b20a94f1e1146c79ec2",
"body": "… daemon-panic\n\nNet: -71 lines. 14/14 sync tests pass (added one).\n\nData-loss bugs closed:\n- cli/push.go and cli/pull.go re-implemented sync logic against\n hardcoded \"Claude Code Account - %s-%s\" keys (with spaces) while\n sync.Engine uses account.BackupCredKey (\"Claude Code-Account-...\").\n push/p\n[…]\ngo can persist after Pull\n mutates the in-memory copy.\n\nTest:\n- TestSync_ActiveSlot_PullMirrorsBoth covers the new dual-write path\n and would catch any regression in the order-sensitive writePulled.",
"is_bot": false,
"headline": "refactor(go): round-3 fixes from review — close data-loss, atomicity,…",
"author_name": "Zach Taylor",
"author_login": "zach-source",
"committed_at": "2026-04-26T14:42:43Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "ac174d8953e5b722a9a7ca5dd256227a544de851",
"body": "Net: -72 lines on top of the initial Go port. All 41 tests still pass.\n\nBig-impact:\n- Wire cli/sync.go and cli/daemon.go through sync.Engine/sync.Daemon.\n Deletes ~120 lines of duplicate sync logic that was diverging in\n key format (\"ccswitch - %s-%s\" vs \"Claude Code Account - %s-%s\").\n Daemon is\n[…]\ns) + http.Client.Timeout=30s for the 5-min daemon\n- vault: drop kvPath identity wrapper\n- Demote per-account \"pushed/pulled\" log lines from Info to Debug\n so a 5-min daemon at idle doesn't flood logs",
"is_bot": false,
"headline": "refactor(go): consolidate sync engine, centralize keys, polish",
"author_name": "Zach Taylor",
"author_login": "zach-source",
"committed_at": "2026-04-26T14:03:51Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "b406e49553d9eb3575d05820ba2408aee5a79b05",
"body": "Initial Go rewrite of ccswitch — feature-equivalent for read paths,\nbacked by a clean package layout for parallel hand-off.\n\nWhat's in:\n- cmd/ccswitch — main, cobra root, all 16 subcommands\n- internal/account — sequence.json (v2 hash IDs), Resolve, atomic save\n- internal/backend — Backend interf\n[…]\n`list` reads \"Unknown\" because the bash sequence.json\n uses \"Personal\" — minor format reconciliation\n- Wire ccswitch-daemon.nix to the Go binary\n- Replace ccswitch.sh on main once verified end-to-end",
"is_bot": false,
"headline": "feat(go): initial Go port (parallel agent team build)",
"author_name": "Zach Taylor",
"author_login": "zach-source",
"committed_at": "2026-04-26T05:10:05Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "a0f7ee4534f908f1d8632f384d7df87085826ae9",
"body": "Move bearer + CF Access headers to a curl config file fed via process\nsubstitution (`-K <(...)`), and pass JSON request bodies on stdin\n(`--data-binary @-`) instead of `--data \"$body\"`. Result: neither the\n1Password Connect bearer, the CF Access service-token client-secret,\nnor credential JSON appea\n[…]\nd for the HTTP path.\n\nDocument the residual `security add-generic-password -w VALUE` argv\nexposure (Apple offers no scriptable stdin alternative on macOS) in\ndocs/SECURITY.md. Tests: 13/13 still pass.",
"is_bot": false,
"headline": "security: keep Connect secrets out of curl argv",
"author_name": "Zach Taylor",
"author_login": "zach-source",
"committed_at": "2026-04-26T00:22:04Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "ace44181820cf23c986604e5a4058b4ff9305770",
"body": "`<<<\"$title\"` appends a newline; @uri encodes it as %0A and bakes it\ninto the filter expression, making every find_item_id miss. `printf %s`\navoids the extra byte.",
"is_bot": false,
"headline": "fix: strip trailing newline before jq @uri in find_item_id",
"author_name": "Zach Taylor",
"author_login": "zach-source",
"committed_at": "2026-04-25T22:52:09Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "3a298985d6e76136ba61b9bb8fc4f59671603848",
"body": "Net: +101 / -117 lines (smaller than the previous round). 13/13 tests pass.\n\nCode reuse:\n- Two new credential helpers replace 5+ inline python heredocs:\n - _cred_field <json> <key> — extract a string from .claudeAiOauth via\n jq (already a hard dep, no python fork)\n - _cred_hours_left <ms> — pri\n[…]\nnger\n re-resolves item_id after _op_read already cached it).\n- Removed python forks from _refresh_via_claude_auth and 4 hours-left\n computations on hot paths (~30 ms × N accounts × every push/pull).",
"is_bot": false,
"headline": "refactor: round-2 simplification from review feedback",
"author_name": "Zach Taylor",
"author_login": "zach-source",
"committed_at": "2026-04-25T22:41:47Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "95ac8a871a0bbaacf4b6daa26fdf54e94681b8e0",
"body": "Net: +84 / -97 lines (smaller, less duplication, no behavior change).\n13/13 integration tests still pass.\n\nCode reuse:\n- Replace 4× duplicated `op_args` read-loop with `mapfile -t _op_argv`\n (bash 4+ already required) and a shared global. _op_read, _op_write,\n _op_delete, _op_check now share one l\n[…]\nficiency:\n- One mapfile vs while-read loop per call (smaller fork count for\n signed-in mode hot path).\n- Vault filter URL encoding no longer forks python per request (was\n ~30ms × N items per sync).",
"is_bot": false,
"headline": "refactor: simplify ccswitch internals from review feedback",
"author_name": "Zach Taylor",
"author_login": "zach-source",
"committed_at": "2026-04-25T22:18:00Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "4c0469133d43c82ad050f168b34a057126fbec8d",
"body": "Connect endpoints behind Cloudflare Access can't be used via the op CLI —\nCF Access strips Authorization: Bearer headers, so the Connect server\nnever sees the token. Replace the op-CLI path with direct HTTP calls\nthat carry three headers (X-OP-Token, CF-Access-Client-Id,\nCF-Access-Client-Secret), wh\n[…]\np-CLI path is preserved as the fallback when\nOP_CONNECT_HOST is unset.\n\nTested: 13/13 integration tests pass (signed-in path). End-to-end HTTP\nConnect validation is interactive / environment-specific.",
"is_bot": false,
"headline": "feat: HTTP Connect backend with Cloudflare Access support",
"author_name": "Zach Taylor",
"author_login": "zach-source",
"committed_at": "2026-04-22T01:14:49Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "97e2cc790b8396edca8d3afa051ebafe09546aec",
"body": "Integration tests (tests/integration_test.sh) exercise round-trip read/write\nfor each backend (file, keychain, 1password) plus config loading and\nbackend resolution. Three real bugs surfaced:\n\n1. _op_fill_args used `local -n` (bash 4.3+ nameref) — rejected by older\n bash. Replaced with a portable \n[…]\n\nPlus a cosmetic: _keychain_delete leaked the deleted item's attribute\ndump to stdout — now `&>/dev/null` to silence both streams.\n\nRun: `bash tests/integration_test.sh`. Results: 13 passed, 0 failed.",
"is_bot": false,
"headline": "fix: bugs caught by new integration tests",
"author_name": "Zach Taylor",
"author_login": "zach-source",
"committed_at": "2026-04-22T00:37:29Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "1cf5088fe1525b414d2fa2f3272791f44b1523cf",
"body": "- New config: [backend.onepassword].connect_host + token_keychain_service\n (env: OP_CONNECT_HOST, CCSWITCH_OP_CONNECT_TOKEN_KEYCHAIN_SERVICE)\n- _op_* functions drop --account flag when in Connect mode\n (Connect tokens are already scoped to a server/vault)\n- _op_check probes via `op vault list` (wo\n[…]\nfrequent op/TouchID permission prompts caused by the sync daemon\nhammering whoami every 5 min. Connect tokens never expire (until revoked),\nso the daemon runs silently after one-time setup per device.",
"is_bot": false,
"headline": "feat: 1Password Connect support — no biometric prompts",
"author_name": "Zach Taylor",
"author_login": "zach-source",
"committed_at": "2026-04-20T19:17:43Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "6624d15860f3d4b7b5aad8a3af0f8c68d174cb9f",
"body": null,
"is_bot": false,
"headline": "fix: _op_check honors CCSWITCH_OP_ACCOUNT for multi-account 1Password",
"author_name": "Zach Taylor",
"author_login": "zach-source",
"committed_at": "2026-04-19T05:46:18Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "66915e4b18b52b821868a4a74fe4648a81976d32",
"body": "Add declarative configuration with precedence:\n env vars > TOML config > built-in defaults\n\nSchema:\n [backend] type = auto|keychain|file|1password|vault\n [backend.onepassword] vault, item_prefix, account\n [backend.vault] addr, path, token\n [sync] interval\n [refre\n[…]\n config key: passes --account to op CLI\n (supports multi-account 1Password setups)\n- CCSWITCH_CONFIG_FILE env var to override config path\n- All op item get/edit/create/delete commands honor --account",
"is_bot": false,
"headline": "feat: TOML config file at ~/.config/ccswitch/config.toml",
"author_name": "Zach Taylor",
"author_login": "zach-source",
"committed_at": "2026-04-19T05:36:58Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "a4609f3905c0789dd66fd31b97820a70b5e53c57",
"body": "Add four new commands for syncing ccswitch state with 1Password:\n\n --push Upload all local credentials + sequence metadata\n --pull Download all credentials + sequence metadata (overwrites local)\n --sync [--quiet] Bi-directional merge; per-account newest expiresAt wins,\n \n[…]\nSWITCH_OP_VAULT}, prefix ${CCSWITCH_OP_ITEM_PREFIX}.\n\nThe active account's live keychain entry is updated when remote is fresher\nso running Claude sessions inherit refreshed tokens on next auth check.",
"is_bot": false,
"headline": "feat: 1Password sync — push, pull, bi-directional sync, and daemon",
"author_name": "Zach Taylor",
"author_login": "zach-source",
"committed_at": "2026-04-19T04:37:34Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "bae0a2636e2cffd6e330b06fc11dfd922c7832ed",
"body": "…ve keychain\n\nRefresh no longer temporarily swaps credentials into the active keychain\nslot, which could disrupt a running Claude session. Instead, creates an\nisolated CLAUDE_CONFIG_DIR with .credentials.json, runs `claude auth login`\nthere, and reads the refreshed creds from the file. The active session's\nkeychain entry is never touched during refresh.",
"is_bot": false,
"headline": "fix: refresh uses isolated CLAUDE_CONFIG_DIR instead of swapping acti…",
"author_name": "Zach Taylor",
"author_login": "zach-source",
"committed_at": "2026-04-10T14:00:33Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "de55b3068b7de1c81f3a1e7bec8eea9b89284f07",
"body": "Remove direct calls to the OAuth token endpoint (console.anthropic.com).\nPer Anthropic guidance:\n- Direct refresh calls can invalidate Claude Code's active token\n- Refresh tokens are single-use; concurrent refreshes race\n- The supported path is `claude auth login` with env vars\n\nNew flow uses CLAUDE\n[…]\nerations run in a temp working directory to avoid\npolluting sessions.\n\nFor inactive accounts, temporarily swaps credentials into the active\nkeychain slot, runs the refresh, then restores the original.",
"is_bot": false,
"headline": "refactor: use claude auth login for refresh instead of direct OAuth API",
"author_name": "Zach Taylor",
"author_login": "zach-source",
"committed_at": "2026-04-10T13:48:36Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "1d85d70024e67172d1c8f58c053fa23241dc713c",
"body": null,
"is_bot": false,
"headline": "fix: --login runs claude in temp dir to avoid polluting project sessions",
"author_name": "Zach Taylor",
"author_login": "zach-source",
"committed_at": "2026-04-10T13:26:16Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "47a2293b42c1278eaee6ab6d35d0dd5aaaf806d7",
"body": "Previous approach used CLAUDE_CONFIG_DIR with temp dirs, but on macOS\nClaude Code writes credentials to Keychain (not .credentials.json),\nusing a hashed service name tied to the config dir path. This meant\ncredentials from interactive login were never captured.\n\nNew approach:\n1. Switch to each expir\n[…]\nt_credentials\n5. Restore the original account when done\n\nThis works because Claude Code's auth flow always writes to the standard\n\"Claude Code-credentials\" Keychain entry when it's the active session.",
"is_bot": false,
"headline": "fix: --login now uses real account switching + native keychain auth",
"author_name": "Zach Taylor",
"author_login": "zach-source",
"committed_at": "2026-04-09T12:32:49Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "5222882eb3e5e5ca53cca98a4d28e1fae5069d92",
"body": "ccswitch --login finds accounts with expired/invalid credentials and\nlaunches `claude /login` in an isolated CLAUDE_CONFIG_DIR for each one,\nprompting the user to log in via browser. After claude exits, the fresh\ncredentials are captured and saved to the backup slot.\n\nOptions:\n --only <hash|email> \n[…]\nR with expected identity\n3. Launch `claude /login` interactively\n4. Capture fresh credentials on exit\n5. Save to backup slot with the expected hash ID\n6. Warn if logged-in email doesn't match expected",
"is_bot": false,
"headline": "feat: add --login for interactive re-auth of expired accounts",
"author_name": "Zach Taylor",
"author_login": "zach-source",
"committed_at": "2026-04-09T02:04:28Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "57397718969b76667dbc6fa3ac02d7f681733c22",
"body": "- Add _refresh_via_claude helper that runs `claude -p` with CLAUDE_CONFIG_DIR\n pointing at a temp directory with the account's credentials. Claude Code's\n internal auth flow handles refresh (including rate limits, one-time tokens).\n- refresh_account_token tries claude CLI first, falls back to dire\n[…]\ntaleness\n scenario (backup slots going stale while active token gets refreshed).\n- Clearer error messages when refresh fails due to invalidated refresh token\n (suggests re-auth via switch + claude).",
"is_bot": false,
"headline": "feat: use claude CLI for token refresh instead of direct OAuth API",
"author_name": "Zach Taylor",
"author_login": "zach-source",
"committed_at": "2026-04-09T01:44:17Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "f769f5ce1730e476a302885aa27333739504f462",
"body": "Account IDs are now deterministic 8-char SHA-256 hex prefix of the email\n(e.g., 86523df2 for zctaylor.work@gmail.com). This makes account identity\nstable and identifiable.\n\nChanges:\n- sequence.json v2 schema: accounts keyed by hash, activeAccountId\n- Auto-migration from v1 (numeric) to v2 on first r\n[…]\nash IDs\n- JSON output uses \"id\" field instead of \"account\" (number)\n\nBackward compatible: numeric index still works as positional lookup\ninto the sequence array (e.g., --switch-to 2 = second account).",
"is_bot": false,
"headline": "refactor: migrate from numeric account keys to email-hash IDs",
"author_name": "Zach Taylor",
"author_login": "zach-source",
"committed_at": "2026-04-06T14:57:32Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "55fa3f5d0c46560b571db43965260b60d6afbf1f",
"body": "After logging in or re-authenticating via Claude Code, run:\n ccswitch --save\n\nThis copies the active keychain credentials to the backup slot,\nensuring the backup has the fresh token. Prevents stale tokens\nin backup slots after Claude Code refreshes during a session.\n\nAlso detects identity mismatch (e.g., logged into a different\naccount than expected) and updates the account mapping.",
"is_bot": false,
"headline": "feat: add --save to capture fresh credentials after login",
"author_name": "Zach Taylor",
"author_login": "zach-source",
"committed_at": "2026-04-06T13:30:37Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "c8a8f8b14b50b180ac452fc7b72b4afeb7058fd6",
"body": "- Add _token_is_expired, _refresh_token, refresh_account_token helpers\n- Auto-refresh in --usage-all before querying the API\n- Auto-refresh in perform_switch before activating target account\n- Add --refresh-all command to manually refresh all expired tokens\n- 2s delay between refreshes to avoid rate limits",
"is_bot": false,
"headline": "feat: automatic OAuth token refresh for expired accounts",
"author_name": "Zach Taylor",
"author_login": "zach-source",
"committed_at": "2026-04-06T13:05:12Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "88917a5b13e814bf1559bc8dbe473426e7f47f54",
"body": "Supports container/CI workflows where credentials are mounted:\n eval \"$(ccswitch --env --creds-file /mnt/secrets/creds.json)\"\n eval \"$(ccswitch --env --creds-file /s/creds.json --config-dir /tmp/ci)\"\n\nCredentials file is symlinked (not copied) so mounted volumes stay live.\nConfig dir gets symlinks to shared settings/hooks/skills/agents/MCP/plugins.",
"is_bot": false,
"headline": "feat: add --creds-file and --config-dir to --env for mounted secrets",
"author_name": "Zach Taylor",
"author_login": "zach-source",
"committed_at": "2026-04-06T01:46:44Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "6ab0152c21af1a14b118fcf05ca1f9b9c5bc7b66",
"body": "Add support for multiple credential storage backends:\n- keychain: macOS Keychain (default on macOS)\n- file: filesystem credentials (default on Linux/WSL)\n- 1password: 1Password CLI (op) with configurable vault\n- vault: HashiCorp Vault / OpenBao KV secrets engine\n\nBackend selection via CCSWITCH_BACKE\n[…]\neychain users are unaffected (auto default).\n\nConfig env vars:\n CCSWITCH_OP_VAULT, CCSWITCH_OP_ITEM_PREFIX (1Password)\n CCSWITCH_VAULT_ADDR, CCSWITCH_VAULT_PATH, CCSWITCH_VAULT_TOKEN (Vault/OpenBao)",
"is_bot": false,
"headline": "feat: pluggable credential backends (1Password, Vault/OpenBao)",
"author_name": "Zach Taylor",
"author_login": "zach-source",
"committed_at": "2026-04-05T21:18:28Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "66e5faee0f75aff40410d52da9956254bdf3023f",
"body": null,
"is_bot": false,
"headline": "feat: add --json flag to --usage-all for machine-readable output",
"author_name": "Zach Taylor",
"author_login": "zach-source",
"committed_at": "2026-04-05T19:20:45Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "c269c6287534f6eb98e26c5d5f8858fcdcfd4442",
"body": "eval \"$(ccswitch --env 2)\" binds the current shell to account 2\nvia CLAUDE_CONFIG_DIR without affecting the global account.\n\nCreates ~/.claude-env-<N>/ with symlinks to shared config\n(settings, hooks, skills, agents, MCP, plugins) and isolated\ncredentials + projects directory per account.\n\neval \"$(ccswitch --env --unset)\" reverts to global.",
"is_bot": false,
"headline": "feat: add --env for per-shell account binding",
"author_name": "Zach Taylor",
"author_login": "zach-source",
"committed_at": "2026-04-05T19:01:01Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "fb1ed87a56ecec98544e6498519614789c6ba907",
"body": null,
"is_bot": false,
"headline": "fix: add dontBuild to prevent Makefile from running in nix build",
"author_name": "Zach Taylor",
"author_login": "zach-source",
"committed_at": "2026-04-05T18:24:44Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "5f37f014f33f3f5d2fa492745e83759e2f4c60f0",
"body": "Multi-account switcher and usage monitor for Claude Code.\nSupports nix flake, homebrew, and manual install.",
"is_bot": false,
"headline": "feat: initial release of ccswitch v1.0.0",
"author_name": "Zach Taylor",
"author_login": "zach-source",
"committed_at": "2026-04-05T18:20:55Z",
"body_truncated": false,
"is_coding_agent": false
}
],
"releases_count": 1,
"commits_last_year": 60,
"latest_release_at": "2026-07-26T18:34:30Z",
"latest_release_tag": "v2.8.0",
"releases_from_tags": false,
"days_since_last_push": 3,
"active_weeks_last_year": 10,
"days_since_latest_release": 3,
"mean_days_between_releases": null
},
"community": {
"has_readme": true,
"has_license": true,
"has_description": true,
"has_contributing": false,
"health_percentage": 57,
"has_issue_template": false,
"has_code_of_conduct": false,
"has_pull_request_template": false
},
"ecosystem": {
"packages": [
{
"name": "github.com/zach-source/ccswitch",
"exists": true,
"license": null,
"keywords": [],
"ecosystem": "go",
"matches_repo": true,
"registry_url": "https://pkg.go.dev/github.com/zach-source/ccswitch",
"is_deprecated": false,
"latest_version": "v1.6.0",
"repository_url": "https://github.com/zach-source/ccswitch",
"versions_count": 17,
"total_downloads": null,
"dependents_count": null,
"deprecation_note": null,
"maintainers_count": null,
"monthly_downloads": null,
"first_published_at": null,
"latest_published_at": "2026-04-06T13:30:37Z",
"latest_version_yanked": null,
"days_since_latest_publish": 114
}
]
},
"popularity": {
"forks": 0,
"stars": 1,
"watchers": 0,
"fork_history": {
"days": [],
"complete": true,
"collected": 0,
"total_forks": 0
},
"star_history": null,
"open_issues_and_prs": 1
},
"ai_readiness": {
"has_nix": true,
"example_dirs": [],
"has_llms_txt": false,
"has_dockerfile": false,
"has_mcp_signal": false,
"bootstrap_files": [
"Makefile"
],
"api_schema_files": [],
"has_devcontainer": false,
"typecheck_configs": [],
"toolchain_manifests": [
"go.mod"
],
"largest_source_bytes": 18504,
"source_files_sampled": 67,
"oversized_source_files": 0,
"agent_instruction_files": [],
"agent_instruction_max_bytes": null
},
"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": [
{
"name": "github.com/hashicorp/vault/api",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v1.23.0"
},
{
"name": "github.com/keybase/go-keychain",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v0.0.1"
},
{
"name": "github.com/pelletier/go-toml/v2",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v2.3.0"
},
{
"name": "github.com/spf13/cobra",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v1.10.2"
},
{
"name": "golang.org/x/term",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v0.42.0"
}
],
"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": 13,
"open_issues": 1,
"closed_ratio": 0,
"closed_issues": 0,
"closed_unmerged_prs": 1
},
"bus_factor": 1,
"bot_contributors": 0,
"top_contributors": [
{
"type": "User",
"login": "zach-source",
"commits": 60,
"avatar_url": "https://avatars.githubusercontent.com/u/61884887?v=4"
}
],
"contributors_sampled": 1,
"top_contributor_share": 1
},
"quality_signals": {
"has_ci": false,
"has_tests": true,
"ci_workflows": [],
"has_docs_dir": true,
"linter_configs": [],
"has_editorconfig": false,
"has_linter_config": false,
"has_precommit_config": false
},
"security_signals": {
"lockfiles": [
"go.sum"
],
"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": 0,
"reason": "branch protection not enabled on development/release branches",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#branch-protection"
},
{
"name": "CI-Tests",
"score": 0,
"reason": "0 out of 13 merged PRs checked by a CI test -- score normalized to 0",
"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": 0,
"reason": "Found 0/16 approved changesets -- score normalized to 0",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#code-review"
},
{
"name": "Contributors",
"score": 3,
"reason": "project has 1 contributing companies or organizations -- score normalized to 3",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#contributors"
},
{
"name": "Dangerous-Workflow",
"score": null,
"reason": "no workflows found",
"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 1 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": null,
"reason": "packaging workflow not detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#packaging"
},
{
"name": "Pinned-Dependencies",
"score": null,
"reason": "no dependencies found",
"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": 4,
"reason": "security policy file detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#security-policy"
},
{
"name": "Signed-Releases",
"score": null,
"reason": "no releases found",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#signed-releases"
},
{
"name": "Token-Permissions",
"score": null,
"reason": "No tokens found",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#token-permissions"
},
{
"name": "Vulnerabilities",
"score": 0,
"reason": "25 existing vulnerabilities detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#vulnerabilities"
}
],
"commit": "4406b5ab832cd4c29b6e1a655cd2269a3ce13a80",
"ran_at": "2026-07-29T21:23:22Z",
"aggregate_score": 2.9,
"scorecard_version": "v5.5.0"
},
"has_codeql_workflow": false,
"has_security_policy": true,
"has_dependabot_config": false
},
"contribution_flow": {
"collected": true,
"ci_last_run_at": null,
"oldest_open_prs": [],
"last_merged_pr_at": "2026-07-26T18:29:58Z",
"ci_last_conclusion": null,
"oldest_open_issues": [
{
"number": 14,
"created_at": "2026-07-18T04:04:07Z",
"last_comment_at": null,
"last_comment_author": null
}
]
}
},
"config": {
"disabled_metrics": [],
"disabled_categories": [],
"disabled_components": {}
},
"source": {
"url": "https://github.com/zach-source/ccswitch",
"host": "github.com",
"name": "ccswitch",
"owner": "zach-source"
},
"metrics": {
"overall": {
"key": "overall",
"band": "at_risk",
"name": "Overall health",
"note": null,
"notes": [],
"value": 45,
"inputs": {
"security": 29,
"vitality": 75,
"community": 24,
"governance": 46,
"engineering": 44
},
"components": []
},
"categories": [
{
"key": "vitality",
"band": "good",
"name": "Vitality",
"value": 75,
"weight": 0.22,
"metrics": [
{
"key": "development_activity",
"band": "moderate",
"name": "Development activity",
"note": null,
"notes": [],
"value": 69,
"inputs": {
"commits_last_year": 60,
"human_commit_share": 1,
"days_since_last_push": 3,
"active_weeks_last_year": 10
},
"components": [
{
"key": "push_recency",
"name": "Push recency",
"detail": "last push 3 days ago",
"points": 36,
"status": "met",
"details": [
{
"code": "push_recency",
"params": {
"days": 3
}
}
],
"max_points": 36
},
{
"key": "commit_cadence",
"name": "Commit cadence",
"detail": "10/52 weeks with commits",
"points": 6.9,
"status": "partial",
"details": [
{
"code": "commit_cadence_weeks",
"params": {
"weeks": 10
}
}
],
"max_points": 36
},
{
"key": "commit_volume",
"name": "Commit volume",
"detail": "60 commits in the last year",
"points": 16,
"status": "partial",
"details": [
{
"code": "commits_last_year",
"params": {
"count": 60
}
}
],
"max_points": 18
},
{
"key": "openssf_scorecard_maintained",
"name": "OpenSSF Scorecard: Maintained",
"detail": "30 commit(s) and 1 issue activity found in the last 90 days -- score normalized to 10",
"points": 10,
"status": "met",
"details": [],
"max_points": 10
}
]
},
{
"key": "release_discipline",
"band": "good",
"name": "Release discipline",
"note": "Excluded from scoring (no data or not applicable): OpenSSF Scorecard: Signed-Releases. Remaining weights renormalized.",
"notes": [
{
"code": "excluded_no_data",
"params": {
"components": [
"openssf_scorecard_signed_releases"
]
}
},
{
"code": "weights_renormalized",
"params": {}
}
],
"value": 84,
"inputs": {
"releases_count": 1,
"latest_release_tag": "v2.8.0",
"releases_from_tags": false,
"days_since_latest_release": 3,
"mean_days_between_releases": null
},
"components": [
{
"key": "ships_releases",
"name": "Ships releases",
"detail": "1 releases published",
"points": 27,
"status": "met",
"details": [
{
"code": "releases_published",
"params": {
"count": 1
}
}
],
"max_points": 27
},
{
"key": "release_recency",
"name": "Release recency",
"detail": "latest release 3 days ago",
"points": 36,
"status": "met",
"details": [
{
"code": "release_recency",
"params": {
"days": 3
}
}
],
"max_points": 36
},
{
"key": "release_cadence",
"name": "Release cadence",
"detail": "cadence unknown (single release)",
"points": 12.6,
"status": "partial",
"details": [
{
"code": "release_cadence_unknown",
"params": {}
}
],
"max_points": 27
},
{
"key": "openssf_scorecard_signed_releases",
"name": "OpenSSF Scorecard: Signed-Releases",
"detail": "no releases found",
"points": 0,
"status": "excluded",
"details": [
{
"code": "no_data",
"params": {}
}
],
"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": "critical",
"name": "Community & Adoption",
"value": 24,
"weight": 0.18,
"metrics": [
{
"key": "popularity",
"band": "critical",
"name": "Popularity & adoption",
"note": null,
"notes": [],
"value": 1,
"inputs": {
"forks": 0,
"stars": 1,
"watchers": 0,
"growth_state": "unverified",
"growth_factor_pct": 100,
"growth_unverified_reason": "no_history"
},
"components": [
{
"key": "stars",
"name": "Stars",
"detail": "1 stars",
"points": 0,
"status": "missed",
"details": [
{
"code": "stars",
"params": {
"count": 1
}
}
],
"max_points": 60
},
{
"key": "forks",
"name": "Forks",
"detail": "0 forks",
"points": 0,
"status": "missed",
"details": [
{
"code": "forks",
"params": {
"count": 0
}
}
],
"max_points": 25
},
{
"key": "watchers",
"name": "Watchers",
"detail": "0 watchers",
"points": 0,
"status": "missed",
"details": [
{
"code": "watchers",
"params": {
"count": 0
}
}
],
"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": "at_risk",
"name": "Sustainability & Governance",
"value": 46,
"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": 1,
"top_contributor_share": 1
},
"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 100% of commits",
"points": 0,
"status": "missed",
"details": [
{
"code": "top_contributor_share",
"params": {
"share": 100
}
}
],
"max_points": 22.5
},
{
"key": "contributor_breadth",
"name": "Contributor breadth",
"detail": "1 contributors",
"points": 1.4,
"status": "partial",
"details": [
{
"code": "contributors_sampled",
"params": {
"count": 1
}
}
],
"max_points": 13.5
},
{
"key": "openssf_scorecard_contributors",
"name": "OpenSSF Scorecard: Contributors",
"detail": "project has 1 contributing companies or organizations -- score normalized to 3",
"points": 3,
"status": "partial",
"details": [],
"max_points": 10
}
]
},
{
"key": "responsiveness",
"band": "at_risk",
"name": "Issue & PR responsiveness",
"note": null,
"notes": [],
"value": 36,
"inputs": {
"merged_prs": 13,
"open_issues": 1,
"closed_issues": 0,
"issue_closed_ratio": 0,
"closed_unmerged_prs": 1
},
"components": [
{
"key": "issue_resolution",
"name": "Issue resolution",
"detail": "0% of issues closed",
"points": 0,
"status": "missed",
"details": [
{
"code": "issues_closed_share",
"params": {
"share": 0
}
}
],
"max_points": 46.75
},
{
"key": "pr_acceptance",
"name": "PR acceptance",
"detail": "13/14 decided PRs merged",
"points": 35.5,
"status": "partial",
"details": [
{
"code": "decided_prs_merged",
"params": {
"merged": 13,
"decided": 14
}
}
],
"max_points": 38.25
},
{
"key": "openssf_scorecard_code_review",
"name": "OpenSSF Scorecard: Code-Review",
"detail": "Found 0/16 approved changesets -- score normalized to 0",
"points": 0,
"status": "missed",
"details": [],
"max_points": 15
}
]
},
{
"key": "stewardship",
"band": "moderate",
"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": 54,
"inputs": {
"followers": 12,
"owner_type": "User",
"is_verified": null,
"owner_login": "zach-source",
"public_repos": 90,
"account_age_days": 2336
},
"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": "12 followers of zach-source",
"points": 8,
"status": "partial",
"details": [
{
"code": "owner_followers",
"params": {
"count": 12,
"login": "zach-source"
}
}
],
"max_points": 25
},
{
"key": "track_record",
"name": "Track record",
"detail": "90 public repos, account ~6 yr old",
"points": 25,
"status": "met",
"details": [
{
"code": "public_repos",
"params": {
"count": 90
}
},
{
"code": "account_age_years",
"params": {
"years": 6
}
}
],
"max_points": 25
}
]
},
{
"key": "package_maintenance",
"band": "excellent",
"name": "Package maintenance",
"note": null,
"notes": [],
"value": 100,
"inputs": {
"packages": [
"github.com/zach-source/ccswitch"
],
"ecosystems": "go",
"any_deprecated": false,
"min_days_since_publish": 114
},
"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 114 days ago",
"points": 35,
"status": "met",
"details": [
{
"code": "publish_recency",
"params": {
"days": 114
}
}
],
"max_points": 35
},
{
"key": "version_history",
"name": "Version history",
"detail": "17 published versions",
"points": 20,
"status": "met",
"details": [
{
"code": "published_versions",
"params": {
"count": 17
}
}
],
"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": "at_risk",
"name": "Engineering Quality",
"value": 44,
"weight": 0.2,
"metrics": [
{
"key": "engineering_practices",
"band": "critical",
"name": "Engineering practices",
"note": null,
"notes": [],
"value": 24,
"inputs": {
"has_ci": false,
"has_tests": true,
"has_editorconfig": false,
"has_linter_config": false,
"has_precommit_config": false
},
"components": [
{
"key": "ci_workflows",
"name": "CI workflows",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"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": null,
"points": 0,
"status": "missed",
"details": [],
"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": "0 out of 13 merged PRs checked by a CI test -- score normalized to 0",
"points": 0,
"status": "missed",
"details": [],
"max_points": 20
}
]
},
{
"key": "documentation",
"band": "good",
"name": "Documentation",
"note": null,
"notes": [],
"value": 75,
"inputs": {
"topics": [],
"has_wiki": true,
"homepage": null,
"has_readme": true,
"has_docs_dir": true,
"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": 25,
"status": "met",
"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": "critical",
"name": "Security",
"value": 29,
"weight": 0.16,
"metrics": [
{
"key": "security_posture",
"band": "critical",
"name": "Security posture",
"note": "Excluded from scoring (no data or not applicable): Dangerous-Workflow, Packaging, Pinned-Dependencies, Signed-Releases, Token-Permissions. Remaining weights renormalized.",
"notes": [
{
"code": "excluded_no_data",
"params": {
"components": [
"dangerous_workflow",
"packaging",
"pinned_dependencies",
"signed_releases",
"token_permissions"
]
}
},
{
"code": "weights_renormalized",
"params": {}
}
],
"value": 29,
"inputs": {
"source": "openssf_scorecard",
"checks_evaluated": 13,
"scorecard_version": "v5.5.0",
"checks_inconclusive": 5,
"scorecard_aggregate": 2.9
},
"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 not enabled on development/release branches",
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.5
},
{
"key": "ci_tests",
"name": "CI-Tests",
"detail": "0 out of 13 merged PRs checked by a CI test -- score normalized to 0",
"points": 0,
"status": "missed",
"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 0/16 approved changesets -- score normalized to 0",
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.5
},
{
"key": "contributors",
"name": "Contributors",
"detail": "project has 1 contributing companies or organizations -- score normalized to 3",
"points": 0.8,
"status": "partial",
"details": [],
"max_points": 2.5
},
{
"key": "dangerous_workflow",
"name": "Dangerous-Workflow",
"detail": "no workflows found",
"points": 0,
"status": "excluded",
"details": [
{
"code": "no_data",
"params": {}
}
],
"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 1 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 not detected",
"points": 0,
"status": "excluded",
"details": [
{
"code": "no_data",
"params": {}
}
],
"max_points": 5
},
{
"key": "pinned_dependencies",
"name": "Pinned-Dependencies",
"detail": "no dependencies found",
"points": 0,
"status": "excluded",
"details": [
{
"code": "no_data",
"params": {}
}
],
"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 detected",
"points": 2,
"status": "partial",
"details": [],
"max_points": 5
},
{
"key": "signed_releases",
"name": "Signed-Releases",
"detail": "no releases found",
"points": 0,
"status": "excluded",
"details": [
{
"code": "no_data",
"params": {}
}
],
"max_points": 7.5
},
{
"key": "token_permissions",
"name": "Token-Permissions",
"detail": "No tokens found",
"points": 0,
"status": "excluded",
"details": [
{
"code": "no_data",
"params": {}
}
],
"max_points": 7.5
},
{
"key": "vulnerabilities",
"name": "Vulnerabilities",
"detail": "25 existing vulnerabilities detected",
"points": 0,
"status": "missed",
"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": 64,
"weight": 0,
"metrics": [
{
"key": "ai_agent_context",
"band": "at_risk",
"name": "Agent context & guidance",
"note": null,
"notes": [],
"value": 40,
"inputs": {
"has_llms_txt": false,
"legible_history_share": 1,
"agent_instruction_files": [],
"agent_instruction_max_bytes": null
},
"components": [
{
"key": "agent_instructions",
"name": "Agent instructions",
"detail": "no CLAUDE.md / AGENTS.md / editor rules",
"points": 0,
"status": "missed",
"details": [
{
"code": "no_agent_instructions",
"params": {}
}
],
"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": "60 of 60 human commits state their intent (structured subject or explanatory body)",
"points": 40,
"status": "met",
"details": [
{
"code": "legible_history",
"params": {
"legible": 60,
"sampled": 60
}
}
],
"max_points": 40
}
]
},
{
"key": "ai_verify_loop",
"band": "moderate",
"name": "Verify loop (build / test / typecheck)",
"note": "Excluded from scoring (no data or not applicable): OpenSSF Scorecard: Pinned-Dependencies. Remaining weights renormalized.",
"notes": [
{
"code": "excluded_no_data",
"params": {
"components": [
"openssf_scorecard_pinned_dependencies"
]
}
},
{
"code": "weights_renormalized",
"params": {}
}
],
"value": 68,
"inputs": {
"has_nix": true,
"has_tests": true,
"lockfiles": [
"go.sum"
],
"has_dockerfile": false,
"typed_language": true,
"bootstrap_files": [
"Makefile"
],
"has_devcontainer": false,
"has_linter_config": false,
"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": "Makefile",
"points": 18,
"status": "met",
"details": [
{
"code": "file_list",
"params": {
"files": "Makefile"
}
}
],
"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": null,
"points": 0,
"status": "missed",
"details": [],
"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": "Nix, lockfile",
"points": 10,
"status": "met",
"details": [
{
"code": "file_list",
"params": {
"files": "Nix, lockfile"
}
}
],
"max_points": 10
},
{
"key": "demonstrated_agent_practice",
"name": "Demonstrated agent practice",
"detail": "no agent-authored commits among the last 60",
"points": 0,
"status": "missed",
"details": [
{
"code": "no_agent_authored_commits",
"params": {
"sampled": 60
}
}
],
"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": "no dependencies found",
"points": 0,
"status": "excluded",
"details": [
{
"code": "no_data",
"params": {}
}
],
"max_points": 10
}
]
},
{
"key": "ai_code_legibility",
"band": "excellent",
"name": "Code legibility for models",
"note": null,
"notes": [],
"value": 100,
"inputs": {
"primary_language": "Go",
"largest_source_bytes": 18504,
"source_files_sampled": 67,
"oversized_source_files": 0
},
"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": "0/67 source files over 60KB",
"points": 55,
"status": "met",
"details": [
{
"code": "oversized_source_files",
"params": {
"kb": 60,
"sampled": 67,
"oversized": 0
}
}
],
"max_points": 55
}
]
}
],
"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-29T21:23:35.110544Z",
"schema_version": "0.27.0",
"badge_url": "https://raw.githubusercontent.com/inspect-software/badges/main/v1/z/zach-source/ccswitch.svg",
"full_name": "zach-source/ccswitch",
"license_state": "standard",
"license_spdx": "MIT"
}