Integrations
GitHub
Issues, pull requests, repos, branches, commits, files, Actions workflows, releases, notifications, and code search — all accessible from your AI client via Conductor. Supports Personal Access Tokens, fine-grained PATs, and GitHub Apps.
Overview
The GitHub plugin exposes 40 tools covering every core GitHub API surface. You can ask your AI client to triage issues, open pull requests, trigger deployments, read files from any branch, and monitor Actions runs — without leaving your chat session.
Issues & PRs
Create, triage, label, comment, review, merge, and close issues and pull requests.
Repositories
List, create, fork, and configure repositories. Manage branch protection rules.
Files & Commits
Read and write files, compare commits, navigate branches and tags.
GitHub Actions
Trigger workflow_dispatch runs with custom inputs, poll run status, download artifacts.
Search
Search code, issues, and repositories across GitHub with the full query syntax.
Releases
Create and publish releases with auto-generated changelogs.
Notifications
List and mark as read your GitHub notification inbox.
Organizations
Work with org repos, teams, and members. Supports SAML SSO orgs.
Branches
Create, delete, list, and protect branches programmatically.
Authentication options
Three authentication methods are supported. Choose based on your use case and security requirements.
Personal Access Token (classic)
EasiestA single token with broad scope-based permissions. Best for personal use, local development, and prototyping. Tokens do not expire unless you set an expiration date. The downside: scopes are coarse — you can't restrict a classic PAT to a single repo.
Fine-grained Personal Access Token
RecommendedNewer token type with per-repository and per-permission granularity. You choose exactly which repos the token can access and which permissions (read/write) it gets for each resource type. Always expires (max 1 year). Best for production personal use.
GitHub App
Teams & OrgsA first-class GitHub entity with its own identity, higher API rate limits (15,000 req/hr per installation vs 5,000 for PATs), and fine-grained permissions. Can be installed organization-wide or on specific repos. Ideal for CI/CD, shared team tooling, and production systems. Requires an App ID, Installation ID, and a PEM private key.
Creating a classic PAT
Navigate to github.com → Settings → Developer settings → Personal access tokens → Tokens (classic) and click Generate new token (classic).
| Scope | What it grants |
|---|---|
repo | Full access to public and private repositories — read/write code, issues, PRs, releases, branches, and deployments. |
public_repo | Read/write access to public repositories only. Use when you don't need private repo access. |
repo:status | Read/write access to commit statuses (CI check state). Required for posting CI results. |
delete_repo | Permission to delete repositories. Requires repo scope too. Only include when specifically needed. |
workflow | Read/write GitHub Actions workflows. Required for github.actions.trigger and creating/editing workflow files. |
read:org | Read organization membership, teams, and projects. Required for listing org repos and members. |
write:org | Write access to org membership and projects. Required for managing teams and inviting members. |
notifications | Access notifications. Required for github.notifications.list and github.notifications.mark-read. |
gist | Create and update Gists. |
read:packages | Download packages from GitHub Packages. |
write:packages | Upload packages to GitHub Packages. |
For most Conductor use cases, selecting repo, workflow, and read:org covers everything. Add notifications if you want the notifications tools.
Creating a fine-grained PAT
Navigate to github.com → Settings → Developer settings → Personal access tokens → Fine-grained tokens and click Generate new token.
Resource owner
Choose your personal account or an organization. For org tokens, the org admin must approve fine-grained PATs if the org has that policy enabled. Check under org Settings → Third-party access → Personal access tokens.
Repository access
Choose All repositories for convenience or Only select repositories for tightest scope. Selecting specific repos is strongly recommended for tokens used in automation.
Expiration
Fine-grained tokens always expire. Maximum is 1 year. Set a calendar reminder to rotate before expiry. Use 90 days for automation tokens and 1 year for personal use.
Permissions
Repository permissions and account permissions are configured separately. Metadata (read-only) is always required and cannot be removed. Start with read-only and elevate to read & write only where needed.
Repository permissions
| Permission | Levels | When you need it |
|---|---|---|
Contents | Read / Read & Write | Read and write files, commits, branches, releases. |
Issues | Read / Read & Write | List, read, create, update, and close issues. |
Pull requests | Read / Read & Write | List, read, create, merge, and review PRs. |
Actions | Read / Read & Write | Trigger workflows, read runs, download artifacts. |
Metadata | Read (mandatory) | Basic repository info. Always required — cannot be deselected. |
Commit statuses | Read / Read & Write | Read and post CI check statuses. |
Deployments | Read / Read & Write | Create deployments and update deployment status. |
Secrets | Read / Read & Write | Manage Actions secrets. Rarely needed — include only if required. |
Administration | Read / Read & Write | Manage branch protection rules, webhooks, and repo settings. |
GitHub App setup
GitHub Apps provide higher rate limits, finer-grained permissions, and a distinct identity that isn't tied to any single user account. Use them for team or organizational deployments.
github.com/settings/apps (for personal) or github.com/organizations/YOUR_ORG/settings/apps (for org). Click New GitHub App.~/.conductor/github-app.pem.github.com/settings/installations/INSTALLATION_ID.Required permissions for full Conductor access
Repository: Contents (R&W), Issues (R&W), Pull requests (R&W), Actions (R&W), Commit statuses (R&W), Metadata (R), Administration (R&W for branch protection). Account permissions: none required unless you need to list org members.
Conductor configuration
Add the GitHub plugin to your Conductor config. Use environment variables for tokens — never commit credentials to source control.
# conductor.config.json
{
"plugins": {
"github": {
"auth": {
"type": "pat",
"token": "ghp_your_personal_access_token"
}
}
}
}# conductor.config.json
{
"plugins": {
"github": {
"auth": {
"type": "fine-grained-pat",
"token": "github_pat_your_fine_grained_token"
}
}
}
}# conductor.config.json
{
"plugins": {
"github": {
"auth": {
"type": "github-app",
"app_id": "123456",
"installation_id": "78901234",
"private_key_path": "~/.conductor/github-app.pem"
}
}
}
}# Using environment variables (recommended for production)
export GITHUB_TOKEN=ghp_your_personal_access_token
# Or for GitHub App auth:
export GITHUB_APP_ID=123456
export GITHUB_INSTALLATION_ID=78901234
export GITHUB_PRIVATE_KEY_PATH=~/.conductor/github-app.pem
# Conductor will pick these up automaticallyAvailable tools
40 tools across repositories, issues, pull requests, branches, commits, files, search, releases, Actions, and notifications.
github.repo.getFetch full metadata for a repository — description, visibility, default branch, star count, topics, and license.{
"tool": "github.repo.get",
"input": {
"owner": "myorg",
"repo": "api-service"
}
}github.repo.listList repositories for a user or org. Filter by type (all, public, private, forks, sources, member) and sort by created, updated, or pushed.github.repo.createCreate a new repository under your account or an organization. Set visibility, default branch, gitignore template, and auto-init.{
"tool": "github.repo.create",
"input": {
"name": "new-service",
"description": "Microservice for payment processing",
"private": true,
"auto_init": true,
"gitignore_template": "Node"
}
}github.repo.forkFork a repository into your account or a specified organization.{
"tool": "github.repo.fork",
"input": {
"owner": "upstream-org",
"repo": "open-source-lib",
"organization": "myorg"
}
}github.issue.listList issues for a repo with filters: state, labels, assignee, milestone, since date, and pagination.{
"tool": "github.issue.list",
"input": {
"owner": "myorg",
"repo": "api-service",
"state": "open",
"labels": ["bug", "priority:high"],
"assignee": "octocat",
"per_page": 50
}
}github.issue.getFetch a single issue by number, including its labels, assignees, milestone, and timeline summary.github.issue.createOpen a new issue with title, body (Markdown), labels, assignees, and optional milestone.{
"tool": "github.issue.create",
"input": {
"owner": "myorg",
"repo": "api-service",
"title": "Rate limiter not resetting after TTL expiry",
"body": "## Description\nThe rate limiter counter is not being reset...\n\n## Steps to reproduce\n1. Send 100 requests\n2. Wait for TTL\n3. Counter remains at 100",
"labels": ["bug"],
"assignees": ["octocat"],
"milestone": 3
}
}github.issue.updateEdit an existing issue — change title, body, state (open/closed), labels, assignees, or milestone.github.issue.closeClose an issue with an optional close reason (completed, not_planned).github.issue.commentPost a comment on an issue or pull request. Supports full GitHub-Flavored Markdown.{
"tool": "github.issue.comment",
"input": {
"owner": "myorg",
"repo": "api-service",
"issue_number": 42,
"body": "I've reproduced this locally. The TTL reset logic in\n`src/rate-limiter.ts:L87` is not awaiting the async clear."
}
}github.pr.listList pull requests filtered by state (open, closed, all), head branch, base branch, and sort order.github.pr.getGet full details of a pull request including review status, merge conflict state, changed files count, and CI check rollup.github.pr.createOpen a pull request from head to base branch. Set draft mode, reviewers, assignees, labels, and milestone.{
"tool": "github.pr.create",
"input": {
"owner": "myorg",
"repo": "api-service",
"title": "fix: await async clear in rate limiter TTL reset",
"body": "## Summary\nFixes #42. Added `await` to the `clearCounter()` call...\n\n## Test plan\n- [x] Unit tests pass\n- [x] Integration tests pass",
"head": "fix/rate-limiter-ttl",
"base": "main",
"draft": false,
"reviewers": ["senior-dev"],
"labels": ["bug", "ready-for-review"]
}
}github.pr.mergeMerge a pull request with merge, squash, or rebase strategy. Optionally auto-delete the head branch after merge.{
"tool": "github.pr.merge",
"input": {
"owner": "myorg",
"repo": "api-service",
"pull_number": 118,
"merge_method": "squash",
"commit_title": "fix: await async clear in rate limiter TTL reset (#118)",
"delete_branch": true
}
}github.pr.reviewSubmit a review with APPROVE, REQUEST_CHANGES, or COMMENT. Supports inline comments on specific file lines.{
"tool": "github.pr.review",
"input": {
"owner": "myorg",
"repo": "api-service",
"pull_number": 118,
"event": "REQUEST_CHANGES",
"body": "Please add a test for the edge case where TTL expires mid-request.",
"comments": [
{
"path": "src/rate-limiter.ts",
"line": 87,
"body": "This should be `await clearCounter()` — it's async."
}
]
}
}github.pr.commentPost a review comment on a specific line or range in a pull request diff.github.branch.listList all branches in a repository with protection status and latest commit SHA.github.branch.createCreate a new branch from any ref (branch name, tag, or commit SHA).{
"tool": "github.branch.create",
"input": {
"owner": "myorg",
"repo": "api-service",
"branch": "feat/new-auth-flow",
"from": "main"
}
}github.branch.deleteDelete a branch by name. Returns an error if the branch is the repo's default branch.github.branch.protectConfigure branch protection rules: required status checks, required reviews, enforce admins, and restrict pushes.{
"tool": "github.branch.protect",
"input": {
"owner": "myorg",
"repo": "api-service",
"branch": "main",
"required_status_checks": {
"strict": true,
"contexts": ["ci/tests", "ci/lint"]
},
"enforce_admins": true,
"required_pull_request_reviews": {
"required_approving_review_count": 2,
"dismiss_stale_reviews": true
}
}
}github.commit.listList commits on a branch or path, optionally filtered by author or date range.github.commit.getGet a commit by SHA — tree, parent commits, diff stats, and verification signature.github.commit.compareCompare two refs (branches, tags, or SHAs). Returns the merge base, commits behind/ahead, and diff stat.github.file.getRead file content at a path on any ref. Returns decoded content and the blob SHA for subsequent updates.{
"tool": "github.file.get",
"input": {
"owner": "myorg",
"repo": "api-service",
"path": "src/rate-limiter.ts",
"ref": "fix/rate-limiter-ttl"
}
}github.file.createCreate a new file in the repository with a commit message. Content is automatically base64-encoded.{
"tool": "github.file.create",
"input": {
"owner": "myorg",
"repo": "api-service",
"path": "docs/rate-limiting.md",
"message": "docs: add rate limiting documentation",
"content": "# Rate Limiting\n\nThis service uses a sliding window...",
"branch": "main"
}
}github.file.updateUpdate an existing file. Requires the current blob SHA (returned by github.file.get) to prevent lost updates.github.file.deleteDelete a file from a branch with a commit message. Requires the current blob SHA.github.search.codeSearch for code across GitHub using the full code search syntax: language, repo, path, extension, and content filters.{
"tool": "github.search.code",
"input": {
"q": "clearCounter language:TypeScript repo:myorg/api-service",
"per_page": 20
}
}github.search.issuesSearch issues and PRs org-wide or across all of GitHub. Supports all GitHub search qualifiers.{
"tool": "github.search.issues",
"input": {
"q": "is:open is:issue label:bug org:myorg created:>2026-01-01",
"sort": "created",
"order": "desc"
}
}github.search.reposSearch repositories by name, topic, language, stars, and forks.github.release.listList all releases for a repository, ordered by created date descending.github.release.createPublish a release with tag, name, body, draft/prerelease flags, and optional auto-generated release notes.{
"tool": "github.release.create",
"input": {
"owner": "myorg",
"repo": "api-service",
"tag_name": "v2.4.0",
"name": "v2.4.0 — Rate limiter fix + Auth improvements",
"body": "## What's Changed\n- fix: await async clear in rate limiter (#118)\n- feat: OAuth2 PKCE flow (#115)\n\n**Full Changelog**: https://github.com/myorg/api-service/compare/v2.3.0...v2.4.0",
"draft": false,
"prerelease": false,
"generate_release_notes": true
}
}github.release.getGet a release by ID or tag name, including asset download URLs.github.actions.list-workflowsList all workflow files in a repository with their IDs, names, paths, and current state.{
"tool": "github.actions.list-workflows",
"input": {
"owner": "myorg",
"repo": "api-service"
}
}github.actions.triggerTrigger a workflow_dispatch event with custom inputs. The workflow must define on.workflow_dispatch in its YAML.{
"tool": "github.actions.trigger",
"input": {
"owner": "myorg",
"repo": "api-service",
"workflow_id": "deploy.yml",
"ref": "main",
"inputs": {
"environment": "production",
"image_tag": "v2.4.0",
"notify_slack": "true"
}
}
}github.actions.list-runsList workflow runs with filters: workflow file, branch, event type, status (queued, in_progress, completed), and actor.github.actions.get-runGet full details of a workflow run including conclusion, timing, jobs URL, and triggered event.{
"tool": "github.actions.get-run",
"input": {
"owner": "myorg",
"repo": "api-service",
"run_id": 9876543210
}
}github.actions.download-artifactDownload a run artifact by artifact ID to a local path. Artifacts expire after 90 days by default.{
"tool": "github.actions.download-artifact",
"input": {
"owner": "myorg",
"repo": "api-service",
"artifact_id": 1234567,
"output_path": "/tmp/build-artifacts"
}
}github.notifications.listList notifications for the authenticated user. Filter to unread only, or those you are participating in.{
"tool": "github.notifications.list",
"input": {
"all": false,
"participating": true,
"per_page": 30
}
}github.notifications.mark-readMark one or all notifications as read. Pass a thread ID for a single notification, or omit to mark all.Working with organizations
Most tools accept an owner field that can be either a personal username or an organization slug. Pass the org slug (the URL-safe name visible in github.com/ORG_SLUG) — not the organization's display name.
Org-level permissions
To list private org repos, list org members, or access org-level team data, your token needs read:org (classic PAT) or the Members account permission (fine-grained PAT). Without this, tools that enumerate org resources will return empty results rather than an error, which can be confusing. If you're seeing fewer repos than expected, check that read:org is enabled.
SAML SSO — authorizing tokens
Organizations that enforce SAML Single Sign-On require every PAT to be explicitly authorized for that org, even if the token has the right scopes. Without SSO authorization, requests to org resources return 403 Resource protected by organization SAML enforcement.
To authorize: go to github.com/settings/tokens, click your token, and look for the Configure SSO button next to the organization name. Click it and complete the SSO flow. Fine-grained PATs for SSO orgs require the org admin to approve the token first.
Org slug vs display name
Always use the org slug (login) in tool inputs, not the display name. The slug is what appears in the GitHub URL: github.com/acme-corp → slug is acme-corp. The display name might be Acme Corporation but that won't work as the owner field.
GitHub Actions integration
Conductor can trigger GitHub Actions workflows, poll for completion, and download artifacts — turning your AI client into a deployment and CI orchestration interface.
Setting up workflow_dispatch
The github.actions.trigger tool requires the target workflow to have an on: workflow_dispatch trigger. Define typed inputs to control what Conductor can pass at trigger time.
# .github/workflows/deploy.yml
name: Deploy
on:
push:
branches: [main]
workflow_dispatch: # Required for github.actions.trigger
inputs:
environment:
description: "Target environment"
required: true
default: "staging"
type: choice
options: [staging, production]
image_tag:
description: "Docker image tag"
required: true
type: string
notify_slack:
description: "Send Slack notification on deploy"
required: false
default: "false"
type: boolean
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Deploy to ${{ inputs.environment }}
run: ./scripts/deploy.sh ${{ inputs.image_tag }} ${{ inputs.environment }}Trigger a run
Call github.actions.trigger with the workflow filename or ID, the target branch, and any inputs defined in the workflow. The tool returns the triggered run's ID for subsequent polling.
Poll run status
Use github.actions.get-run to check a run's status and conclusion. Poll every 15–30 seconds. Status values: queued, in_progress, completed. Conclusion values: success, failure, cancelled, timed_out, skipped.
Download artifacts
After a run completes, use github.actions.list-runs to find the run, then github.actions.download-artifact with the artifact ID to download the zip to a local path. Artifacts are only available while the run is retained — GitHub defaults to 90 days.
Webhooks: GitHub → Conductor
You can configure GitHub to push events (push, issues, pull_request, release, etc.) to Conductor's HTTP webhook endpoint. Conductor validates the HMAC signature and routes the payload to a handler tool. Requires HTTP transport.
# 1. Start Conductor in HTTP transport mode
conductor mcp start --transport http --port 3000
# 2. Register the incoming webhook endpoint
conductor webhooks create \
--name "github-events" \
--path "/hooks/github" \
--secret "whsec_your_32_byte_hex_secret"
# GitHub will now POST to:
# http://your-conductor-host:3000/hooks/githubConfigure webhook on GitHub
Go to your repo or org → Settings → Webhooks → Add webhook. Set Payload URL to your Conductor HTTP server address (must be publicly reachable or use a tunnel like ngrok for local dev). Set Content type to application/json. Paste your HMAC secret into the Secret field. Choose which individual events to subscribe to — avoid Send me everything to minimize noise.
HMAC signature verification
GitHub signs every webhook with your secret using HMAC-SHA256. The signature is sent in the X-Hub-Signature-256 header as sha256=<hex>. Conductor verifies this automatically. If you're handling webhooks in your own code:
const crypto = require("crypto");
// GitHub signs with X-Hub-Signature-256: sha256=<hex>
function verifyGitHubSignature(rawBody, signature, secret) {
const expected = "sha256=" + crypto
.createHmac("sha256", secret)
.update(rawBody)
.digest("hex");
if (signature.length !== expected.length) return false;
return crypto.timingSafeEqual(
Buffer.from(signature, "utf8"),
Buffer.from(expected, "utf8")
);
}Recommended events to subscribe to
pushpull_requestissuesissue_commentpull_request_reviewreleaseworkflow_runcheck_rundeploymentdeployment_statusCommon errors and fixes
GitHub API errors map to specific root causes. Most can be resolved by adjusting token scopes, SSO authorization, or workflow configuration.
401 Bad credentialsCause
Token is expired, revoked, or malformed.
Fix
Generate a new PAT at github.com/settings/tokens. If using a GitHub App, check that the private key matches the app and the installation is still active.
403 Resource not accessible by personal access tokenCause
The token is valid but lacks the required OAuth scope for this operation.
Fix
Re-generate the token and add the missing scope. Common offenders: workflow (Actions), read:org (org resources), notifications, delete_repo.
404 on private repositoryCause
The token lacks repo scope, or the repository doesn't exist, or the token owner doesn't have access.
Fix
Ensure repo scope is checked when creating the PAT. For org repos, the token owner must be a member. For fine-grained PATs, add the specific repo to the token's resource access.
403 on org resourcesCause
The organization has SAML SSO enabled and the token has not been authorized for SSO.
Fix
Go to github.com/settings/tokens, click the token, then click 'Configure SSO' and authorize it for the organization.
422 Validation FailedCause
A required field has an invalid format, duplicate value, or violates a constraint.
Fix
Check the errors array in the response body — it lists which field failed validation and why. Common causes: duplicate branch name, invalid label name, PR head already exists.
429 Too Many Requests (rate limited)Cause
You've hit GitHub's primary rate limit (5,000 req/hr for authenticated users) or a secondary rate limit.
Fix
Check the Retry-After response header and wait that many seconds before retrying. For sustained high volume, switch to a GitHub App (15,000 req/hr) or GraphQL API. Conductor's built-in rate limit handler will respect Retry-After automatically.
Push rejected (branch protection)Cause
A direct push to a protected branch was attempted, bypassing required pull request reviews or status checks.
Fix
Create a branch, push to that branch, open a PR, get approvals and pass CI, then merge via github.pr.merge.
GitHub App: installation not foundCause
The installation_id in your config doesn't match an active installation of your GitHub App.
Fix
Go to github.com/settings/apps/{app-slug}/installations to find the correct installation ID. The app must be installed on the org or repo you're trying to access.
Actions: workflow not triggerableCause
github.actions.trigger requires on.workflow_dispatch to be defined in the workflow YAML. If it's missing or the file doesn't exist on the target ref, GitHub returns 422.
Fix
Add the workflow_dispatch trigger to the workflow YAML and push it to the target branch before calling github.actions.trigger.
Secondary rate limit (403)Cause
Too many concurrent requests or mutations per minute. GitHub enforces secondary limits separately from the hourly quota.
Fix
Reduce request concurrency. Space out write operations (issue creation, PR comments) with small delays between batches. Conductor's retry logic handles this automatically with exponential backoff.
Rate limits
GitHub enforces both primary (per-hour) and secondary (per-minute concurrency) rate limits. Conductor respects the Retry-After and X-RateLimit-Reset headers automatically.
| API | Unauthenticated | PAT | GitHub App |
|---|---|---|---|
REST API | 60 req/hr | 5,000 req/hr | 15,000 req/hr (installation) |
GraphQL API | — | 5,000 points/hr | 15,000 points/hr |
Search API | 10 req/min | 30 req/min | 30 req/min |
Code Search | — | 10 req/min | 10 req/min |
Actions (workflow triggers) | — | 500 per repo/day | 500 per repo/day |
Secondary rate limits
In addition to the hourly quota, GitHub enforces secondary limits on concurrent requests and rapid write mutations (creating issues, comments, etc. in quick succession). These return 403 with a message like You have exceeded a secondary rate limit. Conductor handles these with exponential backoff. If you're doing bulk operations, introduce a small delay (100–500ms) between write calls to stay well within secondary limits.
Security best practices
Prefer fine-grained PATs over classic PATs
Fine-grained tokens let you restrict access to exactly the repos and permissions needed. A classic PAT with repo scope grants read/write access to all your private repos — a significant blast radius if leaked.
Apply minimal scopes
Only grant the permissions your workflow actually requires. Start with read-only and escalate to write only when a tool fails with 403. This limits damage from token exposure.
Set expiration dates
Always set an expiration on tokens — 90 days for automation, up to 1 year for personal use. Calendar a reminder to rotate them before they expire. Fine-grained PATs enforce expiration; classic PATs do not.
Never commit tokens to source control
Use environment variables or Conductor's built-in secret store (conductor secret set GITHUB_TOKEN). GitHub automatically scans repositories for accidentally committed tokens and immediately revokes them when found — but the exposure window before revocation can still be exploited.
Use GitHub Apps for team and production use
GitHub Apps have their own identity, don't rely on a user account, and survive employee offboarding. Use them for any automation that multiple people depend on.
Scope GitHub App installations tightly
Install GitHub Apps on only the repos they need, not the entire organization. Use the 'Only select repositories' option when installing.
Store private keys securely
GitHub App private keys (.pem files) are equivalent to a master password for your app. Store them in a secrets manager (AWS Secrets Manager, HashiCorp Vault, 1Password Secrets Automation) rather than on disk in plaintext.
Rotate tokens on any suspected exposure
If a token may have been exposed — leaked log, committed to a repo, sent in a message — revoke it immediately at github.com/settings/tokens and generate a new one. Don't wait for GitHub's automatic scanning.