Pull requests, reviews, comments, checks, labels, assignees, issues and Projects on
GitHub.com and GitHub Enterprise Server, through the REST API and, for
review threads, PR status, auto-merge, the merge queue, drafts and Projects, the
GraphQL API. The two differ only in host, so they’re one area with a configurable
baseUrl. Verification level: unit.
Supported versions: The oldest GitHub Enterprise Server version toil supports hasn’t been established. toil pins
REST API version 2022-11-28 and uses GraphQL for review threads, PR status, auto-merge,
the merge queue, drafts and Projects. GitHub.com is always current; no Enterprise Server
release has been verified yet. The auto-merge and merge-queue commands need a release
that has those features, and so do issue types, sub-issues and Projects (v2). A release
without issue types just leaves type off each issue; one without sub-issues
(issue get --sub-issues) or Projects (project …) gets UNSUPPORTED, saying so.
Credential
A fine-grained personal access token: Settings → Developer settings → Personal
access tokens → Fine-grained tokens, with access to the repositories you work on
(pull requests, issues, contents and checks, read or write as needed). toil sends it as
Authorization: Bearer <token>, with Accept: application/vnd.github+json and
X-GitHub-Api-Version: 2022-11-28. There is no OAuth app, username, password or
browser login.
What each group of commands needs from the token:
| Commands | Fine-grained token | Classic token |
|---|---|---|
issue list, issue search, issue get, issue history | Issues: read, on the repository | repo (public_repo for public repositories only) |
project list, project fields, project items | Projects: read, under the organization’s permissions. A fine-grained token can’t read a user’s own projects | read:project (plus repo to see items from private repositories) |
| Pull request, review, comment and check commands | Pull requests, contents and checks, read or write as needed | repo |
A token without the Projects permission gets AUTH from the project commands,
naming the scope.
Configuration
| Key | Env var | Required | Meaning |
|---|---|---|---|
baseUrl | TOIL_GITHUB_BASE_URL, then GITHUB_API_URL | yes | The REST API root: https://api.github.com, or https://ghe.imagile.dev/api/v3 for Enterprise Server |
token | TOIL_GITHUB_TOKEN, then GITHUB_TOKEN | yes | Fine-grained personal access token |
owner | TOIL_GITHUB_OWNER | no | Default owner (user or org) |
repo | TOIL_GITHUB_REPO | no | Default repository name |
targetBranch | TOIL_GITHUB_TARGET_BRANCH | no | Default base branch for pr create (main when unset) |
writes | TOIL_GITHUB_WRITES | no | true lets write commands run (with --allow-write) |
CI fallbacks: in GitHub Actions, the default connection takes its token from
GITHUB_TOKEN when TOIL_GITHUB_TOKEN isn’t set, and its base URL from
GITHUB_API_URL when TOIL_GITHUB_BASE_URL isn’t set. Each sits directly below its
TOIL_GITHUB_* variable and above the config file.
The GraphQL endpoint is derived from baseUrl: a trailing /v3 is dropped and
/graphql appended, so https://api.github.com uses https://api.github.com/graphql
and https://ghe.imagile.dev/api/v3 uses https://ghe.imagile.dev/api/graphql.
Environment variables (CI, or a one-off shell):
export TOIL_GITHUB_BASE_URL=https://ghe.imagile.dev/api/v3
export TOIL_GITHUB_TOKEN=<your fine-grained token>
Or ~/.toil/config.json, with owner, repo and targetBranch usually set once
under defaults.github:
{
"version": 2,
"connections": {
"corp-github": { "area": "github", "baseUrl": "https://ghe.imagile.dev/api/v3" }
},
"defaults": { "github": { "connection": "corp-github", "owner": "imagile", "repo": "toil-probe" } }
}
The token never goes in this file; a plaintext one there is refused with
CONFIG_INVALID. Run toil connections add corp-github --area github (or
toil connections login corp-github for an existing connection) to keep it in the OS
credential store, or set TOIL_GITHUB_TOKEN.
Owner and repository
Every command except repo create needs an owner and a repository, which come
from, in order:
--ownerand--repo, before or after the command (toil github --owner imagile --repo toil-probe pr get 7); onpr createthe ones after the command win- the first of the working folder’s remotes whose host is this connection’s host,
of any name, trying
originfirst (so a fork’supstreamcounts) (api.github.comcounts asgithub.com).git@host:o/r,ssh://git@host[:port]/o/randhttps://host[:port]/o/rremotes are read, each with or without.git; an HTTPS remote with a user name in it isn’t - the connection’s
ownerandrepo(usuallydefaults.github)
With neither found, the command fails with “Could not determine GitHub owner/repo”.
pr resolve needs them too, though it acts by thread id alone. repo create
reads only an explicit --owner, always as an organization (POST /orgs/<owner>/repos);
without it the repository is created under the token’s user.
Commands
Every command is toil github <resource> <action> [ids...], and its MCP tool is the
path with underscores (github_pr_get, github_commit_checks). Numbers (<number>,
<comment-id>, --line) are read as whole numbers from the start of the text, so
12abc is 12. Write commands need writes on the connection and --allow-write. The
deletes (pr delete-comment, pr delete-review-comment, issue unlabel,
pr remove-reviewers, issue unassign) run on the CLI only and are never MCP tools.
Owner, repo, labels and refs go into request paths as typed; a value that would make a
. or .. path segment is refused with INVALID_INPUT.
- Repositories:
repo create(--name,--description,--private,--auto-init). - Issues: each issue is GitHub’s own, with the issue type in
type, sub-issue counts insub_issues_summaryand the parent inparent_issue_url, where the server has them.issue create(--title,--bodyor--body-file <path>with-for stdin, repeatable--labeland--assignee).issue list(--state open|closed|all, defaultopen; repeatable--label, all of which must match;--assignee,--typewithnoneor*too;--sort created|updated|comments,--direction asc|desc;--updated-since <iso>, GitHub’ssince). The issues endpoint mixes pull requests in; toil leaves them out (pr listhas them).issue search --query <q>(GitHub search syntax;--sort,--order,--updated-since). toil addsis:issue, andupdated:>=<iso>with--updated-since, but not--owneror--repo: scope the query withrepo:,org:oruser:. GitHub serves only the first 1,000 results of a search, so past that toil stops with aGITHUB_SEARCH_CAPPEDwarning; a search GitHub timed out part of getsGITHUB_SEARCH_INCOMPLETE.issue get <number...>, up to 100 numbers. One number returns the issue itself. Several return{ issues, errors }, read four at a time, where an issue GitHub can’t find or answers with an error goes intoerrorsas{ number, code, message }, with aGITHUB_ISSUES_FAILEDwarning; a bad token or a timeout still fails the call.--sub-issuesaddssub_issues, each issue’s sub-issues, one more request per issue.issue history <number>: the issue’s timeline, oldest first, as GitHub returns it:closedandreopened(withstate_reason),labeled,assigned,issue_type_addedandissue_type_changed,sub_issue_added,cross-referenced(the PRs that mention it),commentedand the rest.--updated-sincereads a date the way--created-afterdoes (a date alone is UTC midnight) and sends it as UTC to the second,2025-01-31T00:00:00Z.- Labels and assignees, on an issue or a pull request by its number:
issue label <number>(repeatable--label),issue unlabel <number> --label,issue assign <number>andissue unassign <number>(repeatable--assignee).pr label,pr unlabel,pr assignandpr unassignare the same commands.
- Projects (v2): GitHub’s boards, read over GraphQL. They belong to an owner, so
only
--owneris read;<project>is the number in the project’s URL.project list: the owner’s projects (id,number,title,url,closed, …).project fields <project>: each field’sid,nameanddataType, a single-select field’soptions(Status), and an iteration field’sconfigurationwith itsiterationsandcompletedIterations.project items <project>: each item’sid,type(ISSUE,PULL_REQUEST,DRAFT_ISSUE),content(number, title, state, url and repository) andfieldValues, each with itsfield.nameand value (text,number,date, a single-selectname, or an iteration’stitleandstartDate). An item’s first 100 values are read, with aGITHUB_PROJECT_VALUES_TRUNCATEDwarning past that.
- Pull requests (
<number>is the pull request number):pr list(--state open|closed|all, defaultopen;--head user:branch,--base;--authorand--created-after/--created-before, ISO 8601, are filtered as each page comes in, the author case-insensitively; a date alone is UTC midnight, a date-time with no zone local time),pr get <number>,pr create(--title,--head,--basedefaulting totargetBranchthenmain,--body/--body-file,--draft),pr update <number>(--title,--body,--base),pr merge <number>(--method merge|squash|rebase, defaultmerge, always sent;--commit-title,--commit-message),pr close <number>,pr reopen <number>,pr draft <number>,pr ready <number>. - Merging:
pr enable-auto-merge <number>andpr enqueue <number>(--method,--match-head-commit <sha>),pr disable-auto-merge <number>. - Comments:
pr comments <number>andpr comment <number> --body(the general comments, which work on an issue’s number too;issue commentsandissue commentare the same commands),pr review-comments <number>,pr comment-inline <number>(--commit,--file,--line,--body,--side LEFT|RIGHT, defaultRIGHT),pr reply <number> <comment-id> --body,pr delete-comment <comment-id>,pr delete-review-comment <comment-id>. - Diff and files:
pr diff <number>returns{ diff }, the unified diff as text;pr files <number>. - Reviews:
pr reviews <number>,pr approve <number>(--bodyoptional),pr request-changes <number>(--bodyrequired),pr reviewers <number>,pr threads <number>(thread ids forpr resolve; the first 100 threads with aGITHUB_REVIEW_THREADS_TRUNCATEDwarning past that, and the first 10 comments of each),pr resolve <thread-id>,pr add-reviewers <number>andpr remove-reviewers <number>(repeatable--reviewerand--team-reviewer, at least one). - Status:
commit status <ref>(the combined status; GitHub’s first 30 statuses),commit checks <ref>,pr status <number>(review decision, mergeability, draft and auto-merge state, and the first 100 checks counted intochecks.passed,failed,pendingandother).
Lists page 100 at a time until a short page, and stop with an error after 1,000 pages.
Every list (pr list, pr files, pr comments, pr review-comments, pr reviews,
commit checks, issue list, issue search, issue history and the three project
lists) reads every page by default. --limit <n> stops after n items and sets
meta.page.nextCursor; pass it back as --cursor with the same --limit for the next
n, until nextCursor is null. On pr list, --limit counts the pull requests that
pass --author and the date filters.
toil github issue list --state all --sort updated --direction asc --updated-since 2025-01-31T00:00:00Z --limit 100
toil github issue get 9 10 --sub-issues
toil github --owner imagile project items 3
toil github pr list --state all --author octo-dev
toil github --owner imagile --repo toil-probe pr status 7
toil github pr create --title "Add the probe" --head feature --body-file pr.md --allow-write
Checking a dossier
check-dossier checks the call’s dossier: each owner it names (owner, per repo or not, and owners) is a user or organization, and each repository (repo) exists under its owner. It’s toil github check-dossier (--dossier <name|file>, or the dossier the folder resolves to), and it returns { dossier, connection, env, ok, checked, checks, unchecked }, one check per value with its key path. The CLI exits 1 when one is missing. A failure other than not-found (a bad token, an unreachable host) fails the command. Read only.
Settings at a glance
-
baseUrlrequiredREST API root: https://api.github.com, or https://ghe.imagile.dev/api/v3 for Enterprise Server
TOIL_GITHUB_BASE_URLorGITHUB_API_URL -
tokenrequired secretFine-grained personal access token
TOIL_GITHUB_TOKENorGITHUB_TOKEN -
ownerDefault owner (user or org)
TOIL_GITHUB_OWNER -
repoDefault repository name
TOIL_GITHUB_REPO -
targetBranchDefault base branch for pr create (main when unset)
TOIL_GITHUB_TARGET_BRANCH
Commands at a glance
toil githubrepo createwriteCreate a new repository (personal or org)
toil githubissue createwriteCreate a GitHub issue
toil githubissue labelwritealsotoil github pr labelAdd labels to an issue or pull request
toil githubissue unlabelwriteCLI onlyalsotoil github pr unlabelRemove a label from an issue or pull request
toil githubissue assignwritealsotoil github pr assignAdd assignees to an issue or pull request
toil githubissue unassignwriteCLI onlyalsotoil github pr unassignRemove assignees from an issue or pull request
toil githubissue listList issues in a repository (pull requests left out)
toil githubissue searchSearch issues with GitHub search syntax (is:issue is added)
toil githubissue getGet one or more issues by number (give several numbers to read several), with issue type and, on request, sub-issues
toil githubissue historyList an issue's timeline: state changes, labels, assignments, issue types, sub-issues, cross-references and comments
toil githubproject listList an owner's projects (v2)
toil githubproject fieldsList a project's fields, with single-select options and iterations
toil githubproject itemsList a project's items (issues, pull requests, drafts) with their field values
toil githubpr listList pull requests
toil githubpr getGet a pull request by number
toil githubpr createwriteCreate a pull request
toil githubpr updatewriteUpdate a pull request
toil githubpr mergewriteMerge a pull request (immediate merge — use pr enable-auto-merge for auto-merge)
toil githubpr closewriteClose a pull request
toil githubpr reopenwriteReopen a closed pull request
toil githubpr diffGet unified diff for a pull request
toil githubpr filesList files changed in a pull request
toil githubpr enable-auto-mergewriteEnable auto-merge on a pull request (merges automatically when all requirements are met)
toil githubpr disable-auto-mergewriteDisable auto-merge on a pull request
toil githubpr enqueuewriteAdd a pull request to the repository merge queue
toil githubpr draftwriteConvert an open pull request to a draft
toil githubpr readywriteMark a draft pull request as ready for review
toil githubpr statusAggregated PR status: review decision, checks, mergeability, draft state, and auto-merge
toil githubpr commentsalsotoil github issue commentsList general comments on a pull request (or an issue, by its number)
toil githubpr commentwritealsotoil github issue commentAdd a general comment to a pull request (or an issue, by its number)
toil githubpr review-commentsList inline review comments on a pull request
toil githubpr comment-inlinewriteAdd an inline review comment to a file in a pull request
toil githubpr replywriteReply to a review comment on a pull request
toil githubpr delete-commentwriteCLI onlyDelete a general issue comment
toil githubpr delete-review-commentwriteCLI onlyDelete an inline review comment
toil githubpr reviewsList reviews on a pull request
toil githubpr approvewriteApprove a pull request
toil githubpr request-changeswriteRequest changes on a pull request
toil githubpr reviewersList requested reviewers for a pull request
toil githubpr threadsList review threads on a pull request (includes thread node IDs for pr resolve)
toil githubpr resolvewriteMark a review thread as resolved (use pr threads to get the thread id)
toil githubpr add-reviewerswriteRequest reviewers on a pull request
toil githubpr remove-reviewerswriteCLI onlyRemove requested reviewers from a pull request
toil githubcommit statusGet combined commit status for a ref (branch, tag, or SHA)
toil githubcommit checksList check runs for a ref (branch, tag, or SHA)
toil githubcheck-dossierCheck the call's dossier against GitHub: its owners and repositories exist