Skip to Content
IntegrationsGitHub

GitHub Integration

Pilot integrates with GitHub to receive issues and create pull requests. This is the primary adapter for most Pilot deployments, supporting both polling and webhook modes for real-time issue detection.

GitHub is Pilot’s flagship integration. It supports label-based issue intake, automatic PR creation, CI status tracking, auto-merge via Autopilot, and rich PR comments with execution metrics.

Setup

1. Create a GitHub Token

You can use either a Personal Access Token (PAT) or a GitHub App token.

Personal Access Token (Classic):

  1. Go to GitHubSettingsDeveloper settingsPersonal access tokensTokens (classic)
  2. Click Generate new token (classic)
  3. Select scopes:
    • repo — full repository access
    • workflow — if you need GitHub Actions integration

Fine-grained PAT (recommended):

  1. Go to SettingsDeveloper settingsPersonal access tokensFine-grained tokens
  2. Select the target repository
  3. Set permissions:
    • Repository permissions: Contents (Read and write), Issues (Read and write), Pull requests (Read and write), Metadata (Read)

For production deployments, use a dedicated service account and fine-grained PAT scoped to specific repositories for better security isolation.

2. Create the pilot Label

In your GitHub repository, create a label that triggers Pilot:

  1. Go to your repo → IssuesLabels
  2. Click New label
  3. Create a label named pilot (or your preferred name)

3. Configure Pilot

# ~/.pilot/config.yaml adapters: github: enabled: true token: ${GITHUB_TOKEN} repo: owner/repo project_path: /path/to/local/repo pilot_label: pilot polling: enabled: true interval: 30s label: pilot

Configuration Reference

FieldTypeDefaultDescription
enabledboolfalseEnable the GitHub adapter
tokenstringrequiredPersonal Access Token or GitHub App token
repostringrequiredRepository in owner/repo format
project_pathstringrequiredLocal filesystem path to the cloned repository
webhook_secretstringHMAC secret for webhook signature verification
pilot_labelstring"pilot"Label that triggers Pilot to process an issue
polling.enabledboolfalseEnable polling for new issues
polling.intervalduration30sHow often to poll for new issues
polling.labelstring"pilot"Label to filter issues by when polling
stale_label_cleanup.enabledbooltrueAuto-remove orphaned pilot-in-progress labels
stale_label_cleanup.intervalduration30mHow often to check for stale labels
stale_label_cleanup.thresholdduration1hAge after which a label is considered stale
stale_label_cleanup.failed_thresholdduration24hAge after which pilot-failed is removed

Polling Mode

When polling is enabled, Pilot periodically checks for open issues with the pilot label:

  1. Fetches issues sorted by creation date (oldest first)
  2. Filters out issues with pilot-in-progress, pilot-done, or pilot-failed labels
  3. Processes the oldest unprocessed issue
  4. Creates a PR and waits for merge (in sequential mode)
  5. Moves to the next issue

Sequential vs Parallel Execution

orchestrator: execution: mode: sequential # or "parallel" wait_for_merge: true poll_interval: 30s pr_timeout: 1h

Sequential mode (default):

  • Processes one issue at a time
  • Waits for PR merge before starting the next issue
  • Prevents merge conflicts between concurrent PRs
  • Recommended for most workflows

Parallel mode:

  • Processes multiple issues concurrently
  • Configurable concurrency limit via max_concurrent
  • Useful for independent, non-overlapping changes

Dependency Resolution

Pilot respects issue dependencies declared in the issue body:

## Summary Add user authentication ## Depends on - #123 - #124

Issues with open dependencies are skipped until their dependencies are closed.

Webhook Mode

For real-time issue detection, configure GitHub webhooks:

1. Set Up the Webhook

  1. Go to your repository → SettingsWebhooks
  2. Click Add webhook
  3. Set Payload URL to https://your-pilot.example.com/webhooks/github
  4. Set Content type to application/json
  5. Set Secret to match your webhook_secret config
  6. Select events: Issues, Pull request reviews

2. Configure Webhook Secret

adapters: github: webhook_secret: ${GITHUB_WEBHOOK_SECRET}

If webhook_secret is empty, signature verification is skipped (development mode only). Always set a secret in production.

Signature Verification

GitHub webhooks use HMAC-SHA256 signatures via the X-Hub-Signature-256 header. Pilot validates every incoming webhook against this signature.

Supported Webhook Events

EventActionBehavior
issuesopenedProcess if issue has pilot label
issueslabeledProcess if pilot label was just added
pull_request_reviewsubmittedNotify Autopilot of approval status

Pull Request Management

When Pilot completes work on an issue, it creates a pull request with rich metadata.

PR Features

  • Automatic branch naming: pilot/GH-{issue_number}
  • Issue linking: PR body references the source issue
  • Execution metrics: Duration, phase breakdown, files changed
  • CI integration: Waits for checks to pass before considering merge

PR Labels

Pilot applies labels to track issue status:

LabelPurpose
pilotTriggers Pilot to process the issue
pilot-in-progressApplied while Pilot is working
pilot-doneApplied after successful completion
pilot-failedApplied if execution fails
pilot-retry-readyPR closed without merge, ready for retry

Merge Methods

Pilot supports all GitHub merge methods:

autopilot: merge_method: squash # "merge", "squash", or "rebase"
MethodDescription
mergeCreate a merge commit
squashSquash all commits into one
rebaseRebase and merge (linear history)

CI Status Tracking

Pilot monitors both commit statuses and check runs:

Commit Statuses

StatusDescription
pendingChecks are running
successAll checks passed
failureOne or more checks failed
errorCheck encountered an error

Check Runs (GitHub Actions)

StatusConclusionDescription
queuedWaiting to run
in_progressCurrently running
completedsuccessAll steps passed
completedfailureOne or more steps failed
completedcancelledRun was cancelled

Autopilot Integration

With Autopilot enabled, Pilot can automatically merge PRs after checks pass:

autopilot: enabled: true environment: dev auto_merge: true require_approval: false max_failures: 3

Auto-Merge Flow

  1. Pilot creates PR from issue
  2. CI checks run (build, test, lint)
  3. If all checks pass and auto_merge: true:
    • PR is automatically merged
    • Issue is closed
    • Next issue is processed
  4. If checks fail:
    • Pilot retries implementation (up to max_failures)
    • After max failures, issue is marked pilot-failed

Approval Requirements

autopilot: require_approval: true

When enabled, Pilot waits for a human approval review before auto-merging.

Stale Label Cleanup

Pilot automatically removes orphaned status labels that may remain after restarts or failures:

stale_label_cleanup: enabled: true interval: 30m threshold: 1h failed_threshold: 24h

The cleaner:

  • Runs every interval
  • Removes pilot-in-progress if no active execution exists and label is older than threshold
  • Removes pilot-failed after failed_threshold to allow automatic retry
  • Posts a comment explaining the cleanup

Projects V2 Board Sync

Pilot can automatically move issues across your GitHub Projects V2 board columns as tasks progress through the execution pipeline. This keeps your project board in sync without manual card dragging.

Prerequisites

  • A GitHub Projects V2 board (classic projects not supported)
  • Personal Access Token with project scope (classic PAT required — fine-grained tokens don’t support Projects V2 GraphQL API yet)

Board sync requires a classic PAT with the project scope. Fine-grained tokens do not yet support the Projects V2 GraphQL API.

Configuration

adapters: github: project_board: enabled: true project_number: 5 # From your project URL status_field: "Status" # Field name (default: "Status") statuses: in_progress: "In Progress" # Column for active work review: "In Review" # Column after PR created (optional) done: "Done" # Column on merge failed: "Blocked" # Column on failure (optional)
FieldTypeDefaultDescription
project_board.enabledboolfalseEnable board sync
project_board.project_numberintrequiredProject number from GitHub URL
project_board.status_fieldstring"Status"Single-select field name
project_board.statuses.in_progressstringStatus for active execution
project_board.statuses.reviewstringStatus after PR created
project_board.statuses.donestringStatus on successful merge
project_board.statuses.failedstringStatus on failure

How It Works

  1. On task dispatch → moves card to in_progress column
  2. On PR creation → moves card to review column (if configured)
  3. On merge → moves card to done column
  4. On failure → moves card to failed column (if configured)

Finding Your Project Number

Navigate to your project board. The URL is github.com/users/{owner}/projects/{NUMBER} or github.com/orgs/{owner}/projects/{NUMBER}. Use that number.

Status names must match exactly (case-insensitive) — Pilot looks up option IDs by name from your project’s Status field.

Non-Blocking Design

Board sync errors are logged as warnings but never block task execution. If the GraphQL API is down or the project is misconfigured, tasks still run normally.

Performance

  • First sync: 3–4 GraphQL calls (resolves project ID, field ID, option IDs)
  • Subsequent syncs: 2 calls per update (cached IDs)
  • IDs cached for process lifetime — no repeated lookups

Autopilot Integration

Board sync also works with Autopilot. When Autopilot merges a PR, the card moves to Done. When CI fails and Autopilot creates a fix issue, the card moves to Failed.

Partial Configuration

Leave any status empty to skip that transition:

statuses: in_progress: "" # Skip — don't move on dispatch review: "" # Skip — don't move on PR creation done: "Done" # Move to Done on merge failed: "Blocked" # Move to Blocked on failure

Merged PR Guard

Before retrying a failed issue, Pilot checks whether a merged PR already exists for that issue. This prevents wasted execution on work that was already completed (e.g., a PR was merged manually or via a different workflow).

How It Works

  1. On retry, Pilot searches GitHub: GH-{number} in:title is:pr is:merged
  2. If a merged PR is found, the issue is marked pilot-done and retry is skipped
  3. If no merged PR exists, normal retry proceeds

This guard runs automatically — no configuration needed. It prevents duplicate work when issues are retried after a restart or label cleanup.

Auto-Delete Branches

Pilot automatically deletes remote branches after PR lifecycle events to keep your repository clean.

  • On merge: Branch deleted immediately after successful merge
  • On close/fail: Branch deleted when PR is closed without merge or execution fails
# Branch cleanup is enabled by default — no configuration required

Branch names containing slashes (e.g., pilot/GH-42) are URL-encoded before deletion to avoid 404 errors from the GitHub API.

Auto-Rebase on Conflict

When Autopilot detects a merge conflict on a PR, it attempts to resolve it automatically before falling back to a full retry.

Resolution Strategy

  1. Update branch: Calls the GitHub Update a pull request branch  API to merge the latest base branch into the PR branch
  2. If update succeeds: CI re-runs on the updated branch, normal flow continues
  3. If update fails (true conflict): Pilot closes the PR, creates a new branch from the latest main, and retries execution from scratch

Dependency Annotations

When a CI fix creates a new PR that depends on another, Pilot adds a dependency annotation to the PR body:

Depends on: #123

This helps reviewers understand the relationship between fix PRs.

Priority Labels

Pilot recognizes priority labels and can process higher-priority issues first:

LabelPriorityValue
priority:urgent / P0Urgent1
priority:high / P1High2
priority:medium / P2Medium3
priority:low / P3Low4

Task ID Format

GitHub issues are converted to Pilot tasks with the format GH-{number}:

  • Issue #42 → Task ID GH-42
  • Branch name: pilot/GH-42

API Operations

Pilot uses the following GitHub API operations:

OperationEndpointPurpose
List issuesGET /repos/{owner}/{repo}/issuesPoll for new issues
Get issueGET /repos/{owner}/{repo}/issues/{number}Fetch issue details
Add labelsPOST /repos/{owner}/{repo}/issues/{number}/labelsMark progress
Remove labelsDELETE /repos/{owner}/{repo}/issues/{number}/labels/{name}Clean up
Create PRPOST /repos/{owner}/{repo}/pullsSubmit changes
Merge PRPUT /repos/{owner}/{repo}/pulls/{number}/mergeComplete workflow
Add commentPOST /repos/{owner}/{repo}/issues/{number}/commentsPost updates
Get check runsGET /repos/{owner}/{repo}/commits/{sha}/check-runsMonitor CI
Get statusGET /repos/{owner}/{repo}/commits/{sha}/statusMonitor CI

Troubleshooting

Issue Not Being Picked Up

  1. Verify the issue has the pilot label
  2. Check that no pilot-in-progress or pilot-done labels exist
  3. Ensure the issue is open (not closed)
  4. Check Pilot logs for polling activity

Webhook Not Triggering

  1. Verify webhook URL is accessible from GitHub
  2. Check webhook delivery logs in GitHub (Settings → Webhooks → Recent Deliveries)
  3. Ensure webhook_secret matches between GitHub and Pilot config
  4. Look for signature verification errors in Pilot logs

PR Not Merging

  1. Check if CI checks are passing
  2. Verify branch protection rules allow Pilot to merge
  3. Check if require_approval is enabled
  4. Look for merge conflicts in the PR

Rate Limiting

GitHub has API rate limits (5000 requests/hour for authenticated requests). If you hit limits:

  • Increase polling interval
  • Use webhooks instead of polling
  • Check for runaway polling loops