> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/ComposioHQ/agent-orchestrator/llms.txt
> Use this file to discover all available pages before exploring further.

# GitHub SCM Plugin

> Source control management plugin for GitHub PRs, CI checks, reviews, and merge readiness

# GitHub SCM Plugin

The GitHub SCM plugin provides comprehensive GitHub integration for pull request management, CI/CD monitoring, code review tracking, and merge readiness checks.

## Overview

This plugin uses the GitHub CLI (`gh`) to interact with the GitHub API. It monitors PR state, CI checks, code reviews, and determines when PRs are ready to merge. The orchestrator uses this information to automatically handle routine tasks and notify humans only when their judgment is needed.

<Note>
  The SCM plugin is designed for push-based workflows: agents create PRs, the orchestrator monitors CI/reviews, and auto-merges when ready.
</Note>

## Configuration

Configure the GitHub SCM plugin in your `agent-orchestrator.yaml`:

```yaml theme={null}
plugins:
  scm:
    name: github

projects:
  - id: my-app
    repo: owner/repo-name  # GitHub repository in owner/repo format
```

### Configuration Options

The GitHub SCM plugin requires no additional configuration parameters. All settings are derived from the project's `repo` field.

<ParamField path="repo" type="string" required>
  GitHub repository in `owner/repo` format (e.g., `octocat/hello-world`).
</ParamField>

## Requirements

<Warning>
  Prerequisites:

  * GitHub CLI (`gh`) installed and in PATH
  * Authenticated with `gh auth login`
  * Read/write access to pull requests in the target repository
  * Repository must have Actions or Checks configured for CI
</Warning>

### Installing GitHub CLI

```bash theme={null}
# macOS
brew install gh

# Linux (Debian/Ubuntu)
sudo apt install gh

# Login
gh auth login
```

### Verifying Authentication

```bash theme={null}
# Check authentication status
gh auth status

# Test PR access
gh pr list --repo owner/repo-name --limit 5
```

## Features

### PR Detection and State

**Detect PR**

Find a PR for a specific branch:

```typescript theme={null}
const pr = await scm.detectPR(session, project);
// Returns: PRInfo | null
// { number, url, title, owner, repo, branch, baseBranch, isDraft }
```

**Get PR State**

Check if a PR is open, closed, or merged:

```typescript theme={null}
const state = await scm.getPRState(pr);
// Returns: "open" | "closed" | "merged"
```

**Get PR Summary**

Get high-level PR information:

```typescript theme={null}
const summary = await scm.getPRSummary(pr);
// Returns: { state, title, additions, deletions }
```

### PR Lifecycle

**Merge PR**

Merge a PR with configurable merge method:

```typescript theme={null}
await scm.mergePR(pr, "squash");  // "squash" | "merge" | "rebase"
// Automatically deletes the branch after merge
```

**Close PR**

Close a PR without merging:

```typescript theme={null}
await scm.closePR(pr);
```

### CI/CD Monitoring

**Get CI Checks**

Fetch all CI checks for a PR:

```typescript theme={null}
const checks = await scm.getCIChecks(pr);
// Returns: CICheck[]
// [
//   { name: "Build", status: "passed", url: "...", conclusion: "SUCCESS", ... },
//   { name: "Test", status: "running", ... },
//   { name: "Lint", status: "failed", ... }
// ]
```

**Get CI Summary**

Get high-level CI status:

```typescript theme={null}
const status = await scm.getCISummary(pr);
// Returns: "passing" | "failing" | "pending" | "none"
```

<Info>
  CI Summary Logic:

  * `passing`: All checks passed (at least one check exists)
  * `failing`: At least one check failed
  * `pending`: No failures, but at least one check is pending/running
  * `none`: No checks configured or PR is merged/closed
</Info>

### CI Check Status Mapping

GitHub Check State → CI Status:

| GitHub State | CI Status |
| - | - |
| `SUCCESS` | `passed` |
| `PENDING`, `QUEUED` | `pending` |
| `IN_PROGRESS` | `running` |
| `FAILURE`, `TIMED_OUT`, `CANCELLED` | `failed` |
| `SKIPPED`, `NEUTRAL` | `skipped` |
| Unknown | `failed` (fail-closed) |

### Code Review Tracking

**Get Reviews**

Fetch all reviews for a PR:

```typescript theme={null}
const reviews = await scm.getReviews(pr);
// Returns: Review[]
// [
//   { author: "reviewer1", state: "approved", body: "LGTM", submittedAt: Date },
//   { author: "reviewer2", state: "changes_requested", body: "...", submittedAt: Date }
// ]
```

**Get Review Decision**

Get the overall review decision (GitHub's aggregate status):

```typescript theme={null}
const decision = await scm.getReviewDecision(pr);
// Returns: "approved" | "changes_requested" | "pending" | "none"
```

### Review Comments

**Get Pending Comments**

Fetch unresolved review comments (excludes bot comments):

```typescript theme={null}
const comments = await scm.getPendingComments(pr);
// Returns: ReviewComment[]
// [
//   {
//     id: "comment-123",
//     author: "reviewer1",
//     body: "This could be refactored...",
//     path: "src/index.ts",
//     line: 42,
//     isResolved: false,
//     createdAt: Date,
//     url: "..."
//   }
// ]
```

<Note>
  Pending comments only include unresolved threads from human reviewers. Bot comments are filtered out.
</Note>

**Get Automated Comments**

Fetch comments from bots (CI tools, linters, security scanners):

```typescript theme={null}
const botComments = await scm.getAutomatedComments(pr);
// Returns: AutomatedComment[]
// [
//   {
//     id: "comment-456",
//     botName: "codecov[bot]",
//     body: "Coverage decreased by 2%",
//     path: "src/utils.ts",
//     line: 15,
//     severity: "warning",  // "error" | "warning" | "info"
//     createdAt: Date,
//     url: "..."
//   }
// ]
```

### Known Bot Authors

The plugin filters these bot accounts:

* `cursor[bot]`
* `github-actions[bot]`
* `codecov[bot]`
* `sonarcloud[bot]`
* `dependabot[bot]`
* `renovate[bot]`
* `codeclimate[bot]`
* `deepsource-autofix[bot]`
* `snyk-bot`
* `lgtm-com[bot]`

### Merge Readiness

**Get Mergeability**

Comprehensive merge readiness check:

```typescript theme={null}
const readiness = await scm.getMergeability(pr);
// Returns: MergeReadiness
// {
//   mergeable: true,        // Overall readiness
//   ciPassing: true,        // All CI checks passed
//   approved: true,         // Reviews approved
//   noConflicts: true,      // No merge conflicts
//   blockers: []            // List of blocking issues
// }
```

**Blocker Examples**

When `mergeable: false`, the `blockers` array contains reasons:

```typescript theme={null}
blockers: [
  "CI is failing",
  "Changes requested in review",
  "Merge conflicts",
  "Branch is behind base branch",
  "PR is still a draft",
  "Review required",
  "Merge is blocked by branch protection",
  "Required checks are failing"
]
```

<Warning>
  The plugin uses a fail-closed approach: if it can't determine CI status or review state, it reports the PR as not ready to merge.
</Warning>

## Usage Example

### Auto-Merge Workflow

```yaml theme={null}
# agent-orchestrator.yaml
reactions:
  - event: ci_passed
    conditions:
      - type: review_approved
      - type: no_conflicts
    action: merge_pr
    merge_method: squash
```

This configuration automatically merges PRs when:

1. All CI checks pass
2. Reviews are approved
3. No merge conflicts exist

### Monitor PR Progress

```bash theme={null}
# Check PR status
ao status session-id

# Output:
# PR #123: Fix login bug
# State: open
# CI: passing (3/3 checks)
# Reviews: approved
# Blockers: Branch is behind base branch
```

### Handle CI Failures

```yaml theme={null}
reactions:
  - event: ci_failed
    action: notify
    message: "CI failed on PR {{pr.number}}: {{pr.url}}"
```

## Troubleshooting

<Accordion title="Error: gh command not found">
  The GitHub CLI is not installed or not in PATH.

  Solution:

  ```bash theme={null}
  # macOS
  brew install gh

  # Linux
  sudo apt install gh

  # Verify
  which gh
  ```
</Accordion>

<Accordion title="Error: Failed to fetch CI checks">
  The plugin couldn't retrieve CI check status.

  Common causes:

  * No CI checks configured for the repository
  * GitHub API timeout
  * Network connectivity issues
  * PR is closed/merged (no check data)

  The plugin fails closed: reports CI as "failing" to prevent auto-merge.
</Accordion>

<Accordion title="CI status shows 'none' but checks exist">
  This happens when all checks are skipped or neutral.

  The plugin only reports `passing` if at least one check actually passed (not all skipped).
</Accordion>

<Accordion title="Review decision is 'none' but reviews exist">
  GitHub's `reviewDecision` field aggregates reviews. It's `none` when:

  * No review is required by branch protection
  * All reviews are comments (not approvals or change requests)
  * Reviews were dismissed
</Accordion>

<Accordion title="Pending comments include bot comments">
  The plugin filters bot comments using a predefined list of known bot authors.

  If a new bot is not filtered, add it to `BOT_AUTHORS` in the source code:

  ```typescript theme={null}
  const BOT_AUTHORS = new Set([
    "cursor[bot]",
    "your-new-bot[bot]",  // Add here
    // ...
  ]);
  ```
</Accordion>

<Accordion title="Merge fails with 'blocked by branch protection'">
  GitHub branch protection rules are preventing the merge.

  Common protections:

  * Required reviews not met
  * Required status checks not passed
  * Branch not up to date with base
  * Signed commits required

  Check repository settings → Branches → Branch protection rules.
</Accordion>

<Accordion title="PR state is 'unknown' in mergeability check">
  GitHub is still computing merge state (happens for large PRs or complex conflicts).

  The plugin reports this as a blocker: "Merge status unknown (GitHub is computing)"

  Wait a few seconds and check again.
</Accordion>

## API Reference

### SCM Interface Methods

**detectPR(session, project)**

* Finds PR by branch name
* Returns: `PRInfo | null`

**getPRState(pr)**

* Returns: `"open" | "closed" | "merged"`

**getPRSummary(pr)**

* Returns: `{ state, title, additions, deletions }`

**mergePR(pr, method)**

* Merges PR with specified method
* Deletes branch automatically
* Returns: `void`

**closePR(pr)**

* Closes PR without merging
* Returns: `void`

**getCIChecks(pr)**

* Returns: `CICheck[]`

**getCISummary(pr)**

* Returns: `"passing" | "failing" | "pending" | "none"`

**getReviews(pr)**

* Returns: `Review[]`

**getReviewDecision(pr)**

* Returns: `"approved" | "changes_requested" | "pending" | "none"`

**getPendingComments(pr)**

* Returns: `ReviewComment[]` (human reviewers only)

**getAutomatedComments(pr)**

* Returns: `AutomatedComment[]` (bots only)

**getMergeability(pr)**

* Returns: `MergeReadiness`

## Advanced Usage

### Merge Methods

```typescript theme={null}
// Squash: All commits into one (default)
await scm.mergePR(pr, "squash");

// Merge: Create merge commit
await scm.mergePR(pr, "merge");

// Rebase: Rebase and fast-forward
await scm.mergePR(pr, "rebase");
```

### CI Monitoring Loop

```typescript theme={null}
// Poll CI status until completion
let status = await scm.getCISummary(pr);
while (status === "pending") {
  await sleep(30_000);  // Wait 30 seconds
  status = await scm.getCISummary(pr);
}

if (status === "passing") {
  console.log("CI passed!");
} else if (status === "failing") {
  const checks = await scm.getCIChecks(pr);
  const failed = checks.filter(c => c.status === "failed");
  console.error(`CI failed: ${failed.map(c => c.name).join(", ")}`);
}
```

### Review Comment Handling

```typescript theme={null}
// Check for pending human review comments
const pending = await scm.getPendingComments(pr);
if (pending.length > 0) {
  console.log(`${pending.length} unresolved comments`);
  for (const comment of pending) {
    console.log(`${comment.path}:${comment.line} - ${comment.author}`);
    console.log(comment.body);
  }
}

// Check for automated feedback
const automated = await scm.getAutomatedComments(pr);
const errors = automated.filter(c => c.severity === "error");
if (errors.length > 0) {
  console.log(`${errors.length} automated errors to address`);
}
```

### Comprehensive Merge Check

```typescript theme={null}
const readiness = await scm.getMergeability(pr);

if (readiness.mergeable) {
  await scm.mergePR(pr, "squash");
  console.log("PR merged successfully!");
} else {
  console.log("PR not ready to merge:");
  for (const blocker of readiness.blockers) {
    console.log(`  - ${blocker}`);
  }
}
```

## Integration with Other Plugins

### With Tracker Plugin

The SCM and tracker plugins work together:

1. **Tracker** creates issue and generates prompt
2. **Agent** writes code and creates PR
3. **SCM** monitors CI and reviews
4. **Tracker** updates issue when PR merges

```yaml theme={null}
reactions:
  - event: pr_created
    action: run
    command: |
      # Link PR to Linear issue
      echo "PR created: $PR_URL" >> $ISSUE_COMMENT
  
  - event: pr_merged
    action: run
    command: |
      # Close issue
      ao tracker update $ISSUE_ID --state closed --comment "Fixed in PR $PR_URL"
```

### With Notifier Plugin

Send notifications based on PR events:

```yaml theme={null}
reactions:
  - event: ci_failed
    action: notify
    channel: slack
    message: |
      CI failed on PR #{{pr.number}}
      {{pr.url}}
      
      Failed checks:
      {{#each failedChecks}}
      - {{name}}: {{url}}
      {{/each}}
  
  - event: changes_requested
    action: notify
    channel: desktop
    message: "Changes requested on PR #{{pr.number}}"
```

## Performance Considerations

### API Calls

The plugin makes multiple API calls per operation:

* `getMergeability`: 3-4 calls (PR state, CI, reviews, merge status)
* `getCIChecks`: 1 call
* `getReviews`: 1 call
* `getPendingComments`: 1 call (GraphQL)

### Rate Limits

GitHub API rate limits (authenticated):

* REST API: 5,000 requests/hour
* GraphQL API: 5,000 points/hour

The `gh` CLI handles authentication and rate limiting automatically.

### Caching

The plugin does not cache responses. The orchestrator should implement caching if polling frequently.

## Security Considerations

<Warning>
  * All GitHub API calls are made through the `gh` CLI (no direct token handling)
  * Commands are executed with `execFile` (not `exec`) to prevent shell injection
  * 30-second timeout prevents hanging on network issues
  * Repository format is validated before use
  * Fail-closed approach: unknown states are treated as blocking
</Warning>

## Source Code

Source: `packages/plugins/scm-github/src/index.ts`


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.