@@ -14,8 +14,14 @@ scored and how, and to set own policy thresholds.
1414
1515HealthyCode uses [ GrimoireLab] ( https://github.com/chaoss/grimoirelab ) to collect
1616data, [ ScanCode.io] ( https://github.com/aboutcode-org/scancode.io ) to run
17- pipelines, and [ PurlDB] ( https://github.com/aboutcode-org/purldb ) to store the
18- data.
17+ pipelines, and [ PurlDB] ( https://github.com/aboutcode-org/purldb ) to store and
18+ access the data.
19+
20+ The main entry point is the PurlDB ` health/ ` API endpoint accessed with a PURL.
21+
22+ A live demo system is available at https://health.purldb.io/api/health/
23+ Use https://health.purldb.io/api/health/?purl=pkg:npm/lodash as an example
24+ of a health metric for the lodash npm.
1925
2026## Why project health matters
2127
@@ -41,7 +47,8 @@ you keep watching the ones you already use as dependencies.
4147## What's provided
4248
4349For this first iteration, we designed HealthyCode's scoring model to be specific
44- to one open source packaging ecosystem, npm. We will extend future support to other ecosystems.
50+ to one open source packaging ecosystem, npm. We will extend future support to
51+ other ecosystems.
4552
4653Given a PURL (Package-URL) for a package, HealthyCode's API returns:
4754
@@ -50,76 +57,80 @@ contributor activity and growth, days since last commit, pony factor (how many
5057people do half the work), and the elephant factor (how many organizations do
5158half the work). The full list is in [ METRICS.md] ( METRICS.md ) .
5259
53- - A health score is calculted from the metrics, between 0 and 1 that is the
54- model's estimate of how likely the project is to be healthy. 0 means unhealthy
55- or risky, and 1 means healthier and less risky.
60+ - A health score is calculated from the metrics, with a value between 0 and 1
61+ that is the model's estimate of how likely the project is to be healthy.
62+ 0 means unhealthy or risky, and 1 means healthier and less risky.
5663
5764- The settings used for the run: time window, thresholds, and the versions of
5865HealthyCode and the scoring model.
5966
6067The API results are JSON, so you can pull these into a dashboard, a report, or
6168in your software supply processing and management pipelines, including policies
6269to allow or block or alert in your own tooling about the health of a software
63- page. HealthyCode gives you the evidence, but the policy decision stays with
64- you.
70+ page. HealthyCode returns metrics (evidence) and a score (interpretation) and
71+ you make decisions based you own policies.
72+
6573
6674Here is a sample result for the ` pkg:npm/semver ` package:
6775``` json
6876{
69- "purl" : " pkg:npm/semver" ,
70- "source_purl" : " pkg:github/npm/node-semver" ,
71- "vcs_url" : " https://github.com/npm/node-semver.git" ,
72- "scoring_model" : " npm-health-0.2" ,
73- "score" : 1.0 ,
74- "commit_range" : {
75- "last_commit" : " 3484e1785e18a7ae4f06365f35c7b6eaec05088a " ,
76- "first_commit" : " a25789b09b1192fa8414c35f2cd679ae2e1d5192 " ,
77- "last_commit_date" : " 2026-09-10T19:51:52+00 :00" ,
78- "first_commit_date" : " 2025-10-07T10:26:26 -07:00"
79- },
80- "run_start_date" : " 2026-10-07T21:22:06.088852Z " ,
81- "run_end_date" : " 2026-10-07T21:22:06.799342Z " ,
82- "metrics" : {
83- "pony_factor" : 2 ,
84- "total_commits" : 45 ,
85- "recent_commits" : 45 ,
86- "active_branches" : 10 ,
87- "elephant_factor" : 1 ,
88- "file_types_code" : 37 ,
89- "commits_per_week" : 0.8630136986301369 ,
90- "commits_per_year" : 45 .0 ,
91- "file_types_other" : 61 ,
92- "commits_per_month" : 3.6986301369863015 ,
93- "file_types_binary" : 0 ,
94- "message_size_mean" : 2538.8444444444444 ,
95- "contributor_growth" : 5 ,
96- "found_file_license" : 1 ,
97- "message_size_total" : 114248 ,
98- "total_contributors" : 16 ,
99- "found_file_adopters" : 0 ,
100- "message_size_median" : 593 ,
101- "recent_contributors" : 16 ,
102- "total_organizations" : 5 ,
103- "recent_organizations" : 5 ,
104- "days_since_last_commit" : 26 ,
105- "returning_contributors" : 0 ,
106- "commit_size_added_lines" : 930 ,
107- "contributor_growth_rate" : 0.7142857142857143 ,
108- "coefficient_of_variation" : 1.0786365421788087 ,
109- "commit_size_removed_lines" : 137 ,
110- "commits_over_periods_rate" : 1.0 ,
111- "developer_categories_core" : 7 ,
112- "developer_categories_casual" : 0 ,
113- "developer_categories_regular" : 9 ,
114- "casual_regular_contributors_rate" : 0.0
115- },
116- "date_collected" : " 2026-10-07T21:22:07.178202Z "
77+ "purl" : " pkg:npm/semver" ,
78+ "source_purl" : " pkg:github/npm/node-semver" ,
79+ "vcs_url" : " https://github.com/npm/node-semver.git" ,
80+ "scoring_model" : " npm-health-0.2" ,
81+ "score" : 1.0 ,
82+ "commit_range" : {
83+ "last_commit" : " c45ec23921ef57d82a420cb6f04f28cf12563ab2 " ,
84+ "first_commit" : " ab9e28a582f524e8d40157f3d2b75fcc764d0765 " ,
85+ "last_commit_date" : " 2026-10-26T15:48:35-04 :00" ,
86+ "first_commit_date" : " 2025-10-30T09:00:25 -07:00"
87+ },
88+ "run_start_date" : " 2026-10-27T13:52:38.948855Z " ,
89+ "run_end_date" : " 2026-10-27T13:52:39.721434Z " ,
90+ "metrics" : {
91+ "pony_factor" : 3 ,
92+ "total_commits" : 56 ,
93+ "recent_commits" : 56 ,
94+ "active_branches" : 16 ,
95+ "elephant_factor" : 2 ,
96+ "file_types_code" : 99 ,
97+ "commits_per_week" : 1.073972602739726 ,
98+ "commits_per_year" : 56 .0 ,
99+ "file_types_other" : 55 ,
100+ "commits_per_month" : 4.602739726027398 ,
101+ "file_types_binary" : 0 ,
102+ "message_size_mean" : 1803.4464285714287 ,
103+ "contributor_growth" : 6 ,
104+ "found_file_license" : 1 ,
105+ "message_size_total" : 100993 ,
106+ "total_contributors" : 17 ,
107+ "found_file_adopters" : 0 ,
108+ "message_size_median" : 471 ,
109+ "recent_contributors" : 17 ,
110+ "total_organizations" : 5 ,
111+ "recent_organizations" : 5 ,
112+ "days_since_last_commit" : 0 ,
113+ "returning_contributors" : 0 ,
114+ "commit_size_added_lines" : 10619 ,
115+ "contributor_growth_rate" : 0.8571428571428571 ,
116+ "coefficient_of_variation" : 1.145922229081032 ,
117+ "commit_size_removed_lines" : 449 ,
118+ "commits_over_periods_rate" : 1.0 ,
119+ "developer_categories_core" : 6 ,
120+ "developer_categories_casual" : 3 ,
121+ "developer_categories_regular" : 8 ,
122+ "casual_regular_contributors_rate" : 0.21428571428571427
123+ },
124+ "date_collected" : " 2026-10-27T13:52:40.041878Z "
117125}
118126
119127```
120128
121129## Who is HealthyCode for?
122130
131+ We designed HealthyCode to support software supply chain(s) decisions making.
132+ This is for:
133+
123134- Software and engineering teams deciding whether to adopt, upgrade, replace, or
124135drop a dependency in their codebases
125136
@@ -149,7 +160,10 @@ configuration or security posture of a project. For those, see:
149160You access health data by Package-URL (PURL) using the PurlDB/health API.
150161This is accessible at https://health.purldb.io/api/health for demonstration.
151162For instance, check https://health.purldb.io/api/health/?purl=pkg:npm/semver or https://health.purldb.io/api/health/?purl=pkg:npm/lodash .
152-
163+
164+ Or https://health.purldb.io/api/health/?purl=pkg:npm/semver&format=json
165+
166+
153167You call the health API for a package using its PURL (for example,
154168` pkg:npm/semver ` ) and get JSON back. If the package has already been analyzed,
155169the answer comes back immediately. If not, you can poll the same URL until the
@@ -172,20 +186,22 @@ access to a configured GrimoireLab instance and HealthCode models.
172186
173187## Run HealthCode locally
174188
175- HealthyCode needs a running [ GrimoireLab 2.x] ( https://github.com/chaoss/grimoirelab/blob/2.x/README.md ) with
176- OpenSearch. GrimoireLab collects the data, and HealthyCode turns the data into metrics
177- (like the menagerie of ponies and elephants) and computes a score.
178-
179- The installation, setup, and command-line usage guidance for GrimoireLab is in
180- [ grimoirelab-guide.md] /(grimoirelab-guide.md).
189+ See [ Installation guide] /(deploy/README.md).
181190
191+ ## High Theory of Operations for HealthyCode
182192
183- ## How HealthyCode works
184- 1 . HealthyCode is given a Git repository URL, or an SPDX SBOM that lists Git repositories.
185- 2 . HealthyCode asks GrimoireLab to collect each repository's history. Repositories GrimoireLab hasn't seen yet are added and analyzed.
186- 3 . When the data is ready, HealthyCode computes the metrics over a time window. The default is 12 months.
187- 4 . The npm health model turns those metrics into a score.
188- 5 . The metrics, score, and run settings are written to a JSON file.
193+ - PurlDB health API receives a PURL. If the health score is available in the DB
194+ the score and metrics are return as-is.
195+ - Otherwise, PurlDB finds the corresponding Git repository.
196+ - PurlDB calls is scan worker (ScanCode.io) to run the "scan_repo_health"
197+ pipeline on that git repo
198+ - That pipeline calls the HealthyCode script
199+ - HealthyCode calls GrimoireLab to clone and collect the repository history
200+ - When the data is ready, HealthyCode computes the metrics over a time window.
201+ - The npm health model turns those metrics into a score.
202+ - The metrics, score, and run settings are written to a JSON file
203+ - That JSON is passed back to ScanCode.io, and then passed back PurlDB
204+ - PurlDB stores the metrics and score for the PURL and return the API results as JSON
189205
190206#### High-level overview of HealthyCode components
191207
@@ -294,7 +310,8 @@ chains. Exposing the /health endpoint in PurlDB also puts a package's health
294310data next to its license and origin data collected in PurlDB from ScanCode,
295311eventually delivering better visibility into the packages from multiple angles.
296312
297- HealthyCode is developed by the AboutCode and GrimoireLab community and contributors like you!
313+ HealthyCode is developed by the AboutCode and GrimoireLab community and
314+ contributors like you!
298315
299316## Contributing
300317
0 commit comments