# ๐Ÿš€ Gitea โ†’ n8n โ†’ OpenHands SDK Integration Guide **Last Updated:** 2025-12-01 **Status:** โœ… WORKING (with variable fix needed) **Total Time:** ~8 hours across multiple sessions --- ## ๐ŸŽฏ OVERVIEW This guide documents the successful integration of: - **Gitea** (Git hosting) - **n8n** (Workflow automation) - **OpenHands SDK v1.3.0** (AI-powered build/test agent) **Flow:** `git push` โ†’ `Gitea webhook` โ†’ `n8n workflow` โ†’ `SSH to OpenHands SDK` --- ## โœ… WHAT WORKS ### 1. Repository Setup ```bash # New clean repository with only 8 essential files # No .env files in git history (security) # Deploy keys configured for SSH access ``` ### 2. n8n Workflow Import ```bash # Import command docker exec n8n n8n import:workflow --input=/tmp/workflow.json # Must include "active": true in JSON ``` ### 3. Webhook Configuration - **URL:** `https://n8n.oky.sh/webhook-test/openhands-sdk` - **Method:** POST - **Content-Type:** application/json - **Active:** โœ… ### 4. SSH Authentication - **Key:** `/home/bam/.ssh/n8n_key` - **Mounted:** In n8n container as `/home/node/.ssh` - **Credentials ID:** `v2BMXeCFGpXaoIyb` ### 5. OpenHands SDK Wrapper - **Location:** `/home/bam/claude/mvp-factory/openhands-sdk-wrapper-sh.sh` - **Env File:** `/home/bam/openhands/.env` - **SDK Path:** `/tmp/software-agent-sdk` - **Python Wrapper:** `/home/bam/openhands-sdk-wrapper-fixed.py` --- ## ๐Ÿ”ง WORKFLOW STRUCTURE ### Node 1: Webhook Trigger ```json { "type": "n8n-nodes-base.webhook", "parameters": { "httpMethod": "POST", "path": "openhands-sdk" } } ``` ### Node 2: Extract Repo Info (JavaScript) ```javascript const payload = $input.item.json; const repoName = payload.repository?.name || 'unknown'; const repoFullName = payload.repository?.full_name || 'unknown'; const branch = payload.ref?.replace('refs/heads/', '') || 'main'; // ... extract more fields const task = 'Build and test project ' + repoFullName + ' on branch ' + branch + '. ' + 'Clone the repository and run: npm install && npm test && npm build.'; return { repo_name: repoName, task: task, ... }; ``` ### Node 3: Execute OpenHands SDK (SSH) ```json { "type": "n8n-nodes-base.ssh", "parameters": { "command": "={{ 'sh /home/bam/claude/mvp-factory/openhands-sdk-wrapper-sh.sh \"' + $json.task + '\"' }}", "sessionId": "gitea-session" } } ``` ### Node 4: Webhook Response ```json { "type": "n8n-nodes-base.respondToWebhook", "parameters": { "respondWith": "text", "responseBody": "โœ… Build triggered successfully!" } } ``` --- ## โš ๏ธ CRITICAL NOTES ### n8n Test Mode vs Production - **Test URL:** `https://n8n.oky.sh/webhook-test/openhands-sdk` - Requires clicking "Execute workflow" button in UI - Webhook active for ONE call only - Variables work properly - **Production URL:** `https://n8n.oky.sh/webhook/openhands-sdk` - Always active (if workflow set to active: true) - **DOES NOT WORK** with Gitea webhook node (known limitation) ### Variable Substitution in SSH โŒ **DOESN'T WORK:** ```json "command": "sh /home/bam/claude/mvp-factory/openhands-sdk-wrapper-sh.sh \"{{ $json.task }}\"" ``` โœ… **WORKS:** ```json "command": "={{ 'sh /home/bam/claude/mvp-factory/openhands-sdk-wrapper-sh.sh \"' + $json.task + '\"' }}" ``` **Why?** n8n needs explicit expression evaluation for SSH node commands. --- ## ๐Ÿ”จ STEP-BY-STEP WORKFLOW ### Step 1: Import Workflow ```bash # Copy workflow JSON to n8n container docker cp /path/to/workflow.json n8n:/tmp/workflow.json # Import docker exec -e N8N_BASIC_AUTH_ACTIVE=false n8n \ n8n import:workflow --input=/tmp/workflow.json ``` ### Step 2: Activate Workflow 1. Open n8n UI: https://n8n.oky.sh 2. Find workflow "Gitea โ†’ OpenHands SDK" 3. **Toggle to activate** (make it green) 4. OR for test mode: Click "Execute workflow" button ### Step 3: Configure Gitea Webhook 1. Go to Gitea repository 2. Settings โ†’ Webhooks โ†’ Add Webhook 3. Configure: - **URL:** `https://n8n.oky.sh/webhook-test/openhands-sdk` - **Method:** POST - **Content Type:** application/json - **Push Events:** โœ… - **Active:** โœ… 4. Test webhook (optional) ### Step 4: Test Integration ```bash # Make a change and push echo "test" > test.txt git add test.txt git commit -m "Test webhook" git push origin main ``` ### Step 5: Monitor Execution ```bash # Watch n8n logs docker logs -f n8n # Should see: # - "Workflow was started" # - OpenHands SDK output # - Task with actual repo/branch values ``` --- ## ๐Ÿ“ KEY FILES ### Workflow Files - `/tmp/openhands-sdk-webhook-FINAL.json` - โœ… Working workflow with fixes - `/home/bam/claude/mvp-factory/openhands-sdk-n8n-CLEAN.json` - Reference workflow ### Wrapper Scripts - `/home/bam/claude/mvp-factory/openhands-sdk-wrapper-sh.sh` - Main wrapper (sh-compatible) - `/home/bam/openhands-sdk-wrapper-fixed.py` - Python wrapper - `/home/bam/openhands/.env` - API keys (NOT in git) ### Configuration - `/home/bam/.ssh/n8n_key` - SSH private key for n8n - `/home/bam/services/services-stack/docker-compose.yml` - n8n config with SSH mount --- ## ๐Ÿงช TESTING CHECKLIST ### โœ… Verified Working - [x] Workflow imports to n8n - [x] Webhook receives Gitea events - [x] n8n parses webhook payload - [x] SSH connects to localhost - [x] OpenHands SDK starts - [x] Task sent to OpenHands ### ๐Ÿ”ง Still Needs Fixing - [ ] Variable substitution in SSH command (use expression syntax) - [ ] Production webhook URL (test URL works, production doesn't) - [ ] OpenHands task parsing (sometimes shows "unknown") --- ## ๐Ÿšจ TROUBLESHOOTING ### "Webhook not registered" - **Cause:** Workflow not active - **Fix:** Toggle workflow to active in n8n UI - **Or:** Click "Execute workflow" for test mode ### "unknown webhook" error - **Cause:** Wrong URL path - **Fix:** Use `/webhook-test/` not `/webhook/` for n8n+Gitea ### SSH authentication fails - **Cause:** Key not mounted or wrong permissions - **Fix:** Verify in docker-compose.yml: ```yaml volumes: - /home/bam/.ssh:/home/node/.ssh:ro ``` ### Variables show "{{ $json.field }}" - **Cause:** n8n expression not evaluated - **Fix:** Use explicit expression: `"={{ 'text ' + $json.field + ' more' }}"` ### OpenHands SDK not found - **Cause:** Virtual environment not activated - **Fix:** Wrapper script activates venv before running Python --- ## ๐Ÿ“š REFERENCE COMMANDS ### Check n8n Logs ```bash docker logs --tail 100 n8n 2>&1 | grep -i "openhands\|ssh\|webhook" ``` ### Test Webhook Directly ```bash curl -X POST https://n8n.oky.sh/webhook-test/openhands-sdk \ -H "Content-Type: application/json" \ -d '{"repository":{"full_name":"test/repo"},"ref":"refs/heads/main"}' ``` ### Verify Workflow Active ```bash curl -s https://n8n.oky.sh/api/v1/workflows | jq '.data[] | select(.name=="Gitea โ†’ OpenHands SDK") | .active' ``` ### Restart n8n ```bash docker compose -f /home/bam/services/services-stack/docker-compose.yml restart n8n ``` --- ## ๐ŸŽ“ KEY LEARNINGS 1. **Test URLs are required for n8n+Gitea integration** - Production `/webhook/` doesn't work with Gitea - Must use test mode `/webhook-test/` 2. **SSH variable substitution requires explicit expressions** - Can't use `{{ }}` syntax directly in SSH command field - Must wrap in expression: `"={{ 'prefix' + $json.field + 'suffix' }}"` 3. **Workflows deactivate on import** - Always re-activate after importing new version - Set `"active": true` in JSON before import 4. **SSH keys need proper mounting** - n8n container needs `/home/bam/.ssh` mounted as `/home/node/.ssh` - Use read-only mount: `:ro` 5. **OpenHands wrapper must be sh-compatible** - Use `#!/bin/sh` not `#!/bin/bash` - Load env vars with `source` not dot (`.` works for both) --- ## ๐Ÿš€ NEXT STEPS ### Immediate 1. Import `/tmp/openhands-sdk-webhook-FINAL.json` 2. Activate workflow in n8n UI 3. Test with new git push ### Future Enhancements 1. **Production webhook support** - Find workaround for n8n+Gitea limitation 2. **Retry logic** - Add loop for build completion checking 3. **Commit status updates** - Post results back to Gitea 4. **Error handling** - Better error messages and recovery 5. **Multiple repos** - Support for different repository patterns --- ## ๐Ÿ“ž SUPPORT If issues occur: 1. Check n8n logs: `docker logs n8n` 2. Verify workflow is active in n8n UI 3. Test webhook manually with curl 4. Confirm SSH key mounting in docker-compose.yml 5. Check OpenHands wrapper script permissions --- **Status:** Integration Complete โœ… **Last Test:** 2025-12-01 17:30:00 **Commit:** 290b79c (E2E test successful)