---
title: GitHub Reference
description: GitHub channel options, credentials, inbound hooks, CI events, delivery, PR context, sandbox checkout, and proactive sessions.
url: "https://eve.dev/docs/channels/github/reference"
docs_index: /llms.txt
type: reference
---

> For an index of all documentation, see [/llms.txt](/llms.txt).

This page documents every part of `githubChannel` from `eve/channels/github`. For setup and common tasks, start with [GitHub](/docs/channels/github).

The GitHub channel lets people reach your agent from issues and pull requests. It lives in `agent/channels/github.ts`. Write the agent's invocation token, such as `@my-agent`, in a new issue, PR, or review comment, and the agent replies in that thread. It sees the PR diff and works in a checkout of the repo.

[Vercel Connect](/docs/guides/auth-and-route-protection) can manage the GitHub App, its token, and webhook checks, so you hold no private key or webhook secret. See [Channels](/docs/channels) for what all channels share.

## Guided Connect setup

Run the registry setup from the agent directory:

```bash
eve add channel/github
```

The command signs you in to Vercel, links a project, and creates an app-scoped GitHub Connect client that sends webhooks to `/eve/v1/github`. It then installs `@vercel/connect` and writes the channel file:

```ts title="agent/channels/github.ts"
import { connectGitHubCredentials } from "@vercel/connect/eve";
import { githubChannel } from "eve/channels/github";

export default githubChannel({
  botName: "my-agent",
  credentials: connectGitHubCredentials("github/my-agent"),
});
```

Connect creates the GitHub App and forwards its webhooks, and eve checks their Vercel OIDC signature. Connect also handles token rotation and multiple installations. After you deploy, open the GitHub App in the Connect dashboard and install it in your organization or account.

### Bring your own GitHub App

To run a GitHub App you manage yourself, pass its credentials directly:

```ts title="agent/channels/github.ts"
import { githubChannel } from "eve/channels/github";

export default githubChannel({
  botName: "my-agent",
  credentials: {
    appId: process.env.GITHUB_APP_ID,
    privateKey: process.env.GITHUB_APP_PRIVATE_KEY,
    webhookSecret: process.env.GITHUB_WEBHOOK_SECRET,
  },
});
```

Omit any field, or the whole `credentials` block, to read it from these env vars:

```bash
GITHUB_APP_ID=...            # GitHub App id
GITHUB_APP_PRIVATE_KEY=...   # GitHub App private key (PEM)
GITHUB_WEBHOOK_SECRET=...    # verifies the webhook signature
GITHUB_APP_SLUG=...          # supplies botName when it is not set in config
```

`appId`, `privateKey`, `webhookSecret`, and `botName` also accept a function. A `botName` function runs when a webhook arrives, so it can use that request's credentials. eve keeps its result, or tries again on the next event if it fails. Omit `botName` to use the credentials' `appSlug`, then `GITHUB_APP_SLUG`.

Point the GitHub App webhook URL at `https://<deployment>/eve/v1/github`. Subscribe to `issue_comment` and `pull_request_review_comment` so comments reach the agent. Add `issues`, `pull_request`, `check_suite`, `check_run`, or `workflow_run` for their opt-in hooks. Install the App on the repository, and a new comment that includes `@botName` starts a turn.

The invocation token is plain text, not a GitHub mention, so GitHub may not autocomplete or link `@botName`. GitHub may show the App as `botName[bot]`.

## Options

`githubChannel(config)` takes these options. All are optional.

| Option               | Default                                                                | Description                                                                                                                   |
| -------------------- | ---------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| `botName`            | `credentials.appSlug`, then `GITHUB_APP_SLUG`                          | Invocation token without `@`. A string or a lazy resolver.                                                                    |
| `credentials`        | `GITHUB_APP_ID`, `GITHUB_APP_PRIVATE_KEY`, and `GITHUB_WEBHOOK_SECRET` | From `connectGitHubCredentials(...)`, or `{ appId, privateKey, webhookSecret, appSlug, installationToken, webhookVerifier }`. |
| `route`              | `/eve/v1/github`                                                       | Webhook path.                                                                                                                 |
| `api`                | `https://api.github.com` and the global `fetch`                        | `{ apiBaseUrl, fetch }` for GitHub REST calls.                                                                                |
| `progress`           | `{ reactions: true }`                                                  | Set `reactions: false` to skip the `eyes` reaction when a turn starts.                                                        |
| `pullRequestContext` | Built-in skip list for generated files                                 | `{ excludedFiles }` adds glob patterns whose patches are left out of PR context.                                              |
| `turnPolicy`         | `"steer"`                                                              | `"steer"` or `"queue"` for messages that arrive during a turn.                                                                |
| `onComment`          | Dispatch comments that include the invocation token                    | `(ctx, comment)` hook for issue, pull request, and review comments.                                                           |
| `onIssue`            | None                                                                   | `(ctx, issue)` hook for `issues` events.                                                                                      |
| `onPullRequest`      | None                                                                   | `(ctx, pullRequest)` hook for `pull_request` events.                                                                          |
| `onCheckSuite`       | None                                                                   | `(ctx, checkSuite)` hook for `check_suite` events.                                                                            |
| `onCheckRun`         | None                                                                   | `(ctx, checkRun)` hook for `check_run` events.                                                                                |
| `onWorkflowRun`      | None                                                                   | `(ctx, workflowRun)` hook for `workflow_run` events.                                                                          |
| `events`             | eve's default handlers                                                 | Per-event handler overrides for replies, reactions, and checkout.                                                             |

The channel mounts `POST /eve/v1/github`.

## Dispatch

Each hook returns `{ auth }` to start a turn or `null` to ignore the event. Add `title` to set the run title when the event starts a run. `defaultGitHubAuth(ctx)` builds auth from the person who triggered the event.

The model sees a `<github_context>` block with `sender` and, when known, `bot_name`. For comments it also has `is_mentioned`, which eve sets before it removes the invocation token from the text.

```ts
import { defaultGitHubAuth, githubChannel } from "eve/channels/github";

export default githubChannel({
  botName: "my-agent",
  // Replaces the default invocation-token gate. ctx.conversation.kind is "issue", "pull_request", or "review_thread".
  onComment: (ctx, comment) => ({ auth: defaultGitHubAuth(ctx) }),
  // Opt in; no default dispatch on these events.
  onIssue: (ctx, issue) => (issue.action === "opened" ? { auth: defaultGitHubAuth(ctx) } : null),
  onPullRequest: (ctx, pr) => (pr.action === "opened" ? { auth: defaultGitHubAuth(ctx) } : null),
  onCheckSuite: (ctx, suite) =>
    suite.action === "completed" &&
    suite.conclusion === "failure" &&
    suite.app.slug === "github-actions" &&
    suite.pullRequests.length > 0
      ? {
          auth: defaultGitHubAuth(ctx),
          context: [`Triage failed check suite ${suite.checkSuiteId} at ${suite.headSha}.`],
        }
      : null,
});
```

The CI hooks expose normalized `action`, `status`, `conclusion`, `app.slug`, `headSha`, and `pullRequests` fields, plus `checkSuiteId`, `checkRunId`, or `workflowRunId`. For `workflow_run`, which only GitHub Actions sends, `app.slug` is `"github-actions"`. A CI turn replies on the first PR in `pullRequests`. When the array is empty, the hook still runs but must return `null`, because there is no thread to reply in.

## Delivery

When a turn starts, the channel adds an `eyes` reaction to the comment that triggered it. Set `progress: { reactions: false }` to skip it. The reply posts as a comment on the timeline or in the review thread, split across several comments when long. A failed turn posts a short error comment with an error id.

## Human-in-the-loop (HITL)

GitHub comments have no buttons or cards, so an approval or question posts as a comment. The user answers it with a reply comment. Declare an `events["interaction.opened"]` handler to change the prompt.

## Proactive sessions

To start a session without a comment, call `to(github, target).send(message, { auth })` from a schedule's `run` handler. From another channel, call `ctx.to(github, target).send(message, { auth })`. The target needs `owner`, `repo`, and exactly one of `issueNumber` or `pullRequestNumber`. This sends a message to the agent, not a comment to GitHub.

To post without invoking the model, use `ctx.channel.thread.post(...)` inside a GitHub event handler. To retry and deduplicate notifications across providers yourself, see [Durable cross-channel notifications](/docs/patterns/durable-cross-channel-notifications).

## Attachments

The channel doesn't accept inbound file attachments. Repository contents reach the agent through the [sandbox checkout](#sandbox-checkout).

## PR context

On a PR, the agent always gets the PR metadata and the patch of each changed file in `context`. Large generated files stay in the file list without their patch. Add more paths to skip with `pullRequestContext.excludedFiles`.

## Sandbox checkout

Before the first model call, each turn checks out the repo into the sandbox. `read_file`, `glob`, `grep`, and `bash` then work on the real files.

The installation token never enters the sandbox, because the sandbox firewall adds auth to outbound `git` requests. Checkout needs a sandbox with a firewall (Vercel), so the local sandbox skips it.

## Arbitrary API calls

For any other GitHub API call, use `ctx.github.request({ method, path, body })`. It sends the installation token.

## What to read next

- [Channels overview](/docs/channels): the channel contract and every built-in channel
- [Auth & route protection](/docs/guides/auth-and-route-protection): authenticating inbound traffic

---

For a semantic overview of all documentation, see [/sitemap.md](/sitemap.md)

For an index of all available documentation, see [/llms.txt](/llms.txt)

For agent-facing discovery, including API and MCP surfaces, see [/agents.md](/agents.md)