
github-api
by jchidley
SDK-based GitHub repository manager - better than gh CLI for automation and LLM integration
SKILL.md
name: github-api description: Octokit (official GitHub SDK) best practices, common operations, and code examples for GitHub API automation. Use when creating repos, updating files, managing issues/PRs, or any GitHub API interaction.
GitHub API / Octokit Skill
This skill provides guidance, patterns, and examples for using Octokit (the official GitHub SDK) to interact with the GitHub API.
When to Use This Skill
Use this skill when you need to:
- Create, update, or manage GitHub repositories
- Update files in repositories programmatically
- Manage issues, pull requests, or discussions
- Work with GitHub Actions, releases, or webhooks
- Automate GitHub operations via the API
- Implement GitHub integrations or bots
Authentication
Environment Variable (Recommended)
const { Octokit } = require('@octokit/rest');
const octokit = new Octokit({
auth: process.env.GITHUB_TOKEN
});
Personal Access Token Requirements
Generate at: https://github.com/settings/tokens
Minimum scopes needed:
repo- Full control of private repositories (includes public repos)workflow- Update GitHub Action workflows (if needed)admin:org- Manage organization settings (if working with orgs)
Token format: Starts with ghp_ (personal access token)
Checking Authentication
// Test if token is valid
const { data: user } = await octokit.users.getAuthenticated();
console.log(`Authenticated as: ${user.login}`);
Common Operations
1. Repository Operations
Create Repository
const { data: repo } = await octokit.repos.createForAuthenticatedUser({
name: 'my-new-repo',
description: 'Repository description',
private: false,
auto_init: true, // Initialize with README
license_template: 'mit', // Optional: add license
});
console.log(`Created: ${repo.html_url}`);
Get Repository Info
const { data: repo } = await octokit.repos.get({
owner: 'username',
repo: 'repo-name'
});
console.log(`Stars: ${repo.stargazers_count}`);
console.log(`Forks: ${repo.forks_count}`);
console.log(`Default branch: ${repo.default_branch}`);
Update Repository Settings
await octokit.repos.update({
owner: 'username',
repo: 'repo-name',
description: 'Updated description',
homepage: 'https://example.com',
has_issues: true,
has_wiki: false,
has_projects: true,
});
Delete Repository
await octokit.repos.delete({
owner: 'username',
repo: 'repo-name'
});
2. File Operations
Get File Contents
const { data: file } = await octokit.repos.getContent({
owner: 'username',
repo: 'repo-name',
path: 'path/to/file.md',
ref: 'main' // branch name
});
// Decode base64 content
const content = Buffer.from(file.content, 'base64').toString('utf8');
console.log(content);
Create or Update File
const { data } = await octokit.repos.createOrUpdateFileContents({
owner: 'username',
repo: 'repo-name',
path: 'path/to/file.md',
message: 'Commit message',
content: Buffer.from('file content here').toString('base64'),
sha: file.sha, // Required for updates, omit for new files
branch: 'main'
});
console.log(`Commit: ${data.commit.html_url}`);
Important: Content must be base64 encoded!
Delete File
await octokit.repos.deleteFile({
owner: 'username',
repo: 'repo-name',
path: 'path/to/file.md',
message: 'Delete file',
sha: file.sha, // Required - get from getContent first
branch: 'main'
});
Get Multiple Files (Directory)
const { data: contents } = await octokit.repos.getContent({
owner: 'username',
repo: 'repo-name',
path: 'src',
ref: 'main'
});
// contents is an array if path is a directory
contents.forEach(item => {
console.log(`${item.type}: ${item.path}`);
});
3. Branch Operations
List Branches
const { data: branches } = await octokit.repos.listBranches({
owner: 'username',
repo: 'repo-name'
});
branches.forEach(branch => {
console.log(`${branch.name}: ${branch.commit.sha}`);
});
Create Branch
// First, get the SHA of the commit you want to branch from
const { data: ref } = await octokit.git.getRef({
owner: 'username',
repo: 'repo-name',
ref: 'heads/main'
});
// Create new branch
await octokit.git.createRef({
owner: 'username',
repo: 'repo-name',
ref: 'refs/heads/new-branch-name',
sha: ref.object.sha
});
Delete Branch
await octokit.git.deleteRef({
owner: 'username',
repo: 'repo-name',
ref: 'heads/branch-to-delete'
});
4. Issues and Pull Requests
Create Issue
const { data: issue } = await octokit.issues.create({
owner: 'username',
repo: 'repo-name',
title: 'Issue title',
body: 'Issue description',
labels: ['bug', 'help wanted'],
assignees: ['username']
});
console.log(`Issue #${issue.number}: ${issue.html_url}`);
Update Issue
await octokit.issues.update({
owner: 'username',
repo: 'repo-name',
issue_number: 123,
state: 'closed',
body: 'Updated description'
});
List Issues
const { data: issues } = await octokit.issues.listForRepo({
owner: 'username',
repo: 'repo-name',
state: 'open', // 'open', 'closed', 'all'
labels: 'bug',
sort: 'created',
direction: 'desc',
per_page: 100
});
Create Pull Request
const { data: pr } = await octokit.pulls.create({
owner: 'username',
repo: 'repo-name',
title: 'PR title',
body: 'PR description',
head: 'feature-branch', // branch with changes
base: 'main' // target branch
});
console.log(`PR #${pr.number}: ${pr.html_url}`);
5. Releases
Create Release
const { data: release } = await octokit.repos.createRelease({
owner: 'username',
repo: 'repo-name',
tag_name: 'v1.0.0',
name: 'Version 1.0.0',
body: 'Release notes here',
draft: false,
prerelease: false
});
List Releases
const { data: releases } = await octokit.repos.listReleases({
owner: 'username',
repo: 'repo-name'
});
6. Organization Operations
List Repositories
const { data: repos } = await octokit.repos.listForOrg({
org: 'organization-name',
type: 'all', // 'all', 'public', 'private'
sort: 'updated',
per_page: 100
});
Create Organization Repository
const { data: repo } = await octokit.repos.createInOrg({
org: 'organization-name',
name: 'repo-name',
description: 'Description',
private: false
});
7. User Operations
Get Authenticated User
const { data: user } = await octokit.users.getAuthenticated();
console.log(`Username: ${user.login}`);
console.log(`Name: ${user.name}`);
console.log(`Email: ${user.email}`);
List User Repositories
const { data: repos } = await octokit.repos.listForAuthenticatedUser({
visibility: 'all', // 'all', 'public', 'private'
sort: 'updated',
per_page: 100
});
Pagination
For endpoints that return many results, use pagination:
const iterator = octokit.paginate.iterator(octokit.repos.listForAuthenticatedUser, {
per_page: 100
});
for await (const { data: repos } of iterator) {
for (const repo of repos) {
console.log(repo.name);
}
}
Or get all at once:
const allRepos = await octokit.paginate(octokit.repos.listForAuthenticatedUser);
console.log(`Total repos: ${allRepos.length}`);
Error Handling
Basic Error Handling
try {
const { data } = await octokit.repos.get({
owner: 'username',
repo: 'repo-name'
});
} catch (error) {
console.error('Error:', error.message);
if (error.status === 404) {
console.error('Repository not found');
} else if (error.status === 401) {
console.error('Authentication failed - check your token');
} else if (error.status === 403) {
console.error('Forbidden - insufficient permissions');
}
if (error.response) {
console.error('Response:', error.response.data);
}
}
Common Error Codes
401- Bad credentials / invalid token403- Forbidden / rate limited / insufficient permissions404- Not found422- Validation failed / unprocessable entity500- Server error
Rate Limiting
Check rate limit status:
const { data: rateLimit } = await octokit.rateLimit.get();
console.log(`Remaining: ${rateLimit.rate.remaining}/${rateLimit.rate.limit}`);
console.log(`Reset: ${new Date(rateLimit.rate.reset * 1000)}`);
Best Practices
1. Always Check Authentication First
async function verifyAuth(octokit) {
try {
const { data: user } = await octokit.users.getAuthenticated();
console.log(`✅ Authenticated as: ${user.login}`);
return true;
} catch (error) {
console.error('❌ Authentication failed:', error.message);
return false;
}
}
2. Get SHA Before Updating Files
async function updateFile(owner, repo, path, content, message) {
// Get current file to get SHA
const { data: currentFile } = await octokit.repos.getContent({
owner,
repo,
path
});
// Update with SHA
await octokit.repos.createOrUpdateFileContents({
owner,
repo,
path,
message,
content: Buffer.from(content).toString('base64'),
sha: currentFile.sha
});
}
3. Use Environment Variables for Tokens
Never hardcode tokens!
// ✅ Good
const octokit = new Octokit({
auth: process.env.GITHUB_TOKEN
});
// ❌ Bad
const octokit = new Octokit({
auth: 'ghp_hardcoded_token_here' // NEVER DO THIS!
});
4. Handle Pagination for Large Result Sets
async function getAllRepos(octokit) {
return await octokit.paginate(octokit.repos.listForAuthenticatedUser, {
per_page: 100
});
}
5. Batch Operations with Error Recovery
async function updateMultipleFiles(files) {
const results = [];
for (const file of files) {
try {
const result = await updateFile(file.path, file.content);
results.push({ success: true, file: file.path, result });
} catch (error) {
results.push({ success: false, file: file.path, error: error.message });
}
}
return results;
}
Complete Example Script
#!/usr/bin/env node
const { Octokit } = require('@octokit/rest');
const fs = require('fs');
// Initialize Octokit
const octokit = new Octokit({
auth: process.env.GITHUB_TOKEN
});
const owner = 'username';
const repo = 'repo-name';
const filePath = 'README.md';
async function main() {
try {
// 1. Verify authentication
const { data: user } = await octokit.users.getAuthenticated();
console.log(`✅ Authenticated as: ${user.login}`);
// 2. Get current file
console.log(`\n📥 Getting ${filePath}...`);
const { data: currentFile } = await octokit.repos.getContent({
owner,
repo,
path: filePath
});
console.log(`Current SHA: ${currentFile.sha}`);
// 3. Read new content from local file
const newContent = fs.readFileSync('./new-readme.md', 'utf8');
// 4. Update file
console.log(`\n📤 Updating ${filePath}...`);
const { data } = await octokit.repos.createOrUpdateFileContents({
owner,
repo,
path: filePath,
message: 'Update README with new content',
content: Buffer.from(newContent).toString('base64'),
sha: currentFile.sha
});
console.log(`\n✅ Successfully updated ${filePath}`);
console.log(`Commit: ${data.commit.html_url}`);
} catch (error) {
console.error('\n❌ Error:', error.message);
if (error.response) {
console.error('Response:', error.response.data);
}
process.exit(1);
}
}
main();
Installation
npm install @octokit/rest
# or
yarn add @octokit/rest
TypeScript Support
Octokit has full TypeScript support:
import { Octokit } from '@octokit/rest';
const octokit = new Octokit({
auth: process.env.GITHUB_TOKEN
});
// Type-safe API calls
const { data: repo } = await octokit.repos.get({
owner: 'username',
repo: 'repo-name'
});
// repo is fully typed
console.log(repo.stargazers_count);
Useful Links
- Octokit Documentation: https://octokit.github.io/rest.js/
- GitHub REST API Docs: https://docs.github.com/en/rest
- Generate Token: https://github.com/settings/tokens
- Rate Limits: https://docs.github.com/en/rest/rate-limit
- Octokit GitHub: https://github.com/octokit/rest.js
Common Patterns
Pattern: Update File in Repository
async function updateRepoFile(owner, repo, path, content, message) {
const octokit = new Octokit({ auth: process.env.GITHUB_TOKEN });
// Get current file for SHA
const { data: currentFile } = await octokit.repos.getContent({
owner,
repo,
path
});
// Update
const { data } = await octokit.repos.createOrUpdateFileContents({
owner,
repo,
path,
message,
content: Buffer.from(content).toString('base64'),
sha: currentFile.sha
});
return data.commit.html_url;
}
Pattern: Clone Repository Settings
async function cloneSettings(sourceRepo, targetRepo) {
const octokit = new Octokit({ auth: process.env.GITHUB_TOKEN });
// Get source repo settings
const { data: source } = await octokit.repos.get({
owner: 'username',
repo: sourceRepo
});
// Apply to target
await octokit.repos.update({
owner: 'username',
repo: targetRepo,
description: source.description,
homepage: source.homepage,
has_issues: source.has_issues,
has_wiki: source.has_wiki,
has_projects: source.has_projects
});
}
Pattern: Bulk File Operations
async function updateMultipleFiles(owner, repo, files) {
const octokit = new Octokit({ auth: process.env.GITHUB_TOKEN });
const results = [];
for (const file of files) {
try {
const url = await updateRepoFile(
owner,
repo,
file.path,
file.content,
file.message
);
results.push({ success: true, path: file.path, url });
} catch (error) {
results.push({ success: false, path: file.path, error: error.message });
}
}
return results;
}
Troubleshooting
"Bad credentials" Error
- Check that GITHUB_TOKEN is set:
echo $GITHUB_TOKEN - Verify token starts with
ghp_ - Generate new token at: https://github.com/settings/tokens
- Ensure token has correct scopes (usually
repo)
"Not Found" Error (404)
- Verify repository exists
- Check spelling of owner/repo names
- Ensure token has access to private repos (if applicable)
- Check if repository is in an organization you don't have access to
"Validation Failed" Error (422)
- For file updates: Ensure SHA is provided and correct
- For branch creation: Check branch name doesn't already exist
- For PRs: Verify head and base branches exist
Rate Limiting (403)
- Check rate limit:
octokit.rateLimit.get() - Authenticated requests: 5,000/hour
- Unauthenticated: 60/hour
- Wait for reset time or use multiple tokens
Resources
- github-manager.js - Full implementation example
- Octokit REST API Docs
- GitHub REST API Reference
スコア
総合スコア
リポジトリの品質指標に基づく評価
SKILL.mdファイルが含まれている
ライセンスが設定されている
100文字以上の説明がある
GitHub Stars 100以上
1ヶ月以内に更新
10回以上フォークされている
オープンIssueが50未満
プログラミング言語が設定されている
1つ以上のタグが設定されている
レビュー
レビュー機能は近日公開予定です

