On-chain GitHub repository health scoring via GenLayer intelligent contracts and validator consensus.
contract/git_health.py: GenLayer intelligent contract that computes and stores health scores.src/: React + Vite frontend for wallet connection, analyze transactions, cached reads, and score history.contract/tests/: Contract unit tests covering scoring, trust signals, bounds, and v0.2.0 API behavior.
- Production URL:
https://git-health.vercel.app
- User connects wallet (MetaMask-compatible) on GenLayer Studio network (
chainId = 61999). - User submits a GitHub repo URL to
analyze_repo(repo_url). - Contract fetches repository signals from GitHub:
- Primary source: GitHub REST API (
api.github.com) - Fallback/augmentation source: GitHub repo HTML page parsing
- Each validator returns a JSON breakdown including
health_score. - Consensus accepts results only when all validator
health_scorevalues are within 5 points. - If accepted, the most conservative value (lowest score) is selected.
- Contract stores both:
repo_scores[repo_url](numeric score)repo_details[repo_url](full JSON breakdown)
- Frontend reads results via
get_scoreandget_details.
- Parses
owner/repofrom GitHub URL. - Uses GitHub API first (
/repos/{owner}/{repo}, commits, readme, contents, workflows). - Uses HTML parsing as fallback and to fill missing signals.
- If API and HTML both fail, returns previous cached score with error metadata:
"used_cached_score": true
Score starts at 100, then deductions are applied:
- Commit recency:
- Unknown date:
-25 <= 30 days:-031-180 days:-15181-365 days:-40> 365 days:-65- Empty repo:
-20and recency penalty treated as-65 - Open issues:
min(20, open_issues_count // 10) - Missing trust signals:
- No README:
-5 - No CI/workflows:
-5 - No license:
-5 - Forked repo:
-5
Guardrails:
- Final score is clamped to
[0, 100]. get_score(repo_url)returns cached score or0if never analyzed.get_details(repo_url)returns the last JSON breakdown or{}if none exists.
- Network-gated to GenLayer Studio (
chainId 61999, hex0xF22F). - Contract calls use
genlayer-jswithstudionet. - Analyze flow:
- Submits
analyze_repotransaction. - Waits for
FINALIZEDreceipt. - Verifies execution success from leader/validator execution status.
- On success, reads and displays
get_score+get_details. - On execution failure, attempts
debugTraceTransactionfor diagnostics. - Cached read flow:
- Calls
get_score+get_detailswithout submitting a tx. - UI keeps per-session history of analyzed/read entries.
.env.example:
VITE_CONTRACT_ADDRESS=0xF8776A393393e6268fF06B1800d897E905242206
VITE_CHAIN_ID=61999
VITE_RPC_URL=http://localhost:4000/apiAddress resolution behavior:
- Uses
VITE_CONTRACT_ADDRESSwhen set and non-zero. - Falls back to
src/constants.jsdefault address when missing/zero.
Prerequisites:
- Python
3.11+ - Node.js
20+ - GenLayer Studio running locally (
http://localhost:4000) - MetaMask or compatible EIP-1193 wallet
Install and run frontend:
cp .env.example .env
npm install
npm run devRun all contract tests:
PYTHONPATH=. PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 pytest -q contract/tests -vruff check contract/git_health.py contract/tests/
ruff format --check contract/git_health.py contract/tests/