GitHub
name: github
by byungkyu · published 2026-03-22
$ claw add gh:byungkyu/byungkyu-github-api---
name: github
description: |
GitHub API integration with managed OAuth. Access repositories, issues, pull requests, commits, branches, and users.
Use this skill when users want to interact with GitHub repositories, manage issues and PRs, search code, or automate workflows.
For other third party apps, use the api-gateway skill (https://clawhub.ai/byungkyu/api-gateway).
compatibility: Requires network access and valid Maton API key
metadata:
author: maton
version: "1.0"
clawdbot:
emoji: 🧠
requires:
env:
- MATON_API_KEY
---
# GitHub
Access the GitHub REST API with managed OAuth authentication. Manage repositories, issues, pull requests, commits, branches, users, and more.
Quick Start
# Get authenticated user
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://gateway.maton.ai/github/user')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOFBase URL
https://gateway.maton.ai/github/{native-api-path}Replace `{native-api-path}` with the actual GitHub API endpoint path. The gateway proxies requests to `api.github.com` and automatically injects your OAuth token.
Authentication
All requests require the Maton API key in the Authorization header:
Authorization: Bearer $MATON_API_KEY**Environment Variable:** Set your API key as `MATON_API_KEY`:
export MATON_API_KEY="YOUR_API_KEY"Getting Your API Key
1. Sign in or create an account at [maton.ai](https://maton.ai)
2. Go to [maton.ai/settings](https://maton.ai/settings)
3. Copy your API key
Connection Management
Manage your GitHub OAuth connections at `https://ctrl.maton.ai`.
List Connections
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://ctrl.maton.ai/connections?app=github&status=ACTIVE')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOFCreate Connection
python <<'EOF'
import urllib.request, os, json
data = json.dumps({'app': 'github'}).encode()
req = urllib.request.Request('https://ctrl.maton.ai/connections', data=data, method='POST')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Content-Type', 'application/json')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOFGet Connection
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://ctrl.maton.ai/connections/{connection_id}')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF**Response:**
{
"connection": {
"connection_id": "83e7c665-60f6-4a64-816c-5e287ea8982f",
"status": "ACTIVE",
"creation_time": "2026-02-06T03:00:43.860014Z",
"last_updated_time": "2026-02-06T03:01:06.027323Z",
"url": "https://connect.maton.ai/?session_token=...",
"app": "github",
"metadata": {}
}
}Open the returned `url` in a browser to complete OAuth authorization.
Delete Connection
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://ctrl.maton.ai/connections/{connection_id}', method='DELETE')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOFSpecifying Connection
If you have multiple GitHub connections, specify which one to use with the `Maton-Connection` header:
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://gateway.maton.ai/github/user')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Maton-Connection', '83e7c665-60f6-4a64-816c-5e287ea8982f')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOFIf omitted, the gateway uses the default (oldest) active connection.
API Reference
Users
#### Get Authenticated User
GET /github/user#### Get User by Username
GET /github/users/{username}#### List Users
GET /github/users?since={user_id}&per_page=30Repositories
#### List User Repositories
GET /github/user/repos?per_page=30&sort=updatedQuery parameters: `type` (all, owner, public, private, member), `sort` (created, updated, pushed, full_name), `direction` (asc, desc), `per_page`, `page`
#### List Organization Repositories
GET /github/orgs/{org}/repos?per_page=30#### Get Repository
GET /github/repos/{owner}/{repo}#### Create Repository (User)
POST /github/user/repos
Content-Type: application/json
{
"name": "my-new-repo",
"description": "A new repository",
"private": true,
"auto_init": true
}#### Create Repository (Organization)
POST /github/orgs/{org}/repos
Content-Type: application/json
{
"name": "my-new-repo",
"description": "A new repository",
"private": true
}#### Update Repository
PATCH /github/repos/{owner}/{repo}
Content-Type: application/json
{
"description": "Updated description",
"has_issues": true,
"has_wiki": false
}#### Delete Repository
DELETE /github/repos/{owner}/{repo}Repository Contents
#### List Contents
GET /github/repos/{owner}/{repo}/contents/{path}#### Get File Contents
GET /github/repos/{owner}/{repo}/contents/{path}?ref={branch}#### Create or Update File
PUT /github/repos/{owner}/{repo}/contents/{path}
Content-Type: application/json
{
"message": "Create new file",
"content": "SGVsbG8gV29ybGQh",
"branch": "main"
}Note: `content` must be Base64 encoded.
#### Delete File
DELETE /github/repos/{owner}/{repo}/contents/{path}
Content-Type: application/json
{
"message": "Delete file",
"sha": "{file_sha}",
"branch": "main"
}Branches
#### List Branches
GET /github/repos/{owner}/{repo}/branches?per_page=30#### Get Branch
GET /github/repos/{owner}/{repo}/branches/{branch}#### Rename Branch
POST /github/repos/{owner}/{repo}/branches/{branch}/rename
Content-Type: application/json
{
"new_name": "new-branch-name"
}#### Merge Branches
POST /github/repos/{owner}/{repo}/merges
Content-Type: application/json
{
"base": "main",
"head": "feature-branch",
"commit_message": "Merge feature branch"
}Commits
#### List Commits
GET /github/repos/{owner}/{repo}/commits?per_page=30Query parameters: `sha` (branch name or commit SHA), `path` (file path), `author`, `committer`, `since`, `until`, `per_page`, `page`
#### Get Commit
GET /github/repos/{owner}/{repo}/commits/{ref}#### Compare Two Commits
GET /github/repos/{owner}/{repo}/compare/{base}...{head}Issues
#### List Repository Issues
GET /github/repos/{owner}/{repo}/issues?state=open&per_page=30Query parameters: `state` (open, closed, all), `labels`, `assignee`, `creator`, `mentioned`, `sort`, `direction`, `since`, `per_page`, `page`
#### Get Issue
GET /github/repos/{owner}/{repo}/issues/{issue_number}#### Create Issue
POST /github/repos/{owner}/{repo}/issues
Content-Type: application/json
{
"title": "Found a bug",
"body": "Bug description here",
"labels": ["bug"],
"assignees": ["username"]
}#### Update Issue
PATCH /github/repos/{owner}/{repo}/issues/{issue_number}
Content-Type: application/json
{
"state": "closed",
"state_reason": "completed"
}#### Lock Issue
PUT /github/repos/{owner}/{repo}/issues/{issue_number}/lock
Content-Type: application/json
{
"lock_reason": "resolved"
}#### Unlock Issue
DELETE /github/repos/{owner}/{repo}/issues/{issue_number}/lockIssue Comments
#### List Issue Comments
GET /github/repos/{owner}/{repo}/issues/{issue_number}/comments?per_page=30#### Create Issue Comment
POST /github/repos/{owner}/{repo}/issues/{issue_number}/comments
Content-Type: application/json
{
"body": "This is a comment"
}#### Update Issue Comment
PATCH /github/repos/{owner}/{repo}/issues/comments/{comment_id}
Content-Type: application/json
{
"body": "Updated comment"
}#### Delete Issue Comment
DELETE /github/repos/{owner}/{repo}/issues/comments/{comment_id}Labels
#### List Labels
GET /github/repos/{owner}/{repo}/labels?per_page=30#### Create Label
POST /github/repos/{owner}/{repo}/labels
Content-Type: application/json
{
"name": "priority:high",
"color": "ff0000",
"description": "High priority issues"
}Milestones
#### List Milestones
GET /github/repos/{owner}/{repo}/milestones?state=open&per_page=30#### Create Milestone
POST /github/repos/{owner}/{repo}/milestones
Content-Type: application/json
{
"title": "v1.0",
"state": "open",
"description": "First release",
"due_on": "2026-03-01T00:00:00Z"
}Pull Requests
#### List Pull Requests
GET /github/repos/{owner}/{repo}/pulls?state=open&per_page=30Query parameters: `state` (open, closed, all), `head`, `base`, `sort`, `direction`, `per_page`, `page`
#### Get Pull Request
GET /github/repos/{owner}/{repo}/pulls/{pull_number}#### Create Pull Request
POST /github/repos/{owner}/{repo}/pulls
Content-Type: application/json
{
"title": "New feature",
"body": "Description of changes",
"head": "feature-branch",
"base": "main",
"draft": false
}#### Update Pull Request
PATCH /github/repos/{owner}/{repo}/pulls/{pull_number}
Content-Type: application/json
{
"title": "Updated title",
"state": "closed"
}#### List Pull Request Commits
GET /github/repos/{owner}/{repo}/pulls/{pull_number}/commits?per_page=30#### List Pull Request Files
GET /github/repos/{owner}/{repo}/pulls/{pull_number}/files?per_page=30#### Check If Merged
GET /github/repos/{owner}/{repo}/pulls/{pull_number}/merge#### Merge Pull Request
PUT /github/repos/{owner}/{repo}/pulls/{pull_number}/merge
Content-Type: application/json
{
"commit_title": "Merge pull request",
"merge_method": "squash"
}Merge methods: `merge`, `squash`, `rebase`
Pull Request Reviews
#### List Reviews
GET /github/repos/{owner}/{repo}/pulls/{pull_number}/reviews?per_page=30#### Create Review
POST /github/repos/{owner}/{repo}/pulls/{pull_number}/reviews
Content-Type: application/json
{
"body": "Looks good!",
"event": "APPROVE"
}Events: `APPROVE`, `REQUEST_CHANGES`, `COMMENT`
Search
#### Search Repositories
GET /github/search/repositories?q={query}&per_page=30Example queries:
#### Search Issues
GET /github/search/issues?q={query}&per_page=30Example queries:
#### Search Code
GET /github/search/code?q={query}&per_page=30Example queries:
Note: Code search may timeout on broad queries.
#### Search Users
GET /github/search/users?q={query}&per_page=30Organizations
#### List User Organizations
GET /github/user/orgs?per_page=30Note: Requires `read:org` scope.
#### Get Organization
GET /github/orgs/{org}#### List Organization Members
GET /github/orgs/{org}/members?per_page=30Rate Limit
#### Get Rate Limit
GET /github/rate_limitResponse:
{
"rate": {
"limit": 5000,
"remaining": 4979,
"reset": 1707200000
},
"resources": {
"core": { "limit": 5000, "remaining": 4979 },
"search": { "limit": 30, "remaining": 28 }
}
}Pagination
GitHub uses page-based and link-based pagination:
GET /github/repos/{owner}/{repo}/issues?per_page=30&page=2Response headers include pagination links:
Common pagination parameters:
Some endpoints use cursor-based pagination with `since` parameter (e.g., listing users).
Code Examples
JavaScript
const response = await fetch(
'https://gateway.maton.ai/github/repos/owner/repo/issues?state=open&per_page=10',
{
headers: {
'Authorization': `Bearer ${process.env.MATON_API_KEY}`
}
}
);
const issues = await response.json();Python
import os
import requests
response = requests.get(
'https://gateway.maton.ai/github/repos/owner/repo/issues',
headers={'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}'},
params={'state': 'open', 'per_page': 10}
)
issues = response.json()Notes
Error Handling
| Status | Meaning |
|--------|---------|
| 400 | Missing GitHub connection |
| 401 | Invalid or missing Maton API key |
| 403 | Forbidden - insufficient permissions or scope |
| 404 | Resource not found |
| 408 | Request timeout (common for complex searches) |
| 422 | Validation failed |
| 429 | Rate limited |
| 4xx/5xx | Passthrough error from GitHub API |
Troubleshooting: API Key Issues
1. Check that the `MATON_API_KEY` environment variable is set:
echo $MATON_API_KEY2. Verify the API key is valid by listing connections:
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://ctrl.maton.ai/connections')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOFTroubleshooting: Invalid App Name
1. Ensure your URL path starts with `github`. For example:
Resources
More tools from the same signal band
Order food/drinks (点餐) on an Android device paired as an OpenClaw node. Uses in-app menu and cart; add goods, view cart, submit order (demo, no real payment).
Sign plugins, rotate agent credentials without losing identity, and publicly attest to plugin behavior with verifiable claims and authenticated transfers.
The philosophical layer for AI agents. Maps behavior to Spinoza's 48 affects, calculates persistence scores, and generates geometric self-reports. Give your...