Agent Skill
2/7/2026

github

Access GitHub repositories via the GitHub REST API. Use this skill when the user wants to interact with GitHub including reading files, creating/updating files, listing repos, managing branches, viewing commits, working with issues, or managing pull requests. All scripts use PEP 723 inline metadata for dependencies and run via `uv run`. Requires GITHUB_TOKEN environment variable (a Personal Access Token with appropriate scopes).

F
fpl9000
2GitHub Stars
1Views
npx skills add fpl9000/ai-skills

SKILL.md

Namegithub
DescriptionAccess GitHub repositories via the GitHub REST API. Use this skill when the user wants to interact with GitHub including reading files, creating/updating files, listing repos, managing branches, viewing commits, working with issues, or managing pull requests. All scripts use PEP 723 inline metadata for dependencies and run via `uv run`. Requires GITHUB_TOKEN environment variable (a Personal Access Token with appropriate scopes).

name: github description: Access GitHub repositories via the GitHub REST API. Use this skill when the user wants to interact with GitHub including reading files, creating/updating files, listing repos, managing branches, viewing commits, working with issues, or managing pull requests. All scripts use PEP 723 inline metadata for dependencies and run via uv run. Requires GITHUB_TOKEN environment variable (a Personal Access Token with appropriate scopes).

Skill Overview

This skill provides access to GitHub repositories via a set of Python scripts that wrap the GitHub REST API.

Prerequisites

Tool Dependency:

  • uv - The scripts in this skill require the uv package manager/runner. Most cloud-based AI agents have uv pre-installed (or they can install it). Local agents should install it via curl -LsSf https://astral.sh/uv/install.sh | sh or see the uv installation docs.

Environment Variables (must be set before running any script):

  • GITHUB_TOKEN - A GitHub Personal Access Token (classic or fine-grained) with appropriate scopes

Recommended Token Scopes (for classic PAT):

  • repo - Full control of private repositories (or public_repo for public only)
  • read:org - Read organization membership (optional, for org repos)

Important: Use a fine-grained personal access token when possible for better security. Configure only the repositories and permissions you need.

Network Access

Important: The scripts in this skill require network access to the following domain:

  • api.github.com

If you (the AI agent) have network restrictions, the user may need to whitelist this domain in the agent's settings for this skill to function.

Common Code Used by All Scripts

This skill uses a shared common module (github_common.py) to centralize authentication, token management, HTTP header construction, repository string parsing, error handling, and retry logic with exponential backoff.

All scripts import from github_common.py, which makes maintenance easier and ensures consistent behavior across all operations.

API Versioning

This skill uses explicit GitHub API versioning for long-term stability:

  • API Version: 2022-11-28
  • Header: X-GitHub-Api-Version: 2022-11-28

This ensures consistent behavior even if GitHub releases new API versions with breaking changes.

Available Scripts

All scripts include PEP 723 inline metadata declaring their dependencies. Just run with uv run — no manual dependency installation needed.


Repository Operations

List Repositories (scripts/repo_list.py)

uv run scripts/repo_list.py                          # List your repos
uv run scripts/repo_list.py --user octocat           # List user's repos
uv run scripts/repo_list.py --org github             # List org's repos
uv run scripts/repo_list.py --type public --sort updated --json
ArgumentDescription
--userList repos for this user
--orgList repos for this organization
--typeFilter: all, public, private, forks, sources, member
--sortSort by: created, updated, pushed, full_name
--per-pageResults per page (max 100, default: 30)
--pagePage number (default: 1)
--json, -jOutput as JSON

Get Repository Contents (scripts/repo_contents.py)

uv run scripts/repo_contents.py owner/repo                    # Root listing
uv run scripts/repo_contents.py owner/repo --path README.md   # Get file
uv run scripts/repo_contents.py owner/repo --path src/        # List directory
uv run scripts/repo_contents.py owner/repo --path config.json --ref develop --json
ArgumentDescription
repoRepository in owner/repo format (required)
--path, -pPath to file or directory (default: root)
--ref, -rGit ref (branch, tag, or commit SHA)
--json, -jOutput as JSON with full metadata

Get Repository Tree (scripts/repo_tree.py)

uv run scripts/repo_tree.py owner/repo               # Full tree
uv run scripts/repo_tree.py owner/repo --ref develop # Specific branch
uv run scripts/repo_tree.py owner/repo --path src/   # Filter by path
uv run scripts/repo_tree.py owner/repo --json
ArgumentDescription
repoRepository in owner/repo format (required)
--ref, -rGit ref (branch, tag, or commit SHA)
--path, -pFilter to paths starting with this prefix
--json, -jOutput as JSON

File Operations

Create or Update File (scripts/file_write.py)

# Create new file
uv run scripts/file_write.py owner/repo \
    --path docs/README.md \
    --content "# Documentation" \
    --message "Add docs"

# Update existing file (SHA required)
uv run scripts/file_write.py owner/repo \
    --path README.md \
    --content "# Updated" \
    --message "Update README" \
    --sha abc123...

# From local file
uv run scripts/file_write.py owner/repo \
    --path remote/script.py \
    --from-file local/script.py \
    --message "Upload script"

# Create an executable script (with --mode)
uv run scripts/file_write.py owner/repo \
    --path scripts/build.sh \
    --from-file build.sh \
    --message "Add build script" \
    --mode 755
ArgumentDescription
repoRepository in owner/repo format (required)
--path, -pPath for the file in the repo (required)
--content, -cFile content as string
--from-file, -fRead content from this local file
--message, -mCommit message (required)
--shaSHA of file being replaced (required for updates)
--branch, -bBranch to commit to
--modeFile mode (e.g., 755 for executable). Creates a second commit to set mode.
--json, -jOutput as JSON

Note on --mode: The GitHub Contents API doesn't support setting file modes directly. When --mode is specified, the script first creates/updates the file, then makes a second commit to set the mode using the Git Data API. Common modes: 755 (executable), 644 (regular file).


Change File Mode (scripts/file_chmod.py)

Change file permissions (mode) for existing files. Useful for making scripts executable or reverting to regular file mode.

# Make a single file executable
uv run scripts/file_chmod.py owner/repo --path script.py --mode 755

# Make multiple files executable in one commit
uv run scripts/file_chmod.py owner/repo \
    --path scripts/build.sh \
    --path scripts/deploy.sh \
    --path scripts/test.py \
    --mode 755

# Remove executable bit
uv run scripts/file_chmod.py owner/repo --path script.py --mode 644

# On a specific branch with custom message
uv run scripts/file_chmod.py owner/repo \
    --path scripts/run.py \
    --mode 755 \
    --branch develop \
    --message "Make run.py executable"
ArgumentDescription
repoRepository in owner/repo format (required)
--path, -pPath to file (required, can be repeated for multiple files)
--mode, -mTarget mode (required, e.g., 755 or 644)
--branch, -bBranch to commit to (default: main)
--messageCommit message (auto-generated if not provided)
--json, -jOutput as JSON

Common modes:

  • 755 - Executable file (rwxr-xr-x)
  • 644 - Regular file (rw-r--r--)

How it works: This script uses the Git Data API to modify file modes, which requires creating a new tree object and commit. Multiple files can be changed in a single commit for efficiency. Files that already have the target mode are skipped with a warning.


Delete File (scripts/file_delete.py)

uv run scripts/file_delete.py owner/repo \
    --path docs/old.md \
    --sha abc123... \
    --message "Remove old doc"
ArgumentDescription
repoRepository in owner/repo format (required)
--path, -pPath to the file to delete (required)
--shaSHA of the file to delete (required)
--message, -mCommit message (required)
--branch, -bBranch to delete from
--json, -jOutput as JSON

Branch Operations

List Branches (scripts/branch_list.py)

uv run scripts/branch_list.py owner/repo
uv run scripts/branch_list.py owner/repo --json
ArgumentDescription
repoRepository in owner/repo format (required)
--per-pageResults per page (max 100, default: 30)
--pagePage number (default: 1)
--json, -jOutput as JSON

Create Branch (scripts/branch_create.py)

uv run scripts/branch_create.py owner/repo --name feature/new-feature
uv run scripts/branch_create.py owner/repo --name hotfix/123 --from develop
uv run scripts/branch_create.py owner/repo --name release/v1.0 --from abc123...
ArgumentDescription
repoRepository in owner/repo format (required)
--name, -nName for the new branch (required)
--from, -fSource branch or commit SHA
--json, -jOutput as JSON

Delete Branch (scripts/branch_delete.py)

uv run scripts/branch_delete.py owner/repo --name feature/old-branch
uv run scripts/branch_delete.py owner/repo --name merged-branch --force
ArgumentDescription
repoRepository in owner/repo format (required)
--name, -nBranch name to delete (required)
--force, -fSkip confirmation prompt
--json, -jOutput as JSON

Commit Operations

List Commits (scripts/commit_list.py)

uv run scripts/commit_list.py owner/repo
uv run scripts/commit_list.py owner/repo --branch develop
uv run scripts/commit_list.py owner/repo --path src/main.py
uv run scripts/commit_list.py owner/repo --author octocat
uv run scripts/commit_list.py owner/repo --since 2024-01-01 --json
ArgumentDescription
repoRepository in owner/repo format (required)
--branch, -bBranch name
--path, -pFilter to commits affecting this path
--author, -aFilter by author username or email
--sinceOnly commits after this date (ISO 8601)
--untilOnly commits before this date (ISO 8601)
--per-pageResults per page (max 100, default: 30)
--pagePage number (default: 1)
--json, -jOutput as JSON

Get Commit Details (scripts/commit_get.py)

uv run scripts/commit_get.py owner/repo abc123def456
uv run scripts/commit_get.py owner/repo abc123def456 --json
ArgumentDescription
repoRepository in owner/repo format (required)
shaCommit SHA (required)
--json, -jOutput as JSON

Issue Operations

List Issues (scripts/issue_list.py)

uv run scripts/issue_list.py owner/repo
uv run scripts/issue_list.py owner/repo --state all
uv run scripts/issue_list.py owner/repo --labels "bug,urgent"
uv run scripts/issue_list.py owner/repo --assignee octocat --json
ArgumentDescription
repoRepository in owner/repo format (required)
--stateFilter: open, closed, all (default: open)
--labelsComma-separated list of label names
--assigneeFilter by assignee username
--sortSort by: created, updated, comments
--directionSort direction: asc, desc
--per-pageResults per page (max 100)
--pagePage number
--json, -jOutput as JSON

Create Issue (scripts/issue_create.py)

uv run scripts/issue_create.py owner/repo --title "Bug report" --body "Description..."
uv run scripts/issue_create.py owner/repo --title "Feature" --labels "enhancement"
uv run scripts/issue_create.py owner/repo --title "Task" --assignees "user1,user2"
ArgumentDescription
repoRepository in owner/repo format (required)
--title, -tIssue title (required)
--body, -bIssue body/description
--labelsComma-separated list of label names
--assigneesComma-separated list of usernames
--milestoneMilestone number
--json, -jOutput as JSON

Update Issue (scripts/issue_update.py)

uv run scripts/issue_update.py owner/repo 123 --title "New title"
uv run scripts/issue_update.py owner/repo 123 --state closed
uv run scripts/issue_update.py owner/repo 123 --state closed --reason not_planned
uv run scripts/issue_update.py owner/repo 123 --labels "bug,urgent"
uv run scripts/issue_update.py owner/repo 123 --assignees "user1,user2"
ArgumentDescription
repoRepository in owner/repo format (required)
issue_numberIssue number to update (required)
--title, -tNew title
--body, -bNew body/description
--state, -sNew state: open, closed
--reasonClose reason: completed, not_planned
--labelsComma-separated labels (replaces existing)
--assigneesComma-separated usernames (replaces existing)
--milestoneMilestone number (0 to clear)
--json, -jOutput as JSON

Pull Request Operations

List Pull Requests (scripts/pr_list.py)

uv run scripts/pr_list.py owner/repo
uv run scripts/pr_list.py owner/repo --state all
uv run scripts/pr_list.py owner/repo --base main
uv run scripts/pr_list.py owner/repo --sort updated --json
ArgumentDescription
repoRepository in owner/repo format (required)
--stateFilter: open, closed, all (default: open)
--baseFilter by base branch
--headFilter by head branch
--sortSort by: created, updated, popularity, long-running
--directionSort direction: asc, desc
--per-pageResults per page (max 100)
--pagePage number
--json, -jOutput as JSON

Create Pull Request (scripts/pr_create.py)

uv run scripts/pr_create.py owner/repo --title "Add feature" --head feature-branch
uv run scripts/pr_create.py owner/repo --title "Fix bug" --head fix-123 --base develop
uv run scripts/pr_create.py owner/repo --title "WIP" --head wip-branch --draft
ArgumentDescription
repoRepository in owner/repo format (required)
--title, -tPR title (required)
--head, -hBranch containing changes (required)
--base, -bBranch to merge into (default: default branch)
--bodyPR description
--draft, -dCreate as draft PR
--json, -jOutput as JSON

Get Pull Request Details (scripts/pr_get.py)

uv run scripts/pr_get.py owner/repo 123
uv run scripts/pr_get.py owner/repo 123 --json
ArgumentDescription
repoRepository in owner/repo format (required)
pr_numberPull request number (required)
--json, -jOutput as JSON

Merge Pull Request (scripts/pr_merge.py)

uv run scripts/pr_merge.py owner/repo 123
uv run scripts/pr_merge.py owner/repo 123 --method squash
uv run scripts/pr_merge.py owner/repo 123 --method rebase
uv run scripts/pr_merge.py owner/repo 123 --method squash --title "Feature (#123)"
ArgumentDescription
repoRepository in owner/repo format (required)
pr_numberPull request number (required)
--method, -mMerge method: merge, squash, rebase
--title, -tCustom commit title
--messageCustom commit message body
--shaExpected head SHA (for safety)
--json, -jOutput as JSON

Common Patterns

Setting Credentials

# Set for current session
export GITHUB_TOKEN="ghp_xxxxxxxxxxxx"

# Or inline with command
GITHUB_TOKEN="ghp_xxx" uv run scripts/repo_list.py

Updating a File (Full Workflow)

To update a file, you need its current SHA:

# 1. Get the current file with its SHA
uv run scripts/repo_contents.py owner/repo --path README.md --json > file_info.json

# 2. Extract the SHA
SHA=$(jq -r '.sha' file_info.json)

# 3. Update the file with the SHA
uv run scripts/file_write.py owner/repo \
    --path README.md \
    --content "New content here" \
    --message "Update README" \
    --sha "$SHA"

Creating and Merging a PR (Full Workflow)

# 1. Create a branch
uv run scripts/branch_create.py owner/repo --name feature/my-feature

# 2. Make changes (push commits via git or file_write.py)
uv run scripts/file_write.py owner/repo \
    --path feature.py \
    --content "# New feature" \
    --message "Add feature" \
    --branch feature/my-feature

# 3. Create a PR
uv run scripts/pr_create.py owner/repo \
    --title "Add my feature" \
    --head feature/my-feature \
    --body "This PR adds..."

# 4. Merge the PR
uv run scripts/pr_merge.py owner/repo 123 --method squash

# 5. Delete the branch
uv run scripts/branch_delete.py owner/repo --name feature/my-feature --force

JSON Output for Processing

All scripts support --json for machine-readable output:

# List repos and filter with jq
uv run scripts/repo_list.py --json | jq '.[] | select(.language == "Python")'

# Get commit count
uv run scripts/commit_list.py owner/repo --json | jq 'length'

# Get all open PR numbers
uv run scripts/pr_list.py owner/repo --json | jq '.[].number'

Error Handling

Scripts exit with non-zero status on errors. Common issues:

  • 401 Unauthorized: Check that GITHUB_TOKEN is set and valid
  • 403 Forbidden: Token lacks required scopes, or rate limit exceeded
  • 404 Not Found: Repository, file, or branch doesn't exist (or token lacks access)
  • 409 Conflict: SHA mismatch when updating (file was modified since you read it)
  • 422 Validation Failed: Invalid input (check branch name format, file path, etc.)

Rate Limits

The GitHub API has rate limits:

  • Authenticated requests: 5,000 per hour
  • Search API: 30 per minute

The skill includes automatic retry logic with exponential backoff for rate limit errors.

Check your current limits as follows:

curl -H "Authorization: token $GITHUB_TOKEN" https://api.github.com/rate_limit
Skills Info
Original Name:githubAuthor:fpl9000