Collect structured, read-only professional evidence from a public GitHub user profile and repositories: profile metadata, repository metadata, README text, package.json technology/configuration details, directory listings, and selected file contents.
Use Cases
Use when the caller provides a GitHub username and needs a profile-and-repository overview or deeper evidence from selected public repositories. This recipe is for public API data only and does not infer private activity or access authenticated resources.
Automation Flow
- Fetch the public profile directly:
https://api.github.com/users/{username}
Run this evaluator on the loaded response:
(() => {
const j = JSON.parse(document.body.innerText);
if (j.message) throw new Error(j.message);
return {
login: j.login ?? null,
id: j.id ?? null,
name: j.name ?? null,
company: j.company ?? null,
blog: j.blog ?? null,
location: j.location ?? null,
bio: j.bio ?? null,
public_repos: j.public_repos ?? 0,
followers: j.followers ?? 0,
following: j.following ?? 0,
created_at: j.created_at ?? null,
updated_at: j.updated_at ?? null,
html_url: j.html_url ?? null
};
})()- Fetch the public repository collection directly, sorted by most recently updated:
https://api.github.com/users/{username}/repos?per_page=100&sort=updated
Run this evaluator:
(() => {
const a = JSON.parse(document.body.innerText);
if (!Array.isArray(a)) throw new Error(a.message || "GitHub repositories response is not an array");
return a.map(r => ({
id: r.id ?? null,
name: r.name ?? null,
full_name: r.full_name ?? null,
description: r.description ?? null,
html_url: r.html_url ?? null,
fork: r.fork ?? false,
language: r.language ?? null,
created_at: r.created_at ?? null,
updated_at: r.updated_at ?? null,
pushed_at: r.pushed_at ?? null,
size: r.size ?? null,
stargazers_count: r.stargazers_count ?? 0,
forks_count: r.forks_count ?? 0,
open_issues_count: r.open_issues_count ?? 0,
default_branch: r.default_branch ?? null,
homepage: r.homepage ?? null,
topics: Array.isArray(r.topics) ? r.topics : [],
archived: r.archived ?? false,
license: r.license?.spdx_id ?? null
}));
})()- If more than 100 repositories are needed, request subsequent pages by adding
&page={page-number}and concatenate results until a page returns fewer than 100 items. - For each selected repository, fetch its README directly:
https://api.github.com/repos/{username}/{repo}/readme
Run:
(() => {
const j = JSON.parse(document.body.innerText);
if (j.message) return { url: j.url ?? null, error: j.message };
return {
url: j.html_url ?? null,
sha: j.sha ?? null,
text: j.content ? atob(j.content.replace(/[\r\n]/g, "")) : ""
};
})()- When package metadata is relevant, fetch:
https://api.github.com/repos/{username}/{repo}/contents/package.json
Run:
(() => {
const j = JSON.parse(document.body.innerText);
if (j.message) return { url: j.html_url ?? j.url ?? null, error: j.message };
const text = atob((j.content || "").replace(/[\r\n]/g, ""));
try {
const p = JSON.parse(text);
return {
url: j.html_url ?? null,
sha: j.sha ?? null,
name: p.name ?? null,
version: p.version ?? null,
description: p.description ?? null,
scripts: p.scripts ?? {},
dependencies: p.dependencies ?? {},
devDependencies: p.devDependencies ?? {},
engines: p.engines ?? null
};
} catch (e) {
return { url: j.html_url ?? null, sha: j.sha ?? null, parseError: String(e) };
}
})()- To inspect a repository directory without opening the GitHub HTML UI, use:
https://api.github.com/repos/{username}/{repo}/contents/{path}?ref={branch}
Use an empty {path} for the repository root. Extract directory entries with:
(() => {
const j = JSON.parse(document.body.innerText);
if (!Array.isArray(j)) return { error: j.message || "GitHub contents response is not a directory array" };
return j.map(x => ({
name: x.name ?? null,
path: x.path ?? null,
type: x.type ?? null,
size: x.size ?? null,
html_url: x.html_url ?? null,
url: x.url ?? null,
sha: x.sha ?? null
}));
})()Use the repository's actual default_branch from the repository listing when {branch} is needed; do not assume main or master.
7. To read a selected text file, first obtain its path from a contents listing, then navigate directly to:
https://api.github.com/repos/{username}/{repo}/contents/{path}?ref={branch}
Run:
(() => {
const j = JSON.parse(document.body.innerText);
if (j.message) return { url: j.html_url ?? j.url ?? null, error: j.message };
if (j.type !== "file" && !j.content) return { url: j.html_url ?? null, error: "Contents response is not a file" };
return {
url: j.html_url ?? null,
path: j.path ?? null,
sha: j.sha ?? null,
name: j.name ?? null,
size: j.size ?? null,
text: atob((j.content || "").replace(/[\r\n]/g, ""))
};
})()For directory or file collections larger than one response, add &per_page=100&page={page-number} where supported and concatenate pages.
8. For commit-history evidence, use the fetch-recent-commits skill with the repository owner and name; its direct commits endpoint and pagination rules apply.
Possible Friction Points
- Use REST API endpoints under
api.github.com; they return JSON and avoid GitHub HTML page parsing. - Repository listing is capped at 100 items per response; use
pagepagination when necessary. - Repository-specific contents URLs require the owner, repository name, path, and often an explicit
refbranch. Resolve repository names and default branches from the repository listing rather than guessing. - README and contents responses store file data in base64 in
content; remove embedded CR/LF characters before decoding withatob. - A missing README or package.json is returned as a GitHub error object; preserve it as an error rather than treating it as evidence that the repository is empty.
- Directory contents responses are arrays of entries, while file contents responses are objects; distinguish them before extraction.
topicsmay be absent or empty, andlicensemay be null; retain null/empty values.- Repository
languageis GitHub's primary detected language, not a complete technology inventory; use decoded package.json dependencies and scripts for JavaScript project details. - Do not guess repository names, paths, branches, or opaque IDs. Obtain repository names and default branches from the user's repository listing, and obtain file paths from contents listings before constructing file URLs.
- Keep all requests read-only and public; do not log in, send credentials, or use mutation endpoints.