GitHub

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).

MIT-0 · Free to use, modify, and redistribute. No attribution required.
41 · 13.6k · 39 current installs · 42 all-time installs
MIT-0
Security Scan
VirusTotalVirusTotal
Benign
View report →
OpenClawOpenClaw
Benign
high confidence
Purpose & Capability
Name/description claim GitHub API access; SKILL.md documents using a Maton-managed gateway and explicitly requires MATON_API_KEY. The requested environment variable and the endpoints in the instructions (gateway.maton.ai, ctrl.maton.ai) are consistent with a gateway-based GitHub integration. The repository/source/homepage are missing, but that is a metadata gap rather than an incoherent requirement.
Instruction Scope
Instructions only perform HTTP calls to Maton gateway/controller endpoints and show how to create/list/delete OAuth connections and call proxied GitHub endpoints. They do not instruct reading unrelated files, scanning local paths, or accessing other environment variables beyond MATON_API_KEY. They do require network access and user interaction (open OAuth URL) to complete authorization.
Install Mechanism
No install spec and no code files — the skill is instruction-only. This minimizes disk write/execute risk; nothing is downloaded or installed by the skill itself.
Credentials
Only a single env var (MATON_API_KEY) is required and the SKILL.md shows it is used in Authorization headers to maton.ai endpoints. This is proportionate for a gateway-based integration. Note: maton.ai will hold or mediate OAuth tokens, so trusting that third party is necessary.
Persistence & Privilege
always is false and there is no installation or persistent modification of agent/system state in the instructions. The skill can be invoked autonomously (platform default), which is normal — no elevated or unusual privileges are requested.
Assessment
This skill is coherent: it proxies GitHub API calls through Maton and only needs the MATON_API_KEY. Before installing, confirm you trust maton.ai because OAuth tokens and proxied API traffic will pass through their service; consider using a Maton key with limited scope or a dedicated Maton account. Verify the publisher/source if you require provenance (homepage/source are missing). Also be aware the agent can call the skill autonomously by default; if you want to restrict automated access, disable model invocation or require explicit user approval when installing.

Like a lobster shell, security has layers — review code before you run it.

Current versionv1.0.3
Download zip
latestvk97ckr4n9ynvx56zgy70qy8ccs80weqh

License

MIT-0
Free to use, modify, and redistribute. No attribution required.

Runtime requirements

🧠 Clawdis
EnvMATON_API_KEY

SKILL.md

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))
EOF

Base 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
  2. Go to 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))
EOF

Create 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))
EOF

Get 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))
EOF

Specifying 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))
EOF

If 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=30

Repositories

List User Repositories

GET /github/user/repos?per_page=30&sort=updated

Query 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=30

Query 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=30

Query 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}/lock

Issue 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=30

Query 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=30

Example queries:

  • tetris+language:python - Repositories with "tetris" in Python
  • react+stars:>10000 - Repositories with "react" and 10k+ stars

Search Issues

GET /github/search/issues?q={query}&per_page=30

Example queries:

  • bug+is:open+is:issue - Open issues containing "bug"
  • author:username+is:pr - Pull requests by author

Search Code

GET /github/search/code?q={query}&per_page=30

Example queries:

  • addClass+repo:facebook/react - Search for "addClass" in a specific repo
  • function+extension:js - JavaScript functions

Note: Code search may timeout on broad queries.

Search Users

GET /github/search/users?q={query}&per_page=30

Organizations

List User Organizations

GET /github/user/orgs?per_page=30

Note: Requires read:org scope.

Get Organization

GET /github/orgs/{org}

List Organization Members

GET /github/orgs/{org}/members?per_page=30

Rate Limit

Get Rate Limit

GET /github/rate_limit

Response:

{
  "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=2

Response headers include pagination links:

  • Link: <url>; rel="next", <url>; rel="last"

Common pagination parameters:

  • per_page: Results per page (max 100, default 30)
  • page: Page number (default 1)

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

  • Repository names are case-insensitive but the API preserves case
  • Issue numbers and PR numbers share the same sequence per repository
  • Content must be Base64 encoded when creating/updating files
  • Rate limits: 5000 requests/hour for authenticated users, 30 searches/minute
  • Search queries may timeout on very broad patterns
  • Some endpoints require specific OAuth scopes (e.g., read:org for organization operations). If you receive a scope error, contact Maton support at support@maton.ai with the specific operations/APIs you need and your use-case
  • IMPORTANT: When using curl commands, use curl -g when URLs contain brackets to disable glob parsing
  • IMPORTANT: When piping curl output to jq or other commands, environment variables like $MATON_API_KEY may not expand correctly in some shell environments

Error Handling

StatusMeaning
400Missing GitHub connection
401Invalid or missing Maton API key
403Forbidden - insufficient permissions or scope
404Resource not found
408Request timeout (common for complex searches)
422Validation failed
429Rate limited
4xx/5xxPassthrough error from GitHub API

Troubleshooting: API Key Issues

  1. Check that the MATON_API_KEY environment variable is set:
echo $MATON_API_KEY
  1. 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))
EOF

Troubleshooting: Invalid App Name

  1. Ensure your URL path starts with github. For example:
  • Correct: https://gateway.maton.ai/github/user
  • Incorrect: https://gateway.maton.ai/api.github.com/user

Resources

Files

2 total
Select a file
Select a file to preview.

Comments

Loading comments…