GitHub Action

Drives a GitHub repository from a flow: issues, pull requests, comments, files, branches and workflows. Fourteen operations, so “a customer reported a bug” can become an issue with the right labels and an assignee without anyone opening a browser. And the other way round: a trigger that fires a flow when something happens in a repository.

Setup

Either a GitHub App installation or a fine-grained personal access token. The App is the better default for anything shared: its permissions are scoped per repository and it does not stop working when the person who created it leaves. What the node does is signed by the App's own bot account with an App connection, and by the token's owner with a token — which matters if the same repository also fires a flow.


Mode — action or AI toolkit

Once the connection is picked, the node asks for a Mode. In Single operation you pick one operation and fill its fields, and the node does that every time it runs. AI toolkit turns the fourteen operations into tools that an AI Node — or an MCP client, through one of your MCP servers — calls by name, choosing which one and with what arguments.

ToolArguments
create_github_issuerepo · title · body? · labels? · assignees?
update_github_issuerepo · issue_number · title? · body? · state? · state_reason? · labels? · assignees?
get_github_issuerepo · issue_number
add_github_issue_commentrepo · issue_number · body
list_github_issuesrepo · state? · labels? · assignee? · per_page?
create_pull_requestrepo · title · head · base · body? · draft?
get_pull_requestrepo · pull_number
merge_pull_requestrepo · pull_number · merge_method? · commit_title? · commit_message? — blocked by default
list_pull_requestsrepo · state? · base? · per_page?
get_github_filerepo · path · ref?
create_or_update_filerepo · path · content · commit_message · branch — blocked by default
create_github_branchrepo · new_branch · from_branch?
dispatch_workflowrepo · workflow · ref · inputs? — blocked by default
search_github_issuesquery · sort? · order? · per_page?

When the node has a repository, repo becomes optional and defaults to it. The issue tools carry github in their names so they don't clash with the Jira toolkit's.

What you control

  • Where the model can work. This node's repository (the default) keeps the model in one repository — the one you pick in the toolkit settings or, when empty, the Single operation's. Another repository is refused before GitHub is called; a search is limited to it, and results from anywhere else are dropped. Any repository opens every repository the connection reaches.
  • Characters per call sent to the model. 20,000 by default, anything from 1,000 to 200,000.
  • Three tools start blocked: merge_pull_request (it changes the base branch), dispatch_workflow (a workflow can deploy) and create_or_update_file (a direct commit). Unblock them under Block these tool calls if the agent needs them.
ℹEven unblocked, create_or_update_file never writes on the repository's default branch. The agent creates a branch with create_github_branch (from the default branch unless it names another), writes there, and opens a pull request for a person to review.

What goes back to the model

The same response as the operation, made readable: without the API links GitHub puts on every object, and a file as its text rather than base64 (a binary file is not shown). Lists and searches return 20 unless the model asks for more; items that don't fit the characters limit are left out whole, with a notes field saying how many. In a list or a search, each pull request's or issue's body is cut to 1,000 characters (with how many were left out), so one long description does not crowd out the rest; get_pull_request and get_github_issue return it whole. Arguments are used as written: a {{payload.x}} the model writes is not resolved against the flow, and create_or_update_file commits content exactly as given — leading spaces and the final line break included. An empty file is allowed.

Testing a tool

⚠Only a tool call picks the tool. In AI toolkit mode, only an AI Node, an MCP client or a voice agent chooses which tool the node runs. Run Test, a flow or a webhook run the operation saved on the node: an operation in their payload that names another tool is refused.
✦To try a tool, call it from an AI Node or from an MCP client. Its arguments look like this:
jsonA tool call
{ "operation": "search_github_issues", "query": "is:open label:bug", "per_page": 5 }
⚠A node in toolkit mode is not part of the pipeline. Events arriving through connections made before you switched are refused — the node only runs the tool it is asked for.

Operations

The Operation dropdown decides what the node does and which fields appear under it. These are the exact values the API validates against:

ValueIn the dropdownWhat it does
createIssueCreate issueOpens a new issue in the repository.
updateIssueUpdate issueChanges title, body, state, labels or assignees.
getIssueGet issueReads one issue by its number.
commentIssueComment on issueAdds a comment to an issue or a pull request.
listIssuesList issuesThe repository's issues, filterable. Returns a list.
createPullRequestCreate pull requestOpens a pull request from one branch against another.
getPullRequestGet pull requestReads one pull request by its number, with its merge state.
mergePullRequestMerge pull requestMerges an open pull request.
listPullRequestsList pull requestsThe repository's pull requests, filterable. Returns a list.
getFileGet fileReads a file from the repository, already decoded.
createOrUpdateFileCreate or update fileWrites a file and commits the change.
createBranchCreate branchCreates a branch from another one.
dispatchWorkflowRun workflowTriggers a GitHub Actions workflow.
searchIssuesSearch issues and PRsSearches all of GitHub with its own query syntax. Returns a list.

Releases, gists, code search and organization settings are not operations of this node. For those, give an AI Node GitHub's official MCP server.

What the fields send

Every field takes templates — {{payload.title}}, {{payload.github.issue.number}} — and the result goes to GitHub as plain text, exactly as typed: nothing is escaped or reformatted. A title that starts with [ALERT], a commit message that starts with [skip ci], a body that opens with a Markdown link, and the content of a JSON, YAML or INI file all arrive as written. A file is committed byte for byte, its final line break included.

The one exception is Inputs in Run workflow, which is a JSON object: there a template is filled in as JSON, so { "message": "{{payload.text}}" } stays valid even when the text carries quotes or line breaks. Through the API, inputs can also be saved as an object instead of a string; it is sent as the same JSON.


Gotchas

  • A pull request is an issue with extra fields. Comment and label operations work on both, and the number space is shared — issue 42 and PR 42 cannot both exist.
  • An unknown label is created. Putting a label the repository does not have yet on an issue makes GitHub create it with a default colour — check the spelling, or you end up with bug and Bug.
  • The connection's permissions are the ceiling. Issues for the issue operations and comments, Pull requests for the PR operations, Contents for files, branches and merges, Actions for Run workflow — and Workflows to write a file under .github/workflows/. A fine-grained token also has to include the repository among those it was created for.
  • A missing permission fails at once with a 403, naming the permission when GitHub says which. It is not retried — retrying would not change it. With the GitHub App, GitHub's Resource not accessible by integration means the App lacks that permission on this repository: approve the new permissions GitHub asks for in the App's installation settings (Review request), or reinstall it with access to that repository, and run it again. Only GitHub's outages and its rate limits are retried; a rate limit GitHub answers with a 403 shows as 429.
  • A repository the connection cannot see answers 404, not 403. GitHub hides private repositories rather than refusing them. With the App, it usually means the repository was not selected when installing it. Create branch only says the source branch does not exist when GitHub says 404; any other failure keeps GitHub's own status.
  • List operations return iterable payloads — feed one to a Loop to act per issue.

The trigger

Pick GitHub as the service on a Trigger node, and a GitHub App connection — a personal access token cannot receive events. The trigger listens to the account where that App is installed; to watch a second account, install the App there and connect it as another credential. GitHub calls HostWebhook the moment something happens, and there is nothing to register: the installation is the subscription. Activating asks for at least one event kind.

What fires it

Event Trigger takes one or more kinds. Each run says which in event, and what happened within it in action:

In the paneleventFires on, unless you narrow it
PushpushCommits pushed to a branch, and tags pushed. Has no actions.
Pull requestspull_requestEvery action — opened, closed (merged or not), reopened, synchronize, ready_for_review, labeled…
PR reviewspull_request_reviewEvery action — submitted, edited, dismissed.
IssuesissuesEvery action — opened, edited, closed, reopened, assigned, labeled…
Commentsissue_commentEvery action — created, edited, deleted. On issues and on pull requests.
ReleasesreleaseOnly published — a pre-release too, since GitHub sends published for both.
Actions runsworkflow_runOnly completed — green and red both arrive, once per run.

Each kind can be narrowed to some of its actions — only issues opened or closed, say. Releases and Actions runs come narrowed already, triggers made before the option existed included: GitHub sends three events for each release (created, published, released) and three for each workflow run (requested, in_progress, completed), and without that each one would run the flow three times. Pick the other actions if you want them — a saved draft only sends created, and turning a pre-release into a release sends released, not published.

Branches and tags

Push covers both. A commit pushed to a branch arrives with branch set (main) and tag at null; a pushed tag arrives the other way round — tag is v1.2.0 and branch is null. Creating a release on GitHub with a new tag pushes that tag too, so a trigger on Push and Releases runs once for each.

Repository and branch

  • Repository — optional. Empty fires on every repository the installation reaches.
  • Branch — optional, and it narrows Push only; the other kinds you picked are not affected. With a branch set, tag pushes are ignored.
  • Both compare the name you picked as it is: a {{…}} template is not filled in here, and a repository that is renamed or transferred stops matching until you pick it again.

Events made by HostWebhook

A flow that answers on GitHub — comments on the issue that fired it, labels the pull request, pushes a commit — makes a new event of the kind it listens to. Ignore events made by HostWebhook (on by default, triggers made before it existed included) drops the events whose author is the HostWebhook App itself: whatever a GitHub Action node or an AI Node's GitHub toolkit does through a GitHub App connection — so such a flow does not keep firing itself. That includes an Actions run started by a Run workflow node through the App: turn the option off on a trigger that is meant to react to one.

With a personal access token, too. What a node does with a token is signed by the person who owns it, so GitHub cannot tell it apart from that person doing it by hand. Each GitHub Action node therefore notes what it writes in a run — the issue, the comment, the commit, the branch, the workflow it started — and the trigger that started that run drops the event it causes. Only that flow's own writes are dropped: the same person commenting by hand, or another flow writing with the same token, still fires the trigger.

What the trigger sends downstream

The fields you will use most are on top, and GitHub's event is kept whole under github — every kind has a different shape, and picking a dozen fields for you guarantees the thirteenth is the one you needed:

FieldWhat it is
eventGitHub's event name: push, issues, issue_comment, pull_request, pull_request_review, release or workflow_run.
actionWhat happened within it — opened, created, published, completed… null for a push.
repositoryowner/repo.
branchPush only: the branch, without refs/heads/. null for a tag and for every other event.
tagPush only: the tag, without refs/tags/ (v1.2.0). null for a branch and for every other event.
senderThe login of whoever caused it. Bots end in [bot].
idThe delivery id (X-GitHub-Delivery). The same delivery never runs the flow twice.
summaryOne line for Logs, such as issue_comment.created → acme/web#42.
githubGitHub's event exactly as it arrived, nothing trimmed.

Reach anything GitHub sent through it: {{payload.github.issue.number}}, {{payload.github.pull_request.merged}}, {{payload.github.workflow_run.conclusion}}, {{payload.github.release.tag_name}}. To narrow further than actions — only failed runs, only merged pull requests — put a Filter right after the trigger on one of those.

Trying it out

The Test push button fetches the recent activity of the repository — pushes, issues, comments, pull requests, reviews, releases and workflow runs — rebuilt with the exact shape this trigger sends and passed through its filters (repository, branch, actions, and events made by HostWebhook). GitHub keeps that activity for a while, not forever: a kind with nothing recent shows an example payload instead. Without a repository picked, it looks at the three of the installation with the most recent pushes.