github-harvester
Extract and process data from GitHub repositories
What this skill does
# GitHub Harvester Skill
> Extract and ingest content from GitHub repositories into RAG.
## Overview
GitHub repositories contain valuable documentation, code examples, and discussions. This skill covers:
- README and documentation extraction
- Code example mining
- Issue and discussion harvesting
- Wiki content extraction
- Release notes and changelogs
## Prerequisites
```bash
# GitHub CLI (recommended)
brew install gh # macOS
# or: https://cli.github.com/
# Python libraries
pip install PyGithub httpx
```
## Authentication
```bash
# Authenticate with GitHub CLI
gh auth login
# Or set token for API access
export GITHUB_TOKEN="ghp_..."
```
## Extraction Methods
### Method 1: GitHub CLI (Recommended)
Best for quick extraction and authenticated access.
```bash
#!/bin/bash
# Extract repo content using gh CLI
REPO="$1" # owner/repo format
# Clone with depth 1 for content only
gh repo clone "$REPO" -- --depth 1
# Get repo info
gh repo view "$REPO" --json name,description,readme
# Get issues
gh issue list --repo "$REPO" --limit 100 --json title,body,comments
# Get discussions (if enabled)
gh api "repos/$REPO/discussions" --paginate
# Get releases
gh release list --repo "$REPO" --limit 20
```
### Method 2: PyGithub API
Better for programmatic access and complex queries.
```python
#!/usr/bin/env python3
"""GitHub content extraction using PyGithub."""
from github import Github
from typing import Dict, List, Optional
import base64
import os
class GitHubExtractor:
"""Extract content from GitHub repositories."""
def __init__(self, token: str = None):
self.token = token or os.getenv("GITHUB_TOKEN")
self.github = Github(self.token) if self.token else Github()
def get_repo(self, repo_name: str):
"""Get repository object."""
return self.github.get_repo(repo_name)
def get_readme(self, repo_name: str) -> Dict:
"""Extract README content."""
repo = self.get_repo(repo_name)
try:
readme = repo.get_readme()
content = base64.b64decode(readme.content).decode('utf-8')
return {
"content": content,
"path": readme.path,
"size": readme.size,
"url": readme.html_url
}
except Exception as e:
return {"error": str(e)}
def get_docs(self, repo_name: str) -> List[Dict]:
"""Extract documentation files."""
repo = self.get_repo(repo_name)
docs = []
# Common doc locations
doc_paths = ['docs', 'doc', 'documentation', '.github']
for path in doc_paths:
try:
contents = repo.get_contents(path)
docs.extend(self._extract_dir(repo, contents))
except Exception:
continue
# Also get root markdown files
try:
root_contents = repo.get_contents("")
for item in root_contents:
if item.type == "file" and item.name.endswith('.md'):
content = base64.b64decode(item.content).decode('utf-8')
docs.append({
"path": item.path,
"content": content,
"url": item.html_url
})
except Exception:
pass
return docs
def _extract_dir(self, repo, contents) -> List[Dict]:
"""Recursively extract directory contents."""
docs = []
if not isinstance(contents, list):
contents = [contents]
for item in contents:
if item.type == "dir":
sub_contents = repo.get_contents(item.path)
docs.extend(self._extract_dir(repo, sub_contents))
elif item.type == "file":
if item.name.endswith(('.md', '.rst', '.txt')):
try:
content = base64.b64decode(item.content).decode('utf-8')
docs.append({
"path": item.path,
"content": content,
"url": item.html_url
})
except Exception:
pass
return docs
def get_code_examples(
self,
repo_name: str,
patterns: List[str] = None
) -> List[Dict]:
"""Extract code examples from repository."""
repo = self.get_repo(repo_name)
examples = []
if patterns is None:
patterns = ['examples', 'samples', 'demo', 'tutorials']
for pattern in patterns:
try:
contents = repo.get_contents(pattern)
examples.extend(self._extract_code(repo, contents))
except Exception:
continue
return examples
def _extract_code(self, repo, contents) -> List[Dict]:
"""Extract code files."""
code = []
code_extensions = ['.py', '.js', '.ts', '.go', '.rs', '.java', '.rb']
if not isinstance(contents, list):
contents = [contents]
for item in contents:
if item.type == "dir":
sub = repo.get_contents(item.path)
code.extend(self._extract_code(repo, sub))
elif item.type == "file":
if any(item.name.endswith(ext) for ext in code_extensions):
try:
content = base64.b64decode(item.content).decode('utf-8')
code.append({
"path": item.path,
"content": content,
"language": self._detect_language(item.name),
"url": item.html_url
})
except Exception:
pass
return code
def _detect_language(self, filename: str) -> str:
"""Detect programming language from filename."""
ext_map = {
'.py': 'python',
'.js': 'javascript',
'.ts': 'typescript',
'.go': 'go',
'.rs': 'rust',
'.java': 'java',
'.rb': 'ruby',
'.sh': 'bash',
}
for ext, lang in ext_map.items():
if filename.endswith(ext):
return lang
return 'unknown'
def get_issues(
self,
repo_name: str,
state: str = "all",
limit: int = 100
) -> List[Dict]:
"""Extract issues with comments."""
repo = self.get_repo(repo_name)
issues = []
for issue in repo.get_issues(state=state)[:limit]:
issue_data = {
"number": issue.number,
"title": issue.title,
"body": issue.body or "",
"state": issue.state,
"labels": [l.name for l in issue.labels],
"created_at": issue.created_at.isoformat(),
"url": issue.html_url,
"comments": []
}
# Get comments
for comment in issue.get_comments():
issue_data["comments"].append({
"body": comment.body,
"author": comment.user.login,
"created_at": comment.created_at.isoformat()
})
issues.append(issue_data)
return issues
def get_discussions(self, repo_name: str, limit: int = 50) -> List[Dict]:
"""Extract discussions using GraphQL API."""
# Note: Requires GraphQL query, simplified version here
query = """
query($owner: String!, $name: String!, $first: Int!) {
repository(owner: $owner, name: $name) {
discussions(first: $first) {
nodes {
title
body
url
category { name }
comments(first: 10) {
nodRelated in General
modeling-omnistudio-epc-catalog
IncludedSalesforce Industries CME EPC product-modeling skill for Product2-based catalog creation. Use when creating EPC products, configuring product attributes, building offer bundles with Product Child Items, or reviewing EPC DataPack JSON metadata for product catalog changes. TRIGGER when: user creates or updates Product2 EPC records, AttributeAssignment payloads, AttributeMetadata/AttributeDefaultValues, Offer bundles, or ProductChildItem relationships. DO NOT TRIGGER when: designing OmniScripts/FlexCards/Integration Procedures (use building-omnistudio-omniscript, building-omnistudio-flexcard, or building-omnistudio-integration-procedure), implementing Apex business logic (use generating-apex), or troubleshooting deployment pipelines (use deploying-metadata).
relationship-science-coach
IncludedUse this skill for direct, practical adult relationship coaching: couples conflict, repair, trust, marriage, dating, flirting, attachment patterns, emotional connection, sex, desire differences, eroticism, kink negotiation, affection, love languages, breakups, and long-term passion. Draw on Gottman, EFT and Hold Me Tight, attachment science, modern sex research, Perel, Nagoski, Kerner, Schnarch, Love and Stosny, and flexible love-language tools. Be concrete and low-hedge. Redirect only for imminent danger, abuse, coercive control, minors, non-consent, self-harm, stalking, or medical/legal/psychiatric decisions.
building-sf-integrations
IncludedSalesforce integration architecture and runtime plumbing with 120-point scoring. Use this skill to set up Named Credentials, External Credentials, External Services, REST/SOAP callout patterns, Platform Events, and Change Data Capture. TRIGGER when: user sets up Named Credentials, External Services, REST/SOAP callouts, Platform Events, CDC, or touches .namedCredential-meta.xml files. DO NOT TRIGGER when: Connected App/OAuth config (use configuring-connected-apps), Apex-only logic (use generating-apex), or data import/export (use handling-sf-data).
venue-templates
IncludedAccess comprehensive LaTeX templates, formatting requirements, and submission guidelines for major scientific publication venues (Nature, Science, PLOS, IEEE, ACM), academic conferences (NeurIPS, ICML, CVPR, CHI), research posters, and grant proposals (NSF, NIH, DOE, DARPA). This skill should be used when preparing manuscripts for journal submission, conference papers, research posters, or grant proposals and need venue-specific formatting requirements and templates.
let-fate-decide
IncludedDraws the 12 Houses of the Zodiac Tarot spread to inject entropy into planning when prompts are vague, ambiguous, or casually delegated. Interprets the spread to guide next steps. Use when the user says 'let fate decide', 'YOLO', 'whatever', 'idk', or other nonchalant phrases, makes Yu-Gi-Oh references, or when you are about to arbitrarily pick between multiple reasonable approaches. Prefer over ask-questions-if-underspecified when the user's tone is casual or playful rather than precision-seeking.
net-ops
IncludedCross-platform network troubleshooting (Windows, macOS, Linux) via local or remote shell. Use for: DNS broken, can't resolve hostnames, nslookup/dig works but apps fail, NRPT, WFP, scutil, /etc/resolver, systemd-resolved, /etc/resolv.conf, NetworkManager, VPN DNS leak residue (ProtonVPN/Mullvad/WireGuard/AnyConnect), AV/firewall blocking DNS or DoH, Tailscale DNS interaction, intermittent connectivity, remote diagnostics over SSH.