139 toolsOAuth bearer
github_example.py
actions_list_repo_secrets reads the names, which is the part an agent
debugging a workflow actually needs, and it is an endpoint that cannot return a
value.
Authenticating
This pack takes a GitHub OAuth bearer token, andconfigure() is optional when $GITHUB_TOKEN is set. Which credential provider you hand it depends on whose account the calls run as.
Refer to GitHub’s provider page for the “GITHUB” constant the snippets below name, the scopes these 139 tools ask for, and this server’s refresh behaviour.
A token you hold
For a script, or a notebook.EnvTokenProvider re-reads the variable on every call, so a token rotated beside the process is picked up without a restart; StaticTokenProvider takes one you already hold as a string. Neither renews anything, so the calls stop when the token expires.
github_script.py
One account, refreshed
For an agent or a server acting as you.OAuth2Client turns a client registration and a stored refresh token into an access token, and renews it before it lapses.
github_agent.py
No refresh token yet? Getting the first grant is the one-time consent flow that hands you one.
Many end users
For a product whose users each connect their own account.SubjectProvider builds one credential per user through a factory you write, and use_subject names the user a call acts for. Your users’ accounts is the consent route inside your app; serving many users is the per-subject cache and its eviction.
github_server.py
The client
oauth_tool_factory is the whole client: a thin wrapper over httpx that attaches your token and these endpoint constants to each request. PyGithub does not enter your dependency tree.credentials is whichever of the three you built in Authenticating. A pack takes it through configure(); a client you build takes the same object as credential_provider, and has no configure() of its own.
Paging through a list
A cursor belongs to the tool that returns it, so it is declared on that tool’s builder call:github_pagination.py
Pagination is declared on
issues_list_for_repo, issues_list_comments, pulls_list, pulls_list_files, repos_list_for_authenticated_user, repos_list_commits, pulls_list_reviews, branches_list, actions_list_workflow_runs, search_code, actions_list_jobs_for_run, actions_list_workflows, actions_list_runs_for_workflow, actions_list_run_artifacts, actions_list_repo_secrets, checks_list_for_ref, checks_list_annotations, checks_list_suites_for_ref, repos_get_combined_status, pulls_list_review_comments, pulls_list_review_comments_for_repo, pulls_list_comments_for_review, pulls_list_commits, repos_get_commit, repos_compare_commits, repos_list_tags, issues_list_labels_for_repo, issues_list_milestones, issues_list_timeline, issues_list_events, issues_list_for_authenticated_user, issues_list_sub_issues, releases_list, releases_list_assets, notifications_list, code_scanning_list_alerts, secret_scanning_list_alerts, repos_list_for_org, repos_list_contributors, search_issues, search_repositories, search_commits and search_users. The other 96 take no cursor.Tools
Each is aTool, called with
ainvoke as in the snippet above. The name
links to its parameters, its response and what it costs.
Issuesissues_list_for_repoGETList issues in a repository.issues_getGETGet a single issue by its number, including the full body text.issues_createPOSTOpen an issue.issues_updatePATCHUpdate an issue.issues_create_commentPOSTPost a comment on an issue or pull request.issues_list_commentsGETList the comments on an issue or pull request, oldest first.issues_list_labels_for_repoGETList the labels a repository defines, with their colours and descriptions.issues_add_labelsPOSTAdd labels to an issue, keeping the ones already on it.issues_set_labelsPUTReplace an issue’s labels with exactly this set, dropping any others.issues_remove_labelDELETETake one label off an issue, leaving the others in place.issues_create_labelPOSTDefine a new label on the repository.issues_update_labelPATCHRename a label or change its colour, description, or archived state.issues_delete_labelDELETEDelete a label, removing it from every issue that carries it.issues_add_assigneesPOSTAssign people to an issue, keeping whoever is already assigned.issues_remove_assigneesDELETEUnassign people from an issue.issues_list_milestonesGETList a repository’s milestones, with how many issues in each are open and closed.issues_create_milestonePOSTCreate a milestone.issues_update_milestonePATCHUpdate a milestone.issues_get_commentGETGet one issue comment by its id — the
id from issues_list_comments, not the issue number.issues_update_commentPATCHEdit an issue comment’s text.issues_delete_commentDELETEDelete an issue comment.issues_list_timelineGETList everything that has happened to an issue in order — comments, labels, assignments, cross-references, the commits that mentioned it.issues_list_eventsGETList an issue’s state changes — labelled, assigned, closed, renamed — without the comments.issues_lockPUTLock an issue or pull request’s conversation.issues_unlockDELETEUnlock a conversation that was locked.issues_list_for_authenticated_userGETList the authenticated user’s issues across every repository they can see — the agent’s own queue.issues_list_sub_issuesGETList the sub-issues of an issue — how a tracking issue’s pieces are found.issues_add_sub_issuePOSTAttach an existing issue to this one as a sub-issue.Pullspulls_listGETList pull requests.pulls_getGETGet a single pull request, including its mergeability and the counts of changed files, additions and deletions.pulls_createPOSTOpen a pull request from head into base.pulls_list_filesGETList the files a pull request changes, with per-file additions, deletions and patch text.pulls_updatePATCHUpdate a pull request’s title, body, state or base branch.pulls_mergePUTMerge a pull request.pulls_create_reviewPOSTApprove a pull request, request changes on it, or leave a comment.pulls_list_reviewsGETList the reviews left on a pull request, oldest first.pulls_request_reviewersPOSTAsk users or teams to review a pull request.pulls_create_review_commentPOSTLeave a comment on a specific line of a pull request’s diff — the thing reviewing is made of.pulls_list_review_commentsGETList the line comments on a pull request, each with the file and line it sits on.pulls_reply_to_review_commentPOSTReply to an existing review comment, continuing its thread.pulls_update_review_commentPATCHEdit the text of a review comment.pulls_delete_review_commentDELETEDelete a review comment.pulls_list_review_comments_for_repoGETList the line comments across every pull request in a repository.pulls_get_reviewGETGet one review of a pull request, with its state and summary text.pulls_submit_reviewPOSTSubmit a pending review as an approval, a request for changes, or a comment.pulls_update_reviewPUTEdit a review’s summary text.pulls_dismiss_reviewPUTDismiss a review so it stops blocking the pull request, with a message saying why.pulls_delete_pending_reviewDELETEDiscard a review that was never submitted.pulls_list_comments_for_reviewGETList the line comments that belong to one review, rather than to the pull request as a whole.pulls_get_diffGETGet a pull request’s whole change as a unified diff, in one call.pulls_list_commitsGETList the commits on a pull request.pulls_update_branchPUTBring a pull request’s branch up to date by merging the base branch into it — the fix for a ‘this branch is out of date’ block.pulls_check_mergedGETAsk whether a pull request has been merged.pulls_list_requested_reviewersGETList who has been asked to review and has not answered yet.pulls_remove_requested_reviewersDELETEWithdraw a review request from users or teams.Reposrepos_getGETGet a repository’s metadata, including its default branch and topics.repos_list_for_authenticated_userGETList repositories the authenticated user can access.repos_get_contentGETRead a file, or list a directory.repos_list_commitsGETList commits, newest first.repos_create_or_update_filePUTCreate a file or replace an existing one, in a single commit.branches_listGETList a repository’s branches and the commit each one points at.git_refs_createPOSTCreate a branch or tag pointing at an existing commit.repos_get_commitGETGet one commit with its diff and per-file line counts.repos_compare_commitsGETCompare two refs and get what is in one and not the other: the status, how far ahead or behind, the commits and the changed files.repos_delete_fileDELETEDelete a file in a commit of its own.repos_merge_branchesPOSTMerge one branch into another directly, without opening a pull request.repos_get_branchGETGet one branch: its head commit and whether it is protected.repos_rename_branchPOSTRename a branch.repos_get_branch_protectionGETRead a branch’s protection rules — required checks, required reviews, linear history — before attempting a write that they would refuse.repos_list_branches_for_head_commitGETList the branches whose head is this exact commit — ‘has this landed, and where’, asked from the commit’s side.repos_get_readmeGETGet the repository’s README, decoded to text.repos_list_tagsGETList a repository’s tags with the commit each points at, newest first.repos_create_forkPOSTFork a repository, optionally into an organization or under a new name.repos_list_for_orgGETList an organization’s repositories.repos_list_languagesGETList a repository’s languages with bytes of code each — the quickest way to find out what a repository is written in before reading any of it.repos_list_contributorsGETList contributors, most commits first — who to ask about a repository.Searchsearch_issuesGETSearch issues and pull requests across GitHub with qualifiers, e.g. ‘repo:owner/name is:issue is:open label:bug’.search_repositoriesGETSearch repositories with qualifiers, e.g. ‘topic:cli language:go stars:>500’.search_codeGETSearch code across GitHub.search_commitsGETSearch commits by message, author or date across GitHub — ‘repo:owner/name fix flaky test’.search_usersGETSearch users and organizations — ‘type:org language:rust’.Usersusers_get_authenticatedGETGet the authenticated user.Actionsactions_list_workflow_runsGETList CI runs, most recent first.actions_rerun_workflowPOSTRun a workflow again from the start, including jobs that passed.actions_cancel_workflow_runPOSTAsk GitHub to cancel a running workflow.actions_get_workflow_runGETGet one workflow run: its status, conclusion, branch, commit and attempt number.actions_list_jobs_for_runGETList a run’s jobs, each with its conclusion and its failing steps named.actions_get_jobGETGet one job of a workflow run, with the steps that did not pass named individually and the runner it ran on.actions_download_job_logsGETRead a failing job’s log.actions_download_run_logsGETRead a whole run’s logs in one call.actions_rerun_failed_jobsPOSTRe-run only the failed jobs of a run, and the jobs that depend on them.actions_list_workflowsGETList the repository’s workflows, with the file each one is defined in and whether it is active or disabled.actions_get_workflowGETGet one workflow.actions_create_workflow_dispatchPOSTTrigger a workflow by hand on a branch or tag.actions_list_runs_for_workflowGETList the runs of one workflow, most recent first — ‘is this pipeline green’, rather than ‘is anything red’.actions_list_run_artifactsGETList what a run uploaded, with each artifact’s size and whether it has expired.actions_get_artifactGETGet one artifact’s name, size, expiry and digest.actions_download_artifactGETDownload an artifact and report what is in it: every entry’s name and size, plus the contents of the small text files — a JUnit report or a coverage summary comes back readable.actions_get_run_usageGETGet a run’s total run time and its billable milliseconds per runner operating system.actions_list_pending_deploymentsGETList the environments a run is waiting on for approval, and who can approve them.actions_review_pending_deploymentsPOSTApprove or reject a run’s pending deployments.actions_list_repo_secretsGETList the names of the repository’s Actions secrets, with when each was created and last changed.Checkschecks_list_for_refGETList the check runs reported against a commit, branch or tag — every CI provider that reports as a GitHub App, Actions included.checks_get_runGETGet one check run, with its summary text and how many annotations it produced.checks_list_annotationsGETList a check run’s annotations: each failure with the file, the line range, a level and a message, already extracted by whoever ran the check.checks_list_suites_for_refGETList the check suites for a commit, branch or tag — one suite per app that reported.repos_get_combined_statusGETGet the single rolled-up state of a commit — ‘success’, ‘failure’, ‘pending’ or ‘error’ — plus one line per reporting context.Gitgit_refs_getGETGet a reference and the commit SHA it points at — how you read a branch’s current head before building on it.git_refs_updatePATCHPoint a branch or tag at a different commit — the step that makes a commit built with git_trees_create and git_commits_create visible.git_refs_deleteDELETEDelete a branch or tag, by reference.git_refs_list_matchingGETList every reference under a prefix — heads/ for all branches, tags/v2 for the v2 tags.git_blobs_createPOSTWrite a file’s content into the object store and get its SHA back, without committing anything.git_blobs_getGETRead a blob by SHA, decoded to text.git_trees_createPOSTBuild one commit’s worth of changes across any number of files.git_trees_getGETRead a tree: every path in it with its mode and object SHA.git_commits_createPOSTCreate a commit pointing at a tree.git_commits_getGETRead a commit object: its message, its tree SHA and its parents.git_tags_createPOSTCreate an annotated tag object.Releasesreleases_listGETList a repository’s releases, newest first.releases_getGETGet one release by its numeric id, with its notes and its assets.releases_get_latestGETGet the latest published release — GitHub’s definition, meaning the most recent release that is neither a draft nor a prerelease.releases_get_by_tagGETGet a release by its tag name, such as ‘v1.4.0’.releases_createPOSTPublish a release, creating its tag if it does not exist.releases_updatePATCHUpdate a release; anything omitted is left unchanged.releases_deleteDELETEDelete a release.releases_generate_notesPOSTGenerate release-note text from the pull requests merged since a previous tag.releases_list_assetsGETList the files attached to a release, with sizes and download counts.releases_upload_assetPOSTAttach a file to a release.Monitoringnotifications_listGETList your unread notifications — mentions, review requests, assignments — most recently updated first.notifications_mark_readPUTMark notifications as read — all of them, or everything up to last_read_at.notifications_get_threadGETGet one notification thread: what it concerns, and the reason you were notified.notifications_mark_thread_readPATCHMark one notification thread as read — how an agent takes a handled item off its own queue.dependabot_list_alertsGETList a repository’s Dependabot alerts: which dependency, how severe, and the first version that fixes it.dependabot_get_alertGETGet one Dependabot alert, with its advisory summary and the patched version.dependabot_update_alertPATCHDismiss a Dependabot alert or reopen one.code_scanning_list_alertsGETList code scanning alerts, each with the rule that fired and the file and line it fired on.code_scanning_get_alertGETGet one code scanning alert, with the rule’s description and the most recent place it was seen.secret_scanning_list_alertsGETList secret scanning alerts: which pattern matched, which provider, and whether the credential is still valid.rate_limit_getGETCheck how much API budget is left, per resource.Constant headers beside a bearer token
GitHub wants three headers on every request that have nothing to do with the model: anAccept naming the media type, an X-GitHub-Api-Version, and a User-Agent
— GitHub answers 403 to a request without one.
They are declared once as static_headers on the factory and sent verbatim. None
of them appears in any tool’s LLM schema, so they cost nothing in context and a
model has no path to setting them. This is the OAuth-plus-constant-headers shape
that static_headers exists for.
Pinning the version is the point of the exercise: an unpinned integration is one
that breaks on GitHub’s schedule rather than on yours. github.API_VERSION is the
version these schemas were written against.
Paging by number
There is no cursor. You ask for page 1, 2, 3 and stop when a page comes back shorter thanper_page, which is why both parameters are required on a
page-number Pagination — without the page size there is no way to tell a full
page from the last one. Both are real fields on the schemas that declare it.
github_page_through_issues.py
items rather than returning a bare
array, so they declare the same style with items_field="items". That is the only
difference between GITHUB_PAGINATION and SEARCH_PAGINATION.
Response trimming
One issue is 4–6KB of nested user objects, reaction counts and twenty*_url
fields; a page of thirty is a quarter of a million characters, almost none of it
actionable. Twenty-four of the twenty-nine tools carry a response handler.
The handlers project rather than filter — they narrow each object but never
drop one, because dropping an item would corrupt the page-length signal that
page-number pagination depends on.
issues_create_comment, issues_list_comments and pulls_list_files have no
handler and return GitHub’s payload as it arrived. pulls_list_files in
particular carries full patch text, which is the point of calling it and also the
largest response in the pack.
Gotchas
Issues include pull requests
Issues include pull requests
That is GitHub’s model, not a quirk of this pack:
issues_list_for_repo
returns both. GitHub’s own signal for it is the presence of a pull_request
key, which does not survive trimming, so the handler sets is_pull_request
on the ones that are.The Link header is not read
The Link header is not read
GitHub also advertises the next page in a
Link header (RFC 8288). A
Charter response is the parsed body, so the page number is the marker this
pack declares. In practice the two agree; where they differ is a repository
mutating under you mid-walk, and neither marker is reliable then.Search has its own rate limit and its own envelope
Search has its own rate limit and its own envelope
30 requests per minute, against 5,000 per hour for the rest of the REST API.
A search-heavy agent hits that long before it hits the general limit. When it
does,
APIError.retry_after carries GitHub’s own answer to “when?” — see
the wire contract.issues_update replaces sets, it does not add to them
issues_update replaces sets, it does not add to them
labels and assignees on issues_update overwrite what is there. To add
one label, read the current set with issues_get and send the union. Closing
an issue is state="closed", with state_reason saying why.repos_list_for_authenticated_user rejects some combinations
repos_list_for_authenticated_user rejects some combinations
Passing
type together with visibility or affiliation is a 422 from
GitHub. Use one or the other; a request carrying both is refused locally,
before the round trip.All three carry a documented default, and none of them is set on the schema.
That is deliberate. GitHub’s defaults describe what it applies to a request
that omits the parameter, so copying them onto the fields put all three on
the wire for every call and made the 422 the normal case rather than the
edge one. A default you send is not a default.repos_get_content is two endpoints wearing one name
repos_get_content is two endpoints wearing one name
Pass a file path and it returns that file with its contents decoded as text;
pass a directory path and it returns a listing. Pass an empty
path for the
repository root. The shape of the response depends on what the path pointed
at, which is GitHub’s design.Two files repos_get_content cannot hand you
Two files repos_get_content cannot hand you
A binary file and a file over 1MB both come back as a
content string
saying which of the two happened, plus the download_url to fetch it with.
Neither is an error, and both are silent if you do not look for them: a
binary file base64-decodes to replacement characters, which reads as content
until you try to use it, and GitHub answers a file between 1MB and 100MB
with encoding: "none" and an empty string. Over 100MB it does not serve
this endpoint at all.Search stops at 1,000 results, whatever total_count says
Search stops at 1,000 results, whatever total_count says
GitHub serves only the first 1,000 matches of any query.
total_count
reports the real size of the match set, so a page-number walk has every
reason to keep going and gets a 422 when page × per_page passes 1,000.
The search schemas check that pair locally and say to narrow the query
instead — a date range, a repository, a label.Related
- GitHub — OAuth app flow and token types
- The wire contract —
static_headersand page-number pagination - Observability — what a call records