Public record
Software health reportschema 0.26.0 · metrics 1.13.0 · 2026-07-22 19:08 UTC

itdove / ai-guardian

AI IDE security hook: blocks directories, scans secrets, and protects AI interactions

PythonCustom license★ 10 stars⑂ 5 forkssince Mar 2026View on GitHub ↗

itdove/ai-guardian holds a health index of 64 out of 100, placing it in the Moderate band. It scores highest on Vitality (82/100) and lowest on Community & Adoption (41/100). It was last updated today. A single contributor accounts for most of its recent work.

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

64
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

Dominique VernierPersonal account
6 followers77 public repossince May 2017Red Hat

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 publishTags
PyPIai-guardian1.15.0-330 days agoaiclaudecursorgitleakshookssecretssecurity

Metrics by category

Vitality

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

82Good · 22% of overall
How it's scored
36/36Push recency — last push 0 days ago
11.8/36Commit cadence — 17/52 weeks with commits
18/18Commit volume — 1,722 commits in the last year
10/10OpenSSF Scorecard: Maintained — 30 commit(s) and 30 issue activity found in the last 90 days -- score normalized to 10
Inputs used
commits_last_year1,722
human_commit_share1
days_since_last_push0
active_weeks_last_year17
How it's scored
27/27Ships releases — 100 releases published
36/36Release recency — latest release 0 days ago
27/27Release cadence — a release every ~0.1 days
0/10OpenSSF Scorecard: Signed-Releases — Project has not signed or included provenance with any releases.
Inputs used
releases_count100
latest_release_tagrc-1.16.0-dev-main.2f11f5e
releases_from_tagsno
days_since_latest_release0
mean_days_between_releases0.1

Community & Adoption

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

41At risk · 18% of overall
How it's scored
15.5/60Stars — 10 stars
5/25Forks — 5 forks
0/15Watchers — 0 watchers
Inputs used
forks5
stars10
watchers0
growth_stateunverified
growth_factor_pct100
growth_unverified_reasonno_history
How it's scored
22.5/22.5README
16.9/22.5License — license file present, not a recognized license
18/18CONTRIBUTING guide
0/13.5Code of conduct
0/7.2Issue template
0/6.3PR template
Inputs used
has_readmeyes
has_licenseyes
has_contributingyes
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?

59Moderate · 24% of overall
How it's scored
9/54Bus factor — 1 contributor(s) cover half of all commits
0/22.5Commit distribution — top contributor authored 100% of commits
2.7/13.5Contributor breadth — 2 contributors
6/10OpenSSF Scorecard: Contributors — project has 2 contributing companies or organizations -- score normalized to 6
Inputs used
bus_factor1
contributors_sampled2
top_contributor_share0.998
How it's scored
45/46.8Issue resolution — 96% of issues closed
38.2/38.3PR acceptance — 811/813 decided PRs merged
0/15OpenSSF Scorecard: Code-Review — Found 0/30 approved changesets -- score normalized to 0
Inputs used
merged_prs811
open_issues33
closed_issues865
issue_closed_ratio0.963
closed_unmerged_prs2
How it's scored
10/30Ownership backing — personal (user) account
0/20Verified domain — not applicable to user accounts
6.1/25Owner reach — 6 followers of itdove
25/25Track record — 77 public repos, account ~9 yr old
Inputs used
followers6
owner_typeUser
is_verified
owner_loginitdove
public_repos77
account_age_days3,359
Excluded from scoring (no data or not applicable): Verified domain. Remaining weights renormalized.
How it's scored
25/25Published & resolvable — 1 package(s) on pypi
35/35Publish recency — latest publish 0 days ago
20/20Version history — 33 published versions
20/20Not deprecated — active, not deprecated or yanked
Inputs used
packagesai-guardian
ecosystemspypi
any_deprecatedno
min_days_since_publish0

Engineering Quality

Are baseline engineering and documentation practices in place?

82Good · 20% of overall
How it's scored
24/24CI workflows — 12 workflow(s)
24/24Tests present
16/16Linter config
9.6/9.6Pre-commit hooks
0/6.4.editorconfig
20/20OpenSSF Scorecard: CI-Tests — 26 out of 26 merged PRs checked by a CI test -- score normalized to 10
Inputs used
has_ciyes
has_testsyes
has_editorconfigno
has_linter_configyes
has_precommit_configyes

Documentation

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

Security

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

53Moderate · 16% of overall
How it's scored
7.5/7.5Binary-Artifacts — no binaries found in the repo
4.5/7.5Branch-Protection — branch protection is not maximal on development and all release branches
2.5/2.5CI-Tests — 26 out of 26 merged PRs checked by a CI test -- score normalized to 10
0/2.5CII-Best-Practices — no effort to earn an OpenSSF best practices badge detected
0/7.5Code-Review — Found 0/30 approved changesets -- score normalized to 0
1.5/2.5Contributors — project has 2 contributing companies or organizations -- score normalized to 6
10/10Dangerous-Workflow — no dangerous workflow patterns detected
7.5/7.5Dependency-Update-Tool — update tool detected
0/5Fuzzing — project is not fuzzed
2.2/2.5License — license file detected
7.5/7.5Maintained — 30 commit(s) and 30 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_aggregate5.3

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.

73Good · 0% of overall
How it's scored
45/45Agent instructions — AGENTS.md, CLAUDE.md, examples/aider/.aider.conf.yml
0/15Machine-readable docs (llms.txt)
40/40Legible commit history — 99 of 100 human commits state their intent (structured subject or explanatory body)
Inputs used
has_llms_txtno
legible_history_share0.99
agent_instruction_filesAGENTS.md, CLAUDE.md, examples/aider/.aider.conf.yml
agent_instruction_max_bytes70,167
How it's scored
18/18One-command bootstrap — Makefile
22/22Automated tests
11/11Lint / format config
0/11Static type checking
10/10Reproducible environment — Dockerfile
10/10Demonstrated agent practice — 99 of the last 100 commits agent-authored or agent-credited
5/8Automated maintenance — dependency automation configured, none observed in the sampled commits
0/10OpenSSF Scorecard: Pinned-Dependencies — dependency not pinned by hash detected -- score normalized to 0
Inputs used
has_nixno
has_testsyes
lockfiles
has_dockerfileyes
typed_languageno
bootstrap_filesMakefile
has_devcontainerno
has_linter_configyes
typecheck_configs
agent_commit_share0.99
toolchain_manifests
dependency_bot_commit_share0
How it's scored
0/45Type-checkable code — Python without a type-check config
53.3/55Manageable file sizes — 17/558 source files over 60KB
Inputs used
primary_languagePython
largest_source_bytes259,298
source_files_sampled558
oversized_source_files17
How it's scored
0/40API schema (OpenAPI/GraphQL/proto)
20/20MCP server
40/40Runnable examples — examples
Inputs used
example_dirsexamples
has_mcp_signalyes
api_schema_files

Key facts

10GitHub stars
2contributors
1,722commits, last 12 months
0days since last push
100releases
1bus factor
33open issues
PyPIpackage ecosystems

Data collection warnings

  • Star history unavailable: GitHub GraphQL error: Resource not accessible by personal access token
  • deps.dev does not index pypi:ai-guardian@1.15.0; advisories assessed against the repository dependency graph instead
  • No resolved dependencies carried a version and a supported ecosystem

More detail

Star and fork history 0 ★ / 5 ⇿
0Stars
5Forks

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.

12345512026-042026-052026-06
OpenSSF Scorecard 5.3 / 10
5.3aggregate

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-22 19:07 UTC

10Binary-Artifactsno binaries found in the repo
6Branch-Protectionbranch protection is not maximal on development and all release branches
10CI-Tests26 out of 26 merged PRs checked by a CI test -- score normalized to 10
0CII-Best-Practicesno effort to earn an OpenSSF best practices badge detected
0Code-ReviewFound 0/30 approved changesets -- score normalized to 0
6Contributorsproject has 2 contributing companies or organizations -- score normalized to 6
10Dangerous-Workflowno dangerous workflow patterns detected
10Dependency-Update-Toolupdate tool detected
0Fuzzingproject is not fuzzed
9Licenselicense file detected
10Maintained30 commit(s) and 30 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
Direct dependencies 28
RegistryPackageVersion constraintManifest
PyPItextual>=0.47.0pyproject.toml
PyPIjsonschema>=4.0.0pyproject.toml
PyPIrequests>=2.28.0pyproject.toml
PyPItomli>=2.0.0pyproject.toml
PyPItomli-w>=1.0.0pyproject.toml
PyPIpyyaml>=6.0.0pyproject.toml
PyPItree-sitter>=0.25.0pyproject.toml
PyPItree-sitter-json>=0.24.0pyproject.toml
PyPItree-sitter-python>=0.23pyproject.toml
PyPItree-sitter-javascript>=0.23pyproject.toml
PyPItree-sitter-typescript>=0.23pyproject.toml
PyPItree-sitter-go>=0.23pyproject.toml
PyPItree-sitter-rust>=0.23pyproject.toml
PyPItree-sitter-java>=0.23pyproject.toml
PyPItree-sitter-ruby>=0.23pyproject.toml
PyPItree-sitter-c>=0.23pyproject.toml
PyPItree-sitter-cpp>=0.23pyproject.toml
PyPItree-sitter-bash>=0.23pyproject.toml
PyPIpystray>=0.19.0pyproject.toml
PyPIPillow>=9.0.0pyproject.toml
PyPIdocker>=7.0,<9pyproject.toml
PyPImcp>=1.10.0pyproject.toml
PyPIrapidocr-onnxruntime>=1.4.0pyproject.toml
PyPIonnxruntime>=1.15.0pyproject.toml
PyPInicegui>=3.0.0pyproject.toml
PyPItokenizers>=0.15.0pyproject.toml
PyPIboto3>=1.28.0pyproject.toml
PyPIbandit>=1.7.0pyproject.toml
All dependencies 29

Full resolved dependency set from the GitHub dependency graph: 26 direct and 3 indirect (transitive) packages. The transitive closure is complete when the repository commits a lockfile.

RegistryPackageVersionRelation
PyPIbanditdirect
PyPIboto3direct
PyPIdockerdirect
PyPIjsonschemadirect
PyPImcpdirect
PyPIniceguidirect
PyPIonnxruntimedirect
PyPIpillowdirect
PyPIpystraydirect
PyPIpyyamldirect
PyPIrequestsdirect
PyPItextualdirect
PyPItokenizersdirect
PyPItomli-wdirect
PyPItree-sitterdirect
PyPItree-sitter-bashdirect
PyPItree-sitter-cdirect
PyPItree-sitter-cppdirect
PyPItree-sitter-godirect
PyPItree-sitter-javadirect
PyPItree-sitter-javascriptdirect
PyPItree-sitter-jsondirect
PyPItree-sitter-pythondirect
PyPItree-sitter-rubydirect
PyPItree-sitter-rustdirect
PyPItree-sitter-typescriptdirect
PyPIpygobjectindirect
PyPIpytestindirect
PyPIpytest-asyncioindirect
Dependency advisories not assessed

Advisory matching could not run for this report: No resolved dependencies carried a version and a supported ecosystem

Raw JSON report machine-readable
{
  "data": {
    "repo": {
      "topics": [],
      "is_fork": false,
      "size_kb": 18540,
      "has_wiki": false,
      "homepage": null,
      "languages": {
        "Shell": 65736,
        "Python": 9412247,
        "Makefile": 230,
        "Dockerfile": 6869,
        "PowerShell": 9832
      },
      "pushed_at": "2026-07-22T17:41:21Z",
      "created_at": "2026-03-23T16:55:42Z",
      "owner_type": "User",
      "updated_at": "2026-07-22T17:41:18Z",
      "description": "AI IDE security hook: blocks directories, scans secrets, and protects AI interactions",
      "is_archived": false,
      "is_disabled": false,
      "license_spdx": null,
      "default_branch": "main",
      "license_spdx_raw": "NOASSERTION",
      "primary_language": "Python",
      "significant_languages": [
        "Python"
      ]
    },
    "owner": {
      "blog": null,
      "name": "Dominique Vernier",
      "type": "User",
      "login": "itdove",
      "company": "Red Hat",
      "location": null,
      "followers": 6,
      "avatar_url": "https://avatars.githubusercontent.com/u/28610057?v=4",
      "created_at": "2017-05-10T21:35:07Z",
      "is_verified": null,
      "public_repos": 77,
      "account_age_days": 3359
    },
    "license": {
      "state": "custom",
      "spdx_id": null,
      "raw_spdx": "NOASSERTION",
      "file_present": true,
      "scorecard_found": true,
      "profile_has_license": true
    },
    "activity": {
      "releases": [
        {
          "tag": "rc-1.16.0-dev-main.2f11f5e",
          "kind": "other",
          "published_at": "2026-07-22T17:41:22Z"
        },
        {
          "tag": "rc-1.16.0-dev-main.22b17fd",
          "kind": "other",
          "published_at": "2026-07-22T17:40:35Z"
        },
        {
          "tag": "v1.15.0",
          "kind": "minor",
          "published_at": "2026-07-22T17:38:15Z"
        },
        {
          "tag": "rc-1.15.0-dev-1713",
          "kind": "other",
          "published_at": "2026-07-22T16:42:05Z"
        },
        {
          "tag": "rc-1.15.0-dev-1709",
          "kind": "other",
          "published_at": "2026-07-22T13:02:07Z"
        },
        {
          "tag": "rc-1.15.0-dev-1708",
          "kind": "other",
          "published_at": "2026-07-22T11:44:47Z"
        },
        {
          "tag": "rc-1.15.0-dev-1707",
          "kind": "other",
          "published_at": "2026-07-22T11:23:10Z"
        },
        {
          "tag": "rc-1.15.0-dev-1705",
          "kind": "other",
          "published_at": "2026-07-22T10:21:04Z"
        },
        {
          "tag": "rc-1.15.0-dev-1704",
          "kind": "other",
          "published_at": "2026-07-22T01:45:37Z"
        },
        {
          "tag": "rc-1.15.0-dev-1703",
          "kind": "other",
          "published_at": "2026-07-22T01:42:20Z"
        },
        {
          "tag": "rc-1.15.0-dev-1702",
          "kind": "other",
          "published_at": "2026-07-22T01:00:19Z"
        },
        {
          "tag": "rc-1.15.0-dev-1699",
          "kind": "other",
          "published_at": "2026-07-22T00:19:01Z"
        },
        {
          "tag": "rc-1.15.0-dev-1698",
          "kind": "other",
          "published_at": "2026-07-21T23:25:57Z"
        },
        {
          "tag": "rc-1.15.0-dev-1697",
          "kind": "other",
          "published_at": "2026-07-21T23:06:39Z"
        },
        {
          "tag": "rc-1.15.0-dev-1696",
          "kind": "other",
          "published_at": "2026-07-21T20:52:13Z"
        },
        {
          "tag": "rc-1.15.0-dev-1695",
          "kind": "other",
          "published_at": "2026-07-21T20:07:53Z"
        },
        {
          "tag": "rc-1.15.0-dev-1694",
          "kind": "other",
          "published_at": "2026-07-21T19:35:52Z"
        },
        {
          "tag": "rc-1.15.0-dev-1693",
          "kind": "other",
          "published_at": "2026-07-21T18:24:46Z"
        },
        {
          "tag": "rc-1.15.0-dev-1677",
          "kind": "other",
          "published_at": "2026-07-21T17:43:00Z"
        },
        {
          "tag": "rc-1.15.0-dev-1691",
          "kind": "other",
          "published_at": "2026-07-21T17:42:44Z"
        },
        {
          "tag": "rc-1.15.0-dev-1685",
          "kind": "other",
          "published_at": "2026-07-21T16:47:54Z"
        },
        {
          "tag": "rc-1.15.0-dev-1674",
          "kind": "other",
          "published_at": "2026-07-21T16:47:31Z"
        },
        {
          "tag": "rc-1.15.0-dev-1679",
          "kind": "other",
          "published_at": "2026-07-21T14:05:00Z"
        },
        {
          "tag": "rc-1.15.0-dev-1665",
          "kind": "other",
          "published_at": "2026-07-21T12:35:06Z"
        },
        {
          "tag": "rc-1.15.0-dev-1675",
          "kind": "other",
          "published_at": "2026-07-20T20:57:13Z"
        },
        {
          "tag": "rc-1.15.0-dev-1673",
          "kind": "other",
          "published_at": "2026-07-20T20:52:45Z"
        },
        {
          "tag": "rc-1.15.0-dev-1671",
          "kind": "other",
          "published_at": "2026-07-20T20:07:43Z"
        },
        {
          "tag": "rc-1.15.0-dev-1653",
          "kind": "other",
          "published_at": "2026-07-20T20:07:35Z"
        },
        {
          "tag": "rc-1.15.0-dev-1666",
          "kind": "other",
          "published_at": "2026-07-20T19:11:24Z"
        },
        {
          "tag": "rc-1.15.0-dev-1585",
          "kind": "other",
          "published_at": "2026-07-20T17:25:40Z"
        },
        {
          "tag": "rc-1.15.0-dev-1661",
          "kind": "other",
          "published_at": "2026-07-20T16:29:48Z"
        },
        {
          "tag": "rc-1.15.0-dev-1659",
          "kind": "other",
          "published_at": "2026-07-20T16:01:01Z"
        },
        {
          "tag": "rc-1.15.0-dev-1658",
          "kind": "other",
          "published_at": "2026-07-20T15:40:16Z"
        },
        {
          "tag": "rc-1.15.0-dev-1656",
          "kind": "other",
          "published_at": "2026-07-20T15:15:53Z"
        },
        {
          "tag": "rc-1.15.0-dev-1654",
          "kind": "other",
          "published_at": "2026-07-20T14:07:30Z"
        },
        {
          "tag": "rc-1.15.0-dev-1652",
          "kind": "other",
          "published_at": "2026-07-20T13:19:19Z"
        },
        {
          "tag": "rc-1.15.0-dev-1651",
          "kind": "other",
          "published_at": "2026-07-17T22:29:39Z"
        },
        {
          "tag": "rc-1.15.0-dev-1650",
          "kind": "other",
          "published_at": "2026-07-17T20:58:46Z"
        },
        {
          "tag": "rc-1.15.0-dev-1649",
          "kind": "other",
          "published_at": "2026-07-17T20:24:34Z"
        },
        {
          "tag": "rc-1.15.0-dev-1642",
          "kind": "other",
          "published_at": "2026-07-17T19:42:06Z"
        },
        {
          "tag": "rc-1.15.0-dev-1648",
          "kind": "other",
          "published_at": "2026-07-17T19:39:50Z"
        },
        {
          "tag": "rc-1.15.0-dev-1646",
          "kind": "other",
          "published_at": "2026-07-17T19:11:54Z"
        },
        {
          "tag": "rc-1.15.0-dev-1645",
          "kind": "other",
          "published_at": "2026-07-17T19:05:07Z"
        },
        {
          "tag": "rc-1.15.0-dev-1640",
          "kind": "other",
          "published_at": "2026-07-17T18:37:49Z"
        },
        {
          "tag": "rc-1.15.0-dev-1638",
          "kind": "other",
          "published_at": "2026-07-17T17:14:12Z"
        },
        {
          "tag": "rc-1.15.0-dev-1637",
          "kind": "other",
          "published_at": "2026-07-17T16:27:58Z"
        },
        {
          "tag": "rc-1.15.0-dev-1635",
          "kind": "other",
          "published_at": "2026-07-17T15:56:23Z"
        },
        {
          "tag": "rc-1.15.0-dev-1630",
          "kind": "other",
          "published_at": "2026-07-17T15:42:52Z"
        },
        {
          "tag": "rc-1.15.0-dev-1632",
          "kind": "other",
          "published_at": "2026-07-17T14:42:53Z"
        },
        {
          "tag": "rc-1.15.0-dev-1631",
          "kind": "other",
          "published_at": "2026-07-17T12:38:42Z"
        },
        {
          "tag": "rc-1.15.0-dev-1629",
          "kind": "other",
          "published_at": "2026-07-17T11:47:58Z"
        },
        {
          "tag": "rc-1.15.0-dev-1624",
          "kind": "other",
          "published_at": "2026-07-17T11:33:18Z"
        },
        {
          "tag": "rc-1.15.0-dev-1623",
          "kind": "other",
          "published_at": "2026-07-17T10:13:44Z"
        },
        {
          "tag": "rc-1.15.0-dev-1606",
          "kind": "other",
          "published_at": "2026-07-16T18:20:14Z"
        },
        {
          "tag": "rc-1.15.0-dev-1619",
          "kind": "other",
          "published_at": "2026-07-16T17:15:02Z"
        },
        {
          "tag": "rc-1.15.0-dev-1615",
          "kind": "other",
          "published_at": "2026-07-16T15:14:49Z"
        },
        {
          "tag": "rc-1.15.0-dev-1613",
          "kind": "other",
          "published_at": "2026-07-16T14:16:51Z"
        },
        {
          "tag": "rc-1.15.0-dev-1610",
          "kind": "other",
          "published_at": "2026-07-16T13:43:45Z"
        },
        {
          "tag": "rc-1.15.0-dev-1611",
          "kind": "other",
          "published_at": "2026-07-16T13:09:18Z"
        },
        {
          "tag": "rc-1.15.0-dev-1604",
          "kind": "other",
          "published_at": "2026-07-16T00:16:39Z"
        },
        {
          "tag": "rc-1.15.0-dev-1605",
          "kind": "other",
          "published_at": "2026-07-15T22:26:57Z"
        },
        {
          "tag": "rc-1.15.0-dev-937",
          "kind": "other",
          "published_at": "2026-07-15T20:30:17Z"
        },
        {
          "tag": "rc-1.15.0-dev-1602",
          "kind": "other",
          "published_at": "2026-07-15T19:02:39Z"
        },
        {
          "tag": "rc-1.15.0-dev-936",
          "kind": "other",
          "published_at": "2026-07-15T10:38:36Z"
        },
        {
          "tag": "rc-1.15.0-dev-1598",
          "kind": "other",
          "published_at": "2026-07-14T20:55:40Z"
        },
        {
          "tag": "rc-1.15.0-dev-650",
          "kind": "other",
          "published_at": "2026-07-14T20:47:37Z"
        },
        {
          "tag": "rc-1.15.0-dev-1597",
          "kind": "other",
          "published_at": "2026-07-14T20:44:26Z"
        },
        {
          "tag": "rc-1.15.0-dev-1593",
          "kind": "other",
          "published_at": "2026-07-14T18:36:26Z"
        },
        {
          "tag": "rc-1.15.0-dev-1592",
          "kind": "other",
          "published_at": "2026-07-14T16:40:56Z"
        },
        {
          "tag": "rc-1.15.0-dev-main.b0ebcb5",
          "kind": "other",
          "published_at": "2026-07-13T20:00:14Z"
        },
        {
          "tag": "rc-1.15.0-dev-main.ecd036d",
          "kind": "other",
          "published_at": "2026-07-13T19:10:06Z"
        },
        {
          "tag": "v1.14.0",
          "kind": "minor",
          "published_at": "2026-07-13T17:47:12Z"
        },
        {
          "tag": "rc-1.14.0-dev-main.7f6aab6",
          "kind": "other",
          "published_at": "2026-07-13T14:25:34Z"
        },
        {
          "tag": "rc-1.14.0-dev-1567",
          "kind": "other",
          "published_at": "2026-07-12T16:43:08Z"
        },
        {
          "tag": "rc-1.14.0-dev-1534",
          "kind": "other",
          "published_at": "2026-07-09T08:31:06Z"
        },
        {
          "tag": "rc-1.14.0-dev-1533",
          "kind": "other",
          "published_at": "2026-07-09T08:31:03Z"
        },
        {
          "tag": "rc-1.14.0-dev-main.3180b07",
          "kind": "other",
          "published_at": "2026-07-09T00:44:28Z"
        },
        {
          "tag": "rc-1.14.0-dev-main.496f536",
          "kind": "other",
          "published_at": "2026-07-09T00:43:27Z"
        },
        {
          "tag": "v1.13.3",
          "kind": "patch",
          "published_at": "2026-07-09T00:41:28Z"
        },
        {
          "tag": "rc-1.14.0-dev-1528",
          "kind": "other",
          "published_at": "2026-07-08T21:50:30Z"
        },
        {
          "tag": "rc-1.14.0-dev-1525",
          "kind": "other",
          "published_at": "2026-07-08T20:33:59Z"
        },
        {
          "tag": "rc-1.14.0-dev-1524",
          "kind": "other",
          "published_at": "2026-07-08T20:14:11Z"
        },
        {
          "tag": "rc-1.14.0-dev-1523",
          "kind": "other",
          "published_at": "2026-07-08T19:41:46Z"
        },
        {
          "tag": "rc-1.14.0-dev-1517",
          "kind": "other",
          "published_at": "2026-07-08T19:04:41Z"
        },
        {
          "tag": "rc-1.14.0-dev-1519",
          "kind": "other",
          "published_at": "2026-07-08T17:24:31Z"
        },
        {
          "tag": "rc-1.14.0-dev-1518",
          "kind": "other",
          "published_at": "2026-07-08T17:19:51Z"
        },
        {
          "tag": "rc-1.14.0-dev-1516",
          "kind": "other",
          "published_at": "2026-07-08T16:54:42Z"
        },
        {
          "tag": "rc-1.14.0-dev-1515",
          "kind": "other",
          "published_at": "2026-07-08T16:37:39Z"
        },
        {
          "tag": "rc-1.14.0-dev-1514",
          "kind": "other",
          "published_at": "2026-07-08T16:26:40Z"
        },
        {
          "tag": "rc-1.14.0-dev-1511",
          "kind": "other",
          "published_at": "2026-07-08T15:48:18Z"
        },
        {
          "tag": "rc-1.14.0-dev-1509",
          "kind": "other",
          "published_at": "2026-07-08T14:10:58Z"
        },
        {
          "tag": "rc-1.14.0-dev-1506",
          "kind": "other",
          "published_at": "2026-07-08T14:10:24Z"
        },
        {
          "tag": "rc-1.14.0-dev-1499",
          "kind": "other",
          "published_at": "2026-07-08T12:44:09Z"
        },
        {
          "tag": "rc-1.14.0-dev-1502",
          "kind": "other",
          "published_at": "2026-07-08T10:44:16Z"
        },
        {
          "tag": "rc-1.14.0-dev-1498",
          "kind": "other",
          "published_at": "2026-07-07T15:45:18Z"
        },
        {
          "tag": "rc-1.14.0-dev-main.ffed89e",
          "kind": "other",
          "published_at": "2026-07-06T20:05:30Z"
        },
        {
          "tag": "v1.13.2",
          "kind": "patch",
          "published_at": "2026-07-06T19:46:27Z"
        },
        {
          "tag": "rc-1.14.0-dev-main.1ea6c76",
          "kind": "other",
          "published_at": "2026-07-06T19:41:11Z"
        },
        {
          "tag": "rc-1.14.0-dev-main.2e7febc",
          "kind": "other",
          "published_at": "2026-07-06T19:24:58Z"
        },
        {
          "tag": "v1.13.1",
          "kind": "patch",
          "published_at": "2026-07-06T19:18:14Z"
        }
      ],
      "recent_commits": [
        {
          "oid": "2f11f5ed6f722e95a2f1618c918bff5049334bda",
          "body": "Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs: regenerate notebooklm-export.md for v1.15.0",
          "author_name": "itdove",
          "author_login": "itdove",
          "committed_at": "2026-07-22T17:41:00Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "22b17fde013091f1d2ce62f30a8d3b1e0232eaac",
          "body": "Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore: bump version to 1.16.0-dev, reset README URLs to main",
          "author_name": "itdove",
          "author_login": "itdove",
          "committed_at": "2026-07-22T17:40:02Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "f3eed84a621a633462e400f8563f17608064f119",
          "body": null,
          "is_bot": false,
          "headline": "Merge release-1.15 into main",
          "author_name": "itdove",
          "author_login": "itdove",
          "committed_at": "2026-07-22T17:39:21Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "36471c37308555bf59b54650cfba0bea16e32688",
          "body": "- Bump version 1.15.0-dev → 1.15.0 in pyproject.toml and __init__.py\n- Populate CHANGELOG.md with all v1.15.0 changes (Added/Changed/Fixed/Security)\n- Remove 23 duplicate \"Exfiltration behavior detection\" entries from old releases\n- Update README: integration table (5→14 IDEs), feature rows, pattern\n[…]\nility verification\n- Update docs: CONFIGURATION, COOKBOOK, TOML_PATTERNS, SECRET_SCANNING, MULTI_DAEMON_TRAY, SCANNER_INSTALLATION\n\nCo-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore: prepare v1.15.0 release",
          "author_name": "itdove",
          "author_login": "itdove",
          "committed_at": "2026-07-22T17:28:13Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "79806ddd7213ca0b02e4674eae44720b1f848dad",
          "body": "…#1713)\n\n- Change missing config file status from failure to informational skip\n- Remove all_configured = False assignment for missing config paths\n- Add test for missing config file not causing FAIL status\n- Add test for mixed configured + missing config producing PASS\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: treat missing IDE config as \"not installed\" instead of failure (…",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-22T16:41:44Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "0a4766ff49e0ca454c4fe0d413c51cc00efdd4dc",
          "body": "- Add credentials-in-git-url rule to secrets.toml with regex matching\n  real passwords/tokens while skipping placeholders and env vars\n- Add detection and false-positive test cases for GitHub, GitLab,\n  Bitbucket, and Azure DevOps URL patterns\n- Exclude test_bundled_toml.py from gitleaks scanning\n- Bump secrets.toml expected rule count to 85\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: detect credentials embedded in git remote URLs (#1709)",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-22T13:01:46Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "2b1148d9f46a026ece031392dc7c3663ad0f0203",
          "body": "- Relocate MCP Security nav item from Configuration to Tools group\n  in both TUI and web navigation\n- Move corresponding help text to Tools section in TUI help docs\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "refactor: move MCP Security panel to Tools section (#1708)",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-22T11:44:27Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "4c2d3937f78db5e7c0714032aefd8ce27e72489f",
          "body": "- Add VIOLATION_FILTER_TYPES list to constants.py with display name,\n  API value, and description for all 20 violation types\n- Refactor TUI violations page to derive filters from shared constant\n  instead of hardcoded inline definitions\n- Refactor web violations page to derive filters from shared constant\n- Add slug/class mappings in TUI/web to adapt shared data to each UI\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "refactor: centralize violation filter types in constants (#1707)",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-22T11:22:44Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "d4700d6b7f8d00f478c9e0555c30e0319f85f667",
          "body": "- Move check_project_config(cwd) before global/dir pause guards so\n  _project_dir_last_seen is updated even when scanning is skipped\n- Wrap early config check in try/except to match prior error handling\n- Add parametrized test covering project dir tracking under both\n  per-directory and global pause modes\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: load project config before pause check in daemon (#1705)",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-22T10:20:41Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "f97d2a6e5a8b85ed0ac0ce3cb0c063d3f38322e5",
          "body": "…ge (#1704)\n\n- Remove badge_row UI element and its population logic\n- Remove per-category badge rendering in _update_mode_hint refresh\n- Simplify layout to content column only\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "refactor: remove unused category badge row from detection patterns pa…",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-22T01:45:08Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "35a1f86eb67ab3541c97ce9d567cad7182c4b6c8",
          "body": "- Build RULE_ID_TO_SLUG via dict comprehension over RULE_ID_TO_CONFIG_SECTION\n  and a reverse lookup of SLUG_TO_CONFIG_SECTION, replacing hand-maintained dict\n- Add special-case for UNICODE-001 → /pi-unicode mapping\n- Add TestRuleIdToSlug test class covering validity, unicode override,\n  and spot-check of expected values\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "refactor: derive RULE_ID_TO_SLUG from existing mappings (#1703)",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-22T01:41:59Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "55fd6a0f14b9cdc6bda975a95ab59f0791d1115a",
          "body": "- Add run_scan_pipeline() and ScanPipelineResult to scan_analyzer.py\n- Replace duplicated scan/analyze logic in TUI scan_configure with pipeline call\n- Replace duplicated scan/analyze logic in web scan_configure with pipeline call\n- Update web tests to mock centralized pipeline instead of individual components\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "refactor: extract shared scan pipeline from TUI and web (#1702)",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-22T00:59:59Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "11e11eb8d29cb7029ba99c7eee5da0bfce170ded",
          "body": "- Move RULE_ID_LABELS, RULE_ID_TO_SCANNER, and related dicts from\n  scan_analyzer.py to constants.py\n- Add SLUG_TO_CONFIG_SECTION, RULE_ID_TO_SLUG, RULE_ID_TO_CONFIG_SECTION,\n  and RULE_ID_TO_VIOLATION_TYPE mappings\n- Replace inline slug/config lookups in TUI and web modules with\n  constant dict references\n- Update tests to match new import paths and config section routing\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "refactor: centralize rule ID mappings in constants module (#1699)",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-22T00:18:42Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "614a1b660018de6ff35d1fe5b6de5438d184db07",
          "body": "- Extract quiet_logging() context manager to tui/utils.py and logging_utils.py\n- Replace inline _suppress/_restore_logging methods across TUI modules\n- Add safe_int() and format_count() helpers to tui/utils.py\n- Add unit tests for new utility functions\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "refactor: centralize logging suppression into shared TUI utility (#1698)",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-21T23:25:36Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "d4ed5867d6d7f004f96cfb83e57ca9cade42ba07",
          "body": "- Add ConfigSaveMixin to schema_defaults.py with shared config\n  load/save/path-resolution helpers used across all TUI panels\n- Replace per-panel duplicated _get_config_path, JSON read/write,\n  and _is_project_scope logic with mixin methods in 20 panel files\n- Add Skill \"release\" permission rule to ai-guardian.json\n- Update tests to match new mixin-based config plumbing\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "refactor: extract ConfigSaveMixin to deduplicate TUI config I/O (#1697)",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-21T23:06:16Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "7d483cf027f3d694675805262c095b777966e35a",
          "body": "- Move _load_overlaid_config to scanners module with internal loader map\n- Pre-compute overlaid configs for all overlay-enabled scanners in both\n  content_pipeline and post_tool_use hooks\n- Add _LOADER_MAP and get_loader to ScannerRegistry for loader lookup\n- Remove per-scanner loader_fn parameter in favor of registry-based dispatch\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "refactor: centralize language overlay config loading (#1696)",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-21T20:51:51Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "633f614ab7356d85e42f451bb0740086fd17e17c",
          "body": "- Replace line-count incremental reads with byte-offset (seek-based)\n  positioning in _read_jsonl_incremental and all adapter callers\n- Add atomic write (tempfile + os.replace) for transcript positions file\n- Update copilot_chat, jsonl, kiro, openclaw, windsurf adapters to pass\n  and receive byte offsets instead of line counts\n- Update corresponding unit tests for new position semantics\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "refactor: switch transcript scanning to byte-offset tracking (#1695)",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-21T20:07:24Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "7b1b3c205b868b69f5f4f00ac8abb897f78179bb",
          "body": "- Add path traversal validation for session_files in _run_session_start_event\n- Add workspace_files param to _run_scenario_event for simulated project dirs\n- Set project_dir_override so language detection uses workspace file structure\n- Add language-overlay.yaml scenario files for minimal/moderator/standard/strict\n- Update scenario schema to include workspace_files and new test coverage\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: add workspace_files support and path traversal guards (#1694)",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-21T19:35:31Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "e943a8cfa8c8841a4762e85010beafed3a18105d",
          "body": "- Change _get_most_recent_entry return type to Optional[Tuple[str, float]]\n- Refactor copilot_chat to use shared _get_most_recent_entry helper\n- Refactor openclaw to use shared _get_most_recent_entry helper\n- Update cline and kiro callers to destructure new tuple return\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "refactor: return mtime from _get_most_recent_entry (#1693)",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-21T18:24:20Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "d98c8a9c8de78f50cae681505589245a4c90ab24",
          "body": "…ole (#1690)\n\n* Feat: add init --scan UI to TUI and web console\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-Authored-By: Claude <noreply@anthropic.com>\n\n* test: relax Directory Scan position assertion in TUI nav\n\n- Remove check that Directory Scan is last item in Tools group\n- Keep a\n[…]\ndocstring to match relaxed constraint\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-Authored-By: Claude <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "itdove/ai-guardian#1677: feat: add init --scan UI to TUI and web cons…",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-21T17:42:41Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "a5d567fe005a21e4a5d15c9c548eb48d279f556c",
          "body": "Operation blocked by ai-guardian: secret detected\n\nOriginal prompt: Based on this git diff, generate a commit message in conventional commit format.\n\nGit Status:\nM tests/unit/test_copilot_chat_transcript.py\n M tests/unit/test_kiro_transcript.py\n M tests/unit/test_openclaw_transcript.py\n M tests/unit\n[…]\nFocus on WHAT changed, not WHY\n- NO JIRA keys or ticket numbers\n\nReturn ONLY the commit message.\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "UserPromptSubmit operation blocked by hook: (#1691)",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-21T17:42:24Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "0793d63ee1ba9bd5c28a07499fd81b02ef2801be",
          "body": "- Remove pattern server URL/version config and test connection binding\n- Remove PatternServerSection widget and server connectivity testing\n- Replace pattern server help text with per-engine pattern server reference\n- Add privacy warning for external liveness validation API calls\n- Delete test_tui_s\n[…]\nets_pattern_server.py (dead tests)\n- Update web secrets page to match TUI pattern server removal\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "refactor: remove pattern server from secrets panel (#1685)",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-21T16:47:21Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "ad8b785740adc7186644a70fd66045023a6141ab",
          "body": "…jection via ScannerEntry flag (#1683)\n\n* refactor: hoist language overlay into content pipeline\n\n- Add _load_overlaid_config() helper in content_pipeline.py\n- Move apply_language_overlays call from scanners.py to callers\n- Pass pre-overlaid config to run_prompt_injection_scan\n- Add supports_languag\n[…]\n (1M context) <noreply@anthropic.com>\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-Authored-By: Claude <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "itdove/ai-guardian#1674: refactor: pipeline-level language overlay in…",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-21T16:47:04Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "999f926ecfb28d785bf39b17f20ef8b5b617870c",
          "body": "- Replace **kwargs with explicit original_file_path param in run_single_engine\n- Pass original_file_path through _parse_secrets_result and _build_scan_result_from_dict\n- Use resolved original path in SecretMatch.file for python scanner and dict builder\n- Add parametrized tests verifying file path appears in scan results\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: thread original_file_path through all scan result paths (#1679)",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-21T14:04:33Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "cc28ad1b6d436e3d74063ae262c8da76d89e4d03",
          "body": "…ining scanner types (#1676)\n\n* refactor: extract config builders and table-driven scanner routing\n\n- Replace if/elif chains in fingerprint_finding and _scanner_for_rule_id\n  with table-driven lookups (_FINGERPRINT_DETAIL_KEY, _RULE_ID_PATTERNS)\n- Extract reusable config builder functions (_build_es\n[…]\nforward slashes regardless of host OS\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-Authored-By: Claude <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "itdove/ai-guardian#1665: feat: init --scan config generation for rema…",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-21T12:34:46Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "4cb85cb9db194d4bfc8a55f04ff76ee4432e84bb",
          "body": "- Extract apply_language_overlays() helper in scanners.py\n- Add scanner_name param to get_language_allowlist_patterns()\n- Cache all scanner patterns together per project_dir\n- Update tests for multi-scanner overlay support\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "refactor: generalize language overlay to all scanners (#1675)",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-20T20:56:52Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "a4d3827fa359d163deb130468d2e2bfe33e9f531",
          "body": "- Add _read_jsonl_incremental() and _scan_jsonl_incremental() to common.py\n- Refactor copilot_chat, kiro, openclaw, windsurf scanners to use shared helpers\n- Remove duplicated JSONL reading/scanning boilerplate from each adapter\n- Update tests to match simplified adapter internals\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "refactor: extract shared JSONL scan logic into common helpers (#1673)",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-20T20:52:19Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "e79aa97577af8852ea594724c048da840a23c069",
          "body": "- Add _get_most_recent_entry() to common.py for finding newest dir entry\n- Replace inline scandir loops in cline.py and kiro.py with shared helper\n- Update tests to cover new helper and parameterized match/mtime functions\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "refactor: extract shared _get_most_recent_entry helper (#1671)",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-20T20:07:23Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "d0f5342749d3542b9012507b260024e4b15cba07",
          "body": "…er executor — skip_file_types relies on temp filename (#1668)\n\n* feat: pass original file path through scan pipeline\n\n- Add original_file_path parameter to run_engine and run_python_scanner\n- Extract original_file_path from strategy context and forward to executors\n- Use original path instead of te\n[…]\nal parameters like original file path\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-Authored-By: Claude <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "itdove/ai-guardian#1653: fix: thread original file_path through scann…",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-20T20:07:07Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "02261d2e316f66965caf6b73b600e2b299555d5d",
          "body": "- Add scan_analyzer module to cluster findings by pattern and identify high-frequency false positives\n- Add --scan and --threshold flags to init-project CLI command\n- Generate tuned config with allowlist patterns and per-scanner directory ignores\n- Add smoke tests for init-project --scan workflows\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: add init-project --scan for false positive analysis (#1666)",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-20T19:11:00Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "3ea3ca2e7321cdbf433af65ad215268ae1ecb0cc",
          "body": "…ess known false positive patterns per language (#1663)\n\n* feat: auto-allowlist language false positives in prompt injection scan\n\n- Add false_positive_patterns dict to LanguageDefinition for per-scanner allowlists\n- Populate prompt_injection patterns for Python, JS, TS, PHP, Ruby, C/C++, Go, Java, \n[…]\ns multiple lines for PEP 8 compliance\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-Authored-By: Claude <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "itdove/ai-guardian#1585: feat: auto-detect project language and suppr…",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-20T17:25:21Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "82221e683f5701cb3d0ae401de04bd1dc02c2b9c",
          "body": "- Add AiderDeskTranscriptAdapter for Markdown chat history files\n- Add OpenClawTranscriptAdapter for JSONL transcript files\n- Register both adapters in TRANSCRIPT_ADAPTERS list\n- Add unit tests for both new scanners\n- Update AGENT_SUPPORT.md with new transcript formats\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: add AiderDesk and OpenClaw transcript scanners (#1661)",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-20T16:29:27Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "40f55eebc0eaa2b99564b4b0c77fc8bfea22ddd8",
          "body": "- Add Copilot Chat (VS Code) JSONL delta journal to transcript adapter table\n- Document Augment Code transcript scanning infeasibility (server-side storage, no UserPromptSubmit hook)\n- Note Crush PreToolUse-only limitation already existed; new entries placed before it\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs: add Copilot Chat and Augment Code agent support notes (#1659)",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-20T16:00:32Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "7784b05dc153107a85ae41cca63a516a026ec49f",
          "body": "- Add CopilotChatTranscriptAdapter for VS Code JSONL delta journal files\n- Register adapter in TRANSCRIPT_ADAPTERS and __all__ exports\n- Document Copilot Chat session path in AGENT_SUPPORT.md\n- Add unit tests for copilot chat transcript scanning\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: add Copilot Chat (VS Code) transcript scanner (#1658)",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-20T15:39:46Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "12f02272f6b32c82f48f640c10b7c450a7357c47",
          "body": "- Add KiroTranscriptAdapter for ~/.kiro/sessions/cli/*.jsonl files\n- Register adapter and incremental scanner in transcript __init__.py\n- Add unit tests for Kiro transcript parsing\n- Document Kiro in AGENT_SUPPORT.md agent table\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: add Kiro transcript scanning support (#1656)",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-20T15:15:33Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "acbed7ab5cd55ab1d8828468f3090d177f009da2",
          "body": "- Add skip_file_types metadata field to TOML rules, converted to\n  frozenset at compile time for fast lookup\n- Thread file_ext parameter through cache.scan() and\n  TomlPatternsScanner to skip rules by extension\n- Apply skip_file_types to yaml-password rule to suppress false\n  positives in source code files\n- Add unit tests for skip_file_types parsing and scanner filtering\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: add skip_file_types support to pattern rules (#1654)",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-20T14:07:05Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "59a5a3af334ca2f9fb2234e46dfbaefcc407bcdb",
          "body": "- Add `ai-guardian ml setup` CLI command that checks deps, downloads\n  model, and configures prompt_injection detection in one step\n- Add `ensure_model_downloaded()` for idempotent model download with\n  verification, used by both CLI and daemon auto-download\n- Add `auto_download_model` config field \n[…]\ne templates with prompt_injection defaults and add\n  unit tests for new setup/download functions\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: add one-command ML detection setup and auto-download (#1652)",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-20T13:18:54Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "543136ab43b0d0c447e343c8b903ffe7bf0495ae",
          "body": "- Add _sanitize_warn_reason() and _build_warn_agent_context() to base\n  adapter, stripping file/line/pattern details from agent-facing output\n- Pass violation_type through warn response chain in all adapters\n  (Claude, Cline, Copilot, Cursor, Gemini, Kiro, Windsurf)\n- Keep full diagnostic details in\n[…]\nason mappings: offensive_language, canary_detected,\n  code_security, exfil_detection, bash_exfil\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: sanitize warn-mode context sent to AI agents (#1651)",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-17T22:29:16Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "d901771f788997044a2fd6c446715e41f670704b",
          "body": "- Add select-based read timeout (30s) to prevent hanging on\n  unresponsive leaktk subprocess; kill and raise on expiry\n- Deduplicate restart() by delegating to stop()\n- Extract _make_started_proc helper in tests to reduce mock boilerplate\n- Replace empty-response test with timeout and crash test cases\n\n\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: add timeout guard to leaktk listen mode scans (#1650)",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-17T20:58:27Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "409530bb74752d62d7842a2642adc9f2cb5a8bc1",
          "body": "- Add token_prefixes config option for token_not_placeholder rules\n- Update Slack token rule to use short \"xox\" keyword with explicit prefixes\n- Update _build_token_prefix_re to prefer token_prefixes over keywords\n- Update sync test to validate token_prefixes with keywords fallback\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: add token_prefixes field to secrets.toml rules (#1649)",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-17T20:24:09Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "be1ffb48e8c8a665a80c2fabd53e5c26b2092528",
          "body": "…ge — reason and systemMessage contain same text (#1647)\n\n* fix: use sanitized message in block response reason field\n\n- Replace raw sys_msg with sanitized value in _block_response reason\n- Update tests to assert reason contains sanitized label components\n- Verify reason differs from raw systemMessa\n[…]\nfor warning vs error in reason string\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-Authored-By: Claude <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "itdove/ai-guardian#1642: bug: PostToolUse block shows duplicate messa…",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-17T19:41:46Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "14c379505b5316abb589925b644330de8050f66a",
          "body": "- Add supports_listen_mode and version_hint fields to EngineConfig\n- Route listen mode and version hints via config flags instead of type checks\n- Make listen mode log message engine-agnostic\n- Add tests for capability flag defaults and preset values\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "refactor: replace leaktk hardcoding with capability flags (#1648)",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-17T19:39:28Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "b206637ed3e3334dc584a61506623ebae888d807",
          "body": "- Change header nav button label from \"Menu\" to \"Quick Links\"\n- Replace hamburger menu icon with link icon\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "refactor: rename nav menu button to Quick Links (#1646)",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-17T19:10:34Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "7ea9cf32e0061f6233e34ab82b9b236b79756c7f",
          "body": "- Add listen_mode.py managing a long-lived LeakTK process that accepts\n  scan requests over stdin/stdout, reducing per-scan latency ~200ms→~5ms\n- Integrate listen mode lifecycle with daemon startup/shutdown and\n  config-change restart\n- Fall back to standard subprocess execution when daemon is not running\n  or listen mode is unavailable\n- Bump LeakTK pinned version to 0.3.4\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: add LeakTK listen mode for persistent process scanning (#1645)",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-17T19:04:37Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "08657855cc964eac1ff91300cc9b7bcacdd5ed66",
          "body": "- Build _TOKEN_PREFIX_RE dynamically from secrets.toml rules with\n  validation=\"token_not_placeholder\" instead of hardcoding prefixes\n- Update Slack token keywords from generic \"xox\" to specific prefixes\n  (xoxb-, xoxa-, xoxp-, xoxr-, xoxs-)\n- Add tests ensuring prefix regex stays in sync with secrets.toml\n- Add fallback to never-match regex when secrets.toml missing or broken\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "refactor: derive token prefix regex from secrets.toml (#1640)",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-17T18:37:23Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "de940fbb28f99109c27f754d7d2da89ae58ead39",
          "body": "- Add _stderr_block_response() to HookAdapter base class\n- Replace duplicated combine/print/metadata pattern in copilot, kiro, windsurf adapters\n- Move sys import from child adapters to base.py\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "refactor: extract stderr block response into base adapter (#1638)",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-17T17:13:47Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "b35482280e8e6c6906ae3b5fa87bab2dfd103d72",
          "body": "…#1637)\n\n- Add TOML rules for openrouter-api-key, google-gemini-auth-key,\n  hashicorp-vault-token, and confluent-cloud-api-key\n- Register new prefixes in token_not_placeholder validator\n- Add display names to SECRET_TYPE_NAMES registry\n- Add detection and false-positive test cases for all four patterns\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: add secret detection for OpenRouter, Gemini, Vault, Confluent (…",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-17T16:27:37Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "1cff2991482750fd0169c78a2fb4f2c10ba7f6de",
          "body": "- Import threading module in stats refresh test helper\n- Replace fixed 0.3s sleep with explicit join on stats-refresh thread\n- Use 2.0s timeout on thread join for reliable synchronization\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "test: replace sleep with thread join in wake detection test (#1635)",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-17T15:55:59Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "7ca2b9a9c5f9a150e5755f83fa8b83d995ebbdd9",
          "body": "…text on PostToolUse secret block (#1634)\n\n* feat: pass redacted output via additionalContext on secret block\n\n- Add redacted_output param to format_response across all hook adapters\n- Route redacted content through additionalContext so agents can\n  continue working with sanitized output instead of \n[…]\nign with project formatting standards\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-Authored-By: Claude <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "itdove/ai-guardian#1630: feat: send redacted output via additionalCon…",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-17T15:42:26Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "2e5a91979f05b0cce2f5b82beaeee3fe77be6563",
          "body": "- Rename env_not_file_path validator to env_not_false_positive and add\n  ALL_CAPS_IDENTIFIER exclusion to skip programming constants\n- Add password_not_false_positive validator for password/secret fields\n  that preserves underscore-prefixed and ALL_CAPS value detection\n- Keep env_not_file_path as ba\n[…]\ncompatible alias in registry\n- Add tests for ALL_CAPS identifier and password validator behavior\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: reduce false positives in env var secret detection (#1632)",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-17T14:42:29Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "7a090452843f4a2261719a8bba4d793b1151167c",
          "body": "======================================================================\n🛡️ Secret Detected\n======================================================================\n\nProtection: Secret Scanning (first-match strategy)\nSecret Type: Environment Variable\nLocation: user_prompt:87:15\nScanner: toml-patterns\nPa\n[…]\nFocus on WHAT changed, not WHY\n- NO JIRA keys or ticket numbers\n\nReturn ONLY the commit message.\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "UserPromptSubmit operation blocked by hook: (#1631)",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-17T12:38:22Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "ca6abd37e8f6a8464e12c7201e99cb029da22f67",
          "body": "- Merge TestNewSecretPatterns and TestGitleaksGapPatterns into single TestSecretPatterns class\n- Combine detection and false-positive cases into ALL_DETECTION_CASES and ALL_FALSE_POSITIVE_CASES lists\n- Remove duplicate parametrized test methods\n\n\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "test: consolidate secret pattern test classes (#1629)",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-17T11:47:39Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "96d0281576340ee524d86fea61b147f392ba4cb4",
          "body": "…tokens — toml patterns not wired into output scanning (#1625)\n\n* fix: block secret-containing output instead of redact-and-pass\n\n- Switch has_secrets to True so post_tool_use blocks when secrets found\n- Add fallback block when redactor produces zero redactions\n- Pass error_message and violation_typ\n[…]\no redact-and-pass / log-only behavior\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-Authored-By: Claude <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "itdove/ai-guardian#1624: bug: PostToolUse secret scan misses env var …",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-17T11:32:58Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "6fd916cb941a660f2d9c2c87535106ede22aff90",
          "body": "- Replace TestNewSecretPatterns class with parametrized test cases\n- Consolidate detection and false-positive tests into data-driven lists\n- Apply same parametrize pattern to TestNewProviderSecretPatterns\n- Reduce test boilerplate while preserving identical coverage\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "test: refactor secret detection tests to parametrized format (#1623)",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-17T10:13:24Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "bb697e6ca51e6bc436ae1f685a6d29c6bbeb0df1",
          "body": "- Add rules for secrets management (Doppler, HashiCorp TF, Pulumi)\n- Add rules for observability (Grafana, Sentry, Datadog)\n- Add rules for cloud providers (Cloudflare, DigitalOcean, Alibaba)\n- Add rules for developer tools (Snyk, Sourcegraph, Codecov, Buildkite)\n- Add Cohere API token detection\n- Update test assertions for new bundled rule count\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: add 30 secret detection patterns for new providers (#1621)",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-16T23:10:30Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "85a1d7b4f09ec116f45797994089dec6ec9d539a",
          "body": "…transcript_text I/O (#1616)\n\n* refactor: extract prune helper and reduce IO in transcript scanner\n\n- Extract _prune_stale_keys() from inline dict comprehensions\n- Remove unused fcntl import block\n- Cache datetime.now() call to avoid redundant UTC lookups\n- Skip saving seen findings when no new entr\n[…]\nn hot path).\nTest updated from assertNotIn to assertIn to reflect this.\n\nCo-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "itdove/ai-guardian#1606: Remove dead fcntl import and optimize _scan_…",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-16T18:19:54Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "65c8f95d289d66a8efdac55b0d6d1bc7ea39efae",
          "body": "- Fix scanner file paths in research reminder workflow to match\n  current src/ai_guardian/scanners/ layout\n- Add supply chain, offensive language, canary detection, and exfil\n  detection sections to research checklist\n- Record 2026-07-16 research review findings in AGENTS.md including\n  new secret patterns (Gemini AQ., OpenRouter, Vault, Confluent)\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs: update pattern research workflow and log review (#1619)",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-16T17:14:43Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "54d4faf3531721c2b3417036e3f767b0c15de390",
          "body": "- Wrap stats-refresh loop body in try/except to log and survive errors\n- Extract shared test helper _run_stats_refresh_tick to reduce nesting\n- Flatten deeply nested context managers using parenthesized with-statement\n- Add test for stats-refresh resilience when a sub-call raises\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: guard stats-refresh tick against unhandled exceptions (#1615)",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-16T15:14:25Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "42c71db166636a3cba7e8b87761763f5dc218939",
          "body": "- Fix prefix vs raw_prefix bug in else branch of read_cursor_transcript\n  where SQL LIKE metachar in composer_id caused wrong key stripping\n- Add test for composer_id containing underscore covering both branches\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: use raw_prefix for bubble ID extraction in cursor scanner (#1613)",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-16T14:16:27Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "ba8ebce2dd993e632e6cc36550eade157935bf26",
          "body": "…rministic startup detection (#1612)\n\n* feat: add ready event to DaemonServer for deterministic startup sync\n\n- Add _ready_event (threading.Event) to DaemonServer, set after socket bind\n- Replace poll-based _wait_server_ready with event-based wait on _ready_event\n- Remove redundant retry loops and r\n[…]\n line before _wait_server_ready calls\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-Authored-By: Claude <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "itdove/ai-guardian#1610: Add readiness event to DaemonServer for dete…",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-16T13:43:25Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "19973508838382b6eafd4f996db5493516ee1e6c",
          "body": "- Move running_server fixture from class method to module-level\n- Extract _connect helper to module-level function\n- Add _wait_server_ready helper with proper ping-based readiness check\n- Replace poll-for-socket-file loop with connection+ping verification\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "refactor: extract shared test helpers in daemon server tests (#1611)",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-16T13:08:54Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "3c2e39fb4c65718e1aa6d97a21b55fe160c5d488",
          "body": "…ript adapters (#1608)\n\n* refactor: extract shared position-tracking logic in transcript scanners\n\n- Add _scan_with_position_tracking helper to deduplicate incremental\n  scan boilerplate across Cline, Cursor, OpenCode, Windsurf, and JSONL\n- Add _discover_path helper for common transcript path resolu\n[…]\ny shared _scan_with_position_tracking\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-Authored-By: Claude <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "itdove/ai-guardian#1604: Refactor: Extract shared helpers from transc…",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-16T00:16:14Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "6145a0655875a2fb181cb860d7ed88a0af752f60",
          "body": "- Add WindsurfTranscriptAdapter and scan_windsurf_transcript_incremental\n- Register adapter in TRANSCRIPT_ADAPTERS and __all__ exports\n- Document Windsurf Cascade transcript path in AGENT_SUPPORT.md\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: add transcript scanning for Windsurf (JSONL format) (#1605)",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-15T22:26:35Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "feddb0a5c84b902c42322524834bdf8eb5d1b6cd",
          "body": "…ON format) (#1603)\n\n* feat: add Cline/ZooCode transcript scanning adapter\n\n- Add ClineTranscriptAdapter for JSON array format conversations\n- Register adapter in TRANSCRIPT_ADAPTERS and __all__ exports\n- Add unit tests for Cline transcript scanning\n- Update AGENT_SUPPORT.md with Cline/ZooCode trans\n[…]\nth directly instead of tuple indexing\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-Authored-By: Claude <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "itdove/ai-guardian#937: Add transcript scanning for Cline/ZooCode (JS…",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-15T20:29:55Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "2c7dfc481879dccf33a1f8853c23e50e3dd86695",
          "body": "🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Remove _hp delegation shims in hook_events/ modules (#1602)",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-15T19:02:16Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "63079b683570b41bd03e2fc34597111e6fc6480d",
          "body": "…rmat) (#1600)\n\n* refactor: extract transcript scanning into polymorphic adapter package\n\n- Refactor monolithic transcript scanner into scanners/transcript/ package\n  with per-IDE adapters (Claude Code, OpenCode, Cursor) behind a common\n  TranscriptAdapter interface\n- Add Cursor IDE transcript scann\n[…]\nll in cursor.py across multiple lines\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-Authored-By: Claude <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "itdove/ai-guardian#936: Add transcript scanning for Cursor (SQLite fo…",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-15T10:38:13Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "9a5583f50388fdf8352630b4af4be99cae91a33d",
          "body": "…1598)\n\n- Add CRUSH_HOOK_EVENTS tuple to constants.py for centralized config\n- Tighten CrushAdapter.can_handle() to validate event against known\n  display names and exclude Claude Code hook data\n- Replace hardcoded \"PreToolUse\" strings in hooks.py with constant\n- Add tests for CRUSH_HOOK_EVENTS and stricter detection logic\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "refactor: extract Crush hook events constant and tighten detection (#…",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-14T20:55:17Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "5664ca16c8d8c03046e3328d69c4a2b7e205b780",
          "body": "…sh notifications (#1596)\n\n* feat: add push-based event subscriptions to daemon\n\n- Add subscribe message type to protocol and server dispatcher\n- Implement container event streaming via Docker SDK in discovery\n- Add connect_subscriber() client helper for push event consumers\n- Wire tray app to recei\n[…]\ne_dir operate on existing directories\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-Authored-By: Claude <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "itdove/ai-guardian#650: Enhancement: Event-driven tray updates via pu…",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-14T20:45:26Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "64ca5461383dbef4d5c905d7c05803929f17611f",
          "body": "…#1597)\n\n- Import CURSOR_HOOK_EVENTS from constants in release_helper, doctor,\n  and test helpers instead of hardcoding event lists\n- Remove redundant Doctor._get_cursor_events() static method\n- Fix doctor _count_cursor_hooks falling back to full config instead\n  of empty dict when \"hooks\" key missing\n- Update test helper to dynamically build settings from EXPECTED_EVENTS\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "refactor: use CURSOR_HOOK_EVENTS constant as single source of truth (…",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-14T20:44:07Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "8a6e0fdfbac4597dd87498cd6cfe2b07e339ae70",
          "body": "- Add crush.py hook adapter with PreToolUse event handling\n- Register crush adapter in hook_adapters __init__ and setup modules\n- Add Crush to hook simulator TUI and web interfaces\n- Document Crush support in AGENT_SUPPORT.md with capability matrix\n- Add unit tests for crush adapter detection and hook generation\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: add Crush (Charmbracelet) hook adapter support (#1593)",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-14T18:36:02Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "9b2d9564dd77693d0cc7c577b60bae0221d24022",
          "body": "- Add preToolUse to Cursor hook events constant and adapter\n- Update doctor checks and hook setup to handle 6 Cursor events\n- Expand release verification flow with preToolUse test steps\n- Update tests for new event count and hook configuration\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: add preToolUse hook event for Cursor IDE (#1592)",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-14T16:40:31Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "b0ebcb53f180e964439109aa2655f717c16d8e65",
          "body": "Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs: regenerate notebooklm-export.md for v1.14.0",
          "author_name": "itdove",
          "author_login": "itdove",
          "committed_at": "2026-07-13T19:59:40Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "ecd036dc8b2158b469599cc564031848b03619dd",
          "body": "Post-release v1.14.0:\n- Bump version to 1.15.0-dev in pyproject.toml and __init__.py\n- Reset install URLs in README.md from v1.14.0 back to main\n\nCo-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore: bump version to 1.15.0-dev, reset README URLs to main",
          "author_name": "itdove",
          "author_login": "itdove",
          "committed_at": "2026-07-13T19:09:16Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "27950d3642c4d7ddb0e4064aea8ab480b9e78de3",
          "body": "v1.14.0 released — architecture refactor, no new features, no breaking changes.\n\nCo-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Merge release-1.14 into main",
          "author_name": "itdove",
          "author_login": "itdove",
          "committed_at": "2026-07-13T18:42:26Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "fe140b66fd3438f853220da79ef52187ace183b1",
          "body": "Prepare for v1.14.0 release:\n- Update version 1.14.0-dev → 1.14.0 in pyproject.toml and __init__.py\n- Move CHANGELOG.md Unreleased section to [1.14.0] - 2026-07-13\n- Update README.md install URLs to v1.14.0\n- Add Cursor v3.10.20 verification and CI fix to CHANGELOG\n\nCo-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore: bump version to 1.14.0 for release",
          "author_name": "itdove",
          "author_login": "itdove",
          "committed_at": "2026-07-13T14:30:22Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "7f6aab65958aa768fa534f6a664d10833c61bac7",
          "body": "- Update 6 stale module paths in DEVELOPER_GUIDE.md (mcp_server, prompt_injection,\n  ssrf_protector, tool_policy, violation_logger, daemon/tray → new subpackage locations)\n- Add 10 missing subpackages to project structure tree in DEVELOPER_GUIDE.md\n- Replace removed secret_scanning.action references\n[…]\nlease-readiness.yml: add secrets: inherit to scenario-tests job call\n  so QUAY_USERNAME/QUAY_PASSWORD propagate to container build\n\nCo-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs: update stale module paths and fix CI secrets passthrough",
          "author_name": "itdove",
          "author_login": "itdove",
          "committed_at": "2026-07-13T14:25:03Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "feda79cb3ed52e8408b046020931c33ccf29b773",
          "body": "* itdove/ai-guardian#1527: refactor: extract shared _block_response/_warn_response/_allow_response methods in base_agent.py — eliminate duplicated format_response branches (#1535)\n\n* refactor(hook-adapters): extract shared response builders in BaseAgentAdapter\n\n- Extract _block_response, _warn_respo\n[…]\not just PRs.\n\nCo-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Release 1.14.0 — refactor, bug fixes, CI improvements (#1567)",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-12T16:42:52Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "9a376afb00353cf6289318fb80bbb9215dec0a5d",
          "body": "- Reformat release_helper.py to comply with black code style\n- Add trailing commas to dict literals and function args\n- Collapse single-expression function calls to one line\n- Update test file formatting to match\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "style(release): format release_helper with black (#1534)",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-09T08:30:48Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "9185fcb352cb2478f69a4e45a56a533c0e05f5ad",
          "body": "- Add preferred approach to reuse existing release-x.y branch for patches\n- Update hotfix workflow with decision tree (release branch vs hotfix branch)\n- Revise branch diagrams and examples to reflect cherry-pick-based flow\n- Rename \"Hotfix Workflow\" to \"Patch / Hotfix Workflow\" throughout\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs(release): prefer release branch for patch fixes (#1533)",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-09T08:26:43Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "3180b07e256d754f0596a0392980145894ba092c",
          "body": "Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs: regenerate notebooklm-export.md for v1.13.3",
          "author_name": "itdove",
          "author_login": "itdove",
          "committed_at": "2026-07-09T00:44:08Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "496f536834eeb48b5a82b9d2438b883ff3b5d9ad",
          "body": "- Fix Cursor beforeShellExecution/afterShellExecution hooks (#1531):\n  afterShellExecution misrouted to HookEvent.PROMPT instead of POST_TOOL_USE;\n  top-level command field not extracted (Bash commands not scanned);\n  can_handle() missing shell/tool events when sent via hook_event_name\n- Add [1.13.3\n[…]\ne docs: MULTI_DAEMON_TRAY.md (stale-code indicator, rebuild hint,\n  in-progress guard), CONSOLE.md (violations directory filter)\n\nCo-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(cursor): shell execution hooks silent failure + v1.13.3 changelog",
          "author_name": "itdove",
          "author_login": "itdove",
          "committed_at": "2026-07-09T00:42:49Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "20f713fb751d865b7f9fd9cfcecba68c859337e7",
          "body": "…esponse (#1528)\n\n- Replace `reason` with `systemMessage` in SessionStart block to avoid duplicate UI display\n- Add `additionalContext` via `_sanitize_block_reason` in `hookSpecificOutput`\n- Add `TestBaseAgentAdapterSessionStartFormat` covering block format, missing reason, additionalContext, and pass-through cases\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(session-start): use systemMessage + additionalContext for block r…",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-08T21:50:18Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "eaf2647f66dbd8d7d29d93fc2a73a748c90ad3b7",
          "body": "…et warnings (#1525)\n\n- Deduplicate transcript secrets by individual rule_id instead of a single\n  fingerprint, so distinct secret types each get their own seen-key\n- Warning message now shows count and type list when _last_secret_findings\n  is available; falls back to original single-finding path when not\n- Violation log includes count and types fields alongside the error reason\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(hook_processing): per-finding dedup and count in transcript secr…",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-08T20:33:43Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "cafa194923ca62712cb4d28399fe8d17651f33ef",
          "body": "…#1524)\n\n- Gate restart stale-vis to local runtime only; container/k8s get separate path\n- Add _stale_vis_remote/_mk_daemon_stale_vis_remote for container and kubernetes runtimes\n- Add version-aware label showing host vs daemon version mismatch with rebuild hint\n- Add disabled menu item for remote stale warning in both single- and multi-daemon menus\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(tray): show rebuild-image hint for stale container/k8s daemons (…",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-08T20:13:56Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "c6e5aae5e44bb51a9de8017ecd61fb6e1732d376",
          "body": "…camelCase) — adapter only checks hook_event_name (snake_case) (#1523)\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Bug: SessionStart not detected when Claude Code sends hookEventName (…",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-08T19:41:28Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "5fb3b7355fd9c6f6cfbe59fc07696e0ec250c0c2",
          "body": "…t + bootstrap scan scenario for AGENTS.md poisoning (#1520)\n\n* feat(dummy-agent): add SessionStart event support to scenario runner\n\n- Add `_run_session_start_event` helper that writes session files to a temp dir and fires the SessionStart hook\n- Thread `daemon_state` through `_run_hook`, `_run_sce\n[…]\nerlay destination path before copying\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-Authored-By: Claude <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "itdove/ai-guardian#1517: feat: add SessionStart support to dummy-agen…",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-08T19:04:25Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "c7211d3d1a7c5e786a6177efe1c62d4162c46d7f",
          "body": "- Entrypoint validates config file exists after setup; exits 1 if missing\n- setup_hooks returns False on config failure regardless of other flags (ide_type, remote_config_url, etc.)\n- resolve_profile accepts bare built-in names without @ prefix (e.g. \"standard\" resolves same as \"@standard\")\n- Add tests for bare-name profile resolution and setup abort behavior\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: abort setup on config failure and accept bare profile names (#1519)",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-08T17:24:11Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "d8eaaf1fbfb3792134b66eeff6282850c7f525d8",
          "body": "…ctions (#1518)\n\n- Block concurrent restart triggers with `_restart_in_progress` flag\n- Refresh menu immediately on restart to reflect in-progress state\n- Poll PID file for local daemons to detect process replacement (up to 10s)\n- Fall back to fixed 3s sleep for non-local runtime targets\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(tray): add in-progress guard and completion polling to restart a…",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-08T17:19:33Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "f8538efed7ab47821c194d7d2a8ffda7db33b764",
          "body": "…(#1516)\n\n- Update `_count_claude_hooks` to check 5 hooks instead of 3\n- Add `SessionEnd` and `PostCompact` to the hook name list\n- Update display string and threshold from 3/3 to 5/5\n- Update tests to reflect new hook count and add missing hook fixtures\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(doctor): expand hook check to include SessionEnd and PostCompact …",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-08T16:54:29Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "8d28619cb3f8d662089628a38f6635206c21d045",
          "body": "- Format block response with structured header, file, reason, and remediation steps\n- Add warn action branch returning warning_message instead of error_message\n- Both messages include recommended actions and false-positive escape hatch\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(bootstrap-scan): add formatted block and warn messages (#1515)",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-08T16:37:26Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "eda6270f4d944f54da8b8daa0e6f4d7c47e7af91",
          "body": "- Add `_is_target_stale()` helper routing local targets to `_stale_code_warned` and remote targets to `_version_mismatch_notified`\n- Add `_mk_daemon_stale_vis()` closure for per-slot stale visibility check\n- Inject \"⚠️ Running old code — click to restart\" menu item per daemon when stale and not restarting\n- Add unit tests for `_is_target_stale()` and multi-daemon stale visibility logic\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: add per-daemon stale-code indicator to tray menu (#1514)",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-08T16:26:00Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "3eeab5269077f6cbcba789874df16b3937896d6e",
          "body": "- Add `_violation_matches_dir` helper to match violations by file path prefix\n- Add directory dropdown with type-ahead and clearable support\n- Add \"Browse...\" button wired to existing directory picker dialog\n- Populate directory options from `load_web_projects` on page load\n- Apply dir filter client-side after fetching violations\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(violations): add directory filter to violations page (#1511)",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-08T15:48:00Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "761ada61a467aab9c595b30c4c6eb28f15fa6a3b",
          "body": "…1509)\n\n- BanditScanner raises BanditUnavailableError instead of silently returning no findings when bandit is not importable\n- doctor.check_bandit_scanner() added to run_all() checks; reports FAIL with reinstall hint when bandit is missing\n- Scanner checklist in AGENTS.md updated to require doctor \n[…]\n for new scanners\n- Tests updated for new BanditUnavailableError behavior and doctor check count\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: surface Bandit unavailability in scan output and doctor check (#…",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-08T14:10:40Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "24cf24f318dd5dd09c1e4df669501fc5cd4fe928",
          "body": "…ode — bootstrap scanning fires on first UserPromptSubmit instead of true session start (#1508)\n\n* feat: add SessionStart as distinct hook event\n\n- Add SESSION_START to HookEvent enum, separate from PROMPT/BeforeAgent\n- Handle SessionStart in base agent adapter with block-on-secrets logic\n- Update h\n[…]\nrt into parenthesized multi-line form\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-Authored-By: Claude <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "itdove/ai-guardian#1506: limitation: no SessionStart hook in Claude C…",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-08T14:10:09Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "2040762c70f5a6707c6cd2edc3653c28c960ab37",
          "body": "… hook call — setup should create cache dir proactively (#1507)\n\n* fix(doctor): downgrade missing default cache dir from FAIL to WARN\n\n- Detect custom cache path via config, `AI_GUARDIAN_CACHE_DIR`, or `XDG_CACHE_HOME`\n- Return WARN (not FAIL) when default cache dir missing; FAIL only for custom pat\n[…]\neflect actual strict profile behavior\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-Authored-By: Claude <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "itdove/ai-guardian#1499: bug: doctor fails on cache path before first…",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-08T12:43:53Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "4c6945585187d7744cf714cc702d85e5e015167b",
          "body": "* feat: add dummy-agent scenario tests to CI/CD pipeline (#1497)\n\nWire bundled dummy-agent scenarios into GitHub Actions. Scenarios are\norganized per profile (standard, strict, minimal, moderator) so each\nprofile's expected behavior is validated independently.\n\nKey decisions:\n- Dockerfile.test write\n[…]\n in minimal. Update expectations accordingly.\n\nCo-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: add dummy-agent scenario tests to CI/CD pipeline (#1502)",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-08T10:43:50Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "268a8a6f4073d0c88ac4c68d78ab095a63c04a78",
          "body": "…498)\n\n- Document test image build and run workflow in AGENTS.md and container/README.md\n- List bundled scenarios (basic-secret, pii-detection, ask-dialog, tool-policy)\n- Specify when to run tests (hook_processing.py, scanner, dummy-agent changes)\n- Add interactive REPL and per-scenario run commands\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs: add hook regression testing guide for dummy-agent container (#1…",
          "author_name": "Dominique Vernier",
          "author_login": "itdove",
          "committed_at": "2026-07-07T15:45:03Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "ffed89e3b01b469dd74b762bd9aa62f2c42b2be8",
          "body": "Brings in container docs fix (#1495 follow-up):\n- README quick-start uses curl for run.sh, pinned v1.13.2, includes auth vars\n\nCo-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Merge release-1.13 into main (v1.13.2)",
          "author_name": "itdove",
          "author_login": "itdove",
          "committed_at": "2026-07-06T20:05:11Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "4332326de85473d393427ef4e2a39db84dcb4095",
          "body": "- Bump version 1.13.1 → 1.13.2 in pyproject.toml and __init__.py\n- Add [1.13.2] CHANGELOG entry: container quick-start docs fix\n- Update install URLs and container image refs to v1.13.2\n- Update CHANGELOG comparison links\n\nCo-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore: bump version to 1.13.2 for patch release",
          "author_name": "itdove",
          "author_login": "itdove",
          "committed_at": "2026-07-06T19:45:09Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "3d6e9e234e45349f7aa106f592935faab44ca382",
          "body": "- Use curl to download run.sh (no full repo clone needed)\n- Pin image version to v1.13.1 instead of :latest\n- Add missing ANTHROPIC_API_KEY and ACCEPT_PROPRIETARY_TOS vars\n\nCo-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs(readme): fix container quick-start examples",
          "author_name": "itdove",
          "author_login": "itdove",
          "committed_at": "2026-07-06T19:44:20Z",
          "body_truncated": false,
          "is_coding_agent": true
        }
      ],
      "releases_count": 100,
      "commits_last_year": 1722,
      "latest_release_at": "2026-07-22T17:41:22Z",
      "latest_release_tag": "rc-1.16.0-dev-main.2f11f5e",
      "releases_from_tags": false,
      "days_since_last_push": 0,
      "active_weeks_last_year": 17,
      "days_since_latest_release": 0,
      "mean_days_between_releases": 0.1
    },
    "community": {
      "has_readme": true,
      "has_license": true,
      "has_description": true,
      "has_contributing": true,
      "health_percentage": 71,
      "has_issue_template": false,
      "has_code_of_conduct": false,
      "has_pull_request_template": false
    },
    "ecosystem": {
      "packages": [
        {
          "name": "ai-guardian",
          "exists": true,
          "license": "Apache-2.0",
          "keywords": [
            "ai",
            "claude",
            "cursor",
            "gitleaks",
            "hooks",
            "secrets",
            "security",
            "Development Status :: 4 - Beta",
            "Intended Audience :: Developers",
            "License :: OSI Approved :: Apache Software License",
            "Operating System :: OS Independent",
            "Programming Language :: Python :: 3",
            "Programming Language :: Python :: 3.10",
            "Programming Language :: Python :: 3.11",
            "Programming Language :: Python :: 3.12",
            "Programming Language :: Python :: 3.13",
            "Programming Language :: Python :: 3.14",
            "Programming Language :: Python :: 3.9",
            "Topic :: Security",
            "Topic :: Software Development"
          ],
          "ecosystem": "pypi",
          "matches_repo": true,
          "registry_url": "https://pypi.org/project/ai-guardian/",
          "is_deprecated": false,
          "latest_version": "1.15.0",
          "repository_url": "https://github.com/itdove/ai-guardian",
          "versions_count": 33,
          "total_downloads": null,
          "dependents_count": null,
          "deprecation_note": null,
          "maintainers_count": null,
          "monthly_downloads": null,
          "first_published_at": "2026-03-24T01:42:59.545984Z",
          "latest_published_at": "2026-07-22T17:37:59.953233Z",
          "latest_version_yanked": null,
          "days_since_latest_publish": 0
        }
      ]
    },
    "popularity": {
      "forks": 5,
      "stars": 10,
      "watchers": 0,
      "fork_history": {
        "days": [
          {
            "date": "2026-04-14",
            "count": 1
          },
          {
            "date": "2026-05-07",
            "count": 1
          },
          {
            "date": "2026-05-28",
            "count": 1
          },
          {
            "date": "2026-05-29",
            "count": 1
          },
          {
            "date": "2026-06-06",
            "count": 1
          }
        ],
        "complete": true,
        "collected": 5,
        "total_forks": 5
      },
      "star_history": null,
      "open_issues_and_prs": 33
    },
    "ai_readiness": {
      "has_nix": false,
      "example_dirs": [
        "examples"
      ],
      "has_llms_txt": false,
      "has_dockerfile": true,
      "has_mcp_signal": true,
      "bootstrap_files": [
        "Makefile"
      ],
      "api_schema_files": [],
      "has_devcontainer": false,
      "typecheck_configs": [],
      "toolchain_manifests": [],
      "largest_source_bytes": 259298,
      "source_files_sampled": 558,
      "oversized_source_files": 17,
      "agent_instruction_files": [
        "AGENTS.md",
        "CLAUDE.md",
        "examples/aider/.aider.conf.yml"
      ],
      "agent_instruction_max_bytes": 70167
    },
    "dependencies": {
      "manifests": [
        "pyproject.toml"
      ],
      "advisories": {
        "error": "No resolved dependencies carried a version and a supported ecosystem",
        "scope": "repository_graph",
        "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": 29,
        "direct_affected_count": 0
      },
      "ecosystems": [
        "pypi"
      ],
      "dependencies": [
        {
          "name": "textual",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": ">=0.47.0"
        },
        {
          "name": "jsonschema",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": ">=4.0.0"
        },
        {
          "name": "requests",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": ">=2.28.0"
        },
        {
          "name": "tomli",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": ">=2.0.0"
        },
        {
          "name": "tomli-w",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": ">=1.0.0"
        },
        {
          "name": "pyyaml",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": ">=6.0.0"
        },
        {
          "name": "tree-sitter",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": ">=0.25.0"
        },
        {
          "name": "tree-sitter-json",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": ">=0.24.0"
        },
        {
          "name": "tree-sitter-python",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": ">=0.23"
        },
        {
          "name": "tree-sitter-javascript",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": ">=0.23"
        },
        {
          "name": "tree-sitter-typescript",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": ">=0.23"
        },
        {
          "name": "tree-sitter-go",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": ">=0.23"
        },
        {
          "name": "tree-sitter-rust",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": ">=0.23"
        },
        {
          "name": "tree-sitter-java",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": ">=0.23"
        },
        {
          "name": "tree-sitter-ruby",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": ">=0.23"
        },
        {
          "name": "tree-sitter-c",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": ">=0.23"
        },
        {
          "name": "tree-sitter-cpp",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": ">=0.23"
        },
        {
          "name": "tree-sitter-bash",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": ">=0.23"
        },
        {
          "name": "pystray",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": ">=0.19.0"
        },
        {
          "name": "Pillow",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": ">=9.0.0"
        },
        {
          "name": "docker",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": ">=7.0,<9"
        },
        {
          "name": "mcp",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": ">=1.10.0"
        },
        {
          "name": "rapidocr-onnxruntime",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": ">=1.4.0"
        },
        {
          "name": "onnxruntime",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": ">=1.15.0"
        },
        {
          "name": "nicegui",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": ">=3.0.0"
        },
        {
          "name": "tokenizers",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": ">=0.15.0"
        },
        {
          "name": "boto3",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": ">=1.28.0"
        },
        {
          "name": "bandit",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": ">=1.7.0"
        }
      ],
      "all_dependencies": {
        "error": null,
        "source": "github-sbom",
        "packages": [
          {
            "name": "bandit",
            "direct": true,
            "version": null,
            "ecosystem": "pypi"
          },
          {
            "name": "boto3",
            "direct": true,
            "version": null,
            "ecosystem": "pypi"
          },
          {
            "name": "docker",
            "direct": true,
            "version": null,
            "ecosystem": "pypi"
          },
          {
            "name": "jsonschema",
            "direct": true,
            "version": null,
            "ecosystem": "pypi"
          },
          {
            "name": "mcp",
            "direct": true,
            "version": null,
            "ecosystem": "pypi"
          },
          {
            "name": "nicegui",
            "direct": true,
            "version": null,
            "ecosystem": "pypi"
          },
          {
            "name": "onnxruntime",
            "direct": true,
            "version": null,
            "ecosystem": "pypi"
          },
          {
            "name": "pillow",
            "direct": true,
            "version": null,
            "ecosystem": "pypi"
          },
          {
            "name": "pystray",
            "direct": true,
            "version": null,
            "ecosystem": "pypi"
          },
          {
            "name": "pyyaml",
            "direct": true,
            "version": null,
            "ecosystem": "pypi"
          },
          {
            "name": "requests",
            "direct": true,
            "version": null,
            "ecosystem": "pypi"
          },
          {
            "name": "textual",
            "direct": true,
            "version": null,
            "ecosystem": "pypi"
          },
          {
            "name": "tokenizers",
            "direct": true,
            "version": null,
            "ecosystem": "pypi"
          },
          {
            "name": "tomli-w",
            "direct": true,
            "version": null,
            "ecosystem": "pypi"
          },
          {
            "name": "tree-sitter",
            "direct": true,
            "version": null,
            "ecosystem": "pypi"
          },
          {
            "name": "tree-sitter-bash",
            "direct": true,
            "version": null,
            "ecosystem": "pypi"
          },
          {
            "name": "tree-sitter-c",
            "direct": true,
            "version": null,
            "ecosystem": "pypi"
          },
          {
            "name": "tree-sitter-cpp",
            "direct": true,
            "version": null,
            "ecosystem": "pypi"
          },
          {
            "name": "tree-sitter-go",
            "direct": true,
            "version": null,
            "ecosystem": "pypi"
          },
          {
            "name": "tree-sitter-java",
            "direct": true,
            "version": null,
            "ecosystem": "pypi"
          },
          {
            "name": "tree-sitter-javascript",
            "direct": true,
            "version": null,
            "ecosystem": "pypi"
          },
          {
            "name": "tree-sitter-json",
            "direct": true,
            "version": null,
            "ecosystem": "pypi"
          },
          {
            "name": "tree-sitter-python",
            "direct": true,
            "version": null,
            "ecosystem": "pypi"
          },
          {
            "name": "tree-sitter-ruby",
            "direct": true,
            "version": null,
            "ecosystem": "pypi"
          },
          {
            "name": "tree-sitter-rust",
            "direct": true,
            "version": null,
            "ecosystem": "pypi"
          },
          {
            "name": "tree-sitter-typescript",
            "direct": true,
            "version": null,
            "ecosystem": "pypi"
          },
          {
            "name": "pygobject",
            "direct": false,
            "version": null,
            "ecosystem": "pypi"
          },
          {
            "name": "pytest",
            "direct": false,
            "version": null,
            "ecosystem": "pypi"
          },
          {
            "name": "pytest-asyncio",
            "direct": false,
            "version": null,
            "ecosystem": "pypi"
          }
        ],
        "collected": true,
        "truncated": false,
        "total_count": 29,
        "direct_count": 26,
        "indirect_count": 3
      }
    },
    "maintainership": {
      "issues": {
        "open_prs": 0,
        "merged_prs": 811,
        "open_issues": 33,
        "closed_ratio": 0.963,
        "closed_issues": 865,
        "closed_unmerged_prs": 2
      },
      "bus_factor": 1,
      "bot_contributors": 1,
      "top_contributors": [
        {
          "type": "User",
          "login": "itdove",
          "commits": 1723,
          "avatar_url": "https://avatars.githubusercontent.com/u/28610057?v=4"
        },
        {
          "type": "User",
          "login": "shanemcd",
          "commits": 4,
          "avatar_url": "https://avatars.githubusercontent.com/u/773186?v=4"
        }
      ],
      "contributors_sampled": 2,
      "top_contributor_share": 0.998
    },
    "quality_signals": {
      "has_ci": true,
      "has_tests": true,
      "ci_workflows": [
        "build-container.yml",
        "build-wheel.yml",
        "integration-tests.yml",
        "lint.yml",
        "parser-compat.yml",
        "pattern-research-reminder.yml",
        "publish.yml",
        "release-readiness.yml",
        "scenario-tests.yml",
        "smoke-tests.yml",
        "tag-monitor.yml",
        "test.yml"
      ],
      "has_docs_dir": true,
      "linter_configs": [],
      "has_editorconfig": false,
      "has_linter_config": true,
      "has_precommit_config": true
    },
    "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": 6,
            "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": 10,
            "reason": "26 out of 26 merged PRs checked by a CI test -- score normalized to 10",
            "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/30 approved changesets -- score normalized to 0",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#code-review"
          },
          {
            "name": "Contributors",
            "score": 6,
            "reason": "project has 2 contributing companies or organizations -- score normalized to 6",
            "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": 10,
            "reason": "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": 9,
            "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 30 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": "2f11f5ed6f722e95a2f1618c918bff5049334bda",
        "ran_at": "2026-07-22T19:07:43Z",
        "aggregate_score": 5.3,
        "scorecard_version": "v5.5.0"
      },
      "has_codeql_workflow": false,
      "has_security_policy": false,
      "has_dependabot_config": true
    },
    "contribution_flow": {
      "collected": true,
      "ci_last_run_at": "2026-07-22T17:51:25Z",
      "oldest_open_prs": [],
      "last_merged_pr_at": "2026-07-22T16:41:45Z",
      "ci_last_conclusion": "SUCCESS",
      "oldest_open_issues": [
        {
          "number": 77,
          "created_at": "2026-04-16T00:54:34Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 251,
          "created_at": "2026-04-25T14:03:00Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 265,
          "created_at": "2026-04-26T18:39:05Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 266,
          "created_at": "2026-04-26T18:39:57Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 267,
          "created_at": "2026-04-26T18:40:40Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 268,
          "created_at": "2026-04-26T18:41:23Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 269,
          "created_at": "2026-04-26T18:42:01Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 270,
          "created_at": "2026-04-26T18:42:50Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 331,
          "created_at": "2026-04-30T20:52:07Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 334,
          "created_at": "2026-04-30T23:59:44Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 437,
          "created_at": "2026-05-04T18:17:02Z",
          "last_comment_at": "2026-05-07T17:03:40Z",
          "last_comment_author": "itdove"
        },
        {
          "number": 438,
          "created_at": "2026-05-04T18:20:29Z",
          "last_comment_at": "2026-05-07T17:03:41Z",
          "last_comment_author": "itdove"
        },
        {
          "number": 453,
          "created_at": "2026-05-06T13:28:08Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 470,
          "created_at": "2026-05-07T13:15:37Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 472,
          "created_at": "2026-05-07T13:20:03Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 473,
          "created_at": "2026-05-07T13:20:04Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 540,
          "created_at": "2026-05-12T03:37:15Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 551,
          "created_at": "2026-05-12T20:49:24Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 609,
          "created_at": "2026-05-15T16:11:52Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 616,
          "created_at": "2026-05-15T19:08:01Z",
          "last_comment_at": null,
          "last_comment_author": null
        }
      ]
    }
  },
  "config": {
    "disabled_metrics": [],
    "disabled_categories": [],
    "disabled_components": {}
  },
  "source": {
    "url": "https://github.com/itdove/ai-guardian",
    "host": "github.com",
    "name": "ai-guardian",
    "owner": "itdove"
  },
  "metrics": {
    "overall": {
      "key": "overall",
      "band": "moderate",
      "name": "Overall health",
      "note": null,
      "notes": [],
      "value": 64,
      "inputs": {
        "security": 53,
        "vitality": 82,
        "community": 41,
        "governance": 59,
        "engineering": 82
      },
      "components": []
    },
    "categories": [
      {
        "key": "vitality",
        "band": "good",
        "name": "Vitality",
        "value": 82,
        "weight": 0.22,
        "metrics": [
          {
            "key": "development_activity",
            "band": "good",
            "name": "Development activity",
            "note": null,
            "notes": [],
            "value": 76,
            "inputs": {
              "commits_last_year": 1722,
              "human_commit_share": 1,
              "days_since_last_push": 0,
              "active_weeks_last_year": 17
            },
            "components": [
              {
                "key": "push_recency",
                "name": "Push recency",
                "detail": "last push 0 days ago",
                "points": 36,
                "status": "met",
                "details": [
                  {
                    "code": "push_recency",
                    "params": {
                      "days": 0
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_cadence",
                "name": "Commit cadence",
                "detail": "17/52 weeks with commits",
                "points": 11.8,
                "status": "partial",
                "details": [
                  {
                    "code": "commit_cadence_weeks",
                    "params": {
                      "weeks": 17
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_volume",
                "name": "Commit volume",
                "detail": "1722 commits in the last year",
                "points": 18,
                "status": "met",
                "details": [
                  {
                    "code": "commits_last_year",
                    "params": {
                      "count": 1722
                    }
                  }
                ],
                "max_points": 18
              },
              {
                "key": "openssf_scorecard_maintained",
                "name": "OpenSSF Scorecard: Maintained",
                "detail": "30 commit(s) and 30 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": 100,
              "latest_release_tag": "rc-1.16.0-dev-main.2f11f5e",
              "releases_from_tags": false,
              "days_since_latest_release": 0,
              "mean_days_between_releases": 0.1
            },
            "components": [
              {
                "key": "ships_releases",
                "name": "Ships releases",
                "detail": "100 releases published",
                "points": 27,
                "status": "met",
                "details": [
                  {
                    "code": "releases_published",
                    "params": {
                      "count": 100
                    }
                  }
                ],
                "max_points": 27
              },
              {
                "key": "release_recency",
                "name": "Release recency",
                "detail": "latest release 0 days ago",
                "points": 36,
                "status": "met",
                "details": [
                  {
                    "code": "release_recency",
                    "params": {
                      "days": 0
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "release_cadence",
                "name": "Release cadence",
                "detail": "a release every ~0.1 days",
                "points": 27,
                "status": "met",
                "details": [
                  {
                    "code": "release_cadence",
                    "params": {
                      "gap": 0.1
                    }
                  }
                ],
                "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": 41,
        "weight": 0.18,
        "metrics": [
          {
            "key": "popularity",
            "band": "critical",
            "name": "Popularity & adoption",
            "note": null,
            "notes": [],
            "value": 20,
            "inputs": {
              "forks": 5,
              "stars": 10,
              "watchers": 0,
              "growth_state": "unverified",
              "growth_factor_pct": 100,
              "growth_unverified_reason": "no_history"
            },
            "components": [
              {
                "key": "stars",
                "name": "Stars",
                "detail": "10 stars",
                "points": 15.5,
                "status": "partial",
                "details": [
                  {
                    "code": "stars",
                    "params": {
                      "count": 10
                    }
                  }
                ],
                "max_points": 60
              },
              {
                "key": "forks",
                "name": "Forks",
                "detail": "5 forks",
                "points": 5,
                "status": "partial",
                "details": [
                  {
                    "code": "forks",
                    "params": {
                      "count": 5
                    }
                  }
                ],
                "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": 64,
            "inputs": {
              "has_readme": true,
              "has_license": true,
              "has_contributing": true,
              "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": "license file present, not a recognized license",
                "points": 16.9,
                "status": "partial",
                "details": [
                  {
                    "code": "license_custom",
                    "params": {}
                  }
                ],
                "max_points": 22.5
              },
              {
                "key": "contributing_guide",
                "name": "CONTRIBUTING guide",
                "detail": null,
                "points": 18,
                "status": "met",
                "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": 59,
        "weight": 0.24,
        "metrics": [
          {
            "key": "maintainer_resilience",
            "band": "critical",
            "name": "Maintainer resilience (bus factor)",
            "note": null,
            "notes": [],
            "value": 18,
            "inputs": {
              "bus_factor": 1,
              "contributors_sampled": 2,
              "top_contributor_share": 0.998
            },
            "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": "partial",
                "details": [
                  {
                    "code": "top_contributor_share",
                    "params": {
                      "share": 100
                    }
                  }
                ],
                "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 2 contributing companies or organizations -- score normalized to 6",
                "points": 6,
                "status": "partial",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "responsiveness",
            "band": "good",
            "name": "Issue & PR responsiveness",
            "note": null,
            "notes": [],
            "value": 83,
            "inputs": {
              "merged_prs": 811,
              "open_issues": 33,
              "closed_issues": 865,
              "issue_closed_ratio": 0.963,
              "closed_unmerged_prs": 2
            },
            "components": [
              {
                "key": "issue_resolution",
                "name": "Issue resolution",
                "detail": "96% of issues closed",
                "points": 45,
                "status": "partial",
                "details": [
                  {
                    "code": "issues_closed_share",
                    "params": {
                      "share": 96
                    }
                  }
                ],
                "max_points": 46.75
              },
              {
                "key": "pr_acceptance",
                "name": "PR acceptance",
                "detail": "811/813 decided PRs merged",
                "points": 38.2,
                "status": "partial",
                "details": [
                  {
                    "code": "decided_prs_merged",
                    "params": {
                      "merged": 811,
                      "decided": 813
                    }
                  }
                ],
                "max_points": 38.25
              },
              {
                "key": "openssf_scorecard_code_review",
                "name": "OpenSSF Scorecard: Code-Review",
                "detail": "Found 0/30 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": 51,
            "inputs": {
              "followers": 6,
              "owner_type": "User",
              "is_verified": null,
              "owner_login": "itdove",
              "public_repos": 77,
              "account_age_days": 3359
            },
            "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": "6 followers of itdove",
                "points": 6.1,
                "status": "partial",
                "details": [
                  {
                    "code": "owner_followers",
                    "params": {
                      "count": 6,
                      "login": "itdove"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "track_record",
                "name": "Track record",
                "detail": "77 public repos, account ~9 yr old",
                "points": 25,
                "status": "met",
                "details": [
                  {
                    "code": "public_repos",
                    "params": {
                      "count": 77
                    }
                  },
                  {
                    "code": "account_age_years",
                    "params": {
                      "years": 9
                    }
                  }
                ],
                "max_points": 25
              }
            ]
          },
          {
            "key": "package_maintenance",
            "band": "excellent",
            "name": "Package maintenance",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "packages": [
                "ai-guardian"
              ],
              "ecosystems": "pypi",
              "any_deprecated": false,
              "min_days_since_publish": 0
            },
            "components": [
              {
                "key": "published_resolvable",
                "name": "Published & resolvable",
                "detail": "1 package(s) on pypi",
                "points": 25,
                "status": "met",
                "details": [
                  {
                    "code": "packages_published",
                    "params": {
                      "count": 1,
                      "ecosystems": "pypi"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "publish_recency",
                "name": "Publish recency",
                "detail": "latest publish 0 days ago",
                "points": 35,
                "status": "met",
                "details": [
                  {
                    "code": "publish_recency",
                    "params": {
                      "days": 0
                    }
                  }
                ],
                "max_points": 35
              },
              {
                "key": "version_history",
                "name": "Version history",
                "detail": "33 published versions",
                "points": 20,
                "status": "met",
                "details": [
                  {
                    "code": "published_versions",
                    "params": {
                      "count": 33
                    }
                  }
                ],
                "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": "good",
        "name": "Engineering Quality",
        "value": 82,
        "weight": 0.2,
        "metrics": [
          {
            "key": "engineering_practices",
            "band": "excellent",
            "name": "Engineering practices",
            "note": null,
            "notes": [],
            "value": 94,
            "inputs": {
              "has_ci": true,
              "has_tests": true,
              "has_editorconfig": false,
              "has_linter_config": true,
              "has_precommit_config": true
            },
            "components": [
              {
                "key": "ci_workflows",
                "name": "CI workflows",
                "detail": "12 workflow(s)",
                "points": 24,
                "status": "met",
                "details": [
                  {
                    "code": "ci_workflows",
                    "params": {
                      "count": 12
                    }
                  }
                ],
                "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": 16,
                "status": "met",
                "details": [],
                "max_points": 16
              },
              {
                "key": "pre_commit_hooks",
                "name": "Pre-commit hooks",
                "detail": null,
                "points": 9.6,
                "status": "met",
                "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": "26 out of 26 merged PRs checked by a CI test -- score normalized to 10",
                "points": 20,
                "status": "met",
                "details": [],
                "max_points": 20
              }
            ]
          },
          {
            "key": "documentation",
            "band": "moderate",
            "name": "Documentation",
            "note": null,
            "notes": [],
            "value": 65,
            "inputs": {
              "topics": [],
              "has_wiki": false,
              "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": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              }
            ]
          }
        ],
        "description": "Are baseline engineering and documentation practices in place?"
      },
      {
        "key": "security",
        "band": "moderate",
        "name": "Security",
        "value": 53,
        "weight": 0.16,
        "metrics": [
          {
            "key": "security_posture",
            "band": "moderate",
            "name": "Security posture",
            "note": null,
            "notes": [],
            "value": 53,
            "inputs": {
              "source": "openssf_scorecard",
              "checks_evaluated": 18,
              "scorecard_version": "v5.5.0",
              "checks_inconclusive": 0,
              "scorecard_aggregate": 5.3
            },
            "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": 4.5,
                "status": "partial",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "ci_tests",
                "name": "CI-Tests",
                "detail": "26 out of 26 merged PRs checked by a CI test -- score normalized to 10",
                "points": 2.5,
                "status": "met",
                "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/30 approved changesets -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "contributors",
                "name": "Contributors",
                "detail": "project has 2 contributing companies or organizations -- score normalized to 6",
                "points": 1.5,
                "status": "partial",
                "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": "update tool detected",
                "points": 7.5,
                "status": "met",
                "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.2,
                "status": "partial",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "maintained",
                "name": "Maintained",
                "detail": "30 commit(s) and 30 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
              }
            ]
          },
          {
            "key": "high_risk_jurisdiction_exposure",
            "band": "excellent",
            "name": "High-Risk Jurisdiction Exposure",
            "note": "Only high-confidence self-published location evidence affects this multiplier. Ambiguous matches are review-only; country evidence is not proof of nationality, citizenship, legal registration, malicious intent, or sanctions status.",
            "notes": [
              {
                "code": "jurisdiction_evidence_limits",
                "params": {}
              }
            ],
            "value": 100,
            "inputs": {
              "meaning": "self-published location evidence; not nationality or citizenship",
              "red_flag": false,
              "exposures": [],
              "policy_countries": [
                "Russia",
                "Iran",
                "North Korea"
              ],
              "review_only_matches": 0,
              "assessed_self_published_locations": 2
            },
            "components": [
              {
                "key": "policy_exposure_multiplier",
                "name": "Policy exposure multiplier",
                "detail": "no confirmed policy-scope location match",
                "points": 100,
                "status": "met",
                "details": [
                  {
                    "code": "jurisdiction_no_match",
                    "params": {}
                  }
                ],
                "max_points": 100
              }
            ]
          }
        ],
        "description": "Are visible security and supply-chain practices strong, with no malicious dependency and no unresolved high-risk jurisdiction exposure?"
      },
      {
        "key": "ai_readiness",
        "band": "good",
        "name": "AI Readiness",
        "value": 73,
        "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.99,
              "agent_instruction_files": [
                "AGENTS.md",
                "CLAUDE.md",
                "examples/aider/.aider.conf.yml"
              ],
              "agent_instruction_max_bytes": 70167
            },
            "components": [
              {
                "key": "agent_instructions",
                "name": "Agent instructions",
                "detail": "AGENTS.md, CLAUDE.md, examples/aider/.aider.conf.yml",
                "points": 45,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "AGENTS.md, CLAUDE.md, examples/aider/.aider.conf.yml"
                    }
                  }
                ],
                "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": "99 of 100 human commits state their intent (structured subject or explanatory body)",
                "points": 40,
                "status": "met",
                "details": [
                  {
                    "code": "legible_history",
                    "params": {
                      "legible": 99,
                      "sampled": 100
                    }
                  }
                ],
                "max_points": 40
              }
            ]
          },
          {
            "key": "ai_verify_loop",
            "band": "good",
            "name": "Verify loop (build / test / typecheck)",
            "note": null,
            "notes": [],
            "value": 76,
            "inputs": {
              "has_nix": false,
              "has_tests": true,
              "lockfiles": [],
              "has_dockerfile": true,
              "typed_language": false,
              "bootstrap_files": [
                "Makefile"
              ],
              "has_devcontainer": false,
              "has_linter_config": true,
              "typecheck_configs": [],
              "agent_commit_share": 0.99,
              "toolchain_manifests": [],
              "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": 11,
                "status": "met",
                "details": [],
                "max_points": 11
              },
              {
                "key": "static_type_checking",
                "name": "Static type checking",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 11
              },
              {
                "key": "reproducible_environment",
                "name": "Reproducible environment",
                "detail": "Dockerfile",
                "points": 10,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "Dockerfile"
                    }
                  }
                ],
                "max_points": 10
              },
              {
                "key": "demonstrated_agent_practice",
                "name": "Demonstrated agent practice",
                "detail": "99 of the last 100 commits agent-authored or agent-credited",
                "points": 10,
                "status": "met",
                "details": [
                  {
                    "code": "agent_authored_commits",
                    "params": {
                      "count": 99,
                      "sampled": 100
                    }
                  }
                ],
                "max_points": 10
              },
              {
                "key": "automated_maintenance",
                "name": "Automated maintenance",
                "detail": "dependency automation configured, none observed in the sampled commits",
                "points": 5,
                "status": "partial",
                "details": [
                  {
                    "code": "dependency_bot_config_only",
                    "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": "moderate",
            "name": "Code legibility for models",
            "note": null,
            "notes": [],
            "value": 53,
            "inputs": {
              "primary_language": "Python",
              "largest_source_bytes": 259298,
              "source_files_sampled": 558,
              "oversized_source_files": 17
            },
            "components": [
              {
                "key": "type_checkable_code",
                "name": "Type-checkable code",
                "detail": "Python without a type-check config",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "no_typecheck_config_language",
                    "params": {
                      "language": "Python"
                    }
                  }
                ],
                "max_points": 45
              },
              {
                "key": "manageable_file_sizes",
                "name": "Manageable file sizes",
                "detail": "17/558 source files over 60KB",
                "points": 53.3,
                "status": "partial",
                "details": [
                  {
                    "code": "oversized_source_files",
                    "params": {
                      "kb": 60,
                      "sampled": 558,
                      "oversized": 17
                    }
                  }
                ],
                "max_points": 55
              }
            ]
          },
          {
            "key": "ai_interfaces",
            "band": "moderate",
            "name": "Machine-readable interfaces",
            "note": null,
            "notes": [],
            "value": 60,
            "inputs": {
              "example_dirs": [
                "examples"
              ],
              "has_mcp_signal": true,
              "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": 20,
                "status": "met",
                "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",
    "deps.dev does not index pypi:ai-guardian@1.15.0; advisories assessed against the repository dependency graph instead",
    "No resolved dependencies carried a version and a supported ecosystem"
  ],
  "report_type": "repository",
  "generated_at": "2026-07-22T19:08:03.664262Z",
  "schema_version": "0.26.0",
  "badge_url": "https://raw.githubusercontent.com/inspect-software/badges/main/v1/i/itdove/ai-guardian.svg",
  "full_name": "itdove/ai-guardian",
  "license_state": "custom",
  "license_spdx": null
}

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.26.0 — full methodology · metrics wiki.

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