The GitHub Analyst agent verifies candidate GitHub profiles, calculates a quality score from 0-100, and extracts project information. It combines GitHub API data with web scraping fallbacks to ensure reliable results even when rate limits are hit.
When the GitHub API is rate-limited or returns low scores, the agent falls back to web scraping:
backend/agents/github_agent.py
if score_val <= 40 or not result.get("projects"): print(f"API Rate Limited? Attempting scraping fallback for {github_url}...") try: import requests from bs4 import BeautifulSoup headers = {"User-Agent": "Mozilla/5.0"} resp = requests.get(github_url, headers=headers, timeout=10) if resp.status_code == 200: soup = BeautifulSoup(resp.text, 'html.parser') # Extract Bio bio_tag = soup.find('div', class_='p-note user-profile-bio') bio = bio_tag.get_text(strip=True) if bio_tag else "No bio found" # Extract Top Repos repos = [] repo_tags = soup.find_all('span', class_='repo')[:5] for r in repo_tags: parent = r.find_parent('div', class_='pinned-item-list-item-content') desc = "Portfolio Project" if parent: desc_tag = parent.find('p', class_='pinned-item-desc') if desc_tag: desc = desc_tag.get_text(strip=True) repos.append(f"{r.get_text(strip=True)}: {desc}") if repos: result["projects"] = " | ".join(repos) result["score"] = max(result["score"], 60) # Extract Email (if public) email_tag = soup.find('a', class_='u-email') if email_tag: result["email"] = email_tag.get_text(strip=True) except Exception as e: print(f"Scraping fallback failed: {e}")
The scraping fallback provides a minimum score of 60 when it successfully extracts pinned repositories. This prevents false negatives for legitimate profiles that hit API rate limits.
The agent returns a JSON object with score, projects, and optionally email:
{ "score": 85, "projects": "awesome-ai-tool: Machine learning framework for text analysis | web-portfolio: Personal portfolio built with React and TypeScript | api-gateway: Microservices API gateway with authentication", "email": "[email protected]"}
The GitHub verifier gracefully handles invalid URLs and API failures:
backend/github_verifier.py
def verify_github(github_link: str) -> dict: result = {"score": 40, "projects": ""} if not github_link or "github.com/" not in github_link: result["score"] = 0 return result try: # API logic here return result except Exception: return result # Return default score
Invalid or missing GitHub links receive a score of 0. Network errors or timeouts return a score of 40, which represents “unable to verify” rather than “definitely bad.”
if __name__ == "__main__": if not os.environ.get("ZYND_API_KEY") or os.environ.get("ZYND_API_KEY") == "REPLACE_ME_WITH_ZYND_API_KEY": print("ERROR: ZYND_API_KEY is not set. Please set it in .env") sys.exit(1) print(f"FairMatch GitHub Analyst Agent running at {agent.webhook_url}") print(f"Price: {agent_config.price} per request") try: while True: time.sleep(1) except KeyboardInterrupt: print("Shutting down...")