mvp-factory-openhands/CLAUDE.md

687 lines
15 KiB
Markdown

# 🚀 AI Dev Factory - Session Continuation Guide
**Last Updated:** 2024-11-28
**Current Phase:** Phase 2 - OpenHands Integration (API Mode)
**Time to Completion:** ~3-4 hours
**Next Approach:** OpenHands Server API Mode ✅
---
## 📊 CURRENT STATUS
### ✅ What's Working:
- **Gitea:** https://git.oky.sh (HTTPS, PostgreSQL backend)
- **n8n:** https://n8n.oky.sh (HTTPS, workflow automation)
- **Caddy:** Auto SSL with Let's Encrypt
- **SSH:** n8n → localhost credentials configured
- **OpenHands CLI:** `/home/bam/.local/bin/openhands` (v1.3.0)
### ⚠️ Current Blocker:
- OpenHands headless mode (Docker) hangs on runtime startup
- **Solution:** Switch to OpenHands Server API mode
### 🎯 Goal:
Create automated workflow: Gitea push → n8n → OpenHands API → Build/Test
---
## 🔧 SYSTEM CONFIGURATION
### VM Details:
```
Hostname: ai-dev-node
IP: 10.10.10.11
User: bam
CPU: 8 vCPU
RAM: 24GB (optimized from 40GB)
OS: Ubuntu 22.04
```
### Services Running:
```bash
docker compose ps
# Expected output:
# - caddy (ports 80, 443)
# - gitea (port 3333 internal, 2229 SSH)
# - n8n (port 5678 internal)
# - postgres (port 5432 internal)
```
### Important Directories:
```
/home/bam/services-stack/ # Docker services (Gitea, n8n, Caddy)
/home/bam/.local/bin/ # OpenHands CLI
/home/bam/.openhands/ # OpenHands config & sessions
├── agent_settings.json # Agent configuration
├── cache/ # Model cache
├── conversations/ # Chat history
├── sessions/ # Active sessions data
└── settings.json # LLM & server settings
/home/bam/workspace/ # Default workspace for builds
/home/bam/.ssh/n8n_key # SSH key for n8n automation
```
### API Keys Location:
```
/home/bam/openhands/.env
# Contains:
# MINIMAX_API_KEY=xxx (Primary LLM)
# DEEPSEEK_API_KEY=xxx (Backup LLM)
# OPENAI_API_KEY=xxx (Optional 2nd backup)
```
---
## 🎯 NEXT STEPS: OpenHands Server API Setup
### Step 1: Start OpenHands in Server Mode (15 min)
**Goal:** Run OpenHands as persistent HTTP API service
**OpenHands serve uses port 3000 by default (cannot be changed in current version)**
```bash
# Test server startup
/home/bam/.local/bin/openhands serve
# Expected: Server starts, listens on http://localhost:3000
```
**Create systemd service for persistence:**
```bash
sudo nano /etc/systemd/system/openhands.service
# Paste:
[Unit]
Description=OpenHands Server
After=network.target docker.service
Requires=docker.service
[Service]
Type=simple
User=bam
WorkingDirectory=/home/bam
Environment="PATH=/home/bam/.local/bin:/usr/local/bin:/usr/bin:/bin"
EnvironmentFile=/home/bam/openhands/.env
ExecStart=/home/bam/.local/bin/openhands serve
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
# Save and enable:
sudo systemctl daemon-reload
sudo systemctl enable openhands.service
sudo systemctl start openhands.service
sudo systemctl status openhands.service
```
**Verify:**
```bash
# Check if running
curl http://localhost:3000/
# Check logs
sudo journalctl -u openhands.service -f
```
---
### Step 1.5: Configure Backup LLM Models (10 min)
**Goal:** Setup DeepSeek V2 as fallback when MiniMax fails
OpenHands can use multiple LLM providers with automatic fallback.
**Check current config:**
```bash
cat /home/bam/.openhands/settings.json
```
**Update settings to include backup models:**
```bash
nano /home/bam/.openhands/settings.json
```
**Add LLM configuration:**
```json
{
"LLM_MODEL": "openai/MiniMax-M2",
"LLM_API_KEY": "${MINIMAX_API_KEY}",
"LLM_BASE_URL": "https://api.minimax.io/v1",
"LLM_FALLBACK_MODELS": [
{
"model": "deepseek/deepseek-coder-v2",
"api_key": "${DEEPSEEK_API_KEY}",
"base_url": "https://api.deepseek.com/v1"
},
{
"model": "gpt-4o",
"api_key": "${OPENAI_API_KEY}",
"base_url": "https://api.openai.com/v1"
}
],
"LLM_TIMEOUT": 60,
"LLM_RETRY_COUNT": 3
}
```
**Verify API keys are loaded:**
```bash
cat /home/bam/openhands/.env
# Should contain:
# MINIMAX_API_KEY=xxx
# DEEPSEEK_API_KEY=xxx
# OPENAI_API_KEY=xxx (optional backup)
```
**Note:** Exact config format may vary. Check OpenHands documentation or existing settings.json structure. The systemd service will load these env vars automatically.
**Restart OpenHands to apply:**
```bash
sudo systemctl restart openhands.service
sudo systemctl status openhands.service
```
---
### Step 2: Discover API Endpoints (15 min)
**Goal:** Find available API endpoints for triggering tasks
**Check OpenHands documentation:**
```bash
# Look for API docs in help
/home/bam/.local/bin/openhands serve --help
# Or check if web UI exposes API docs:
# Visit: http://10.10.10.11:3000/docs
# Or: http://10.10.10.11:3000/api/docs
```
**Expected endpoints (typical OpenHands API):**
```
POST /api/sessions # Create new session
POST /api/sessions/{id}/messages # Send task message
GET /api/sessions/{id} # Get session status
GET /api/sessions/{id}/events # Get execution events
```
**Test manually:**
```bash
# Create session
curl -X POST http://localhost:3000/api/sessions \
-H "Content-Type: application/json" \
-d '{
"workspace": "/home/bam/workspace",
"model": "openai/MiniMax-M2",
"api_key": "your_minimax_key"
}'
# Response should include session_id
```
**If API endpoints unclear:**
- Check OpenHands GitHub docs
- Inspect network requests in web UI (browser DevTools)
- Look for OpenAPI/Swagger spec
---
### Step 3: Create n8n → OpenHands API Workflow (45 min)
**Goal:** Build n8n workflow that calls OpenHands API
#### Workflow Design:
```
[1] Manual Trigger (for testing)
[2] HTTP Request - Create Session
→ POST /api/sessions
→ Save session_id
[3] HTTP Request - Send Task
→ POST /api/sessions/{session_id}/messages
→ Body: { "task": "Create file test.txt" }
[4] Wait 5 seconds
[5] HTTP Request - Get Status (loop until done)
→ GET /api/sessions/{session_id}
→ Check if "status": "completed"
[6] If Node - Check Success
├─ TRUE → [7] Get Results
└─ FALSE → [8] Error Handler
```
#### n8n Configuration:
**Node 1: Manual Trigger**
- Just add it, no config
**Node 2: HTTP Request - Create Session**
```
Method: POST
URL: http://127.0.0.1:3000/api/sessions
Headers:
Content-Type: application/json
Body:
{
"workspace": "/home/bam/workspace",
"model": "openai/MiniMax-M2",
"api_key": "{{$env.MINIMAX_API_KEY}}"
}
Options:
Response Format: JSON
```
**Node 3: HTTP Request - Send Task**
```
Method: POST
URL: http://127.0.0.1:3000/api/sessions/{{ $json.session_id }}/messages
Body:
{
"task": "Create a file named test.txt with content: Hello from n8n API!"
}
```
**Node 4: Wait Node**
```
Time: 5 seconds
```
**Node 5: HTTP Request - Get Status**
```
Method: GET
URL: http://127.0.0.1:3000/api/sessions/{{ $node["HTTP Request"].json.session_id }}
# May need to loop this until status is "completed"
# Use n8n Loop node if available
```
**Node 6: SSH - Verify File Created**
```
Credentials: ai-dev-localhost
Command: cat /home/bam/workspace/test.txt
```
#### Test Workflow:
1. Execute manually
2. Check each node output
3. Verify file created in /home/bam/workspace/
---
### Step 4: Gitea Webhook Integration (30 min)
**Goal:** Trigger n8n workflow on git push
#### In Gitea (https://git.oky.sh):
1. Create test repository: `test-project`
2. Go to Settings → Webhooks → Add Webhook → Gitea
3. Configure:
```
Target URL: https://n8n.oky.sh/webhook/gitea-push
HTTP Method: POST
Content Type: application/json
Secret: [generate random string]
Trigger On: Push events
Active: ✓
```
4. Test webhook
#### In n8n:
1. Replace Manual Trigger with Webhook Trigger
2. Configure:
```
Webhook URLs:
Production: https://n8n.oky.sh/webhook/gitea-push
HTTP Method: POST
Authentication: Header Auth
Name: X-Gitea-Signature
Value: [your secret from Gitea]
Response:
Mode: Last Node
Code: 200
```
3. Extract data:
```
Repository: {{ $json.repository.full_name }}
Commit: {{ $json.commits[0].message }}
Branch: {{ $json.ref }}
```
4. Pass to OpenHands:
```
Task: "Build and test project {{ $json.repository.full_name }} on commit {{ $json.after }}"
Workspace: "/home/bam/workspace/{{ $json.repository.name }}"
```
#### Test:
```bash
# In test-project repo
echo "Test" > README.md
git add .
git commit -m "Test webhook"
git push origin main
# Check n8n workflow executes
# Check OpenHands builds project
```
---
### Step 5: Build Workflow with Retry Logic (1-2 hours)
**Goal:** Production-ready workflow with error handling
#### Enhanced Workflow:
```
[1] Webhook Trigger (Gitea push)
[2] Extract Repo Info
[3] Clone/Update Repository (SSH)
→ git clone or git pull
[4] Create OpenHands Session
[5] Send Build Task
→ Task: "Run npm install, npm test, npm build"
[6] Poll Status (Loop)
→ Check every 10s
→ Timeout: 5 minutes
[7] If Node - Build Success?
├─ YES → [8] Success Notification
│ └─ Update commit status ✅
└─ NO → [9] Get Error Details
[10] Send Feedback to OpenHands
→ "Build failed with: {error}, please fix"
[11] Retry Counter (max 3)
├─ < 3 → Back to [5]
└─ ≥ 3 → [12] Final Failure Notification
```
#### Key Components:
**Clone Repository Node (SSH):**
```bash
cd /home/bam/workspace
if [ -d "{{ $json.repo_name }}" ]; then
cd {{ $json.repo_name }} && git pull
else
git clone {{ $json.clone_url }}
fi
```
**Build Task (to OpenHands):**
```json
{
"task": "Navigate to /home/bam/workspace/{{ $json.repo_name }} and run: npm install && npm test && npm build. Report any errors.",
"workspace": "/home/bam/workspace/{{ $json.repo_name }}",
"max_iterations": 20
}
```
**Retry Logic (n8n Function Node):**
```javascript
// Get retry count from workflow static data
const retries = $workflow.staticData.retry_count || 0;
if (retries >= 3) {
return {
action: 'fail',
message: 'Max retries exceeded'
};
}
// Increment retry
$workflow.staticData.retry_count = retries + 1;
return {
action: 'retry',
attempt: retries + 1,
feedback: $json.error_message
};
```
**Success Notification (HTTP to Gitea API):**
```
POST https://git.oky.sh/api/v1/repos/{{ $json.repo }}/statuses/{{ $json.commit_sha }}
Authorization: token YOUR_GITEA_TOKEN
Body:
{
"state": "success",
"description": "Build passed",
"context": "openhands/build"
}
```
---
## 🧪 TESTING CHECKLIST
### Integration Tests:
- [ ] OpenHands server starts and responds
- [ ] API creates sessions successfully
- [ ] API accepts and executes tasks
- [ ] Tasks complete and return results
- [ ] n8n can call all API endpoints
- [ ] Webhook receives Gitea events
- [ ] Repository clones correctly
- [ ] Build task executes
- [ ] Success path works end-to-end
- [ ] Failure triggers retry
- [ ] Max retries stops infinite loop
- [ ] Notifications sent correctly
### Error Scenarios:
- [ ] Invalid API request
- [ ] OpenHands timeout
- [ ] Build failure (syntax error)
- [ ] Network issues
- [ ] Git clone failure
- [ ] Webhook auth failure
---
## 📋 TROUBLESHOOTING
### OpenHands Server Won't Start:
```bash
# Check if port in use
sudo netstat -tulpn | grep 3000
# Check OpenHands logs
sudo journalctl -u openhands.service -n 50
# Try manual start to see errors
/home/bam/.local/bin/openhands serve
```
### API Endpoints Not Found:
```bash
# Check OpenHands version
/home/bam/.local/bin/openhands --version
# May need to update
pipx upgrade openhands-ai
# Or reinstall
pipx uninstall openhands-ai
pipx install openhands-ai
```
### n8n Cannot Reach OpenHands:
```bash
# Test from n8n container
docker exec -it n8n curl http://host.docker.internal:3000
# If fails, check if n8n has host.docker.internal access
# May need to add to docker-compose:
extra_hosts:
- "host.docker.internal:host-gateway"
```
### Webhook Not Triggering:
```bash
# Check n8n webhook URL is accessible
curl https://n8n.oky.sh/webhook/gitea-push
# Check Gitea webhook logs:
# Gitea UI → Repository → Settings → Webhooks → Recent Deliveries
# Test with manual webhook trigger in Gitea UI
```
---
## 🎯 SUCCESS CRITERIA
**Phase 2 Complete When:**
1. ✅ OpenHands server running persistently
2. ✅ n8n can create sessions via API
3. ✅ Simple test task executes successfully
4. ✅ Gitea webhook triggers n8n workflow
5. ✅ End-to-end: Push → Build → Success/Fail
**Phase 3 Complete When:**
1. ✅ Retry logic working (max 3 attempts)
2. ✅ Error feedback to OpenHands
3. ✅ Commit status updates in Gitea
4. ✅ Tested with real project build
---
## 📚 REFERENCE COMMANDS
### Quick Status Check:
```bash
# All services status
cd /home/bam/services-stack && docker compose ps
# OpenHands server
sudo systemctl status openhands.service
# Check OpenHands API
curl http://localhost:3000/
# n8n workflows
curl -u admin:password https://n8n.oky.sh/api/v1/workflows
```
### Restart Services:
```bash
# Restart all Docker services
cd /home/bam/services-stack
docker compose restart
# Restart OpenHands only
sudo systemctl restart openhands.service
# Restart n8n only
docker compose restart n8n
```
### View Logs:
```bash
# OpenHands logs
sudo journalctl -u openhands.service -f
# n8n logs
docker logs -f n8n
# Caddy logs
docker logs -f caddy
# Gitea logs
docker logs -f gitea
```
---
## 🔐 CREDENTIALS REFERENCE
### n8n Login:
- URL: https://n8n.oky.sh
- User: admin (owner account)
- Password: [set during setup]
### Gitea Login:
- URL: https://git.oky.sh
- User: [admin account]
- Password: [set during setup]
### API Keys:
- MiniMax: `/home/bam/openhands/.env`
- SSH Key: `/home/bam/.ssh/n8n_key`
---
## ⏱️ ESTIMATED TIME BREAKDOWN
- Step 1: OpenHands Server Setup: **15 min**
- Step 1.5: Backup LLM Configuration: **10 min**
- Step 2: API Discovery: **15 min**
- Step 3: n8n API Workflow: **45 min**
- Step 4: Gitea Webhook: **30 min**
- Step 5: Retry Logic: **1-2 hours**
- Testing & Debugging: **30 min**
**Total: 3-4 hours**
---
## 🚀 READY TO START?
**Pre-flight Checklist:**
- [ ] All services running (docker compose ps)
- [ ] Can access Gitea (https://git.oky.sh)
- [ ] Can access n8n (https://n8n.oky.sh)
- [ ] SSH to ai-dev-node working
- [ ] Fresh terminal session
**First Command:**
```bash
/home/bam/.local/bin/openhands serve
```
If starts successfully → proceed to Step 1 systemd service!
If error → investigate OpenHands CLI installation
---
## 📝 NOTES
- **Port 3000:** OpenHands serve uses port 3000 (not configurable in CLI v1.3.0)
- **Note:** This conflicts with Gitea's internal port 3000, but OK since Gitea exposed as 3333
- OpenHands API: http://localhost:3000 (localhost only)
- n8n will access via http://host.docker.internal:3000 from container
- **API Mode vs Headless:** API is more reliable for automation
- **Persistence:** systemd service ensures OpenHands survives reboots
- **Security:** OpenHands API on localhost only (127.0.0.1)
- **Scaling:** Can add more OpenHands instances later
- **LLM Fallback:** MiniMax M2 → DeepSeek V2 → OpenAI GPT-4o (if configured)
**Good luck!** 🎯