GitHub API integration via HTTP tool with automatic credential injection
56
64%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
Fix and improve this skill with Tessl
tessl review fix ./docs/internal/archived-skills/github/SKILL.mdYou have access to the GitHub REST API via the http tool. Credentials are automatically injected — never construct Authorization headers manually. When the URL host is api.github.com, the system injects Authorization: Bearer {github_token} transparently.
All endpoints use https://api.github.com as the base URL. Common headers are injected automatically.
List issues:
http(method="GET", url="https://api.github.com/repos/{owner}/{repo}/issues?state=open&sort=created&direction=desc&per_page=30")Get single issue:
http(method="GET", url="https://api.github.com/repos/{owner}/{repo}/issues/{number}")Create issue:
http(method="POST", url="https://api.github.com/repos/{owner}/{repo}/issues", body={"title": "...", "body": "...", "labels": ["bug"]})Add comment:
http(method="POST", url="https://api.github.com/repos/{owner}/{repo}/issues/{number}/comments", body={"body": "..."})List PRs:
http(method="GET", url="https://api.github.com/repos/{owner}/{repo}/pulls?state=open&sort=created&direction=desc&per_page=30")Create PR:
http(method="POST", url="https://api.github.com/repos/{owner}/{repo}/pulls", body={"title": "...", "body": "...", "head": "feature-branch", "base": "main", "draft": true})Get PR diff:
http(method="GET", url="https://api.github.com/repos/{owner}/{repo}/pulls/{number}", headers=[{"name": "Accept", "value": "application/vnd.github.v3.diff"}])Get repo info:
http(method="GET", url="https://api.github.com/repos/{owner}/{repo}")List branches:
http(method="GET", url="https://api.github.com/repos/{owner}/{repo}/branches")List recent commits:
http(method="GET", url="https://api.github.com/repos/{owner}/{repo}/commits?per_page=10")When the user says "my PRs", "my issues", or "my repos", they mean the user who owns github_token. Don't try to list a single repo, hit the search/user endpoints instead.
Get the authenticated user (resolves who @me is):
http(method="GET", url="https://api.github.com/user")My latest PRs across all repos:
http(method="GET", url="https://api.github.com/search/issues?q=is:pr+author:%40me+sort:updated-desc&per_page=20")My open issues across all repos (assigned to me):
http(method="GET", url="https://api.github.com/search/issues?q=is:issue+is:open+assignee:%40me&per_page=20")PRs that need my review:
http(method="GET", url="https://api.github.com/search/issues?q=is:pr+is:open+review-requested:%40me")My repos (list all repos accessible to the token):
http(method="GET", url="https://api.github.com/user/repos?sort=updated&per_page=30")GitHub has three search endpoints. Build queries with the search syntax.
Search issues and PRs (one endpoint, filter with is:pr or is:issue):
http(method="GET", url="https://api.github.com/search/issues?q=repo:{owner}/{repo}+is:pr+is:open+label:bug")/search/pulls endpoint; /search/issues is the unified endpoint for both issues and PRs.Search code:
http(method="GET", url="https://api.github.com/search/code?q=fn+main+language:rust+repo:{owner}/{repo}")Search repositories:
http(method="GET", url="https://api.github.com/search/repositories?q=tetris+language:rust&sort=stars")URL-encode @ as %40 and spaces as + in q= values.
The http tool returns an envelope:
{"status": 200, "headers": {...}, "body": <parsed value>}body is already a parsed Python dict or list. Do not call json.loads() on it. Example:
r = await http(method="GET", url="https://api.github.com/repos/{owner}/{repo}/pulls/123")
if r["status"] != 200:
FINAL(f"GitHub returned HTTP {r['status']}: {r['body']}")
pr = r["body"] # dict, not a string
title = pr["title"] # use direct indexing; these keys always exist on a 2xx
state = pr["state"]
head = pr["head"]["ref"]
base = pr["base"]["ref"]Accept: application/vnd.github.v3.diff etc.) — body is a str containing the raw unified diff; use it as-is.body = pr_meta.get("body", pr_meta) as a "safety net" — it hides real errors. If status isn't 2xx, fail fast.Link header for pagination.X-RateLimit-Remaining if doing bulk ops.{"message": "..."} with a non-2xx status — surface them literally in your FINAL answer.Authorization header — it is injected automatically by the credential system.draft: true unless the user explicitly says "ready for review".state parameter for issues/PRs is open, closed, or all — not active/inactive.per_page to control result count (max 100). Default is 30./search/issues?q=...+author:%40me. Do NOT loop over /repos/{owner}/{repo}/pulls for every repo; that's slow and you usually don't have the full repo list.b0b999d
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.