github-client-pure
Skill4 starsChanged 5 months agoMITView on GitHub
A GitHub client for environments with only an HTTP request capability — no shell, no jq, no code runtime to post-process responses. Manages its own auth via the OAuth device flow (plain HTTP) and reads GitHub data with GraphQL, so the server returns only the fields you ask for — small responses, no client-side filtering needed; writes go through small REST calls. Use when an agent must talk to GitHub (api.github.com) but can only issue HTTP requests and cannot run scripts or pipe output through jq. If you have a shell and jq available, prefer the `github-client` skill.
- Reads credentials
In this repository2 other files it gives its agents.
- github-apiSkill
- github-clientSkill
The file
We split this skill into the rules it gives an agent
5 rules. About 0 are common, 0 are distinctive, and 5 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈0
Distinctive · estimate
This author's own choices. Worth a look.
5
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 12
Use this skill when the only capability you have is making HTTP requests — no shell, no jq, no language runtime to trim a response after …
- Very specific: line 25
If you *do* have a shell and jq (or any code runtime), the github-client skill is simpler — it trims REST responses with jq.
- Very specific: line 34
Environment: If GITHUB_TOKEN is set, use it as-is — don't cache or overwrite it.
- Very specific: line 57
Only ever send the token to api.github.com (and github.com for the two login endpoints).
- Very specific: line 79
Always check for errors — 200 alone does not mean success.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
GitHub (pure HTTP client)
Use this skill when the only capability you have is making HTTP requests —
no shell, no jq, no language runtime to trim a response after the fact. It
relies on one idea: let the server return only the fields you need.
The REST API has no field selection, so a single list call returns ~30 fields per item — tens of thousands of tokens you'd then have to filter, which you can't do here. GraphQL selects fields server-side, so the response arrives already minimal. This skill therefore:
- reads and searches with GraphQL (
POST https://api.github.com/graphql), and - writes with small REST calls (POST/PATCH/PUT), whose responses are a single object you can read directly.
If you do have a shell and jq (or any code runtime), the github-client
skill is simpler — it trims REST responses with jq. This skill exists for the
transform-free case.
Authentication
Acquire a token in this order; never invent one. (Details, scopes, and the
device-flow request/response fields are in references/authentication.md.)
- Environment. If
GITHUB_TOKENis set, use it as-is — don't cache or overwrite it. - Cached token. Otherwise read
${XDG_CONFIG_HOME:-$HOME/.config}/gh-skills/token.json(shared with thegithub-clientskill). If itsaccess_tokenisn't expired, use it; if expired with arefresh_token, refresh and save. OAuth device flow — over HTTP. With no usable token, log the user in by calling GitHub's device-flow endpoints directly (no PAT prompt, no shelling out, no helper script):
POST https://github.com/login/device/codewithclient_idandscope→ returnsdevice_code,user_code,verification_uri,interval.- Tell the user: open
verification_uriand enteruser_code. - Poll
POST https://github.com/login/oauth/access_tokeneveryintervalseconds (grant typeurn:ietf:params:oauth:grant-type:device_code) until it returns anaccess_token.
Send
Accept: application/jsonto those two endpoints so the response is JSON. The skill's default client id isOv23liz5y2IEXIhpeOJk. If you can write files, save the result to the cache path above (same format asgithub-client) so later runs reuse it; if you can't, keep the token for the session.- Validate a fresh token with a tiny GraphQL call (below). On
401, the token is bad — refresh or re-run the device flow.
Only ever send the token to api.github.com (and github.com for the two login
endpoints). Never put it in a URL or echo it.
The GraphQL request shape
One endpoint, always POST, body is { "query": ..., "variables": ... }:
POST https://api.github.com/graphql
Authorization: Bearer <token>
Content-Type: application/json
{"query":"query{viewer{login}}"}viewer{login} is the GraphQL equivalent of REST GET /user — use it to
validate a token. The response mirrors the query exactly:
{"data":{"viewer":{"login":"..."}}}. There is no X-GitHub-Api-Version
header on GraphQL.
Checking for errors: a malformed query or a field error comes back as
HTTP 200 with a top-level "errors" array (and possibly partial data).
Always check for errors — 200 alone does not mean success. A bad token is
still 401.
Reading (GraphQL)
Pass variables in the variables object; list exactly the fields you want.
references/graphql.md has ready-to-use queries (recent issues, a PR with its
files, repo summary, file text, search) and the field vocabulary, which differs
from REST (author{login} not user.login, etc.). One example — 5 newest open
issues (the issues connection returns issues only, no PRs to filter):
{"query":"query($o:String!,$n:String!,$k:Int!){repository(owner:$o,name:$n){issues(first:$k,states:OPEN,orderBy:{field:CREATED_AT,direction:DESC}){nodes{number title author{login} comments{totalCount}}}}}","variables":{"o":"cli","n":"cli","k":5}}Pagination is cursor-based: connections take first:N/after:$cursor and
return pageInfo{endCursor hasNextPage}; pass endCursor back as after until
hasNextPage is false.
Writing (REST)
Writes return a single small object, so REST is fine here — read the fields you
need straight from the response. Send Authorization: Bearer <token>,
Accept: application/vnd.github+json, X-GitHub-Api-Version: 2022-11-28, and
Content-Type: application/json with a JSON body.
| Operation | Method & path | Body |
| Create issue | POST /repos/{owner}/{repo}/issues | title (req), body, labels, assignees |
| Update/close issue | PATCH /repos/{owner}/{repo}/issues/{number} | title, body, state (open/closed), labels |
| Comment | POST /repos/{owner}/{repo}/issues/{number}/comments | body (req) |
| Create PR | POST /repos/{owner}/{repo}/pulls | title, head, base, body, draft |
| Create/update file | PUT /repos/{owner}/{repo}/contents/{path} | message, content (base64), sha (when updating), branch |
The created/updated object comes back with fields like number and html_url.
Rate limits
GraphQL has a separate, point-based budget (not request counts). Check it
inline: add rateLimit{ limit cost remaining resetAt } to any query, or send
query{rateLimit{remaining resetAt}}. Each call's cost scales with how many
nodes it could return, so request only the first:N you need. REST writes use
the REST limit; on 403/429 honor any Retry-After header.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

