Skip to main content

odoo-knowledge-agent

Scrape Odoo forum solved threads to build error prevention guardrails and auto-fix scripts. Extract patterns from 1000+ solved issues to prevent common mistakes before deployment and auto-heal production problems. Combines web scraping, AI pattern extraction, preventive guardrails generation, and auto-patch scripts for Odoo custom development lifecycle.

Ir a la instalación

Datos de origen

Repositorio
jgtolentino/insightpulse-odoo
Última actividad en el origen
3 de noviembre de 2025 a las 17:52
Idioma detectado de SKILL.md
inglés
Estrellas
22
Forks
10

Opciones de instalación

De forma predeterminada está seleccionado el prompt que primero revisa el origen. Puedes cambiar a un comando directo o descargar una copia local.

Revisa los archivos de origen

Lee SKILL.md y los archivos complementarios que muestra SkillsMP antes de decidir si quieres instalarlo.

Explorador de archivos
2 archivos

Mostrando SKILL.md

SKILL.md
Instrucciones de origen · Vista previa de solo lectura
name
odoo-knowledge-agent
description
Scrape Odoo forum solved threads to build error prevention guardrails and auto-fix scripts. Extract patterns from 1000+ solved issues to prevent common mistakes before deployment and auto-heal production problems. Combines web scraping, AI pattern extraction, preventive guardrails generation, and auto-patch scripts for Odoo custom development lifecycle.
# Odoo Knowledge Agent - Error Prevention & Auto-Fix System ## When to Use This Skill Use this skill when you need to: - **Prevent Odoo errors before deployment** with guardrails - **Auto-heal production issues** using community-validated fixes - **Build intelligence from Odoo forum** solved threads (1000+ cases) - **Generate error code reference** and troubleshooting guides - **Create preventive checks** for module development - **Implement auto-patch systems** for known failure patterns - **Reduce debugging time** by learning from community solutions - **Build SOP library** for common Odoo development errors ## Core Capabilities ### 1. Forum Scraping Intelligence **Scrape Odoo Forum for Solved Threads** - Extract 1000+ solved issues across all categories - Parse accepted answers and code fixes - Identify error patterns and root causes - Build searchable knowledge base ### 2. Guardrails Generation **Preventive Error Checks** - Block common mistakes before deployment - Validate manifest files automatically - Check field synchronization issues - Enforce best practices (OCA standards) ### 3. Auto-Patch Scripts **Automated Error Fixes** - Apply community-validated solutions - Fix known issues automatically - Handle common migration problems - Self-healing production systems ### 4. Vision-Based UI Automation **askui-Compatible Automation** - UI actions without brittle selectors - Cross-browser compatibility - Screenshot-based validation - Self-healing test scripts ## Prerequisites ### Required Software - Python 3.11+ - Beautiful Soup 4 / Firecrawl - Odoo 19 instance for testing - Supabase for knowledge storage ### Optional Integrations - OpenAI API for pattern extraction - GitHub Actions for CI/CD integration - Perplexity for research enhancement ### Python Dependencies ```python beautifulsoup4 requests firecrawl-py supabase-py openai pyyaml gitpython ``` ## Implementation Patterns ### Forum Scraper ```python # scrape_solved_threads.py import requests from bs4 import BeautifulSoup from supabase import create_client import time from datetime import datetime class OdooForumScraper: def __init__(self, supabase_url, supabase_key): self.base_url = "https://www.odoo.com/forum" self.supabase = create_client(supabase_url, supabase_key) self.session = requests.Session() self.session.headers.update({ 'User-Agent': 'OdooKnowledgeBot/1.0' }) def scrape_solved_threads(self, pages=100): """ Scrape Odoo forum for solved threads """ threads = [] for page in range(1, pages + 1): print(f"Scraping page {page}/{pages}...") url = f"{self.base_url}/questions?filters=solved&page={page}" response = self.session.get(url) soup = BeautifulSoup(response.content, 'html.parser') # Extract thread links thread_elements = soup.select('.o_wforum_question') for thread in thread_elements: thread_url = thread.find('a')['href'] if not thread_url.startswith('http'): thread_url = f"https://www.odoo.com{thread_url}" # Get thread details thread_data = self.scrape_thread_details(thread_url) if thread_data: threads.append(thread_data) self.store_thread(thread_data) time.sleep(2) # Rate limiting time.sleep(5) # Pause between pages return threads def scrape_thread_details(self, url): """ Extract question, accepted answer, and code snippets """ try: response = self.session.get(url) soup = BeautifulSoup(response.content, 'html.parser') # Extract question question_elem = soup.select_one('.o_wforum_question_text') question = question_elem.text.strip() if question_elem else "" # Extract title title_elem = soup.select_one('h1.o_wforum_title') title = title_elem.text.strip() if title_elem else "" # Extract accepted answer accepted_answer = soup.select_one('.o_wforum_answer.o_wforum_answer_correct') if not accepted_answer: return None # Skip if no accepted answer answer_text = accepted_answer.select_one('.o_wforum_answer_text').text.strip() # Extract code snippets code_blocks = accepted_answer.select('pre code') code_snippets = [block.text.strip() for block in code_blocks] # Extract tags/category tags = [tag.text.strip() for tag in soup.select('.o_wforum_tag')] # Extract metadata views_elem = soup.select_one('.o_wforum_views') views = int(views_elem.text.strip()) if views_elem else 0 return { 'url': url, 'title': title, 'question': question, 'answer': answer_text, 'code_snippets': code_snippets, 'tags': tags, 'views': views, 'scraped_at': datetime.now().isoformat() } except Exception as e: print(f"Error scraping {url}: {e}") return None def store_thread(self, thread_data): """ Store thread in Supabase knowledge base """ self.supabase.table('odoo_solved_threads').upsert({ 'thread_url': thread_data['url'], 'title': thread_data['title'], 'question': thread_data['question'], 'answer': thread_data['answer'], 'code_snippets': thread_data['code_snippets'], 'tags': thread_data['tags'], 'views': thread_data['views'], 'scraped_at': thread_data['scraped_at'] }).execute() def extract_error_patterns(self): """ Use AI to extract common error patterns """ # Fetch all threads threads = self.supabase.table('odoo_solved_threads').select('*').execute() # Group by error type using AI from openai import OpenAI client = OpenAI() patterns = {} for thread in threads.data: # Ask GPT to categorize the error response = client.chat.completions.create( model="gpt-4", messages=[ {"role": "system", "content": "You are an Odoo expert. Categorize this error and extract the fix pattern."}, {"role": "user", "content": f"Title: {thread['title']}\n\nQuestion: {thread['question']}\n\nAnswer: {thread['answer']}"} ] ) pattern = response.choices[0].message.content # Extract category category = self.extract_category(pattern) if category not in patterns: patterns[category] = [] patterns[category].append({ 'thread': thread, 'pattern': pattern }) return patterns def extract_category(self, pattern_text): """ Extract error category from AI analysis """ # Common Odoo error categories categories = { 'manifest': ['__manifest__', 'module', 'dependency'], 'field': ['field', 'column', 'attribute'], 'view': ['view', 'xml', 'template'], 'security': ['access', 'rights', 'permission'], 'orm': ['orm', 'recordset', 'browse'], 'workflow': ['workflow', 'state', 'transition'], 'accounting': ['invoice', 'payment', 'journal'], 'inventory': ['stock', 'picking', 'quant'] } pattern_lower = pattern_text.lower() for category, keywords in categories.items(): if any(keyword in pattern_lower for keyword in keywords): return category return 'general' # Usage scraper = OdooForumScraper( supabase_url=os.getenv('SUPABASE_URL'), supabase_key=os.getenv('SUPABASE_KEY') ) # Scrape 100 pages (~1,100 solved threads) threads = scraper.scrape_solved_threads(pages=100) # Extract patterns patterns = scraper.extract_error_patterns() print(f"Scraped {len(threads)} solved threads") print(f"Identified {len(patterns)} error patterns") ``` ### Guardrail Generator ```python # generate_guardrails.py import yaml from pathlib import Path class GuardrailGenerator: def __init__(self, patterns): self.patterns = patterns self.guardrails_dir = Path('guardrails') self.guardrails_dir.mkdir(exist_ok=True) def generate_manifest_guardrail(self): """ GR-INSTALL-004: Manifest validation """ guardrail = { 'id': 'GR-INSTALL-004', 'name': 'Manifest Validation', 'description': 'Prevent module installation failures due to invalid __manifest__.py', 'category': 'manifest', 'severity': 'HIGH', 'checks': [ { 'name': 'Required Keys Present', 'pattern': r"'name':|\"name\":", 'error_message': "Missing required 'name' key in __manifest__.py", 'fix': 'Add name = "Module Name" to __manifest__.py' }, { 'name': 'Valid Dependencies', 'pattern': r"'depends':\s*\[.*?\]", 'error_message': "Invalid or missing 'depends' list", 'fix': 'Ensure depends list contains only installed modules' }, { 'name': 'Version Format', 'pattern': r"'version':\s*'\\d+\\.\\d+'", 'error_message': "Invalid version format (should be X.Y)", 'fix': 'Use semantic versioning: version = "1.0"' } ], 'prevention_script': ''' def validate_manifest(manifest_path): with open(manifest_path) as f: manifest = eval(f.read()) required_keys = ['name', 'version', 'depends', 'data'] missing = [k for k in required_keys if k not in manifest] if missing: raise ValueError(f"Missing required keys: {missing}") # Validate version format version = manifest['version'] if not re.match(r'^\\d+\\.\\d+$', version): raise ValueError(f"Invalid version format: {version}") return True ''', 'auto_fix_script': ''' def fix_manifest(manifest_path): with open(manifest_path) as f: content = f.read() # Add missing keys with defaults if "'name'" not in content and '"name"' not in content: content = "{'name': 'My Module',\n" + content if "'version'" not in content: content += "\\n'version': '1.0'," if "'depends'" not in content: content += "\\n'depends': ['base']," with open(manifest_path, 'w') as f: f.write(content) ''' } output_path = self.guardrails_dir / 'GR-INSTALL-004.yaml' with open(output_path, 'w') as f: yaml.dump(guardrail, f, default_flow_style=False) return guardrail def generate_field_sync_guardrail(self): """ GR-POS-001: POS field synchronization """ guardrail = { 'id': 'GR-POS-001', 'name': 'POS Field Sync Prevention', 'description': 'Prevent POS order/line desync when adding custom fields', 'category': 'field', 'severity': 'CRITICAL', 'background': ''' Common Issue: Adding fields to pos.order.line but forgetting to add export/import in pos.order causes data loss on session closure. Affected Models: - pos.order (parent) - pos.order.line (child) Root Cause: POS uses JSON export/import for order data persistence. Custom fields not included in _export_for_ui() are silently dropped. ''', 'checks': [ { 'name': 'Check POS Line Fields', 'pattern': r'class PosOrderLine.*?:', 'error_message': 'Added field to pos.order.line without updating pos.order export', 'fix': 'Add field to _export_for_ui() in pos.order' } ], 'prevention_script': ''' def check_pos_field_sync(module_path): """Validate POS field synchronization""" pos_order_line_file = module_path / 'models' / 'pos_order_line.py'
Ver en GitHub
Este SKILL.md es muy grande, por eso SkillsMP muestra aqui solo la primera seccion. Ver en GitHub