Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

gh-network

Turn your GitHub interaction history into a networking list: who you've worked with, where they work, when you last spoke, and a LinkedIn link where one exists.

It runs in two stages so you only pay the GitHub API cost once and can iterate on the report for free.

gh_interactions.py  ──►  people.json  ──►  linkedin_match.py  ──►  network.md
   (talks to GitHub)      (handoff)         (no network calls)      network.csv

Requirements

  • Python 3.9+ (no third-party packages)
  • gh CLI, authenticated — run gh auth status to check

The scripts shell out to gh api, so they use your existing login. No tokens to manage.

Usage

# Stage 1 — pull your interaction graph from GitHub
python3 gh_interactions.py --all

# Stage 2 — resolve LinkedIn and build the report
python3 linkedin_match.py

Start smaller on a first run to see the shape of the data:

python3 gh_interactions.py --no-comments --max-threads 300

Stage 1 — gh_interactions.py

Everything that touches the GitHub API:

  1. Finds every issue/PR you're involved in via the Search API (involves:you) — authored, commented on, assigned, reviewed, or mentioned in. The Search API caps at 1000 results per query, so it windows by date to walk further back.
  2. Collects the other participants and the most recent time you shared a thread with each.
  3. Fetches each person's profile, plus any LinkedIn URL they put on their GitHub profile (via the social_accounts API, falling back to a scan of their blog/bio).
  4. Infers a company for people who left the field blank — from public org memberships, @handle mentions in their bio, or a non-free email domain.
Flag Effect
--all Pull the entire history (same as --max-threads 0)
--max-threads N Cap the scan (default 1000)
--no-comments Only thread authors, skip fetching every commenter — much faster
--no-org-lookup Skip the org-membership lookup used to infer companies
--user NAME Someone else's public activity
--refresh Ignore caches and re-pull

Stage 2 — linkedin_match.py

No network calls. Reads people.json and:

  1. Keeps LinkedIn URLs found on GitHub profiles.
  2. For everyone else, builds a LinkedIn people-search URL from their name and company — see the caveat below.
  3. Drops anyone with neither a LinkedIn nor a real name.
  4. Groups by company, sorts by most recent contact.
Flag Effect
--min-interactions N Drop people you've shared fewer than N threads with
--company-sources ... Which inferred company sources to trust (see below)
--in PATH Read a different stage-1 file

curate.py

An optional example of post-processing people.json into a hand-tiered CONTACTS.md — ranked tiers, a junk-company blocklist, and an explicit record of what was excluded. Treat it as a starting point to edit, not a finished tool.

Output

Written to gh_network_out/:

File What
interactions.json Cache: threads and participants
profiles.json Cache: fetched user profiles
orgs.json Cache: public org memberships
people.json Handoff file between the two stages
network.md The report, grouped by company
network.csv Same data, flat

All of this is gitignored. See Privacy below.

Caveats worth reading

LinkedIn is not scraped, and can't be. LinkedIn blocks automated access behind a login wall and scraping it violates their terms. So there are exactly two kinds of LinkedIn link in the output:

  • profile — the person put their LinkedIn on their GitHub profile. Reliable.
  • search — no LinkedIn on file, so you get a pre-filled name + company search to confirm by eye. This is a lead, not a match.

If you have legitimate access to a sanctioned lookup API, resolve() in linkedin_match.py is the single seam where it would plug in.

Inferred companies are noisy. GitHub's company field is optional and most people leave it blank. The org-membership fallback roughly halves the unknown bucket, but GitHub orgs are frequently open-source projects rather than employers — llvm, tldr-pages and sonata-project are not anyone's job. Every company is therefore tagged with its source:

Source Trust
profile They typed it themselves — reliable
bio An @handle in their bio — decent
org A public org membership — noisy, verify
email A non-free email domain — weak

Filter with --company-sources profile,bio for a smaller, cleaner list.

Rate limits. A full run with comment-fetching is roughly one API call per thread, per comment page, and per person. Large histories can exceed the 5000/hour authenticated limit; the script sleeps and resumes automatically. Caches are written at the end of the gather step, so killing it mid-pull loses that run's progress.

Privacy

This tool aggregates personal data about real people — names, locations, employers, and social links. It only ever reads public GitHub profile data via the official API, and only for people you have actually interacted with.

.gitignore excludes every output file. Keep it that way. Publishing a generated list would republish third parties' personal data without their consent, and aggregating scattered public details into a single profile is a meaningfully different act from each detail being public on its own. Use it for remembering who you know; not for building a dossier, and not for bulk outreach.

If you're in the EU/UK, note that a list like this falls under GDPR once it leaves personal use.

License

MIT — see LICENSE.

About

Turn your GitHub interaction history into a networking list: who you've worked with, where they work, and when you last spoke.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages