Given a GitHub repo reference (URL, owner/repo slug, deep tree/blob URL, or owner URL), return the repository's core metadata, latest release, license, language breakdown, top contributors, README, and health signals as structured JSON. Read-only.
Works with
AI-first code editor with Composer
Before installing skills in Cursor, ensure your development environment meets these requirements:
node --versionget-repo-metadataExecute the skills CLI command in your project's root directory to begin installation:
Fetches get-repo-metadata from github.com/get-repo-metadata-iglddk and configures it for Cursor.
The CLI shows a list of agents. Use arrow keys and space to select Cursor:
Confirm successful installation by checking the skill directory location:
Restart Cursor to activate get-repo-metadata. Access via /get-repo-metadata in your agent's command palette.
We perform automated surface-level scans (Gen AI Scanner, Socket, Snyk) during installation. These checks detect common vulnerabilities but do not guarantee complete security. Always review skill source code and verify the publisher's reputation before production use.
Skills execute code in your environment. Always review source, verify the publisher, and test in isolation before production.
Submit your Claude Code skill and start earning
Automate repetitive workflows and reduce manual effort
Example
Generate reports, summarize documents, draft communications
Save 3-5 hours per week on routine tasks
Learn new skills, understand complex topics, get expert guidance
Example
Explain concepts, provide examples, suggest learning resources
Accelerate learning and skill development by 2x
Enhance output quality through reviews, suggestions, and refinements
Example
Review drafts, suggest improvements, catch errors
Improve work quality by 30-40% with less effort
0
total installs
0
this week
0
upvotes
Run in your terminal
0
installs
0
this week
—
stars
| name | get-repo-metadata |
| title | GitHub Repository Metadata |
| description | >- Given a GitHub repo reference (URL, owner/repo slug, deep tree/blob URL, or owner URL), return the repository's core metadata, latest release, license, language breakdown, top contributors, README, and health signals as structured JSON. Read-only. |
| website | github.com |
| category | developer-tools |
| tags | - github - git - metadata - rest-api - developer-tools - read-only - open-source |
| source | 'browserbase: agent-runtime 2026-05-18' |
| updated | '2026-05-18' |
| recommended_method | api |
| alternative_methods | - method: mcp rationale: >- GitHub publishes an official MCP server (github/github-mcp-server) that wraps the same REST endpoints with consistent naming, transparent auth, and built-in redirect/User-Agent handling. Prefer it when the calling environment has the MCP server attached. - method: browser rationale: >- Fallback for unauthenticated rate-limit exhaustion (60 req/hour per outbound IP). HTML path is materially worse: star/fork/watcher counts, language bar percentages, latest commit, and contributors are all React-rendered and absent from the static HTML response (curl -fetched HTML contains only the About box, topics, and license link). A real browser session with JS execution and post-load hydration wait is required, not just curl. |
| verified | false |
| proxies | false |
Given a GitHub repo reference (full URL, owner/repo slug, deep tree/{branch}/{path} URL, or bare owner URL), return the repository's core metadata as structured JSON: identity (full name, description, homepage, default branch), social signals (stars, forks, watchers, open issues, open PRs), code shape (primary language + per-language byte breakdown), provenance (created/pushed/updated dates, latest commit on default branch, repo size), licensing (SPDX id + license file URL), distribution (latest release with assets, GitHub Pages URL, topics), people (top contributors, owner profile), health files (CoC, contributing, security policy, funding), and the README (base64 + raw). Owner URLs return a paginated, filterable repo list for that owner. Deep tree/.../path URLs add path-content listings to the repo-level payload. Read-only — never clicks Star, Watch, Fork, or any mutation control.
owner/repo to a canonical full payload before downstream operations.GitHub exposes a first-class public REST API at api.github.com that returns every field above in clean JSON with no anti-bot, no auth required for public data, no cookies, no stealth, no proxy. The browser is shipped as a per-the-browser-harness-pattern fallback for one specific failure mode: unauthenticated rate-limit exhaustion (60 req/hour per outbound IP). The HTML path is materially worse — many counts (stars, forks, watchers, language bar percentages) are React-rendered and absent from the static HTML response, so a real browser session is required, not just curl. Lead with the API; only fall back when 403'd by rate limit.
Accept any of:
| Input shape | Parse |
|---|---|
owner/repo | owner=owner, repo=repo |
https://github.com/owner/repo (with optional trailing /) | same |
https://github.com/owner/repo.git | strip .git |
https://github.com/owner/repo/tree/{branch}/{path...} | owner, repo, branch, path (also fetch path contents in step 7) |
https://github.com/owner/repo/blob/{branch}/{file} | treat like tree/ but fetch the blob, not a directory listing |
https://github.com/owner (no second segment) | owner-listing mode — skip steps 2–7, run step 8 |
URL-decode any encoded segments. Lowercase owner and repo for the request (GitHub is case-insensitive for these; the API echoes back the canonical case).
GET https://api.github.com/repos/{owner}/{repo}
Accept: application/vnd.github+json
X-GitHub-Api-Version: 2022-11-28
User-Agent: <descriptive-agent-id>
A User-Agent is required by GitHub or the call 403s with "Request forbidden by administrative rules." Use a descriptive identifier (e.g. browse-sh-github-metadata/1.0).
Returns ~140 fields. Map directly:
| Output field | API path |
|---|---|
full_name | .full_name |
description | .description |
homepage | .homepage |
default_branch | .default_branch |
is_fork | .fork |
parent (when fork) | .parent.full_name (only present on a follow-up GET when ? ... actually present on this same call's .parent when .fork === true) |
is_archived | .archived |
is_template | .is_template |
visibility | .visibility ("public" only from unauth) |
stars | .stargazers_count |
forks | .forks_count |
watchers | .subscribers_count (NOT .watchers_count — see gotcha) |
open_issues_plus_prs | .open_issues_count (includes PRs — see gotcha for splitting) |
size_kb | .size |
created_at | .created_at |
pushed_at | .pushed_at |
updated_at | .updated_at |
license.spdx_id | .license.spdx_id |
license.name | .license.name |
topics | .topics (array of strings) |
primary_language | .language |
html_url | .html_url |
has_pages | .has_pages (boolean — fetch /pages in step 6 if true) |
GET https://api.github.com/repos/{owner}/{repo}/languages
Returns { "JavaScript": 37953343, "TypeScript": 22036924, ... } — byte counts per language. Compute percentages client-side: pct = bytes / sum(bytes) * 100. The API does not return percentages directly.
GET https://api.github.com/repos/{owner}/{repo}/commits/{default_branch}
Returns .sha, .commit.message, .commit.author.date (ISO 8601), .commit.author.name, .commit.author.email, .author.login (account-linked login, may differ from commit-trailer name). Pass ?per_page=1 to /commits if you'd rather query without supplying the branch name explicitly.
GET https://api.github.com/repos/{owner}/{repo}/releases/latest
Returns .tag_name, .name, .published_at, .body (Markdown), .html_url, and .assets[] (each asset has .name, .size, .download_count, .browser_download_url, .content_type). 404 is normal — many repos have tags but no published release. Treat 404 as latest_release: null and optionally fall back to /tags?per_page=1 for the most-recent git tag.
Run these in parallel — they're independent:
GET /repos/{owner}/{repo}/community/profile # health_percentage, files{} pointers to CoC/contributing/security/license/issue_template/pull_request_template/readme
GET /repos/{owner}/{repo}/license # license file: name, path, spdx, content (base64), download_url
GET /repos/{owner}/{repo}/readme # README: name, path, size, content (base64), download_url, html_url
GET /repos/{owner}/{repo}/pages # GitHub Pages config (only call if .has_pages === true; else 404)
GET /repos/{owner}/{repo}/contributors?per_page=30 # array of contributors with .login, .html_url, .contributions, .avatar_url
GET /repos/{owner}/{repo}/contents/.github/FUNDING.yml # funding sources (404 if not set)
The README/license content field is base64-encoded with embedded newlines (every 60 chars). Decode with atob(content.replace(/\n/g, '')) (JS) or base64.b64decode(content) (Python). Alternatively, follow .download_url for the raw bytes from raw.githubusercontent.com — bypasses base64 and doesn't count against core rate limit (it's served from a different host).
For funding sources, the YAML at .github/FUNDING.yml has keys like github: [user1, user2], patreon: handle, open_collective: name, ko_fi: handle, tidelift: platform-name/pkg, community_bridge: project, liberapay: handle, issuehunt: handle, lfx_crowdfunding: project, polar: handle, buy_me_a_coffee: handle, thanks_dev: handle, custom: [url1, url2]. Parse the decoded body.
tree/.../path URL)GET https://api.github.com/repos/{owner}/{repo}/contents/{path}?ref={branch}
Returns an array of {name, path, type ("file"|"dir"|"symlink"|"submodule"), size, sha, html_url, download_url} entries. For a blob (blob/{branch}/{file} input), this returns a single object with .content (base64). Recurse into subdirs only on caller request — the API limits a single response to 1000 entries.
https://github.com/{owner})First resolve owner type:
GET https://api.github.com/users/{owner} # works for BOTH users and orgs; returns .type = "User" | "Organization"
Then list their repos with the requested filters:
GET /users/{owner}/repos?type={all|owner|member}&sort={created|updated|pushed|full_name}&direction={asc|desc}&per_page={1..100}&page={N}
Or — for organizations only, which also accepts the legacy filter values from the GitHub UI:
GET /orgs/{owner}/repos?type={all|public|private|forks|sources|member}&sort=...&direction=...
The org endpoint's type accepts forks / sources / member (UI's "Repo type" filter), while the user endpoint's type is more limited. To filter by language, fetch a page and post-filter on .language === "<X>" — the REST API has no server-side language filter for repo lists (the GitHub UI does it via the /search/repositories endpoint with q=user:owner+language:X, which has a different rate limit).
For pagination, use Link response header's rel="next" and rel="last" URLs — per_page=100 is the max; default is 30.
open_issues_count).open_issues_count on the repo object is issues + PRs combined. To split:
GET https://api.github.com/repos/{owner}/{repo}/pulls?state=open&per_page=1
# Read the response Link header: rel="last" URL has &page={N}; that N === open_pr_count
Then open_issues = open_issues_count - open_pr_count. The Link-header trick is preferred over /search/issues?q=...is:pr+is:open because the latter uses the search API rate limit (10/min for code_search, 30/hour for unauth users on /search/issues), which exhausts much faster than core.
Trigger when all three of these are true:
core rate-limit x-ratelimit-remaining: 0 AND x-ratelimit-reset is more than ~5 minutes away.Authorization: Bearer <token> is available (an auth token raises the limit 83× to 5,000/hr — almost always preferable to falling back to HTML).Steps:
--proxies (residential) is helpful if the unauth IP is itself blocked (rare; GitHub doesn't anti-bot the public web UI for read traffic). A bare session is usually fine.https://github.com/{owner}/{repo}, wait load, wait timeout 1500 for React hydration of the social-count chips. Without that wait, stargazer/fork counts are still in skeleton state.About box — the description, homepage URL, topics, and license name are in the static HTML under <h2 …>About</h2> (selector: h2.h4 containing "About") followed by <p class="f4 tmp-my-3">{description}</p> and topic anchors (a.topic-tag.topic-tag-link[href^="/topics/"]).[data-view-component="true"][href="/{owner}/{repo}/stargazers"] strong, .../forks, .../watchers. NOT in static HTML — requires real browser DOM. Counts on the listing page are abbreviated ("140k") — for exact values, follow the link to /stargazers and read the page-header count, or read the title attribute on the chip (sometimes "140,234" full).div[aria-label="Language: ..."] spans below the About box, each with style="width: XX.X%". Map each span's aria-label to {language, percent}.div[data-testid="latest-commit"] (selector class is volatile across GitHub redesigns; fall back to the <a> whose href matches /{owner}/{repo}/commit/[0-9a-f]{40}).summary[id^="branch-picker-trigger-button"] or the data-branch attribute on the branch-picker <button>.href="/{owner}/{repo}/releases/tag/{tag}". The latest release publish date is a <relative-time> element; read datetime attr for the ISO 8601 value, not textContent (which is humanized like "2 days ago")./{owner}/{repo}/graphs/contributors.<article id="readme"> rendered HTML, OR navigate to /{owner}/{repo}/raw/{default_branch}/README.md (case-sensitive — try README.md, readme.md, README.rst, README.markdown in order) and read the raw bytes.The browser path costs ~6–10x more turns than the API path (the API is one call for 80% of the fields; the browser needs separate navigations for stars-exact / contributors-full / language-bar / releases / readme). Use it only when API quota is exhausted.
User-Agent header is mandatory. API calls without User-Agent return 403 with "Request forbidden by administrative rules." Use a descriptive UA like browse-sh-github-metadata/1.0. Some libraries set it automatically; if you're using bare fetch or curl --no-default-headers, set it explicitly.x-ratelimit-limit: 60, x-ratelimit-remaining: N, x-ratelimit-used: U, x-ratelimit-reset: <epoch> headers are on every response. One full repo payload (steps 2–6) is ~6–8 calls. With auth (Authorization: Bearer {token}) the limit is 5,000/hour — always include a token when one is available, even for "just one lookup", because rate limits aggregate across calls from the same egress IP and you don't control who else shares it./search/* endpoints are 30/hour unauthenticated, 30/min authenticated. Do NOT use /search/issues for routine field extraction — use the Link rel="last" pagination trick on /issues / /pulls instead.api.github.com/graphql returns 401 from unauth. Don't bother for the public-data path.If-None-Match: <etag> → 304) do not consume rate-limit quota. Every JSON response carries a strong ETag; cache and replay. Especially valuable for the repo object, which changes only on push..open_issues_count includes PRs. Issues and PRs share the same numbering space on GitHub. To split: paginate /pulls?state=open&per_page=1 and read Link: <...&page=N>; rel="last"; that N is the open PR count. Then open_issues = open_issues_count - open_pr_count..watchers_count is NOT watchers — it aliases .stargazers_count. A long-standing GitHub API quirk. The actual watch count (people subscribed to notifications) is .subscribers_count. Use that./repos/{owner}/{repo}/releases/latest 404s when the repo has no published GitHub Release, even if it has git tags. Treat 404 as latest_release: null and optionally fall back to /tags?per_page=1 (returns the most recent tag in alphabetical descending order by default, NOT chronological — sort by tagged commit date if you need temporal ordering).content is base64 with embedded newlines. atob(content) fails until you strip \n: atob(content.replace(/\n/g, '')). Or follow .download_url to get raw bytes from raw.githubusercontent.com (no base64, no rate-limit charge).README.md. Common variants: readme.md (lowercase), README.rst (reST), README.markdown, README.adoc (AsciiDoc), or no extension. The /readme endpoint auto-discovers the canonical one; trust its .name/.download_url rather than guessing./community/profile returns null for files the repo doesn't ship. .files.security_policy === null means no SECURITY.md. .files.code_of_conduct.key === "none" means a placeholder was detected but no actual file. Check both .files.{kind} and .files.{kind}_file — they're separate (one is metadata pointing to a recognized template, the other is the literal file)..github/FUNDING.yml returns 404 if not configured — that's the signal for "no funding sources", not an error..has_pages: true on the repo object means a /pages call will succeed; false means skip the call (don't waste a request)..fork: true repos have a .parent and .source field on the same GET response. .parent is the immediate upstream; .source is the ultimate root of the fork chain (may equal .parent)..language (primary) is not always the language with the most bytes. GitHub uses a Linguist-derived heuristic that can demote vendored / generated / docs paths. The /languages endpoint is the authoritative byte breakdown; .language is best-effort for display.Cache-Control: max-age=60, s-maxage=60 on every response. The data is refreshed at most once per minute on GitHub's edge; consecutive requests within 60s may return identical bodies (and identical ETag). Don't poll faster than 60s for "live" updates.Location: https://api.github.com/repositories/{id}. Follow the redirect (or hit /repositories/{id} directly if you have the numeric id) — the underlying .full_name reflects the new owner/name.not_found./users/{owner} works for both user and org accounts and returns .type: "User" or .type: "Organization". /orgs/{owner} only works for orgs (404 on user); /users/{owner}/repos works for both; /orgs/{owner}/repos only for orgs. When unsure, start with /users/{owner} to discover the type, then route to the right repo-list endpoint.per_page max is 100. Lists default to 30/page. Always send per_page=100 for fewer round-trips. Paginate via Link header.curl https://github.com/{owner}/{repo} returns static HTML containing the About box, topics, and license link but NOT the star/fork/watcher counts (skeleton placeholders), language bar percentages, latest-commit info, or contributor avatars. Browser fallback requires a real DOM with JS executed and a wait timeout 1500ms after wait load for hydration./repos/{owner}/{repo} are exactly what shows under the description on the HTML page. The dedicated /topics endpoint (with Accept: application/vnd.github+json) returns the same {names: [...]} list — but is redundant with .topics on the main response. Skip it.?v=N versioning. Append &s=460 (or 80, 200, 460) to size them server-side. Without s= they're full-resolution (~400 KB each).github/github-mcp-server) that wraps these endpoints with consistent param naming and built-in auth. If the calling environment already has the GitHub MCP server attached, prefer it over hand-rolling REST calls — same data, no rate-limit budgeting code, and the MCP server handles redirects and the User-Agent requirement transparently.owner/repo or repo URL){
"mode": "repo",
"owner": {
"login": "vercel",
"type": "Organization",
"name": "Vercel",
"bio": "Agentic infrastructure for every app and agent.",
"blog": "https://vercel.com",
"location": null,
"company": null,
"email": null,
"twitter": "vercel",
"is_verified_org": true,
"avatar_url": "https://avatars.githubusercontent.com/u/14985020?v=4",
"followers": 28362,
"public_repos": 232,
"public_gists": 0,
"created_at": "2015-10-05T19:40:30Z",
"html_url": "https://github.com/vercel"
},
"repo": {
"full_name": "vercel/next.js",
"description": "The React Framework",
"homepage": "https://nextjs.org",
"html_url": "https://github.com/vercel/next.js",
"default_branch": "canary",
"primary_language": "JavaScript",
"languages": [
{ "name": "JavaScript", "bytes": 37953343, "percent": 52.43 },
{ "name": "TypeScript", "bytes": 22036924, "percent": 30.44 },
{ "name": "Rust", "bytes": 9799856, "percent": 13.54 }
],
"stars": 132845,
"forks": 29013,
"watchers": 1582,
"open_issues": 3201,
"open_prs": 1810,
"size_kb": 6432104,
"is_fork": false,
"is_archived": false,
"is_template": false,
"visibility": "public",
"topics": ["react", "nextjs", "vercel", "ssg", "..."],
"license": {
"spdx_id": "MIT",
"name": "MIT License",
"html_url": "https://github.com/vercel/next.js/blob/canary/license.md"
},
"created_at": "2016-10-05T01:32:38Z",
"pushed_at": "2026-05-18T15:50:37Z",
"updated_at": "2026-05-18T15:50:50Z",
"latest_commit": {
"sha": "15d2272c8ccdd34bef15ab2a46eccd27d1574691",
"message": "Distinguish in-navigation errors in the instant error overlay (#93843)",
"date": "2026-05-18T15:50:37Z",
"author_login": "aurorascharff",
"author_name": "Aurora Scharff"
},
"latest_release": {
"tag": "v16.2.6",
"name": "v16.2.6",
"published_at": "2026-05-15T22:00:00Z",
"html_url": "https://github.com/vercel/next.js/releases/tag/v16.2.6",
"body": "...release notes markdown...",
"assets": [
{ "name": "next-swc-x86_64-unknown-linux-gnu.tar.gz", "size": 14523890, "download_count": 1290, "download_url": "https://github.com/vercel/next.js/releases/download/v16.2.6/...", "content_type": "application/gzip" }
]
},
"readme": {
"name": "readme.md",
"path": "readme.md",
"size": 3212,
"raw_url": "https://raw.githubusercontent.com/vercel/next.js/canary/readme.md",
"raw": "<div align=\"center\">\n <a href=\"https://nextjs.org\">\n...",
"rendered_html_url": "https://github.com/vercel/next.js/blob/canary/readme.md"
},
"health": {
"health_percentage": 87,
"code_of_conduct": "https://github.com/vercel/next.js/blob/canary/CODE_OF_CONDUCT.md",
"contributing": "https://github.com/vercel/next.js/blob/canary/contributing.md",
"security_policy": null,
"pull_request_template": "https://github.com/vercel/next.js/blob/canary/.github/pull_request_template.md",
"issue_template": null
},
"funding": null,
"pages_url": null,
"top_contributors": [
{ "login": "ijjk", "html_url": "https://github.com/ijjk", "contributions": 4521, "avatar_url": "https://avatars.githubusercontent.com/u/22380829?v=4" },
{ "login": "timneutkens", "html_url": "https://github.com/timneutkens", "contributions": 3987, "avatar_url": "..." }
]
},
"source": "rest-api",
"rate_limit_remaining": 41
}
Prerequisites
Time Estimate
15-45 minutes depending on use case complexity
Steps
Common Pitfalls
✓ Do
✗ Don't
💡 Pro Tips
✓ Use when
Use when skill capabilities match your task, clear ROI on time saved, and you can validate outputs. Best for repetitive tasks, learning, and quality improvement.
✗ Avoid when
Avoid when task requires deep expertise you can't validate, involves sensitive decisions, or when learning process is more valuable than speed of completion.
kunchenguid/no-mistakes
garrytan/gstack
mattpocock/skills
github/awesome-copilot
booking.com/search-hotels-asq6cc
mattpocock/skills
Solid pick for teams standardizing on skills: get-repo-metadata is focused, and the summary matches what you get after install.
Keeps context tight: get-repo-metadata is the kind of skill you can hand to a new teammate without a long onboarding doc.
get-repo-metadata has been reliable in day-to-day use. Documentation quality is above average for community skills.
get-repo-metadata is among the better-maintained entries we tried; worth keeping pinned for repeat workflows.
We added get-repo-metadata from the explainx registry; install was straightforward and the SKILL.md answered most questions upfront.
get-repo-metadata has been reliable in day-to-day use. Documentation quality is above average for community skills.
Keeps context tight: get-repo-metadata is the kind of skill you can hand to a new teammate without a long onboarding doc.
Solid pick for teams standardizing on skills: get-repo-metadata is focused, and the summary matches what you get after install.
get-repo-metadata is among the better-maintained entries we tried; worth keeping pinned for repeat workflows.
Keeps context tight: get-repo-metadata is the kind of skill you can hand to a new teammate without a long onboarding doc.
showing 1-10 of 49