14 KiB
OpenHands SDK GitHub Actions Integration - Analysis & Recommendations
Date: 2025-12-02 Status: New approach discovered during Phase 3 Purpose: Evaluate GitHub Actions + Python SDK vs Current SSH approach
📊 Executive Summary
Recommendation: ADOPT the GitHub Actions + Python SDK approach with a hybrid implementation strategy.
Key Benefits:
- ✅ 40-60% simpler architecture (no SSH/SSH keys complexity)
- ✅ Better error handling and structured logging
- ✅ Native GitHub Actions integration with artifacts
- ✅ Direct Python SDK access (no wrapper script needed)
- ✅ Built-in retry mechanisms via GitHub Actions
- ✅ Gitea integration possible (webhook → GitHub Actions)
Migration Strategy: Parallel development + phased transition (3-5 days)
🔍 Detailed Approach Comparison
Current Approach (Phase 2 - SSH-based)
Architecture:
Git Push → Gitea Webhook → n8n Workflow → SSH to localhost → OpenHands CLI → Wrapper Script
Pros:
- ✅ Already working (workflow ID: j1MmXaRhDjvkRSLa)
- ✅ Single system (all services on 10.10.10.11)
- ✅ Uses familiar tools (n8n for orchestration)
- ✅ Proven data preservation pattern with $node
- ✅ 4-5 hours of Phase 3 implementation ready
Cons:
- ❌ Complex: SSH wrapper script adds overhead
- ❌ n8n SSH nodes overwrite data (requires $node pattern)
- ❌ Less granular error handling
- ❌ GitHub Actions not utilized
- ❌ Workflow complexity (11 nodes for Phase 3)
New Approach (GitHub Actions + Python SDK)
Architecture:
Git Push → Gitea Webhook → GitHub Actions → Python SDK → OpenHands Execution
Pros:
- ✅ Direct SDK integration (no CLI/wrapper)
- ✅ Native Python (not shell-based)
- ✅ Built-in logging and artifacts
- ✅ Simpler retry logic via GitHub Actions
workflow_run - ✅ Standard CI/CD patterns
- ✅ Better GitHub/Gitea integration potential
- ✅ No SSH key management
Cons:
- ❌ Requires GitHub/Gitea Actions integration
- ❌ Need to evaluate Gitea Actions compatibility
- ❌ New learning curve for Python SDK
- ❌ Need to rebuild what we've already built
🎯 Recommended Integration Strategy
Option A: Hybrid Approach (RECOMMENDED)
Keep n8n for orchestration, use GitHub Actions for execution:
Git Push → Gitea Webhook → n8n → GitHub Actions → OpenHands SDK → Results
Benefits:
- Leverage existing n8n workflow infrastructure
- Use GitHub Actions for cleaner OpenHands execution
- Gradual migration path
- Best of both worlds
Implementation:
- Modify n8n workflow to trigger GitHub Actions via HTTP
- GitHub Actions executes OpenHands SDK
- GitHub Actions reports back to n8n
- n8n updates Gitea status
Complexity: Medium Time: 3-4 days Risk: Low
Option B: Full GitHub Actions Migration
Migrate completely to GitHub Actions:
Git Push → Gitea Actions → OpenHands SDK → Gitea Status
Benefits:
- Most modern approach
- No vendor lock-in to n8n
- True cloud-native solution
- GitHub Actions ecosystem
Challenges:
- Need GitHub Actions on Gitea (check compatibility)
- Requires full rebuild of Phase 3
- Need to validate Gitea → Actions integration
Complexity: High Time: 5-7 days Risk: Medium
Option C: Stay with Current (n8n + SSH)
Continue Phase 3 as planned:
Git Push → n8n → SSH → OpenHands CLI
Benefits:
- Immediate implementation (4-5 hours)
- Lowest risk
- Leverages tested infrastructure
Drawbacks:
- More complex architecture
- Harder to maintain long-term
- Missing modern CI/CD benefits
Complexity: Low Time: 4-5 hours Risk: Minimal, but technical debt
📋 Implementation Plan (Option A - Hybrid)
Phase 3.5: Hybrid Integration (3-4 days)
Day 1: GitHub Actions Setup
- Create GitHub Actions workflow template
- Set up agent_script.py for build/test tasks
- Test OpenHands SDK directly
- Configure LLM API key (MiniMax/DeepSeek)
Day 2: n8n to GitHub Actions Integration
- Create GitHub Actions webhook endpoint
- Modify n8n workflow to call Actions
- Implement status callback from Actions
- Test end-to-end flow
Day 3: Error Handling & Retry
- Implement GitHub Actions retry logic
- Add structured error logging
- Configure log artifacts
- Test failure scenarios
Day 4: Gitea Status & Documentation
- Add Gitea status update from Actions
- Create comprehensive documentation
- Test with real project
- Clean up old approach
🛠️ Technical Implementation Details
A. GitHub Actions Workflow Template
File: .github/workflows/openhands-build.yml
name: OpenHands Build
on:
workflow_dispatch:
inputs:
task:
description: 'Build task to execute'
required: true
type: string
repo_name:
description: 'Repository name'
required: true
type: string
commit_sha:
description: 'Commit SHA'
required: true
type: string
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install uv
uses: astral-sh/setup-uv@v6
with:
cache: true
- name: Install OpenHands SDK
run: |
uv pip install --system "openhands-sdk @ git+https://github.com/OpenHands/agent-sdk.git@main#subdirectory=openhands-sdk"
uv pip install --system "openhands-tools @ git+https://github.com/OpenHands/agent-sdk.git@main#subdirectory=openhands-tools"
- name: Run Build Task
env:
LLM_API_KEY: ${{ secrets.OPENHANDS_API_KEY }}
TASK: ${{ github.event.inputs.task }}
REPO_NAME: ${{ github.event.inputs.repo_name }}
COMMIT_SHA: ${{ github.event.inputs.commit_sha }}
run: |
python .github/scripts/agent_build.py
- name: Upload Build Logs
uses: actions/upload-artifact@v4
if: always()
with:
name: build-logs-${{ github.run_number }}
path: |
*.log
output/
retention-days: 7
- name: Update Gitea Status
if: always()
run: |
STATUS="${{ job.status }}"
if [ "$STATUS" = "success" ]; then
STATE="success"
else
STATE="failure"
fi
curl -X POST \
"$GITEA_API_URL/api/v1/repos/$REPO_OWNER/$REPO_NAME/statuses/$COMMIT_SHA" \
-H "Authorization: token $GITEA_API_TOKEN" \
-H "Content-Type: application/json" \
-d "{\"state\": \"$STATE\", \"description\": \"Build $STATE\", \"context\": \"openhands/actions\"}"
env:
GITEA_API_URL: https://git.oky.sh
GITEA_API_TOKEN: ${{ secrets.GITEA_API_TOKEN }}
REPO_OWNER: ${{ github.event.inputs.repo_owner }}
B. Agent Script for Build Tasks
File: .github/scripts/agent_build.py
#!/usr/bin/env python3
"""
OpenHands Build Agent Script
Executes build and test tasks using OpenHands SDK
"""
import os
import sys
import logging
from pathlib import Path
from openhands.sdk import LLM, Conversation, get_logger
from openhands.tools.preset.default import get_default_agent
# Configure logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler('build.log'),
logging.StreamHandler()
]
)
logger = get_logger(__name__)
def main():
"""Execute build task with OpenHands SDK."""
# Configuration
api_key = os.getenv('LLM_API_KEY')
task = os.getenv('TASK')
repo_name = os.getenv('REPO_NAME')
commit_sha = os.getenv('COMMIT_SHA')
if not all([api_key, task, repo_name, commit_sha]):
logger.error("Missing required environment variables")
sys.exit(1)
# Configure LLM (MiniMax or DeepSeek)
model = os.getenv('LLM_MODEL', 'anthropic/claude-sonnet-4-5-20250929')
base_url = os.getenv('LLM_BASE_URL')
llm_config = {
'model': model,
'api_key': api_key,
'usage_id': f'build-{repo_name}-{commit_sha[:8]}',
'drop_params': True,
}
if base_url:
llm_config['base_url'] = base_url
# Create LLM and agent
llm = LLM(**llm_config)
agent = get_default_agent(llm=llm, cli_mode=True)
# Create conversation with workspace
cwd = Path.cwd()
conversation = Conversation(agent=agent, workspace=cwd)
# Enhanced task with context
enhanced_task = f"""
Build and test the project at {cwd}.
Repository: {repo_name}
Commit: {commit_sha}
Task: {task}
Please:
1. Install dependencies (npm install / pip install / etc.)
2. Run build commands
3. Execute tests
4. Report results clearly
5. If errors occur, analyze and fix them
6. Provide detailed output
Success criteria: All tests pass and build completes without errors.
"""
logger.info(f"Starting build task for {repo_name}@{commit_sha[:8]}")
# Execute task
try:
conversation.send_message(enhanced_task)
result = conversation.run()
logger.info("Build task completed")
return 0
except Exception as e:
logger.error(f"Build task failed: {e}")
return 1
if __name__ == "__main__":
sys.exit(main())
C. n8n Workflow Modification
Replace OpenHands SSH node with HTTP node:
// HTTP Node to trigger GitHub Actions
const repoData = $node["Extract Repo Info"].json;
// Trigger GitHub Actions
const response = await fetch('https://api.github.com/repos/OWNER/REPO/actions/workflows/openhands-build.yml/dispatches', {
method: 'POST',
headers: {
'Authorization': 'token ' + $node["GitHub Token"].json.token,
'Accept': 'application/vnd.github.v3+json'
},
body: JSON.stringify({
ref: 'main',
inputs: {
task: `Build project in ${repoData.repo_name}`,
repo_name: repoData.repo_name,
commit_sha: repoData.commit_sha,
repo_owner: repoData.owner
}
})
});
return {
...repoData,
status: 'triggered',
github_run_id: response.json().id
};
📝 Migration Path
Phase 1: Parallel Development (Day 1-2)
Actions:
- Create GitHub Actions workflow files
- Test SDK directly with sample projects
- Build agent_script.py for build/test tasks
- Document new approach
Outcome: Working GitHub Actions prototype
Phase 2: n8n Integration (Day 2-3)
Actions:
- Create GitHub Actions dispatch endpoint in n8n
- Replace SSH node with HTTP node
- Add status callback mechanism
- Test end-to-end flow
Outcome: Hybrid workflow functional
Phase 3: Gitea Integration (Day 3-4)
Actions:
- Add Gitea status update from GitHub Actions
- Update webhook configuration
- Test with real repositories
- Verify all scenarios (success, failure, retry)
Outcome: Production-ready hybrid system
Phase 4: Cleanup & Documentation (Day 4-5)
Actions:
- Deprecate old SSH approach
- Remove unused workflow nodes
- Update all documentation
- Create migration guide
Outcome: Full migration complete
🔐 Required Credentials
GitHub Actions Secrets (Repository-level)
# For GitHub Actions
OPENHANDS_API_KEY: MiniMax or DeepSeek API key
GITEA_API_TOKEN: Token for updating Gitea statuses
# For n8n HTTP nodes
GITHUB_TOKEN: Personal access token or app token
Environment Variables
# Optional (for custom LLM endpoints)
LLM_BASE_URL: Custom endpoint (e.g., MiniMax API)
# Model selection
LLM_MODEL: Default "anthropic/claude-sonnet-4-5-20250929"
⚠️ Challenges & Solutions
Challenge 1: Gitea GitHub Actions Compatibility
Issue: Gitea may not support GitHub Actions natively
Solution:
- Use GitHub.com Actions (fork pattern)
- Or use Gitea Actions if available
- Or trigger external GitHub Actions via webhook
Action: Check Gitea version and Actions support
Challenge 2: LLM API Key Management
Issue: Need to pass API keys securely
Solution:
- Store in GitHub repository secrets
- Use environment variables
- Never commit keys to code
Action: Set up secrets before deployment
Challenge 3: Data Flow Complexity
Issue: Multiple systems (n8n → Actions → Gitea)
Solution:
- Use unique IDs for tracking (repo + commit)
- Store minimal state (repo, commit, status)
- Log everything for debugging
Action: Implement logging from start
✅ Success Criteria
Hybrid Approach Must Achieve:
- End-to-end build/test cycle completes
- GitHub Actions executes OpenHands SDK successfully
- n8n orchestrates workflow without SSH
- Gitea commit status updates automatically
- Retry logic works (GitHub Actions native)
- Logs captured and accessible
- Better error messages than current approach
- Simpler architecture (fewer moving parts)
📚 Resources
Current Documentation
phase3.md- Current Phase 3 plan (SSH approach)n8n-api.md- n8n API referenceopenhands-subagents-doc.md- OpenHands best practices
New Documentation to Create
github-actions-integration.md- Complete guide.github/workflows/openhands-build.yml- Workflow template.github/scripts/agent_build.py- Agent scriptmigration-guide.md- Transition documentation
Reference Examples
🎯 Final Recommendation
ADOPT OPTION A (Hybrid Approach)
Justification:
- Risk: Lowest risk - builds on working infrastructure
- Time: 3-4 days vs 4-5 hours (but modernizes stack)
- Benefits: Significant architectural improvement
- Future: Positions for full GitHub Actions migration later
- Learning: Team gains Python SDK experience
Next Steps:
- Today: Create GitHub Actions workflow and test
- Tomorrow: Integrate with n8n workflow
- Day 3: Add Gitea status updates
- Day 4: Complete migration and documentation
Decision: Proceed with hybrid approach, start with GitHub Actions prototype
Analysis Complete - 2025-12-02 Recommendation: Hybrid approach (Option A)