Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,7 @@
{
"group": "Integrations",
"pages": [
"enterprise/integrations/github",
"enterprise/integrations/azure-devops",
"enterprise/integrations/bitbucket-data-center",
"enterprise/integrations/jira-data-center",
Expand Down
311 changes: 311 additions & 0 deletions enterprise/integrations/github.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,311 @@
---
title: GitHub
description: Configure the GitHub App and control the built-in GitHub resolver in OpenHands Enterprise.
icon: github
---

This guide explains how to connect GitHub to a self-hosted OpenHands Enterprise
installation. The integration lets users sign in with GitHub, open repositories,
and invoke OpenHands from issue and pull request comments.

<Info>
For OpenHands Cloud, see [GitHub Integration](/openhands/usage/cloud/github-installation).
This page covers the GitHub App that you create and operate for OpenHands Enterprise.
</Info>

## Overview

A self-hosted installation needs its own GitHub App so GitHub can send events to
your domain. Setup has four parts:

1. Create a GitHub App for the installation.
2. Install the app on the organizations and repositories where OpenHands should run.
3. Add the app credentials to the OpenHands Enterprise Admin Console and deploy the configuration.
4. Have each user sign in to OpenHands with GitHub before they invoke `@openhands`.

The integration uses two GitHub identities:

- The GitHub App posts acknowledgements and completion messages as the OpenHands bot.
- The agent uses the triggering user's GitHub authorization for repository operations,
including formal pull request reviews.

This is why an `I'm on it!` comment can appear as the bot while the resulting pull
request review appears as the user who requested it.

## Prerequisites

Before you start, confirm:

- OpenHands Enterprise is reachable at `https://app.<your-base-domain>`.
- The authentication service is reachable at `https://auth.<your-base-domain>`
when using the default **Simple** hostname mode.

Check warning on line 41 in enterprise/integrations/github.mdx

View check run for this annotation

Mintlify / Mintlify Validation (allhandsai) - vale-spellcheck

enterprise/integrations/github.mdx#L41

Did you really mean 'hostname'?
- Both hostnames use publicly trusted TLS certificates.

Check warning on line 42 in enterprise/integrations/github.mdx

View check run for this annotation

Mintlify / Mintlify Validation (allhandsai) - vale-spellcheck

enterprise/integrations/github.mdx#L42

Did you really mean 'hostnames'?
- You can create a GitHub App for your user or organization.
- You can install the app on the organizations and repositories that should use OpenHands.
- Your workstation has [uv](https://docs.astral.sh/uv/) and can open a browser to GitHub.

## Step 1: Create the GitHub App

Use the helper script in the
[`OpenHands-Cloud`](https://github.com/OpenHands/OpenHands-Cloud/tree/main/scripts/create_github_app)
repository. It creates a private GitHub App with the callback URL, webhook URL,
permissions, and events expected by OpenHands Enterprise.

```bash
git clone https://github.com/OpenHands/OpenHands-Cloud.git
cd OpenHands-Cloud
./scripts/create_github_app/create_github_app.py \
--base-domain <your-base-domain>
```

Use the base domain without the `app.` or `auth.` prefix. For example:

```bash
./scripts/create_github_app/create_github_app.py \
--base-domain openhands.example.com
```

Pass `--org <github-org>` to create the app under a GitHub organization instead
of your personal account. If the installation uses the **Legacy** hostname mode,

Check warning on line 69 in enterprise/integrations/github.mdx

View check run for this annotation

Mintlify / Mintlify Validation (allhandsai) - vale-spellcheck

enterprise/integrations/github.mdx#L69

Did you really mean 'hostname'?
also pass `--dns-layout nested` so the OAuth callback uses
`auth.app.<your-base-domain>` instead of `auth.<your-base-domain>`.

The script starts a temporary callback server on port `9876`, opens GitHub's App
creation page, and asks you to create the app. After creation, it opens the app's
installation page.

Save these values from the script output:

- GitHub App Client ID
- GitHub App Client Secret
- GitHub App ID
- GitHub App Slug
- GitHub App Webhook Secret
- GitHub App Private Key, saved under `scripts/create_github_app/keys/`

<Warning>
Store the client secret, webhook secret, and private key securely. Do not commit
them to a repository.
</Warning>

### App Configuration

The helper configures these URLs:

| GitHub App setting | URL |
|---|---|
| Homepage URL | `https://app.<your-base-domain>` |
| OAuth callback URL | `https://auth.<your-base-domain>/realms/allhands/broker/github/endpoint` |
| Webhook URL | `https://app.<your-base-domain>/integration/github/events` |

The OAuth callback URL above is for the default **Simple** hostname mode. The

Check warning on line 101 in enterprise/integrations/github.mdx

View check run for this annotation

Mintlify / Mintlify Validation (allhandsai) - vale-spellcheck

enterprise/integrations/github.mdx#L101

Did you really mean 'hostname'?
helper uses `auth.app.<your-base-domain>` when run with `--dns-layout nested` for
the **Legacy** mode. The OAuth callback handles user sign-in, while the webhook
URL receives issue and pull request events; these URLs are not interchangeable.

The app subscribes to these events:

- Issue comments
- Pull requests
- Pull request review comments

The app requests write access to repository contents, issues, pull requests,
repository webhooks, commit statuses, Actions, and workflows. It also requests
read access to metadata, user email addresses, and organization events.

## Step 2: Install the GitHub App

On the installation page opened by the helper script:

1. Select the GitHub user or organization that owns the repositories.
2. Choose **All repositories** or select the repositories that should use OpenHands.
3. Review the requested permissions.
4. Select **Install**.

You can change repository access later from the GitHub App's installation settings.
OpenHands receives events only for repositories included in the installation.

<Note>
Installing multiple OpenHands GitHub Apps on the same repository causes each app
to receive the same `@openhands` mention. This can start duplicate conversations
and produce duplicate acknowledgements, reviews, and completion comments.
</Note>

## Step 3: Configure OpenHands Enterprise

Open the Replicated Admin Console and find **GitHub Authentication** in the
application configuration.

1. Enable **GitHub Authentication**.
2. Enter the **GitHub App Client ID**.
3. Enter the **GitHub App Client Secret**.
4. Enter the numeric **GitHub App ID**.
5. Enter the **GitHub App Slug**.
6. Enter the **GitHub App Webhook Secret**.
7. Upload the **GitHub App Private Key** (`.pem`).
8. Save the configuration and deploy the new version.
9. Wait for the deployment to reach **Ready**.

The [Enterprise Quick Start](/enterprise/quick-start) covers the surrounding
installation and deployment steps.

## Step 4: Sign In with GitHub

Each user must sign in to OpenHands with GitHub before invoking the resolver.
The first sign-in links the GitHub identity to the user's OpenHands account and
stores the authorization needed to perform repository operations as that user.

If a GitHub user who has not linked an OpenHands account mentions `@openhands`,
the bot responds with instructions to sign in before starting a job.

## Use the Built-In Resolver

Mention `@openhands` in an issue, pull request comment, or inline pull request
review comment. You can also add the `openhands` label to an issue. Include the
task after the mention, for example:

```text
@openhands explain why this test is failing
```

```text
@openhands /codereview
```

The resolver starts a job only when:

- The GitHub App is installed for the repository.
- GitHub can deliver a valid webhook to the OpenHands webhook URL.
- The triggering user has signed in to OpenHands with GitHub.
- The triggering user has write access to the repository.

When a job starts, OpenHands:

1. Adds an eyes reaction to the triggering issue or comment.
2. Creates an OpenHands conversation with the issue or pull request context.
3. Posts an `I'm on it!` acknowledgement as the GitHub App and links to the conversation.
4. Runs the task using the triggering user's GitHub authorization.
5. Posts the conversation's final response as a completion comment from the GitHub App.

The acknowledgement and completion comment are part of the built-in resolver.
They are not custom event automations.

Check warning on line 191 in enterprise/integrations/github.mdx

View check run for this annotation

Mintlify / Mintlify Validation (allhandsai) - vale-spellcheck

enterprise/integrations/github.mdx#L191

Did you really mean 'automations'?

## Customize Resolver Conversations

The resolver creates a standard OpenHands conversation. The triggering comment
or labeled issue defines the task, and the issue or pull request provides
additional context. Once the conversation starts, normal skill discovery and
triggering apply.

Available skills can come from OpenHands, the repository, or the organization.
OpenHands exposes their names and descriptions to the agent. A matching trigger
injects a skill automatically, and the agent can invoke other skills that appear
relevant to the task.

By default, GitHub resolver conversations automatically receive the built-in
GitHub skill. The resolver's initial message refers to GitHub APIs, which matches

Check warning on line 206 in enterprise/integrations/github.mdx

View check run for this annotation

Mintlify / Mintlify Validation (allhandsai) - vale-spellcheck

enterprise/integrations/github.mdx#L206

Did you really mean 'resolver's'?
the skill's `github` trigger. This gives the agent the baseline instructions for
using GitHub, but it does not limit the conversation to that skill. Repository,
organization, and other task-specific skills can apply alongside it. For example,
`@openhands /codereview` also activates the matching code review skill.

Choose the customization scope that matches the behavior you want to change:

| Goal | Use |
|---|---|
| Apply instructions to every OpenHands task in one repository | Repository `AGENTS.md` |
| Add guidance for a specific workflow, such as issue triage, test diagnosis, or pull request review | Repository skill |
| Apply the same workflow across repositories | Organization skill |
| Change acknowledgements, GitHub identity, trigger eligibility, or completion callbacks | Product or integration change; skills do not control these behaviors |

For example, repository instructions can tell the agent not to push directly, an
issue-triage skill can define labels and escalation rules, and a review skill can
specify the expected format and event for a formal pull request review.

### Pull Request Review Example

Use `@openhands /codereview` to activate the built-in code review skill instead
of relying on the agent to interpret a general `@openhands review` request. Add
repository or organization guidance when your team needs a consistent review
policy.

For example, create `.agents/skills/custom-codereview-guide.md` to tell the agent
to submit informational reviews instead of approvals:

```markdown
---
name: custom-codereview-guide
description: Apply this repository's GitHub pull request review policy.
triggers:
- /codereview
---

# GitHub Review Policy

When submitting a GitHub pull request review:

- Always use `event: COMMENT`.
- Never use `event: APPROVE` or `event: REQUEST_CHANGES`.
- Put all findings in the formal review body or inline review comments.
- Keep the final response brief and point readers to the formal review instead of repeating it.
```

Do not name this skill `code-review`; that name conflicts with the built-in review
skill. Keep the `/codereview` trigger so both skills activate for the same request.
Start a new resolver conversation after committing the skill because skills do
not retroactively change a conversation that is already running.

See [Code Review](/openhands/usage/use-cases/code-review#customization) for more
review examples and [Skills and Plugins](/enterprise/skills-and-plugins) for all
repository and organization distribution options.

## Integration-Owned Behavior

Skills guide the agent after the conversation starts. They do not change how the
GitHub integration authenticates users, accepts events, or posts status messages.

### Review and Comment Identity

The built-in resolver intentionally uses different credentials for different actions:

| Action | GitHub identity |
|---|---|
| Eyes reaction | GitHub App bot |
| `I'm on it!` acknowledgement | GitHub App bot |
| Repository changes and formal pull request reviews | Triggering user |
| Completion comment | GitHub App bot |

There is currently no supported setting that makes formal reviews run as the
GitHub App bot. If your organization requires reviews to have a machine identity,
use an [OpenHands code review automation](/openhands/usage/use-cases/code-review#option-b-openhands-automation-org-wide)
with a dedicated bot credential.

### Completion Comments

The built-in resolver posts the agent's final response as a completion comment.
There is currently no Admin Console setting to disable this comment while keeping
the built-in resolver enabled.

A repository or organization skill can reduce duplication by telling the agent
to keep its final response brief and refer readers to the formal review. A skill
cannot disable the resolver's completion callback itself.

Check warning on line 291 in enterprise/integrations/github.mdx

View check run for this annotation

Mintlify / Mintlify Validation (allhandsai) - vale-spellcheck

enterprise/integrations/github.mdx#L291

Did you really mean 'resolver's'?

## Troubleshooting

| Symptom | Check |
|---|---|
| **Login with GitHub** is not visible | Confirm **GitHub Authentication** is enabled and the updated configuration has been deployed. |
| GitHub OAuth redirects fail | Confirm the callback URL uses `https://auth.<your-base-domain>/realms/allhands/broker/github/endpoint` for **Simple** mode or `https://auth.app.<your-base-domain>/realms/allhands/broker/github/endpoint` for **Legacy** mode. Recreate the app or update its callback URL if the helper was run with the wrong DNS layout. |
| GitHub reports failed webhook deliveries | Confirm GitHub can reach `https://app.<your-base-domain>/integration/github/events`, the TLS certificate is trusted, and the webhook secret matches the Admin Console value. |
| `@openhands` is ignored | Confirm the app is installed for the repository, the sender has write access, and the sender has signed in to OpenHands with GitHub. |
| OpenHands posts duplicate acknowledgements or reviews | Check whether more than one OpenHands GitHub App is installed for the repository. |
| The acknowledgement is from the bot but the review is from a user | This is expected. The app posts resolver status messages, while repository operations use the triggering user's GitHub authorization. |
| A review is submitted as **Approve** instead of **Comment** | Add repository or organization guidance that tells the agent to use `event: COMMENT`, then start a new resolver conversation. |
| The review and completion comment repeat the same content | Add a skill that keeps the final response brief. The completion comment cannot currently be disabled through the Admin Console. |
| OpenHands can read the repository but cannot post a review | Confirm the app and user authorization include write access to pull requests, and confirm the user can review the pull request in GitHub. |

## Related Documentation

- [Enterprise Quick Start](/enterprise/quick-start)
- [Skills and Plugins](/enterprise/skills-and-plugins)
- [Code Review](/openhands/usage/use-cases/code-review)
4 changes: 4 additions & 0 deletions enterprise/quick-start.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
You will need a VM to host OpenHands Enterprise. Choose one of the options below to provision your infrastructure.

<Note>
The requirements below are the trial baseline, which comfortably supports about 15 concurrent sandboxes. For a larger rollout, pick your VM from the [Sizing Guide](/enterprise/sizing-guide) before provisioning.

Check warning on line 39 in enterprise/quick-start.mdx

View check run for this annotation

Mintlify / Mintlify Validation (allhandsai) - vale-spellcheck

enterprise/quick-start.mdx#L39

Did you really mean 'rollout'?
</Note>

<Tabs>
Expand Down Expand Up @@ -209,7 +209,7 @@
done
```

Expected: each hostname resolves to your VM's public IP address through the

Check warning on line 212 in enterprise/quick-start.mdx

View check run for this annotation

Mintlify / Mintlify Validation (allhandsai) - vale-spellcheck

enterprise/quick-start.mdx#L212

Did you really mean 'hostname'?

Check warning on line 212 in enterprise/quick-start.mdx

View check run for this annotation

Mintlify / Mintlify Validation (allhandsai) - vale-spellcheck

enterprise/quick-start.mdx#L212

Did you really mean 'VM's'?
wildcard record.

### Outbound connectivity checks
Expand Down Expand Up @@ -239,7 +239,7 @@
done
```

Any HTTP response code other than `000` is acceptable for reachability checks

Check warning on line 242 in enterprise/quick-start.mdx

View check run for this annotation

Mintlify / Mintlify Validation (allhandsai) - vale-spellcheck

enterprise/quick-start.mdx#L242

Did you really mean 'reachability'?
(for example `200`, `301`, `302`, `401`, `403`, `405`).

If any check fails, stop and resolve before continuing:
Expand All @@ -250,10 +250,10 @@

| Requirement | Why It Exists |
|------------|----------------|
| `443/TCP` inbound | Primary HTTPS entrypoint for users and service hostnames |

Check warning on line 253 in enterprise/quick-start.mdx

View check run for this annotation

Mintlify / Mintlify Validation (allhandsai) - vale-spellcheck

enterprise/quick-start.mdx#L253

Did you really mean 'hostnames'?
| `30000/TCP` inbound | Replicated/KOTS Admin Console for install and configuration |
| `80/TCP` inbound | HTTP entrypoint used for ingress/redirect behavior |
| `*.<domain>` DNS + cert SAN | Application services and sandboxes are addressed by hostnames under the base domain |

Check warning on line 256 in enterprise/quick-start.mdx

View check run for this annotation

Mintlify / Mintlify Validation (allhandsai) - vale-spellcheck

enterprise/quick-start.mdx#L256

Did you really mean 'hostnames'?
| `replicated.app`, `proxy.replicated.com` | Replicated control-plane/license/install paths |
| `images.r9...`, `charts.r9...`, `updates.r9...`, `install.r9...` | Vendor distribution image/chart/update/install endpoints |
| `traefik.github.io` | Embedded cluster ingress chart repository |
Expand Down Expand Up @@ -306,7 +306,7 @@

For trials and production deployments, use a publicly trusted TLS certificate whenever possible.
Private CA certificates may work for users after manual trust setup, but external integrations
such as GitHub, GitLab, Slack, Jira, and Bitbucket must also trust the certificate chain. If they

Check warning on line 309 in enterprise/quick-start.mdx

View check run for this annotation

Mintlify / Mintlify Validation (allhandsai) - vale-spellcheck

enterprise/quick-start.mdx#L309

Did you really mean 'Jira'?
do not, webhook or OAuth callbacks can fail TLS verification and repeatedly retry.
</Warning>

Expand All @@ -326,7 +326,7 @@
### 5. Upload TLS certificate (if not provided with the install command)

If you did not provide certificates with the `install` command, select **"Upload your own"**,
enter `admin.<your-base-domain>` under **Hostname**, upload your private key and SSL certificate, then click **Continue**.

Check warning on line 329 in enterprise/quick-start.mdx

View check run for this annotation

Mintlify / Mintlify Validation (allhandsai) - vale-spellcheck

enterprise/quick-start.mdx#L329

Did you really mean 'Hostname'?

If you upload a private CA certificate, make sure any external webhook or OAuth provider that
calls OpenHands also trusts that CA.
Expand Down Expand Up @@ -354,7 +354,7 @@

### Domain Configuration

- Keep the Hostname Configuration Mode set to **"Simple (default)"**

Check warning on line 357 in enterprise/quick-start.mdx

View check run for this annotation

Mintlify / Mintlify Validation (allhandsai) - vale-spellcheck

enterprise/quick-start.mdx#L357

Did you really mean 'Hostname'?
- Enter your base domain (e.g., `openhands.example.com`)

### Certificate Configuration
Expand Down Expand Up @@ -393,9 +393,13 @@

Go back to the Installer Admin Console in your browser and enter the values from the Create GitHub App script output. For the private key, upload the file from the `keys` directory of the script location.

See [GitHub](/enterprise/integrations/github) for GitHub App installation,
`@openhands` resolver behavior, pull request review identity, and repository-level
review controls.

### Additional Integrations

If your team uses Jira Data Center or Bitbucket Data Center, follow these guides

Check warning on line 402 in enterprise/quick-start.mdx

View check run for this annotation

Mintlify / Mintlify Validation (allhandsai) - vale-spellcheck

enterprise/quick-start.mdx#L402

Did you really mean 'Jira'?
to configure Admin Console values before deployment and complete webhook setup
inside OpenHands after deployment.

Expand All @@ -404,7 +408,7 @@
Configure Bitbucket Data Center login, repository access, bot identity, and pull request webhooks.
</Card>
<Card title="Jira Data Center" icon="building" href="/enterprise/integrations/jira-data-center">
Configure Jira issue triggers, OAuth account linking, service account credentials, and Jira webhooks.

Check warning on line 411 in enterprise/quick-start.mdx

View check run for this annotation

Mintlify / Mintlify Validation (allhandsai) - vale-spellcheck

enterprise/quick-start.mdx#L411

Did you really mean 'Jira'?
</Card>
</CardGroup>

Expand Down
Loading