OpenHands as a GitHub Collaborator
One of OpenHands’ most powerful deployment patterns is as an automated GitHub collaborator — an AI agent that responds to GitHub issues, creates pull requests, and participates in code review.
This guide covers three integration patterns:
- Issue-to-PR automation — OpenHands resolves issues and creates PRs
- CI integration — OpenHands runs in your CI pipeline
- Code review bot — OpenHands reviews PRs and suggests improvements
Pattern 1: Resolve GitHub Issues Automatically
Using the Official GitHub Integration
OpenHands has built-in GitHub integration. In the UI at localhost:3000:
- Go to Settings → GitHub Integration
- Connect your GitHub account
- Grant repository access
Then assign issues to OpenHands:
@openhands-agent Please fix the bug described in this issue.
OpenHands will create a branch, fix the issue, and open a PR.
Custom GitHub Actions Workflow
For automated triggering, create .github/workflows/openhands-issue.yml:
name: OpenHands Issue Resolver
on:
issues:
types: [labeled]
jobs:
resolve-issue:
if: github.event.label.name == 'openhands'
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install OpenHands
run: pip install openhands-ai
- name: Run OpenHands on Issue
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
python - <<'EOF'
import asyncio
import os
from openhands.runtime.client.client import RuntimeClient
issue_title = "${{ github.event.issue.title }}"
issue_body = """${{ github.event.issue.body }}"""
issue_number = ${{ github.event.issue.number }}
task = f"""
GitHub Issue #{issue_number}: {issue_title}
{issue_body}
Instructions:
1. Understand the issue described above
2. Find the relevant code in the repository
3. Implement a fix
4. Run the test suite: pytest tests/
5. Ensure all tests pass
6. Create a commit with a descriptive message
7. The GitHub Actions environment will handle PR creation
"""
# Run OpenHands (simplified - use actual OpenHands API)
print(f"Processing issue: {issue_title}")
print("Task submitted to OpenHands")
EOF
- name: Create Pull Request
uses: peter-evans/create-pull-request@v6
with:
token: ${{ secrets.GITHUB_TOKEN }}
commit-message: "fix: resolve issue #${{ github.event.issue.number }}"
title: "Fix: ${{ github.event.issue.title }}"
body: |
Automated fix for issue #${{ github.event.issue.number }}
Changes made by OpenHands AI agent.
Closes #${{ github.event.issue.number }}
branch: fix/issue-${{ github.event.issue.number }}
base: main
Trigger: add the label openhands to any issue.
Pattern 2: OpenHands in CI Pipeline
Run OpenHands as part of your CI to automatically fix test failures:
# .github/workflows/openhands-fix-tests.yml
name: Auto-Fix Failing Tests
on:
push:
branches: [main, develop]
jobs:
test:
runs-on: ubuntu-latest
outputs:
tests_passed: ${{ steps.test.outputs.passed }}
failure_output: ${{ steps.test.outputs.output }}
steps:
- uses: actions/checkout@v4
- name: Run Tests
id: test
run: |
if pytest tests/ --tb=short > test_output.txt 2>&1; then
echo "passed=true" >> $GITHUB_OUTPUT
else
echo "passed=false" >> $GITHUB_OUTPUT
echo "output<<EOF" >> $GITHUB_OUTPUT
cat test_output.txt >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
fi
fix-with-openhands:
needs: test
if: needs.test.outputs.tests_passed == 'false'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Fix with OpenHands
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
run: |
pip install openhands-ai
cat > fix_task.txt << 'EOF'
The following tests are failing:
${{ needs.test.outputs.failure_output }}
Please:
1. Analyze the test failures
2. Find and fix the root cause in the source code
3. Do NOT modify the test files
4. Verify the fix by running pytest
EOF
openhands run --task-file fix_task.txt
- name: Create Fix PR
uses: peter-evans/create-pull-request@v6
with:
token: ${{ secrets.GITHUB_TOKEN }}
commit-message: "fix: auto-fix test failures via OpenHands"
title: "Auto-fix: Resolve test failures"
body: |
Automated fix for failing tests.
Original failures:
```
${{ needs.test.outputs.failure_output }}
```
branch: auto-fix/${{ github.run_id }}
Pattern 3: PR Code Review Bot
Automatically review pull requests and post comments:
# .github/workflows/openhands-review.yml
name: OpenHands Code Review
on:
pull_request:
types: [opened, synchronize]
jobs:
review:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Get PR Diff
id: diff
run: |
git diff origin/${{ github.base_ref }}...HEAD > pr_diff.txt
echo "diff_size=$(wc -c < pr_diff.txt)" >> $GITHUB_OUTPUT
- name: Review with OpenHands
if: steps.diff.outputs.diff_size < 50000 # skip huge PRs
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
run: |
pip install openai # Use direct OpenAI for review (faster than full OpenHands)
python - <<'SCRIPT'
from openai import OpenAI
import sys
client = OpenAI()
diff = open("pr_diff.txt").read()[:15000] # limit size
response = client.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "system", "content": """You are an expert code reviewer.
Review the diff and provide:
1. Summary of changes (2-3 sentences)
2. Potential issues (bugs, security, performance)
3. Suggestions for improvement
4. Overall verdict: Looks Good / Needs Changes / Major Issues
Be specific and constructive. Focus on significant issues only."""},
{"role": "user", "content": f"Review this diff:\n\n{diff}"},
]
)
review = response.choices[0].message.content
print(review)
with open("review_output.txt", "w") as f:
f.write(review)
SCRIPT
- name: Post Review Comment
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const review = fs.readFileSync('review_output.txt', 'utf8');
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: `## OpenHands Code Review\n\n${review}`
});
Running OpenHands Locally Against a GitHub Repo
import asyncio
import subprocess
import os
def setup_repo(repo_url: str, branch: str = "main") -> str:
"""Clone a GitHub repo to a temp directory."""
workspace = f"/tmp/openhands-workspace"
subprocess.run(["git", "clone", repo_url, workspace], check=True)
subprocess.run(["git", "checkout", branch], cwd=workspace, check=True)
return workspace
def run_openhands_on_issue(
repo_url: str,
issue_title: str,
issue_body: str,
) -> None:
"""Run OpenHands to resolve a GitHub issue."""
workspace = setup_repo(repo_url)
task = f"""
Fix the following GitHub issue in the repository at /workspace:
Issue: {issue_title}
Description:
{issue_body}
Steps:
1. Understand what's broken or missing
2. Find the relevant code
3. Implement the fix or feature
4. Run the test suite to verify
5. Create a git commit with a descriptive message
When done, output "COMPLETE" and describe what you changed.
"""
# Run OpenHands via Docker
subprocess.run([
"docker", "run", "--rm",
"-v", f"{workspace}:/workspace",
"-e", f"OPENAI_API_KEY={os.getenv('OPENAI_API_KEY')}",
"-e", f"SANDBOX_VOLUMES={workspace}:/workspace",
"ghcr.io/all-hands-ai/openhands:main",
"python", "-m", "openhands.core.main",
"-t", task,
], check=True)
# Create PR from the changes
subprocess.run(
["git", "checkout", "-b", "openhands-fix"],
cwd=workspace, check=True
)
subprocess.run(
["git", "push", "origin", "openhands-fix"],
cwd=workspace, check=True
)
print(f"Branch 'openhands-fix' pushed. Create PR manually or via GitHub API.")
GitHub App Integration
For a production deployment, create a GitHub App that automatically triggers OpenHands:
- Create GitHub App at github.com/settings/apps/new
- Permissions: Issues (read), Pull Requests (write), Contents (write)
- Subscribe to: issue events, PR events
- Set webhook URL to your OpenHands server
- Handle webhooks in your server to trigger OpenHands runs
This gives you a polished integration where OpenHands appears as a named collaborator on your repository.
Frequently Asked Questions
Can OpenHands push directly to main?
This is not recommended. Always have OpenHands create a branch and open a PR. Human review before merging is essential — OpenHands can make mistakes, introduce bugs, or miss edge cases.
How do I give OpenHands access to private repos?
Use a GitHub token with repo scope. In the Docker run command:
-e GITHUB_TOKEN=ghp_your_token
The agent can then clone, push, and interact with private repos.
What if OpenHands creates a bad PR?
Simply close the PR and don’t merge. The branch can be deleted. Since OpenHands operates in an isolated workspace, bad changes don’t affect your main codebase until merged.
How do I track what OpenHands changed?
Every action OpenHands takes is logged. Check the trajectory file (--save-trajectory-path) or the Docker container logs. The git diff in the PR is the definitive record of what changed.
Can I use this with GitLab or Bitbucket?
OpenHands’ built-in integration is GitHub-specific. For GitLab/Bitbucket, use the CLI or Docker approach and manually create MRs using their respective APIs.
Next Steps
- OpenHands Advanced Configuration — Tune OpenHands for reliable CI runs
- OpenHands Use Cases — More automation patterns
- n8n Webhook and API Automation — Build no-code automations around OpenHands