This skill converts GitHub repository content and metadata into target formats (Markdown documentation, JSON metadata, CSV tables, folder tree JSON). It preserves structure and content fidelity across formats — not a simple file copy, but a semantic transformation that respects GitHub's data model (repos, trees, commits, issues, PRs, releases).
Key responsibilities:
.git directory/convert-github-repository --markdown#Repository → Markdown documentation. Converts the entire repository into a set of Markdown files:
README.md from repository rootREADME.md describing its contentsissues/YYYY-MM-DD-{number}-{title}.mdpull-requests/YYYY-MM-DD-{number}-{title}.mdreleases/v{semver}.md/convert-github-repository --json#Repository → JSON metadata. Exports repository structure and content as a JSON file:
json
{
"repo": { "name": "...", "description": "...", "stars": N, "license": "...", "topics": [...] },
"files": [{ "path": "...", "size": N, "type": "file|dir", "sha": "..." }],
"branches": [{ "name": "...", "last_commit": "..." }],
"contributors": [{ "login": "...", "contributions": N }]
}
/convert-github-repository --csv#Issues + PRs → CSV. Exports issues and pull requests as CSV rows with columns: number, title, state, author, created_at, updated_at, labels, assignees, milestone, body_preview.
/convert-github-repository --tree#Repository → folder tree JSON. Outputs a tree structure representing the repository layout:
json
{
"path": "/",
"type": "directory",
"children": [
{ "path": "src/index.js", "type": "file", "size": 1234, "language": "JavaScript" },
{ "path": "tests/", "type": "directory", "children": [...] }
]
}
/convert-github-repository --readme-to-json#README.md → structured JSON. Parses a README.md and extracts: title (first H1), description (first paragraph after title), installation steps, usage examples, contributing guidelines, license.
Remote GitHub repo: Parse URL to extract owner and repo:
text
https://github.com/owner/repo -> {owner: "owner", repo: "repo"}
Use GitHub API with GITHUB_TOKEN from env ( os.getenv("GITHUB_TOKEN")).
Local repository: Verify .git directory exists. Use git CLI to extract:
git ls-files for file listgit log --oneline for recent commitsgit remote get-url origin to confirm repo identityIf neither source is available, report: "Cannot identify repository source — provide either a GitHub URL ( https://github.com/owner/repo) or a local path with a .git directory."
For remote repos, call GitHub API:
text
GET https://api.github.com/repos/{owner}/{repo}
Authorization: Bearer {GITHUB_TOKEN}
Accept: application/vnd.github+json
Response contains: full_name, description, stargazers_count, forks_count, license.spdx_id, topics, default_branch, created_at, updated_at, homepage, language.
If the token is missing or rate-limited (403), try unauthenticated (lower rate limit) or report: "GitHub API unavailable — check GITHUB_TOKEN or try again later (rate limit: 60 req/hr unauthenticated)."
Get default branch tree:
text
GET https://api.github.com/repos/{owner}/{repo}/git/trees/{default_branch}?recursive=1
Returns a flat list of all files with path, type (blob/tree), size, sha.
For local repos: Run git ls-tree -r --name-only {branch} to get the file list, then git show {sha}:{path} to read file content.
Filter out common non-essential paths:
node_modules/, .git/, vendor/ — skip unless specifically requested.gitignore-referenced files that are not committed — skip--markdown conversion:
README.md: Preserve as-is, update relative links to point to local files
Code files: Write with syntax-highlighting fence (```language) based on file extension mapping:
.js → ```javascript, .py → ```python, .go → ```go, .rs → ```rust, etc.Directories: Create README.md in each directory with list of contained files
Issues: Each issue becomes {number}-{slug}.md with frontmatter:
yaml
---
number: 42
state: open
author: username
created: 2024-01-15
labels: [bug, help-wanted]
---
# Title
body text...
PRs: Same format as issues, plus merged field and review comments
--json conversion:
--csv conversion:
number,title,state,author,created_at,updated_at,labels,assignees,milestone,body_preview; delimiter; delimiter""--tree conversion:
.js → JavaScript, .py → Python, etc.)--readme-to-json conversion:
# Heading → titleinstallation, usage, contributing, etc.)code_examples array[text](url) → collected in links arrayBefore delivering:
json.loads() and confirm no errorsReturn the converted output plus a manifest:
text
{
"format": "markdown",
"files_converted": 142,
"files_skipped": 3,
"skipped_reasons": [
{"path": "node_modules/package/index.js", "reason": "binary or non-text, excluded by default"},
{"path": ".git/config", "reason": "contains sensitive data"}
],
"total_size_bytes": 2048576,
"output_path": "./{repo-name}-converted/"
}
os.getenv("GITHUB_TOKEN").gitignore unless user explicitly requests --include-ignoredskipped_reasons in the manifestfiles_converted, files_skipped, skipped_reasons\uFFFDgit CLI — never assume raw file access is availableCriterionMinimumIdealContent preservation100% of text file content preservedBinary files listed in manifest, not content-lostFormat validityOutput passes format parserStrict schema validation (JSON: draft-7, CSV: consistent columns)Manifest completenessEvery skipped file has a reasonEvery converted file listed with size and typeEncoding correctnessUTF-8 for all text filesInvalid bytes replaced with U+FFFD, not dropped or garbledRate limit handling403 triggers re-auth attemptProactive pagination with token refresh on 403Large repo handling< 500MB memory for repos up to 10K filesStreaming JSON output, chunked file writes
A good output passes the target format parser without errors, preserves all semantic content, and includes a complete manifest of what was converted and why some files were skipped.
ScenarioBadGoodMissing tokenRetries unauthenticated foreverReports "GitHub API auth required — set GITHUB_TOKEN environment variable"Binary fileTries to read as text, garbles contentSkips binary, reports in manifest: {"path": "logo.png", "reason": "binary/image, excluded"}Large repoLoads all files into memory, crashesStreams output, reports "Processed 8,432 of 12,000 files (70%)"Rate limitedFails silently after 3 requestsReports "Rate limit exceeded (403) — retry after 14:32 UTC or set GITHUB_TOKEN"Missing fieldSkips homepage when absentIncludes "homepage": null — no field silently droppedFormat errorWrites malformed JSON with trailing commaValidates with json.dumps(), reports "Output invalid: unexpected token at line 847"Local repo pathAssumes ~/repo existsChecks .git directory, reports "Path is not a git repository: ./myrepo"