diff --git a/skills/odoo-accounting-setup/SKILL.md b/skills/odoo-accounting-setup/SKILL.md
new file mode 100644
index 00000000..92d62bf8
--- /dev/null
+++ b/skills/odoo-accounting-setup/SKILL.md
@@ -0,0 +1,105 @@
+---
+name: odoo-accounting-setup
+description: "Expert guide for configuring Odoo Accounting: chart of accounts, journals, fiscal positions, taxes, payment terms, and bank reconciliation."
+risk: safe
+source: "self"
+---
+
+# Odoo Accounting Setup
+
+## Overview
+
+This skill guides functional consultants and business owners through setting up Odoo Accounting correctly from scratch. It covers chart of accounts configuration, journal setup, tax rules, fiscal positions, payment terms, and the bank statement reconciliation workflow.
+
+## When to Use This Skill
+
+- Setting up a new Odoo instance for a company for the first time.
+- Configuring multi-currency or multi-company accounting.
+- Troubleshooting tax calculation or fiscal position mapping errors.
+- Creating payment terms for installment billing (e.g., Net 30, 50% upfront).
+
+## How It Works
+
+1. **Activate**: Mention `@odoo-accounting-setup` and describe your accounting scenario.
+2. **Configure**: Receive step-by-step Odoo menu navigation with exact field values.
+3. **Validate**: Get a checklist to verify your setup is complete and correct.
+
+## Examples
+
+### Example 1: Create a Payment Term (Net 30 with 2% Early Pay Discount)
+
+```text
+Menu: Accounting → Configuration → Payment Terms → New
+
+Name: Net 30 / 2% Early Pay Discount
+Company: [Your Company]
+
+Lines:
+ Line 1:
+ - Due Type: Percent
+ - Value: 100%
+ - Due: 30 days (full balance due in 30 days)
+
+Early Payment Discount (Odoo 16+):
+ Discount %: 2
+ Discount Days: 10
+ Balance Sheet Accounts:
+ - Gain: 4900 Early Payment Discounts Granted
+ - Loss: 5900 Early Payment Discounts Received
+```
+
+> **Note (v16+):** Use the built-in **Early Payment Discount** field instead of the old split-line workaround. Odoo now posts the discount automatically when the customer pays within the discount window and generates correct accounting entries.
+
+### Example 2: Fiscal Position for EU VAT (B2B Intra-Community)
+
+```text
+Menu: Accounting → Configuration → Fiscal Positions → New
+
+Name: EU Intra-Community B2B
+Auto-detection: ON
+ - Country Group: Europe
+ - VAT Required: YES (customer must have EU VAT number)
+
+Tax Mapping:
+ Tax on Sales (21% VAT) → 0% Intra-Community VAT
+ Tax on Purchases → 0% Reverse Charge
+
+Account Mapping:
+ (Leave empty unless your localization requires account remapping)
+```
+
+### Example 3: Reconciliation Model for Bank Fees
+
+```text
+Menu: Accounting → Configuration → Reconciliation Models → New
+
+Name: Bank Fee Auto-Match
+Type: Write-off
+Matching Order: 1
+
+Conditions:
+ - Label Contains: "BANK FEE" OR "SERVICE CHARGE"
+ - Amount Type: Amount is lower than: $50.00
+
+Action:
+ - Account: 6200 Bank Charges
+ - Tax: None
+ - Analytic: Administrative
+```
+
+## Best Practices
+
+- ✅ **Do:** Install your country's **localization module** first (`l10n_us`, `l10n_mx`, etc.) before manually creating accounts — it sets up the correct chart of accounts.
+- ✅ **Do:** Use **Fiscal Positions** to automate B2B vs B2C tax switching — never change taxes manually on individual invoices.
+- ✅ **Do:** Lock accounting periods (Accounting → Actions → Lock Dates) after month-end closing to prevent retroactive edits.
+- ✅ **Do:** Use the **Early Payment Discount** feature (v16+) instead of splitting payment term lines for discount modelling.
+- ❌ **Don't:** Delete journal entries — always reverse them with a credit note or the built-in reversal function.
+- ❌ **Don't:** Mix personal and business transactions in the same journal.
+- ❌ **Don't:** Create manual journal entries to fix bank reconciliation mismatches — use the reconciliation model workflow instead.
+
+## Limitations
+
+- Does not cover **multi-currency revaluation** or foreign exchange gain/loss accounting in depth.
+- **Country-specific e-invoicing** (CFDI, FatturaPA, SAF-T) requires additional localization modules — use `@odoo-l10n-compliance` for those.
+- Payroll accounting integration (salary journals, deduction accounts) is not covered here — use `@odoo-hr-payroll-setup`.
+- Odoo Community Edition does not include the full **lock dates** feature; some controls are Enterprise-only.
diff --git a/skills/odoo-automated-tests/SKILL.md b/skills/odoo-automated-tests/SKILL.md
new file mode 100644
index 00000000..62caaf85
--- /dev/null
+++ b/skills/odoo-automated-tests/SKILL.md
@@ -0,0 +1,124 @@
+---
+name: odoo-automated-tests
+description: "Write and run Odoo automated tests using TransactionCase, HttpCase, and browser tour tests. Covers test data setup, mocking, and CI integration."
+risk: safe
+source: "self"
+---
+
+# Odoo Automated Tests
+
+## Overview
+
+Odoo has a built-in testing framework based on Python's `unittest`. This skill helps you write `TransactionCase` unit tests, `HttpCase` integration tests, and JavaScript tour tests. It also covers running tests in CI pipelines.
+
+## When to Use This Skill
+
+- Writing unit tests for a custom model's business logic.
+- Creating an HTTP test to verify a controller endpoint.
+- Debugging test failures in a CI pipeline.
+- Setting up automated test execution with `--test-enable`.
+
+## How It Works
+
+1. **Activate**: Mention `@odoo-automated-tests` and describe the feature to test.
+2. **Generate**: Get complete test class code with setup, teardown, and assertions.
+3. **Run**: Get the exact `odoo` CLI command to execute your tests.
+
+## Examples
+
+### Example 1: TransactionCase Unit Test (Odoo 15+ pattern)
+
+```python
+# tests/test_hospital_patient.py
+from odoo.tests.common import TransactionCase
+from odoo.tests import tagged
+from odoo.exceptions import ValidationError
+
+@tagged('post_install', '-at_install')
+class TestHospitalPatient(TransactionCase):
+
+ @classmethod
+ def setUpClass(cls):
+ # Use setUpClass for performance — runs once per class, not per test
+ super().setUpClass()
+ cls.Patient = cls.env['hospital.patient']
+ cls.doctor = cls.env['res.users'].browse(cls.env.uid)
+
+ def test_create_patient(self):
+ patient = self.Patient.create({
+ 'name': 'John Doe',
+ 'doctor_id': self.doctor.id,
+ })
+ self.assertEqual(patient.state, 'draft')
+ self.assertEqual(patient.name, 'John Doe')
+
+ def test_confirm_patient(self):
+ patient = self.Patient.create({'name': 'Jane Smith'})
+ patient.action_confirm()
+ self.assertEqual(patient.state, 'confirmed')
+
+ def test_empty_name_raises_error(self):
+ with self.assertRaises(ValidationError):
+ self.Patient.create({'name': ''})
+
+ def test_access_denied_for_other_user(self):
+ # Test security rules by running as a different user
+ other_user = self.env.ref('base.user_demo')
+ with self.assertRaises(Exception):
+ self.Patient.with_user(other_user).create({'name': 'Test'})
+```
+
+> **`setUpClass` vs `setUp`:** Use `setUpClass` (Odoo 15+) for shared test data. It runs once per class and is significantly faster than `setUp` which re-initializes for every single test method.
+
+### Example 2: Run Tests via CLI
+
+```bash
+# Run all tests for a specific module
+./odoo-bin --test-enable --stop-after-init -d my_database -u hospital_management
+
+# Run only tests tagged with a specific tag
+./odoo-bin --test-enable --stop-after-init -d my_database \
+ --test-tags hospital_management
+
+# Run a specific test class
+./odoo-bin --test-enable --stop-after-init -d my_database \
+ --test-tags /hospital_management:TestHospitalPatient
+```
+
+### Example 3: HttpCase for Controller Testing
+
+```python
+from odoo.tests.common import HttpCase
+from odoo.tests import tagged
+
+@tagged('post_install', '-at_install')
+class TestPatientController(HttpCase):
+
+ def test_patient_page_authenticated(self):
+ # Authenticate as a user, not with hardcoded password
+ self.authenticate(self.env.user.login, self.env.user.login)
+ resp = self.url_open('/hospital/patients')
+ self.assertEqual(resp.status_code, 200)
+
+ def test_patient_page_redirects_unauthenticated(self):
+ # No authenticate() call = public/anonymous user
+ resp = self.url_open('/hospital/patients', allow_redirects=False)
+ self.assertIn(resp.status_code, [301, 302, 403])
+```
+
+## Best Practices
+
+- ✅ **Do:** Use `setUpClass()` with `cls.env` instead of `setUp()` — it is dramatically faster for large test suites.
+- ✅ **Do:** Use `@tagged('post_install', '-at_install')` to run tests after all modules are installed.
+- ✅ **Do:** Test both the happy path and error conditions (`ValidationError`, `AccessError`, `UserError`).
+- ✅ **Do:** Use `self.with_user(user)` to test access control without calling `sudo()`.
+- ❌ **Don't:** Use a production database for tests — always use a dedicated test database.
+- ❌ **Don't:** Rely on test execution order — each `TransactionCase` test is rolled back in isolation.
+- ❌ **Don't:** Hardcode passwords in `HttpCase.authenticate()` — use `self.env.user.login` or a fixture user.
+
+## Limitations
+
+- **JavaScript tour tests** require a running browser (via `phantomjs` or `Chrome headless`) and a live Odoo server — not covered in depth here.
+- `HttpCase` tests are significantly slower than `TransactionCase` — use them only for controller/route verification.
+- Does not cover **mocking external services** (e.g., mocking an SMTP server or payment gateway in tests).
+- Test isolation is at the **transaction level**, not database level — tests that commit data (e.g., via `cr.commit()`) can leak state between tests.
diff --git a/skills/odoo-backup-strategy/SKILL.md b/skills/odoo-backup-strategy/SKILL.md
new file mode 100644
index 00000000..c984919d
--- /dev/null
+++ b/skills/odoo-backup-strategy/SKILL.md
@@ -0,0 +1,112 @@
+---
+name: odoo-backup-strategy
+description: "Complete Odoo backup and restore strategy: database dumps, filestore backup, automated scheduling, cloud storage upload, and tested restore procedures."
+risk: safe
+source: "self"
+---
+
+# Odoo Backup Strategy
+
+## Overview
+
+A complete Odoo backup must include both the **PostgreSQL database** and the **filestore** (attachments, images). This skill covers manual and automated backup procedures, offsite storage, and the correct restore sequence to bring a down Odoo instance back online.
+
+## When to Use This Skill
+
+- Setting up a backup strategy for a production Odoo instance.
+- Automating daily backups with shell scripts and cron.
+- Restoring Odoo after a server failure or data corruption event.
+- Diagnosing a failed backup or corrupt restore.
+
+## How It Works
+
+1. **Activate**: Mention `@odoo-backup-strategy` and describe your server environment.
+2. **Generate**: Receive a complete backup script tailored to your setup.
+3. **Restore**: Get step-by-step restore instructions for any failure scenario.
+
+## Examples
+
+### Example 1: Manual Database + Filestore Backup
+
+```bash
+#!/bin/bash
+# backup_odoo.sh
+
+DATE=$(date +%Y%m%d_%H%M%S)
+DB_NAME="odoo"
+DB_USER="odoo"
+FILESTORE_PATH="/var/lib/odoo/.local/share/Odoo/filestore/$DB_NAME"
+BACKUP_DIR="/backups/odoo"
+
+mkdir -p "$BACKUP_DIR"
+
+# Step 1: Dump the database
+pg_dump -U $DB_USER -Fc $DB_NAME > "$BACKUP_DIR/db_$DATE.dump"
+
+# Step 2: Archive the filestore
+tar -czf "$BACKUP_DIR/filestore_$DATE.tar.gz" -C "$FILESTORE_PATH" .
+
+echo "✅ Backup complete: db_$DATE.dump + filestore_$DATE.tar.gz"
+```
+
+### Example 2: Automate with Cron (daily at 2 AM)
+
+```bash
+# Run: crontab -e
+# Add this line:
+0 2 * * * /opt/scripts/backup_odoo.sh >> /var/log/odoo_backup.log 2>&1
+```
+
+### Example 3: Upload to S3 (after backup)
+
+```bash
+# Add to backup script after tar command:
+aws s3 cp "$BACKUP_DIR/db_$DATE.dump" s3://my-odoo-backups/db/
+aws s3 cp "$BACKUP_DIR/filestore_$DATE.tar.gz" s3://my-odoo-backups/filestore/
+
+# Optional: Delete local backups older than 7 days
+find "$BACKUP_DIR" -type f -mtime +7 -delete
+```
+
+### Example 4: Full Restore Procedure
+
+```bash
+# Step 1: Stop Odoo
+docker compose stop odoo # or: systemctl stop odoo
+
+# Step 2: Recreate and restore the database
+# (--clean alone fails if the DB doesn't exist; drop and recreate first)
+dropdb -U odoo odoo 2>/dev/null || true
+createdb -U odoo odoo
+pg_restore -U odoo -d odoo db_YYYYMMDD_HHMMSS.dump
+
+# Step 3: Restore the filestore
+FILESTORE=/var/lib/odoo/.local/share/Odoo/filestore/odoo
+rm -rf "$FILESTORE"/*
+tar -xzf filestore_YYYYMMDD_HHMMSS.tar.gz -C "$FILESTORE"/
+
+# Step 4: Restart Odoo
+docker compose start odoo
+
+# Step 5: Verify — open Odoo in the browser and check:
+# - Can you log in?
+# - Are recent records visible?
+# - Are file attachments loading?
+```
+
+## Best Practices
+
+- ✅ **Do:** Test restores monthly in a staging environment — a backup you've never restored is not a backup.
+- ✅ **Do:** Follow the **3-2-1 rule**: 3 copies, 2 different media types, 1 offsite copy (e.g., S3 or a remote server).
+- ✅ **Do:** Back up **immediately before every Odoo upgrade** — this is your rollback point.
+- ✅ **Do:** Verify backup integrity: `pg_restore --list backup.dump` should complete without errors.
+- ❌ **Don't:** Back up only the database without the filestore — all attachments and images will be missing after a restore.
+- ❌ **Don't:** Store backups on the same disk or same server as Odoo — a disk or server failure destroys both.
+- ❌ **Don't:** Run `pg_restore --clean` against a non-existent database — always create the database first.
+
+## Limitations
+
+- Does not cover **Odoo.sh built-in backups** — Odoo.sh has its own backup system accessible from the dashboard.
+- This script assumes a **single-database** Odoo setup. Multi-database instances require looping over all databases.
+- Filestore path may differ between installations (Docker volume vs. bare-metal). Always verify the path with `odoo-bin shell` before running a restore.
+- Large filestores (100GB+) may require incremental backup tools like `rsync` or `restic` rather than full `tar.gz` archives.
diff --git a/skills/odoo-docker-deployment/SKILL.md b/skills/odoo-docker-deployment/SKILL.md
new file mode 100644
index 00000000..77ee4695
--- /dev/null
+++ b/skills/odoo-docker-deployment/SKILL.md
@@ -0,0 +1,139 @@
+---
+name: odoo-docker-deployment
+description: "Production-ready Docker and docker-compose setup for Odoo with PostgreSQL, persistent volumes, environment-based configuration, and Nginx reverse proxy."
+risk: safe
+source: "self"
+---
+
+# Odoo Docker Deployment
+
+## Overview
+
+This skill provides a complete, production-ready Docker setup for Odoo, including PostgreSQL, persistent file storage, environment variable configuration, and an optional Nginx reverse proxy with SSL. It covers both development and production configurations.
+
+## When to Use This Skill
+
+- Spinning up a local Odoo development environment with Docker.
+- Deploying Odoo to a VPS or cloud server (AWS, DigitalOcean, etc.).
+- Troubleshooting Odoo container startup failures or database connection errors.
+- Adding a reverse proxy with SSL to an existing Odoo Docker setup.
+
+## How It Works
+
+1. **Activate**: Mention `@odoo-docker-deployment` and describe your deployment scenario.
+2. **Generate**: Receive a complete `docker-compose.yml` and `odoo.conf` ready to run.
+3. **Debug**: Describe your container error and get a diagnosis with a fix.
+
+## Examples
+
+### Example 1: Production docker-compose.yml
+
+```yaml
+# Note: The top-level 'version' key is deprecated in Docker Compose v2+
+# and can be safely omitted. Remove it to avoid warnings.
+
+services:
+ db:
+ image: postgres:15
+ restart: always
+ environment:
+ POSTGRES_DB: odoo
+ POSTGRES_USER: odoo
+ POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
+ volumes:
+ - postgres-data:/var/lib/postgresql/data
+ networks:
+ - odoo-net
+
+ odoo:
+ image: odoo:17.0
+ restart: always
+ depends_on:
+ db:
+ condition: service_healthy
+ ports:
+ - "8069:8069"
+ - "8072:8072" # Longpolling for live chat / bus
+ environment:
+ HOST: db
+ USER: odoo
+ PASSWORD: ${POSTGRES_PASSWORD}
+ volumes:
+ - odoo-web-data:/var/lib/odoo
+ - ./addons:/mnt/extra-addons # Custom modules
+ - ./odoo.conf:/etc/odoo/odoo.conf
+ networks:
+ - odoo-net
+
+volumes:
+ postgres-data:
+ odoo-web-data:
+
+networks:
+ odoo-net:
+```
+
+### Example 2: odoo.conf
+
+```ini
+[options]
+admin_passwd = ${ODOO_MASTER_PASSWORD} ; set via env or .env file
+db_host = db
+db_port = 5432
+db_user = odoo
+db_password = ${POSTGRES_PASSWORD} ; set via env or .env file
+
+; addons_path inside the official Odoo Docker image (Debian-based)
+addons_path = /mnt/extra-addons,/usr/lib/python3/dist-packages/odoo/addons
+
+logfile = /var/log/odoo/odoo.log
+log_level = warn
+
+; Worker tuning for a 4-core / 8GB server:
+workers = 9 ; (CPU cores × 2) + 1
+max_cron_threads = 2
+limit_memory_soft = 1610612736 ; 1.5 GB — soft kill threshold
+limit_memory_hard = 2147483648 ; 2.0 GB — hard kill threshold
+limit_time_cpu = 600
+limit_time_real = 1200
+limit_request = 8192
+```
+
+### Example 3: Common Commands
+
+```bash
+# Start all services in background
+docker compose up -d
+
+# Stream Odoo logs in real time
+docker compose logs -f odoo
+
+# Restart Odoo only (not DB — avoids data risk)
+docker compose restart odoo
+
+# Stop all services
+docker compose down
+
+# Backup the database to a local SQL dump
+docker compose exec db pg_dump -U odoo odoo > backup_$(date +%Y%m%d).sql
+
+# Update a custom module without restarting the server
+docker compose exec odoo odoo -d odoo --update my_module --stop-after-init
+```
+
+## Best Practices
+
+- ✅ **Do:** Store all secrets in a `.env` file and reference them with `${VAR}` — never hardcode passwords in `docker-compose.yml`.
+- ✅ **Do:** Use `depends_on: condition: service_healthy` with a PostgreSQL healthcheck to prevent Odoo starting before the DB is ready.
+- ✅ **Do:** Put Nginx in front of Odoo for SSL termination (Let's Encrypt / Certbot) — never expose Odoo directly on port 80/443.
+- ✅ **Do:** Set `workers = (CPU cores × 2) + 1` in `odoo.conf` — `workers = 0` uses single-threaded mode and blocks all users.
+- ❌ **Don't:** Expose port 5432 (PostgreSQL) to the public internet — keep it on the internal Docker network only.
+- ❌ **Don't:** Use the `latest` or `17` Docker image tags in production — always pin to a specific patch-level tag (e.g., `odoo:17.0`).
+- ❌ **Don't:** Mount `odoo.conf` and rely on it for secrets in CI/CD — use Docker secrets or environment variables instead.
+
+## Limitations
+
+- This skill covers **self-hosted Docker deployments** — Odoo.sh (cloud-managed hosting) has a completely different deployment model.
+- **Horizontal scaling** (multiple Odoo containers behind a load balancer) requires shared filestore (NFS or S3-compatible storage) not covered here.
+- Does not include an Nginx configuration template — consult the [official Odoo Nginx docs](https://www.odoo.com/documentation/17.0/administration/install/deploy.html) for the full reverse proxy config.
+- The `addons_path` inside the Docker image may change with new base image versions — always verify after upgrading the Odoo image.
diff --git a/skills/odoo-ecommerce-configurator/SKILL.md b/skills/odoo-ecommerce-configurator/SKILL.md
new file mode 100644
index 00000000..b9e153d9
--- /dev/null
+++ b/skills/odoo-ecommerce-configurator/SKILL.md
@@ -0,0 +1,133 @@
+---
+name: odoo-ecommerce-configurator
+description: "Expert guide for Odoo eCommerce and Website: product catalog, payment providers, shipping methods, SEO, and order-to-fulfillment workflow."
+risk: safe
+source: "self"
+---
+
+# Odoo eCommerce Configurator
+
+## Overview
+
+This skill helps you set up and optimize an Odoo-powered online store. It covers product publishing, payment gateway integration, shipping carrier configuration, cart and checkout customization, and the workflow from online order to warehouse fulfillment.
+
+## When to Use This Skill
+
+- Launching an Odoo eCommerce store for the first time.
+- Integrating a payment provider (Stripe, PayPal, Adyen).
+- Configuring shipping rates with carrier integration (UPS, FedEx, DHL).
+- Optimizing product pages for SEO with Odoo Website tools.
+
+## How It Works
+
+1. **Activate**: Mention `@odoo-ecommerce-configurator` and describe your store scenario.
+2. **Configure**: Receive step-by-step Odoo eCommerce setup with menu paths.
+3. **Optimize**: Get SEO, conversion, and catalog best practices.
+
+## Examples
+
+### Example 1: Publish a Product to the Website
+
+```text
+Menu: Website → eCommerce → Products → Select Product
+
+Fields to complete for a great product listing:
+ Name: Ergonomic Mesh Office Chair (keyword-rich)
+ Internal Reference: CHAIR-MESH-001 (required for inventory)
+ Sales Price: $299.00
+ Website Description (website tab): 150–300 words of unique content
+
+Publishing:
+ Toggle "Published" in the top-right corner of the product form
+ or via: Website → Go to Website → Toggle "Published" button
+
+SEO (website tab → SEO section):
+ Page Title: Ergonomic Mesh Chair | Office Chairs | YourStore
+ Meta Description: Discover the most comfortable ergonomic mesh office
+ chair, designed for all-day support... (≤160 chars)
+
+Website tab:
+ Can be Sold: YES
+ Website: yourstore.com (if running multiple websites)
+```
+
+### Example 2: Configure Stripe Payment Provider
+
+```text
+Menu: Website → Configuration → Payment Providers → Stripe → Configure
+(or: Accounting → Configuration → Payment Providers → Stripe)
+
+State: Test (use Test mode until fully validated, then switch to Enabled)
+
+Credentials (from your Stripe Dashboard → Developers → API Keys):
+ Publishable Key: pk_live_XXXXXXXX
+ Secret Key: sk_live_XXXXXXXX (store securely; never expose client-side)
+
+Payment Journal: Bank (USD)
+Capture Mode: Automatic (charge card immediately on order confirmation)
+ or Manual (authorize only; charge later on fulfillment)
+
+Webhook:
+ Add Odoo's webhook URL in Stripe Dashboard → Webhooks
+ URL: https://yourstore.com/payment/stripe/webhook
+ Events: payment_intent.succeeded, payment_intent.payment_failed
+```
+
+### Example 3: Set Up Flat Rate Shipping with Free Threshold
+
+```text
+Menu: Inventory → Configuration → Delivery Methods → New
+
+Name: Standard Shipping (3–5 business days)
+Provider: Fixed Price
+Delivery Product: [Shipping] Standard (used for invoicing)
+
+Pricing:
+ Price: $9.99
+ ☑ Free if order amount is above: $75.00
+
+Availability:
+ Countries: United States
+ States: All states
+
+Publish to website:
+ ☑ Published (visible to customers at checkout)
+```
+
+### Example 4: Set Up Abandoned Cart Recovery
+
+```text
+Menu: Email Marketing → Mailing Lists → (create a list if needed)
+
+For automated abandoned cart emails in Odoo 16/17:
+Menu: Marketing → Marketing Automation → New Campaign
+
+Trigger: Odoo record updated
+Model: eCommerce Cart (sale.order with state = 'draft')
+Filter: Cart not updated in 1 hour AND not confirmed
+
+Actions:
+ 1. Wait 1 hour
+ 2. Send Email: "You left something behind!" (use a recovery email template)
+ 3. Wait 24 hours
+ 4. Send Email: "Last chance — items selling fast"
+
+Note: Some Odoo hosting plans may require "Email Marketing" app enabled.
+```
+
+## Best Practices
+
+- ✅ **Do:** Use **Product Variants** (color, size) instead of duplicate products — cleaner catalog and shared inventory tracking.
+- ✅ **Do:** Enable **HTTPS** (SSL certificate) via your hosting provider and set HSTS in Website → Settings → Security.
+- ✅ **Do:** Set up **Abandoned Cart Recovery** using Marketing Automation or a scheduled email sequence.
+- ✅ **Do:** Add a **Stripe webhook** so Odoo is notified of payment events in real time — without it, failed payments may not update correctly.
+- ❌ **Don't:** Leave the payment provider in **Test mode** in production — no real charges will be processed.
+- ❌ **Don't:** Publish products without an **Internal Reference (SKU)** — it breaks inventory tracking and order fulfillment.
+- ❌ **Don't:** Use the same Stripe key for Test and Production environments — always rotate to live keys before going live.
+
+## Limitations
+
+- **Carrier integration** (live UPS/FedEx rate calculation) requires the specific carrier connector module (e.g., `delivery_ups`) and a carrier account API key.
+- Does not cover **multi-website** configuration — running separate storefronts with different pricelists and languages requires Enterprise.
+- **B2B eCommerce** (customer login required, custom catalog and prices per customer) has additional configuration steps not fully covered here.
+- Odoo eCommerce does not support **subscription billing** natively — that requires the Enterprise **Subscriptions** module.
diff --git a/skills/odoo-edi-connector/SKILL.md b/skills/odoo-edi-connector/SKILL.md
new file mode 100644
index 00000000..3d5bfbb8
--- /dev/null
+++ b/skills/odoo-edi-connector/SKILL.md
@@ -0,0 +1,111 @@
+---
+name: odoo-edi-connector
+description: "Guide for implementing EDI (Electronic Data Interchange) with Odoo: X12, EDIFACT document mapping, partner onboarding, and automated order processing."
+---
+
+# Odoo EDI Connector
+
+## Overview
+
+Electronic Data Interchange (EDI) is the standard for automated B2B document exchange — purchase orders, invoices, ASNs (Advance Shipping Notices). This skill guides you through mapping EDI transactions (ANSI X12 or EDIFACT) to Odoo business objects, setting up trading partner configurations, and automating inbound/outbound document flows.
+
+## When to Use This Skill
+
+- A retail partner requires EDI 850 (Purchase Orders) to do business with you.
+- You need to send EDI 856 (ASN) when goods are shipped.
+- Automating EDI 810 (Invoice) generation from Odoo confirmed deliveries.
+- Mapping EDI fields to Odoo fields for a new trading partner.
+
+## How It Works
+
+1. **Activate**: Mention `@odoo-edi-connector` and specify the EDI transaction set and trading partner.
+2. **Map**: Receive a complete field mapping table between EDI segments and Odoo fields.
+3. **Automate**: Get Python code to parse incoming EDI files and create Odoo records.
+
+## EDI ↔ Odoo Object Mapping
+
+| EDI Transaction | Odoo Object |
+|---|---|
+| 850 Purchase Order | `sale.order` (inbound customer PO) |
+| 855 PO Acknowledgment | Confirmation email / SO confirmation |
+| 856 ASN (Advance Ship Notice) | `stock.picking` (delivery order) |
+| 810 Invoice | `account.move` (customer invoice) |
+| 846 Inventory Inquiry | `product.product` stock levels |
+| 997 Functional Acknowledgment | Automated receipt confirmation |
+
+## Examples
+
+### Example 1: Parse EDI 850 and Create Odoo Sale Order (Python)
+
+```python
+from pyx12 import x12file # pip install pyx12
+
+import xmlrpc.client
+
+odoo_url = "https://myodoo.example.com"
+db, uid, pwd = "my_db", 2, "api_key"
+models = xmlrpc.client.ServerProxy(f"{odoo_url}/xmlrpc/2/object")
+
+def process_850(edi_file_path):
+ """Parse X12 850 Purchase Order and create Odoo Sale Order"""
+ with x12file.X12File(edi_file_path) as f:
+ for transaction in f.get_transaction_sets():
+ # Extract header info (BEG segment)
+ po_number = transaction['BEG'][3] # Purchase Order Number
+ po_date = transaction['BEG'][5] # Purchase Order Date
+
+ # Extract partner (N1 segment — Buyer)
+ partner_name = transaction['N1'][2]
+
+ # Find partner in Odoo
+ partner = models.execute_kw(db, uid, pwd, 'res.partner', 'search',
+ [[['name', 'ilike', partner_name]]])
+ partner_id = partner[0] if partner else False
+
+ # Extract line items (PO1 segments)
+ order_lines = []
+ for po1 in transaction.get_segments('PO1'):
+ sku = po1[7] # Product ID
+ qty = float(po1[2])
+ price = float(po1[4])
+
+ product = models.execute_kw(db, uid, pwd, 'product.product', 'search',
+ [[['default_code', '=', sku]]])
+ if product:
+ order_lines.append((0, 0, {
+ 'product_id': product[0],
+ 'product_uom_qty': qty,
+ 'price_unit': price,
+ }))
+
+ # Create Sale Order
+ if partner_id and order_lines:
+ models.execute_kw(db, uid, pwd, 'sale.order', 'create', [{
+ 'partner_id': partner_id,
+ 'client_order_ref': po_number,
+ 'order_line': order_lines,
+ }])
+```
+
+### Example 2: Send EDI 997 Acknowledgment
+
+```python
+def generate_997(isa_control, gs_control, transaction_control):
+ """Generate a functional acknowledgment for received EDI"""
+ return f"""ISA*00* *00* *ZZ*YOURISAID *ZZ*PARTNERISAID *{today}*1200*^*00501*{isa_control}*0*P*>~
+GS*FA*YOURGID*PARTNERGID*{today}*1200*{gs_control}*X*005010X231A1~
+ST*997*0001~
+AK1*PO*{gs_control}~
+AK9*A*1*1*1~
+SE*4*0001~
+GE*1*{gs_control}~
+IEA*1*{isa_control}~"""
+```
+
+## Best Practices
+
+- ✅ **Do:** Store every raw EDI transaction in an audit log table before processing.
+- ✅ **Do:** Always send a **997 Functional Acknowledgment** within 24 hours of receiving a transaction.
+- ✅ **Do:** Negotiate a test cycle with trading partners before going live — use test ISA qualifier `T`.
+- ❌ **Don't:** Process EDI files synchronously in web requests — queue them for async processing.
+- ❌ **Don't:** Hardcode trading partner qualifiers — store them in a configuration table per partner.
diff --git a/skills/odoo-hr-payroll-setup/SKILL.md b/skills/odoo-hr-payroll-setup/SKILL.md
new file mode 100644
index 00000000..62b55bf5
--- /dev/null
+++ b/skills/odoo-hr-payroll-setup/SKILL.md
@@ -0,0 +1,106 @@
+---
+name: odoo-hr-payroll-setup
+description: "Expert guide for Odoo HR and Payroll: salary structures, payslip rules, leave policies, employee contracts, and payroll journal entries."
+risk: safe
+source: "self"
+---
+
+# Odoo HR & Payroll Setup
+
+## Overview
+
+This skill guides HR managers and payroll accountants through setting up Odoo HR and Payroll correctly. It covers salary structure creation with Python-computed rules, time-off policies, employee contract types, and the payroll → accounting journal posting flow.
+
+## When to Use This Skill
+
+- Creating a salary structure with gross pay, deductions, and net pay.
+- Configuring annual leave, sick leave, and public holiday policies.
+- Troubleshooting incorrect payslip amounts or missing rule contributions.
+- Setting up the payroll journal to correctly post to accounting.
+
+## How It Works
+
+1. **Activate**: Mention `@odoo-hr-payroll-setup` and describe your payroll scenario.
+2. **Configure**: Receive step-by-step setup for salary rules and leave allocation.
+3. **Debug**: Paste a salary rule or payslip issue and receive a root cause analysis.
+
+## Examples
+
+### Example 1: Salary Structure with Deductions
+
+```text
+Menu: Payroll → Configuration → Salary Structures → New
+
+Name: US Employee Monthly
+Payslip Code: MONTHLY
+
+Rules (executed top-to-bottom — order matters):
+ Code | Name | Formula | Category
+ ----- | ---------------------- | ------------------------------ | ---------
+ BASIC | Basic Wage | contract.wage | Basic
+ GROSS | Gross | BASIC | Gross
+ SS | Social Security (6.2%) | -GROSS * 0.062 | Deduction
+ MED | Medicare (1.45%) | -GROSS * 0.0145 | Deduction
+ FIT | Federal Income Tax | -GROSS * inputs.FIT_RATE.amount| Deduction
+ NET | Net Salary | GROSS + SS + MED + FIT | Net
+```
+
+> **Federal Income Tax:** The standard Odoo US localization does not expose a single `l10n_us_w4_rate` field. Use an **input** (salary input type) to pass the withholding rate per employee, or install a community US payroll module (OCA `l10n_us_hr_payroll`) which handles W4 filing status properly.
+
+### Example 2: Configure a Time Off Type
+
+```text
+Menu: Time Off → Configuration → Time Off Types → New
+
+Name: Annual Leave / PTO
+Approval: Time Off Officer
+Leave Validation: Time Off Officer (single approver)
+ or: "Both" for HR + Manager double approval
+
+Allocation:
+ ☑ Employees can allocate time off themselves
+ Requires approval: No
+
+Negative Balance: Not allowed (employees cannot go negative)
+
+Then create initial allocations:
+Menu: Time Off → Managers → Allocations → New
+ Employee: [Each employee]
+ Time Off Type: Annual Leave / PTO
+ Allocation: 15 days
+ Validity: Jan 1 – Dec 31 [current year]
+```
+
+### Example 3: Payroll Journal Entry Result
+
+```text
+After validating a payroll batch, Odoo generates:
+
+Debit Salary Expense Account $5,000.00
+ Credit Social Security Payable $310.00
+ Credit Medicare Payable $72.50
+ Credit Federal Tax Payable (varies)
+ Credit Salary Payable $4,617.50+
+
+When net salary is paid:
+Debit Salary Payable $4,617.50
+ Credit Bank Account $4,617.50
+
+Employer taxes (e.g., FUTA, SUTA) post as separate journal entries.
+```
+
+## Best Practices
+
+- ✅ **Do:** Install your country's **payroll localization** (`l10n_us_hr_payroll`, `l10n_mx_hr_payroll`, etc.) before building custom rules — it provides pre-configured tax structures.
+- ✅ **Do:** Use **salary rule inputs** (`inputs.ALLOWANCE.amount`) to pass variable values (bonuses, allowances, withholding rates) rather than hardcoding them in the rule formula.
+- ✅ **Do:** Archive old salary structures rather than deleting them — active payslips reference their structure and will break if the structure is deleted.
+- ✅ **Do:** Always set an active **Employee Contract** with correct dates and salary before generating payslips.
+- ❌ **Don't:** Manually edit posted payslips — cancel and regenerate the payslip batch if corrections are needed.
+- ❌ **Don't:** Use `contract.wage` in deduction rules without verifying whether the structure is monthly or annual — always check the contract wage period.
+
+## Limitations
+
+- **Odoo Payroll is Enterprise-only** — the Community Edition does not include the Payroll module (`hr_payroll`).
+- US-specific compliance (W2, 941, state SUI/SDI filing) requires additional modules beyond the base localization; Odoo does not generate tax filings directly.
+- Does not cover **multi-country payroll** (employees in different countries require separate structures and localizations).
+- **Expense reimbursements** via payslip (e.g., mileage, home office) require a custom salary rule input and are not covered in standard HR Payroll documentation.
diff --git a/skills/odoo-inventory-optimizer/SKILL.md b/skills/odoo-inventory-optimizer/SKILL.md
new file mode 100644
index 00000000..62581b16
--- /dev/null
+++ b/skills/odoo-inventory-optimizer/SKILL.md
@@ -0,0 +1,111 @@
+---
+name: odoo-inventory-optimizer
+description: "Expert guide for Odoo Inventory: stock valuation (FIFO/AVCO), reordering rules, putaway strategies, routes, and multi-warehouse configuration."
+risk: safe
+source: "self"
+---
+
+# Odoo Inventory Optimizer
+
+## Overview
+
+This skill helps you configure and optimize Odoo Inventory for accuracy, efficiency, and traceability. It covers stock valuation methods, reordering rules, putaway strategies, warehouse routes, and multi-step flows (receive → quality → store).
+
+## When to Use This Skill
+
+- Choosing and configuring FIFO vs AVCO stock valuation.
+- Setting up minimum stock reordering rules to avoid stockouts.
+- Designing a multi-step warehouse flow (2-step receipt, 3-step delivery).
+- Configuring putaway rules to direct products to specific storage locations.
+- Troubleshooting negative stock, incorrect valuation, or missing moves.
+
+## How It Works
+
+1. **Activate**: Mention `@odoo-inventory-optimizer` and describe your warehouse scenario.
+2. **Configure**: Receive step-by-step configuration instructions with exact Odoo menu paths.
+3. **Optimize**: Get recommendations for reordering rules and stock accuracy improvements.
+
+## Examples
+
+### Example 1: Enable FIFO Stock Valuation
+
+```text
+Menu: Inventory → Configuration → Settings
+
+Enable: Storage Locations
+Enable: Multi-Step Routes
+Costing Method: (set per Product Category, not globally)
+
+Menu: Inventory → Configuration → Product Categories → Edit
+
+ Category: All / Physical Goods
+ Costing Method: First In First Out (FIFO)
+ Inventory Valuation: Automated
+ Account Stock Valuation: [Balance Sheet inventory account]
+ Account Stock Input: [Stock Received Not Billed]
+ Account Stock Output: [Stock Delivered Not Invoiced]
+```
+
+### Example 2: Set Up a Min/Max Reordering Rule
+
+```text
+Menu: Inventory → Operations → Replenishment → New
+
+Product: Office Paper A4
+Location: WH/Stock
+Min Qty: 100 (trigger reorder when stock falls below this)
+Max Qty: 500 (purchase up to this quantity)
+Multiple Qty: 50 (always order in multiples of 50)
+Route: Buy (triggers a Purchase Order automatically)
+ or Manufacture (triggers a Manufacturing Order)
+```
+
+### Example 3: Configure Putaway Rules
+
+```text
+Menu: Inventory → Configuration → Putaway Rules → New
+
+Purpose: Direct products from WH/Input to specific bin locations
+
+Rules:
+ Product Category: Refrigerated Goods
+ → Location: WH/Stock/Cold Storage
+
+ Product: Laptop Model X
+ → Location: WH/Stock/Electronics/Shelf A
+
+ (leave Product blank to apply the rule to an entire category)
+
+Result: When a receipt is validated, Odoo automatically suggests
+the correct destination location per product or category.
+```
+
+### Example 4: Configure 3-Step Warehouse Delivery
+
+```text
+Menu: Inventory → Configuration → Warehouses → [Your Warehouse]
+
+Outgoing Shipments: Pick + Pack + Ship (3 steps)
+
+Operations created automatically:
+ PICK — Move goods from storage shelf to packing area
+ PACK — Package items and print shipping label
+ OUT — Hand off to carrier / mark as shipped
+```
+
+## Best Practices
+
+- ✅ **Do:** Use **Lots/Serial Numbers** for high-value or regulated items (medical devices, electronics).
+- ✅ **Do:** Run a **physical inventory adjustment** at least quarterly (Inventory → Operations → Physical Inventory) to correct drift.
+- ✅ **Do:** Set reordering rules on fast-moving items so purchase orders are generated automatically.
+- ✅ **Do:** Enable **Putaway Rules** on warehouses with multiple storage zones — it eliminates manual location selection errors.
+- ❌ **Don't:** Switch stock valuation method (FIFO ↔ AVCO) after recording transactions — it produces incorrect historical cost data.
+- ❌ **Don't:** Use "Update Quantity" to fix stock errors — always use Inventory Adjustments to maintain a proper audit trail.
+- ❌ **Don't:** Mix product categories with different costing methods in the same storage location without understanding the valuation impact.
+
+## Limitations
+
+- **Serial number tracking** at the individual unit level (SN per line) adds significant UI overhead; test performance with large volumes before enabling.
+- Does not cover **landed costs** (import duties, freight allocation to product cost) — that requires the `stock_landed_costs` module.
+- **Cross-warehouse stock transfers** have routing complexities (transit locations, intercompany invoicing) not fully covered here.
+- Automated inventory valuation requires the **Accounting** module; Community Edition installations without it cannot post stock journal entries.
diff --git a/skills/odoo-l10n-compliance/SKILL.md b/skills/odoo-l10n-compliance/SKILL.md
new file mode 100644
index 00000000..2223d94a
--- /dev/null
+++ b/skills/odoo-l10n-compliance/SKILL.md
@@ -0,0 +1,101 @@
+---
+name: odoo-l10n-compliance
+description: "Country-specific Odoo localization: tax configuration, e-invoicing (CFDI, FatturaPA, SAF-T), fiscal reporting, and country chart of accounts setup."
+---
+
+# Odoo Localization & Compliance (l10n)
+
+## Overview
+
+Odoo provides localization modules (`l10n_*`) for 80+ countries that configure the correct chart of accounts, tax types, and fiscal reporting. This skill helps you install and configure the right localization, set up country-specific e-invoicing (Mexico CFDI, Italy FatturaPA, Poland SAF-T), and ensure fiscal compliance.
+
+## When to Use This Skill
+
+- Setting up Odoo for a company in a specific country (Mexico, Italy, Spain, US, etc.).
+- Configuring country-required e-invoicing (electronic invoice submission to tax authorities).
+- Setting up VAT/GST/IVA tax rules with correct fiscal positions.
+- Generating required fiscal reports (VAT return, SAF-T, DIAN report).
+
+## How It Works
+
+1. **Activate**: Mention `@odoo-l10n-compliance` and specify your country and Odoo version.
+2. **Install**: Get the exact localization module and configuration steps.
+3. **Configure**: Receive tax code setup, fiscal position rules, and reporting guidance.
+
+## Country Localization Modules
+
+| Country | Module | Key Features |
+|---|---|---|
+| 🇺🇸 USA | `l10n_us` | GAAP CoA, Payroll (ADP bridge), 1099 reporting |
+| 🇲🇽 Mexico | `l10n_mx_edi` | CFDI 4.0 e-invoicing, SAT integration, IEPS tax |
+| 🇪🇸 Spain | `l10n_es` | SII real-time VAT, Modelo 303/390, AEAT |
+| 🇮🇹 Italy | `l10n_it_edi` | FatturaPA XML, SDI submission, reverse charge |
+| 🇵🇱 Poland | `l10n_pl` | SAF-T JPK_FA, VAT-7 return |
+| 🇧🇷 Brazil | `l10n_br` | NF-e, NFS-e, SPED, ICMS/PIS/COFINS |
+| 🇩🇪 Germany | `l10n_de` | SKR03/SKR04 CoA, DATEV export, UStVA |
+| 🇨🇴 Colombia | `l10n_co_edi` | DIAN e-invoicing, UBL 2.1 |
+
+## Examples
+
+### Example 1: Configure Mexico CFDI 4.0
+
+```
+Step 1: Install module
+ Apps → Search "Mexico" → Install "Mexico - Accounting"
+ Also install: "Mexico - Electronic Invoicing" (l10n_mx_edi)
+
+Step 2: Configure Company
+ Settings → Company → [Your Company]
+ Country: Mexico
+ RFC: Your RFC number (tax ID)
+ Company Type: Moral Person or Physical Person
+
+Step 3: Upload SAT Certificates
+ Accounting → Configuration → Certificates → New
+ CSD Certificate (.cer file from SAT)
+ Private Key (.key file from SAT)
+ Password: Your FIEL password
+
+Step 4: Issue a CFDI Invoice
+ Create invoice → Confirm → CFDI XML generated automatically
+ Sent to SAT → Receive UUID (folio fiscal)
+ PDF includes QR code + UUID for buyer verification
+```
+
+### Example 2: EU Intra-Community VAT Setup (Any EU Country)
+
+```
+Menu: Accounting → Configuration → Taxes → New
+
+Tax Name: EU Intra-Community Sales (0%)
+Tax Type: Sales
+Tax Scope: Services or Goods
+Tax Computation: Fixed
+Amount: 0%
+Tax Group: Intra-Community
+
+Label on Invoice: "Intra-Community Supply - VAT Exempt per Art. 138 VAT Directive"
+
+Fiscal Position (created separately):
+ Name: EU B2B Intra-Community
+ Auto-detect: Country Group = Europe + VAT Required = YES
+ Tax Mapping: Standard VAT Rate → 0% Intra-Community
+```
+
+### Example 3: Install and Validate a Localization
+
+```bash
+# Install via CLI (if module not in Apps)
+./odoo-bin -d mydb --stop-after-init -i l10n_mx_edi
+
+# Verify in Odoo:
+# Apps → Installed → Search "l10n_mx" → Should show as Installed
+```
+
+## Best Practices
+
+- ✅ **Do:** Install the localization module **before** creating any accounting entries — it sets up the correct accounts.
+- ✅ **Do:** Use **Fiscal Positions** to automate tax switching for international customers (B2B vs B2C, domestic vs export).
+- ✅ **Do:** Test e-invoicing in the **SAT/tax authority test environment** before going live.
+- ❌ **Don't:** Manually create a chart of accounts if a localization module exists for your country.
+- ❌ **Don't:** Mix localization tax accounts with custom accounts — it breaks fiscal reports.
diff --git a/skills/odoo-manufacturing-advisor/SKILL.md b/skills/odoo-manufacturing-advisor/SKILL.md
new file mode 100644
index 00000000..1070d7d5
--- /dev/null
+++ b/skills/odoo-manufacturing-advisor/SKILL.md
@@ -0,0 +1,99 @@
+---
+name: odoo-manufacturing-advisor
+description: "Expert guide for Odoo Manufacturing: Bills of Materials (BoM), Work Centers, routings, MRP planning, and production order workflows."
+risk: safe
+source: "self"
+---
+
+# Odoo Manufacturing Advisor
+
+## Overview
+
+This skill helps you configure and optimize Odoo Manufacturing (MRP). It covers Bills of Materials (BoM), Work Centers, routing operations, production order lifecycle, and Material Requirements Planning (MRP) runs to ensure you never run short of materials.
+
+## When to Use This Skill
+
+- Creating or structuring Bills of Materials for finished goods.
+- Setting up Work Centers with capacity and efficiency settings.
+- Running an MRP to automatically generate purchase and production orders from demand.
+- Troubleshooting production order discrepancies or component availability issues.
+
+## How It Works
+
+1. **Activate**: Mention `@odoo-manufacturing-advisor` and describe your manufacturing scenario.
+2. **Configure**: Receive step-by-step instructions for BoM setup, routing, and MRP configuration.
+3. **Plan**: Get guidance on running MRP and interpreting procurement messages.
+
+## Examples
+
+### Example 1: Create a Bill of Materials
+
+```text
+Menu: Manufacturing → Products → Bills of Materials → New
+
+Product: Finished Widget v2
+BoM Type: Manufacture This Product
+Quantity: 1 (produce 1 unit per BoM)
+
+Components Tab:
+ - Raw Plastic Sheet | Qty: 0.5 | Unit: kg
+ - Steel Bolt M6 | Qty: 4 | Unit: Units
+ - Rubber Gasket | Qty: 1 | Unit: Units
+
+Operations Tab (requires "Work Orders" enabled in MFG Settings):
+ - Operation: Injection Molding | Work Center: Press A | Duration: 30 min
+ - Operation: Assembly | Work Center: Line 1 | Duration: 15 min
+```
+
+> **BoM Types explained:**
+>
+> - **Manufacture This Product** — standard production BoM, creates a Manufacturing Order
+> - **Kit** — sold as a bundle; components are delivered separately (no MO created)
+> - **Subcontracting** — components are sent to a subcontractor who returns the finished product
+
+### Example 2: Configure a Work Center
+
+```text
+Menu: Manufacturing → Configuration → Work Centers → New
+
+Work Center: CNC Machine 1
+Working Hours: Standard 40h/week
+Time Efficiency: 85% (machine downtime factored in; 85% = 34 effective hrs/week)
+Capacity: 2 (can run 2 production operations simultaneously)
+OEE Target: 90% (Overall Equipment Effectiveness KPI target)
+Costs per Hour: $75.00 (used for manufacturing cost reporting)
+```
+
+### Example 3: Run the MRP Scheduler
+
+```text
+The MRP scheduler runs automatically via a daily cron job.
+To trigger it manually:
+
+Menu: Inventory → Operations → Replenishment → Run Scheduler
+(or Manufacturing → Planning → Replenishment in some versions)
+
+After running, review procurement exceptions:
+Menu: Inventory → Operations → Replenishment
+
+Message Types:
+ "Replenish" — Stock is below minimum; needs a PO or MO
+ "Reschedule" — An order's scheduled date conflicts with demand
+ "Cancel" — Demand no longer exists; the order can be cancelled
+```
+
+## Best Practices
+
+- ✅ **Do:** Enable **Work Orders** in Manufacturing Settings to use routing and time-tracking per operation.
+- ✅ **Do:** Use **BoM with variants** (via product attributes) for products that come in multiple configurations (color, size, voltage) — avoids duplicate BoMs.
+- ✅ **Do:** Set **Lead Times** on components (vendor lead time + security lead time) so MRP schedules purchase orders in advance.
+- ✅ **Do:** Use **Scrap Orders** when discarding defective components during production — never adjust stock manually.
+- ❌ **Don't:** Manually create purchase orders for MRP-managed items — override MRP suggestions only when justified.
+- ❌ **Don't:** Confuse **Kit** BoM with **Manufacture This Product** — a Kit never creates a Manufacturing Order.
+
+## Limitations
+
+- This skill targets **Odoo Manufacturing (mrp)** module. **Maintenance**, **PLM** (Product Lifecycle Management), and **Quality** modules are separate Enterprise modules not covered here.
+- **Subcontracting** workflows (sending components to a third-party manufacturer) have additional receipt and valuation steps not fully detailed here.
+- **Lot/serial number traceability** in production (tracking which lot was consumed per MO) adds complexity; test with small batches before full rollout.
+- MRP calculations assume demand comes from **Sale Orders** and **Reordering Rules** — forecasts from external systems require custom integration.
diff --git a/skills/odoo-migration-helper/SKILL.md b/skills/odoo-migration-helper/SKILL.md
new file mode 100644
index 00000000..18137876
--- /dev/null
+++ b/skills/odoo-migration-helper/SKILL.md
@@ -0,0 +1,102 @@
+---
+name: odoo-migration-helper
+description: "Step-by-step guide for migrating Odoo custom modules between versions (v14→v15→v16→v17). Covers API changes, deprecated methods, and view migration."
+risk: safe
+source: "self"
+---
+
+# Odoo Migration Helper
+
+## Overview
+
+Migrating Odoo modules between major versions requires careful handling of API changes, deprecated methods, renamed fields, and new view syntax. This skill guides you through the migration process systematically, covering the most common breaking changes between versions.
+
+## When to Use This Skill
+
+- Upgrading a custom module from Odoo 14/15/16 to a newer version.
+- Getting a checklist of things to check before running `odoo-upgrade`.
+- Fixing deprecation warnings after a version upgrade.
+- Understanding what changed between two specific Odoo versions.
+
+## How It Works
+
+1. **Activate**: Mention `@odoo-migration-helper`, specify your source and target versions, and paste your module code.
+2. **Analyze**: Receive a list of breaking changes with before/after code fixes.
+3. **Validate**: Get a migration checklist specific to your module's features.
+
+## Key Migration Changes by Version
+
+### Odoo 16 → 17
+
+| Topic | Old (v16) | New (v17) |
+|---|---|---|
+| View visibility | `attrs="{'invisible': [...]}"` | `invisible="condition"` |
+| Chatter | `
` | `
` |
+| Required/Readonly | `attrs="{'required': [...]}"` | `required="condition"` |
+| Python minimum | 3.10 | 3.10+ |
+| JS modules | Legacy `define(['web.core'])` | ES module `import` syntax |
+
+### Odoo 15 → 16
+
+| Topic | Old (v15) | New (v16) |
+|---|---|---|
+| Website published flag | `website_published = True` | `is_published = True` |
+| Mail aliases | `alias_domain` on company | Moved to `mail.alias.domain` model |
+| Report render | `_render_qweb_pdf()` | `_render_qweb_pdf()` (same, but signature changed) |
+| Accounting move | `account.move.line` grouping | Line aggregation rules updated |
+| Email threading | `mail_thread_id` | Deprecated; use `message_ids` |
+
+## Examples
+
+### Example 1: Migrate `attrs` visibility to Odoo 17
+
+```xml
+
+
+
+
+
+
+
+```
+
+### Example 2: Migrate Chatter block
+
+```xml
+
+
+
+
+
+
+
+
+
+```
+
+### Example 3: Migrate website_published flag (v15 → v16)
+
+```python
+# v15
+record.website_published = True
+
+# v16+
+record.is_published = True
+```
+
+## Best Practices
+
+- ✅ **Do:** Test with `--update=your_module` on each version before pushing to production.
+- ✅ **Do:** Use the official [Odoo Upgrade Guide](https://upgrade.odoo.com/) to get an automated pre-upgrade analysis report.
+- ✅ **Do:** Check OCA migration notes and the module's `HISTORY.rst` for community modules.
+- ✅ **Do:** Run `npm run validate` after migration to catch manifest or frontmatter issues early.
+- ❌ **Don't:** Skip intermediate versions — go v14→v15→v16→v17 sequentially; never jump.
+- ❌ **Don't:** Forget to update `version` in `__manifest__.py` (e.g., `17.0.1.0.0`).
+- ❌ **Don't:** Assume OCA modules are migration-ready; check their GitHub branch for the target version.
+
+## Limitations
+
+- Covers **v14 through v17** only — does not address v13 or older (pre-manifest era has fundamentally different module structure).
+- The **Odoo.sh automated upgrade** path has additional steps not covered here; refer to Odoo.sh documentation.
+- **Enterprise-specific modules** (e.g., `account_accountant`, `sign`) may have undocumented breaking changes; test on a staging environment with Enterprise license.
+- JavaScript OWL component migration (v15 Legacy → v16 OWL) is a complex topic not fully covered by this skill.
diff --git a/skills/odoo-module-developer/SKILL.md b/skills/odoo-module-developer/SKILL.md
new file mode 100644
index 00000000..243719ae
--- /dev/null
+++ b/skills/odoo-module-developer/SKILL.md
@@ -0,0 +1,102 @@
+---
+name: odoo-module-developer
+description: "Expert guide for creating custom Odoo modules. Covers __manifest__.py, model inheritance, ORM patterns, and module structure best practices."
+risk: safe
+source: "self"
+---
+
+# Odoo Module Developer
+
+## Overview
+
+This skill transforms your AI into an expert Odoo custom module developer. It guides you through scaffolding new modules, defining models, setting up security, and following Odoo's coding conventions for both Community and Enterprise editions.
+
+## When to Use This Skill
+
+- Starting a new custom Odoo module from scratch.
+- Extending an existing Odoo model (e.g., adding fields to `sale.order`).
+- Troubleshooting module loading errors or manifest issues.
+- Implementing `onchange`, `compute`, and `constraint` methods correctly.
+
+## How It Works
+
+1. **Activate**: Mention `@odoo-module-developer` and describe the module you want to build.
+2. **Scaffold**: Get the full folder structure with `__manifest__.py`, `__init__.py`, models, views, and security files.
+3. **Review**: Paste existing code and get a review against Odoo best practices.
+
+## Examples
+
+### Example 1: Scaffold a New Module
+
+**Prompt:** `Create a module called "hospital_management" with a model for patients`
+
+**Generated structure:**
+
+```text
+hospital_management/
+├── __manifest__.py
+├── __init__.py
+├── models/
+│ ├── __init__.py
+│ └── hospital_patient.py
+├── views/
+│ └── hospital_patient_views.xml
+├── security/
+│ ├── ir.model.access.csv
+│ └── security.xml
+└── data/
+```
+
+**`__manifest__.py`:**
+
+```python
+{
+ 'name': 'Hospital Management',
+ 'version': '17.0.1.0.0',
+ 'category': 'Healthcare',
+ 'depends': ['base', 'mail'],
+ 'data': [
+ 'security/ir.model.access.csv',
+ 'views/hospital_patient_views.xml',
+ ],
+ 'installable': True,
+ 'license': 'LGPL-3',
+}
+```
+
+**`models/hospital_patient.py`:**
+
+```python
+from odoo import models, fields, api
+
+class HospitalPatient(models.Model):
+ _name = 'hospital.patient'
+ _description = 'Hospital Patient'
+ _inherit = ['mail.thread', 'mail.activity.mixin']
+
+ name = fields.Char(string='Patient Name', required=True, tracking=True)
+ birth_date = fields.Date(string='Birth Date')
+ doctor_id = fields.Many2one('res.users', string='Assigned Doctor')
+ state = fields.Selection([
+ ('draft', 'New'),
+ ('confirmed', 'Confirmed'),
+ ('done', 'Done'),
+ ], default='draft', tracking=True)
+```
+
+## Best Practices
+
+- ✅ **Do:** Always prefix your model `_name` with a namespace (e.g., `hospital.patient`).
+- ✅ **Do:** Use `_inherit = ['mail.thread']` to add chatter/logging automatically.
+- ✅ **Do:** Specify `version` in manifest as `{odoo_version}.{major}.{minor}.{patch}`.
+- ✅ **Do:** Set `'author'` and `'website'` in `__manifest__.py` so your module is identifiable in the Apps list.
+- ❌ **Don't:** Modify core Odoo model files directly — always use `_inherit`.
+- ❌ **Don't:** Forget to add new models to `ir.model.access.csv` or users will get access errors.
+- ❌ **Don't:** Use spaces or uppercase in folder names — Odoo requires snake_case module names.
+
+## Limitations
+
+- Does not cover **OWL JavaScript components** or frontend widget development — use `@odoo-xml-views-builder` for view XML.
+- **Odoo 13 and below** have a different module structure (no `__manifest__.py` auto-loading) — this skill targets v14+.
+- Does not cover **multi-company** or **multi-website** configuration; those require additional model fields (`company_id`, `website_id`).
+- Does not generate automated test files — use `@odoo-automated-tests` for that.
diff --git a/skills/odoo-orm-expert/SKILL.md b/skills/odoo-orm-expert/SKILL.md
new file mode 100644
index 00000000..d356676c
--- /dev/null
+++ b/skills/odoo-orm-expert/SKILL.md
@@ -0,0 +1,89 @@
+---
+name: odoo-orm-expert
+description: "Master Odoo ORM patterns: search, browse, create, write, domain filters, computed fields, and performance-safe query techniques."
+risk: safe
+source: "self"
+---
+
+# Odoo ORM Expert
+
+## Overview
+
+This skill teaches you Odoo's Object Relational Mapper (ORM) in depth. It covers reading/writing records, building domain filters, working with relational fields, and avoiding common performance pitfalls like N+1 queries.
+
+## When to Use This Skill
+
+- Writing `search()`, `browse()`, `create()`, `write()`, or `unlink()` calls.
+- Building complex domain filters for views or server actions.
+- Implementing computed, stored, and related fields.
+- Debugging slow queries or optimizing bulk operations.
+
+## How It Works
+
+1. **Activate**: Mention `@odoo-orm-expert` and describe what data operation you need.
+2. **Get Code**: Receive correct, idiomatic Odoo ORM code with explanations.
+3. **Optimize**: Ask for performance review on existing ORM code.
+
+## Examples
+
+### Example 1: Search with Domain Filters
+
+```python
+# Find all confirmed sale orders for a specific customer, created this year
+import datetime
+
+start_of_year = datetime.date.today().replace(month=1, day=1).strftime('%Y-%m-%d')
+
+orders = self.env['sale.order'].search([
+ ('partner_id', '=', partner_id),
+ ('state', '=', 'sale'),
+ ('date_order', '>=', start_of_year),
+], order='date_order desc', limit=50)
+
+# Note: pass dates as 'YYYY-MM-DD' strings in domains,
+# NOT as fields.Date objects — the ORM serializes them correctly.
+```
+
+### Example 2: Computed Field
+
+```python
+total_order_count = fields.Integer(
+ string='Total Orders',
+ compute='_compute_total_order_count',
+ store=True
+)
+
+@api.depends('sale_order_ids')
+def _compute_total_order_count(self):
+ for record in self:
+ record.total_order_count = len(record.sale_order_ids)
+```
+
+### Example 3: Safe Bulk Write (avoid N+1)
+
+```python
+# ✅ GOOD: One query for all records
+partners = self.env['res.partner'].search([('country_id', '=', False)])
+partners.write({'country_id': self.env.ref('base.us').id})
+
+# ❌ BAD: Triggers a separate query per record
+for partner in partners:
+ partner.country_id = self.env.ref('base.us').id
+```
+
+## Best Practices
+
+- ✅ **Do:** Use `mapped()`, `filtered()`, and `sorted()` on recordsets instead of Python loops.
+- ✅ **Do:** Use `sudo()` sparingly and only when you understand the security implications.
+- ✅ **Do:** Prefer `search_count()` over `len(search(...))` when you only need a count.
+- ✅ **Do:** Use `with_context(...)` to pass context values cleanly rather than modifying `self.env.context` directly.
+- ❌ **Don't:** Call `search()` inside a loop — this is the #1 Odoo performance killer.
+- ❌ **Don't:** Use raw SQL unless absolutely necessary; use ORM for all standard operations.
+- ❌ **Don't:** Pass Python `datetime`/`date` objects directly into domain tuples — always stringify them as `'YYYY-MM-DD'`.
+
+## Limitations
+
+- Does not cover **`cr.execute()` raw SQL** patterns in depth — use the Odoo performance tuner skill for SQL-level optimization.
+- **Stored computed fields** can cause significant write overhead at scale; this skill does not cover partitioning strategies.
+- Does not cover **transient models** (`models.TransientModel`) or wizard patterns.
+- ORM behavior can differ slightly between Odoo SaaS and On-Premise due to config overrides.
diff --git a/skills/odoo-performance-tuner/SKILL.md b/skills/odoo-performance-tuner/SKILL.md
new file mode 100644
index 00000000..3d5bcfff
--- /dev/null
+++ b/skills/odoo-performance-tuner/SKILL.md
@@ -0,0 +1,105 @@
+---
+name: odoo-performance-tuner
+description: "Expert guide for diagnosing and fixing Odoo performance issues: slow queries, worker configuration, memory limits, PostgreSQL tuning, and profiling tools."
+risk: safe
+source: "self"
+---
+
+# Odoo Performance Tuner
+
+## Overview
+
+This skill helps diagnose and resolve Odoo performance problems — from slow page loads and database bottlenecks to worker misconfiguration and memory bloat. It covers PostgreSQL query tuning, Odoo worker settings, and built-in profiling tools.
+
+## When to Use This Skill
+
+- Odoo is slow in production (slow page loads, timeouts).
+- Getting `MemoryError` or `Worker timeout` errors in logs.
+- Diagnosing a slow database query using Odoo's profiler.
+- Tuning `odoo.conf` for a specific server spec.
+
+## How It Works
+
+1. **Activate**: Mention `@odoo-performance-tuner` and describe your performance issue.
+2. **Diagnose**: Share relevant log lines or config and receive a root cause analysis.
+3. **Fix**: Get exact configuration changes with explanations.
+
+## Examples
+
+### Example 1: Recommended Worker Configuration
+
+```ini
+# odoo.conf — tuned for a 4-core, 8GB RAM server
+
+workers = 9 # (CPU_cores × 2) + 1 — never set to 0 in production
+max_cron_threads = 2 # background cron jobs; keep ≤ 2 to preserve user-facing capacity
+limit_memory_soft = 1610612736 # 1.5 GB — worker is recycled gracefully after this
+limit_memory_hard = 2147483648 # 2.0 GB — worker is killed immediately; prevents OOM crashes
+limit_time_cpu = 600 # max CPU seconds per request
+limit_time_real = 1200 # max wall-clock seconds per request
+limit_request = 8192 # max requests before worker recycles (prevents memory leaks)
+```
+
+### Example 2: Find Slow Queries with PostgreSQL
+
+```sql
+-- Step 1: Enable pg_stat_statements extension (run once as postgres superuser)
+CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
+
+-- Step 2: Also add to postgresql.conf and reload:
+-- shared_preload_libraries = 'pg_stat_statements'
+-- log_min_duration_statement = 1000 -- log queries taking > 1 second
+
+-- Step 3: Find the top 10 slowest average queries
+SELECT
+ LEFT(query, 100) AS query_snippet,
+ round(mean_exec_time::numeric, 2) AS avg_ms,
+ calls,
+ round(total_exec_time::numeric, 2) AS total_ms
+FROM pg_stat_statements
+ORDER BY mean_exec_time DESC
+LIMIT 10;
+
+-- Step 4: Check for missing indexes causing full table scans
+SELECT schemaname, tablename, attname, n_distinct, correlation
+FROM pg_stats
+WHERE tablename = 'sale_order_line'
+ AND correlation < 0.5 -- low correlation = poor index efficiency
+ORDER BY n_distinct DESC;
+```
+
+### Example 3: Use Odoo's Built-In Profiler
+
+```text
+Prerequisites: Run Odoo with ?debug=1 in the URL to enable debug mode.
+
+Menu: Settings → Technical → Profiling
+
+Steps:
+ 1. Click "Enable Profiling" — set a duration (e.g., 60 seconds)
+ 2. Navigate to and reproduce the slow action
+ 3. Return to Settings → Technical → Profiling → View Results
+
+What to look for:
+ - Total SQL queries > 100 on a single page → N+1 query problem
+ - Single queries taking > 100ms → missing DB index
+ - Same query repeated many times → missing cache, use @ormcache
+ - Python time high but SQL low → compute field inefficiency
+```
+
+## Best Practices
+
+- ✅ **Do:** Use `mapped()`, `filtered()`, and `sorted()` on in-memory recordsets — they don't trigger additional SQL.
+- ✅ **Do:** Add PostgreSQL B-tree indexes on columns frequently used in domain filters (`partner_id`, `state`, `date_order`).
+- ✅ **Do:** Enable Odoo's HTTP caching for static assets and put a CDN (Cloudflare, AWS CloudFront) in front of the website.
+- ✅ **Do:** Use `@tools.ormcache` decorator on methods pulled repeatedly with the same arguments.
+- ❌ **Don't:** Set `workers = 0` in production — single-threaded mode serializes all requests and blocks all users on any slow operation.
+- ❌ **Don't:** Ignore `limit_memory_soft` — workers exceeding it are recycled between requests; without the limit they grow unbounded and crash.
+- ❌ **Don't:** Directly manipulate `prefetch_ids` on recordsets — rely on Odoo's automatic batch prefetching, which activates by default.
+
+## Limitations
+
+- PostgreSQL tuning (`shared_buffers`, `work_mem`, `effective_cache_size`) is highly server-specific and not covered in depth here — use [PGTune](https://pgtune.leopard.in.ua/) as a starting baseline.
+- The built-in Odoo profiler only captures **Python + SQL** traces; JavaScript rendering performance requires browser DevTools.
+- **Odoo.sh** managed hosting restricts direct PostgreSQL and `odoo.conf` access — some tuning options are unavailable.
+- Does not cover **Redis-based session store** or **Celery task queue** optimizations, which are advanced patterns for very high-traffic instances.
diff --git a/skills/odoo-project-timesheet/SKILL.md b/skills/odoo-project-timesheet/SKILL.md
new file mode 100644
index 00000000..44d760db
--- /dev/null
+++ b/skills/odoo-project-timesheet/SKILL.md
@@ -0,0 +1,116 @@
+---
+name: odoo-project-timesheet
+description: "Expert guide for Odoo Project and Timesheets: task stages, billable time tracking, timesheet approval, budget alerts, and invoicing from timesheets."
+risk: safe
+source: "self"
+---
+
+# Odoo Project & Timesheet
+
+## Overview
+
+This skill helps you configure Odoo Project and Timesheets for service businesses, agencies, and consulting firms. It covers project setup with budgets, task stage management, employee timesheet logging, approval workflows, and converting approved timesheet hours to customer invoices.
+
+## When to Use This Skill
+
+- Setting up a new project with tasks, deadlines, and team assignments.
+- Configuring billable vs. non-billable time tracking per project.
+- Creating a timesheet approval workflow for managers.
+- Invoicing customers based on logged hours (Time & Materials billing).
+
+## How It Works
+
+1. **Activate**: Mention `@odoo-project-timesheet` and describe your project or billing scenario.
+2. **Configure**: Receive step-by-step setup instructions.
+3. **Automate**: Get guidance on automatically generating invoices from approved timesheets.
+
+## Examples
+
+### Example 1: Create a Billable Project
+
+```text
+Menu: Project → New Project (or the "+" button in Project view)
+
+Name: Website Redesign — Acme Corp
+Customer: Acme Corporation
+Billable: YES (toggle ON)
+
+Settings tab:
+ Billing Type: Based on Timesheets (Time & Materials)
+ Service Product: Consulting Hours ($150/hr)
+ ☑ Timesheets
+ ☑ Task Dependencies
+ ☑ Subtasks
+
+Budget:
+ Planned Hours: 120 hours
+ Budget Alert: at 80% (96 hrs) → notify project manager
+```
+
+### Example 2: Log Time on a Task
+
+```text
+Method A — Directly inside the Task (recommended for accuracy):
+ Open Task → Timesheets tab → Add a Line
+ Employee: John Doe
+ Date: Today
+ Description: "Initial wireframes and site map" (required for clear invoices)
+ Duration: 3:30 (3 hours 30 minutes)
+
+Method B — Timesheets app (for end-of-day bulk entry):
+ Menu: Timesheets → My Timesheets → New
+ Project: Website Redesign
+ Task: Wireframe Design
+ Duration: 3:30
+```
+
+### Example 3: Enable Timesheet Approval Before Invoicing
+
+```text
+Menu: Timesheets → Configuration → Settings
+ ☑ Timesheet Approval (employees submit; managers approve)
+
+Approval flow:
+ 1. Employee submits timesheet at week/month end
+ 2. Manager reviews: Timesheets → Managers → Timesheets to Approve
+ 3. Manager clicks "Approve" → entries are locked and billable
+ 4. Only approved entries flow into the invoice
+
+If Approval is disabled, all logged hours are immediately billable.
+```
+
+### Example 4: Invoice from Timesheets
+
+```text
+Step 1: Verify approved hours
+ Menu: Timesheets → Managers → All Timesheets
+ Filter: Billable = YES, Timesheet Invoice State = "To Invoice"
+
+Step 2: Generate Invoice
+ Menu: Sales → Orders → To Invoice → Timesheets (v15/v16)
+ or: Accounting → Customers → Invoiceable Time (v17)
+ Filter by Customer: Acme Corporation
+ Select entries → Create Invoices
+
+Step 3: Invoice pre-populates with:
+ Product: Consulting Hours
+ Quantity: Sum of approved hours
+ Unit Price: $150.00
+ Total: Calculated automatically
+```
+
+## Best Practices
+
+- ✅ **Do:** Enable **Timesheet Approval** so only manager-approved hours appear on customer invoices.
+- ✅ **Do:** Set a **budget alert** at 80% of planned hours so PMs can intervene before overruns.
+- ✅ **Do:** Require **timesheet descriptions** — vague entries like "Work done" on invoices destroy client trust.
+- ✅ **Do:** Use **Subtasks** to break work into granular pieces while keeping the parent task on the Kanban board.
+- ❌ **Don't:** Mix billable and internal projects without tagging — it corrupts profitability and utilization reports.
+- ❌ **Don't:** Log time on the Project itself (without a Task) — it cannot be reported at the task level.
+
+## Limitations
+
+- **Timesheet Approval** is an Enterprise-only feature in some Odoo versions — verify your plan includes it.
+- Does not cover **Project Forecast** (resource capacity planning) — that requires the Enterprise Forecast app.
+- **Time & Materials** invoicing works well for hourly billing but is not suited for **fixed-price projects** — use milestones or manual invoice lines for those.
+- Timesheet entries logged outside an active project-task pair (e.g., on internal projects) are not assignable to customer invoices without custom configuration.
diff --git a/skills/odoo-purchase-workflow/SKILL.md b/skills/odoo-purchase-workflow/SKILL.md
new file mode 100644
index 00000000..637efe9c
--- /dev/null
+++ b/skills/odoo-purchase-workflow/SKILL.md
@@ -0,0 +1,104 @@
+---
+name: odoo-purchase-workflow
+description: "Expert guide for Odoo Purchase: RFQ → PO → Receipt → Vendor Bill workflow, purchase agreements, vendor price lists, and 3-way matching."
+risk: safe
+source: "self"
+---
+
+# Odoo Purchase Workflow
+
+## Overview
+
+This skill guides you through the complete Odoo Purchase workflow — from sending a Request for Quotation (RFQ) to receiving goods and matching the vendor bill. It also covers purchase agreements, vendor price lists on products, automated reordering, and 3-way matching controls.
+
+## When to Use This Skill
+
+- Setting up the purchase flow for a new Odoo instance.
+- Implementing purchase order approval workflows (2-level approval).
+- Configuring vendor price lists with quantity-based discounts.
+- Troubleshooting billing/receipt mismatches in 3-way matching.
+
+## How It Works
+
+1. **Activate**: Mention `@odoo-purchase-workflow` and describe your purchasing scenario.
+2. **Configure**: Receive exact Odoo menu paths and field-by-field configuration.
+3. **Troubleshoot**: Describe a billing or receiving issue and get a root cause diagnosis.
+
+## Examples
+
+### Example 1: Standard RFQ → PO → Receipt → Bill Flow
+
+```text
+Step 1: Create RFQ
+ Menu: Purchase → Orders → Requests for Quotation → New
+ Vendor: Acme Supplies
+ Add product lines with quantity and unit price
+
+Step 2: Send RFQ to Vendor
+ Click "Send by Email" → Vendor receives PDF with RFQ details
+
+Step 3: Confirm as Purchase Order
+ Click "Confirm Order" → Status changes to "Purchase Order"
+
+Step 4: Receive Goods
+ Click "Receive Products" → Validate received quantities
+ (partial receipts are supported; PO stays open for remaining qty)
+
+Step 5: Match Vendor Bill (3-Way Match)
+ Click "Create Bill" → Bill pre-filled from PO quantities
+ Verify: PO qty = Received qty = Billed qty
+ Post Bill → Register Payment
+```
+
+### Example 2: Enable 2-Level Purchase Approval
+
+```text
+Menu: Purchase → Configuration → Settings
+
+Purchase Order Approval:
+ ☑ Purchase Order Approval
+ Minimum Order Amount: $5,000
+
+Result:
+ Orders ≤ $5,000 → Confirm directly to PO
+ Orders > $5,000 → Status: "Waiting for Approval"
+ A purchase manager must click "Approve"
+```
+
+### Example 3: Vendor Price List (Quantity Breaks on a Product)
+
+```text
+Vendor price lists are configured per product, not as a global menu.
+
+Menu: Inventory → Products → [Select Product] → Purchase Tab
+ → Vendor Pricelist section → Add a line
+
+Vendor: Acme Supplies
+Currency: USD
+Price: $12.00
+Min. Qty: 1
+
+Add another line for quantity discount:
+Min. Qty: 100 → Price: $10.50 (12.5% discount)
+Min. Qty: 500 → Price: $9.00 (25% discount)
+
+Result: Odoo automatically selects the right price on a PO
+based on the ordered quantity for this vendor.
+```
+
+## Best Practices
+
+- ✅ **Do:** Enable **Purchase Order Approval** for orders above your company's approval threshold.
+- ✅ **Do:** Use **Purchase Agreements (Blanket Orders)** for recurring vendors with pre-negotiated annual contracts.
+- ✅ **Do:** Set a **vendor lead time** on products (Purchase tab) so Odoo can schedule arrival dates accurately.
+- ✅ **Do:** Set the **Bill Control** policy to "Based on received quantities" (not ordered qty) for accurate 3-way matching.
+- ❌ **Don't:** Confirm a PO before prices are agreed — use Draft/RFQ status to negotiate first.
+- ❌ **Don't:** Post a vendor bill without linking it to a receipt — bypassing 3-way matching creates accounting discrepancies.
+- ❌ **Don't:** Delete a PO that has received quantities — archive it instead to preserve the stock and accounting trail.
+
+## Limitations
+
+- Does not cover **subcontracting purchase flows** — those require the Manufacturing module and subcontracting BoM type.
+- **EDI-based order exchange** (automated PO import/export) requires custom integration — use `@odoo-edi-connector` for that.
+- Vendor pricelist currency conversion depends on the active **currency rate** in Odoo; rates must be kept current for accuracy.
+- The **2-level approval** is a binary threshold; more complex approval matrices (department-based, multi-tier) require custom development or the Approvals app.
diff --git a/skills/odoo-qweb-templates/SKILL.md b/skills/odoo-qweb-templates/SKILL.md
new file mode 100644
index 00000000..b69446a3
--- /dev/null
+++ b/skills/odoo-qweb-templates/SKILL.md
@@ -0,0 +1,95 @@
+---
+name: odoo-qweb-templates
+description: "Expert in Odoo QWeb templating for PDF reports, email templates, and website pages. Covers t-if, t-foreach, t-field, and report actions."
+risk: safe
+source: "self"
+---
+
+# Odoo QWeb Templates
+
+## Overview
+
+QWeb is Odoo's primary templating engine, used for PDF reports, website pages, and email templates. This skill generates correct, well-structured QWeb XML with proper directives, translation support, and report action bindings.
+
+## When to Use This Skill
+
+- Creating a custom PDF report (invoice, delivery slip, certificate).
+- Building a QWeb email template triggered by workflow actions.
+- Designing Odoo website pages with dynamic content.
+- Debugging QWeb rendering errors (`t-if`, `t-foreach` issues).
+
+## How It Works
+
+1. **Activate**: Mention `@odoo-qweb-templates` and describe the report or template needed.
+2. **Generate**: Receive a complete `ir.actions.report` record and QWeb template.
+3. **Debug**: Paste a broken template to identify and fix rendering issues.
+
+## Examples
+
+### Example 1: Custom PDF Report
+
+```xml
+
+
+ Patient Card
+ hospital.patient
+ qweb-pdf
+ hospital_management.report_patient_card
+
+
+
+
+
+
+
+
+
+
Patient Card
+
+
+ | Name: |
+ |
+
+
+ | Doctor: |
+ |
+
+
+ | Status: |
+ |
+
+
+
+
+
+
+
+```
+
+### Example 2: Conditional Rendering
+
+```xml
+
+
+
+ Warning: This patient has not been confirmed yet.
+
+
+```
+
+## Best Practices
+
+- ✅ **Do:** Use `t-field` for model fields — Odoo auto-formats dates, monetary values, and booleans correctly.
+- ✅ **Do:** Use `t-out` (Odoo 15+) for safe HTML output of non-field strings. Use `t-esc` only on Odoo 14 and below (it HTML-escapes output).
+- ✅ **Do:** Call `web.external_layout` for PDF reports to automatically include the company header, footer, and logo.
+- ✅ **Do:** Use `_lt()` (lazy translation) for translatable string literals inside Python report helpers, not inline `t-esc`.
+- ❌ **Don't:** Use raw Python expressions inside QWeb — compute values in the model or a report `_get_report_values()` helper.
+- ❌ **Don't:** Forget `t-as` when using `t-foreach`; without it, you can't access the current record in the loop body.
+- ❌ **Don't:** Use `t-esc` where you intend to render HTML content — it will escape the tags and print them as raw text.
+
+## Limitations
+
+- Does not cover **website controller routing** for dynamic QWeb pages — that requires Python `http.route` knowledge.
+- **Email template** QWeb has different variable scope than report QWeb (`object` vs `docs`) — this skill primarily focuses on PDF reports.
+- QWeb JavaScript (used in Kanban/Form widgets) is a different engine; this skill covers **server-side QWeb only**.
+- Does not cover **wkhtmltopdf configuration** for PDF rendering issues (page size, margins, header/footer overlap).
diff --git a/skills/odoo-rpc-api/SKILL.md b/skills/odoo-rpc-api/SKILL.md
new file mode 100644
index 00000000..bf888807
--- /dev/null
+++ b/skills/odoo-rpc-api/SKILL.md
@@ -0,0 +1,103 @@
+---
+name: odoo-rpc-api
+description: "Expert on Odoo's external JSON-RPC and XML-RPC APIs. Covers authentication, model calls, record CRUD, and real-world integration examples in Python, JavaScript, and curl."
+risk: safe
+source: "self"
+---
+
+# Odoo RPC API
+
+## Overview
+
+Odoo exposes a powerful external API via JSON-RPC and XML-RPC, allowing any external application to read, create, update, and delete records. This skill guides you through authenticating, calling models, and building robust integrations.
+
+## When to Use This Skill
+
+- Connecting an external app (e.g., Django, Node.js, a mobile app) to Odoo.
+- Running automated scripts to import/export data from Odoo.
+- Building a middleware layer between Odoo and a third-party platform.
+- Debugging API authentication or permission errors.
+
+## How It Works
+
+1. **Activate**: Mention `@odoo-rpc-api` and describe the integration you need.
+2. **Generate**: Get copy-paste ready RPC call code in Python, JavaScript, or curl.
+3. **Debug**: Paste an error and get a diagnosis with a corrected call.
+
+## Examples
+
+### Example 1: Authenticate and Read Records (Python)
+
+```python
+import xmlrpc.client
+
+url = 'https://myodoo.example.com'
+db = 'my_database'
+username = 'admin'
+password = 'my_api_key' # Use API keys, not passwords, in production
+
+# Step 1: Authenticate
+common = xmlrpc.client.ServerProxy(f'{url}/xmlrpc/2/common')
+uid = common.authenticate(db, username, password, {})
+print(f"Authenticated as UID: {uid}")
+
+# Step 2: Call models
+models = xmlrpc.client.ServerProxy(f'{url}/xmlrpc/2/object')
+
+# Search confirmed sale orders
+orders = models.execute_kw(db, uid, password,
+ 'sale.order', 'search_read',
+ [[['state', '=', 'sale']]],
+ {'fields': ['name', 'partner_id', 'amount_total'], 'limit': 10}
+)
+for order in orders:
+ print(order)
+```
+
+### Example 2: Create a Record (Python)
+
+```python
+new_partner_id = models.execute_kw(db, uid, password,
+ 'res.partner', 'create',
+ [{'name': 'Acme Corp', 'email': 'info@acme.com', 'is_company': True}]
+)
+print(f"Created partner ID: {new_partner_id}")
+```
+
+### Example 3: JSON-RPC via curl
+
+```bash
+curl -X POST https://myodoo.example.com/web/dataset/call_kw \
+ -H "Content-Type: application/json" \
+ -d '{
+ "jsonrpc": "2.0",
+ "method": "call",
+ "id": 1,
+ "params": {
+ "model": "res.partner",
+ "method": "search_read",
+ "args": [[["is_company", "=", true]]],
+ "kwargs": {"fields": ["name", "email"], "limit": 5}
+ }
+ }'
+# Note: "id" is required by the JSON-RPC 2.0 spec to correlate responses.
+# Odoo 16+ also supports the /web/dataset/call_kw endpoint but
+# prefer /web/dataset/call_kw for model method calls.
+```
+
+## Best Practices
+
+- ✅ **Do:** Use **API Keys** (Settings → Technical → API Keys) instead of passwords — available from Odoo 14+.
+- ✅ **Do:** Use `search_read` instead of `search` + `read` to reduce network round trips.
+- ✅ **Do:** Always handle connection errors and implement retry logic with exponential backoff in production.
+- ✅ **Do:** Store credentials in environment variables or a secrets manager (e.g., AWS Secrets Manager, `.env` file).
+- ❌ **Don't:** Hardcode passwords or API keys directly in scripts — rotate them and use env vars.
+- ❌ **Don't:** Call the API in a tight loop without batching — bulk operations reduce server load significantly.
+- ❌ **Don't:** Use the master admin password for API integrations — create a dedicated integration user with minimum required permissions.
+
+## Limitations
+
+- Does not cover **OAuth2 or session-cookie-based authentication** — the examples use API key (token) auth only.
+- **Rate limiting** is not built into the Odoo XMLRPC layer; you must implement throttling client-side.
+- The XML-RPC endpoint (`/xmlrpc/2/`) does not support file uploads — use the REST-based `ir.attachment` model via JSON-RPC for binary data.
+- Odoo.sh (SaaS) may block some API calls depending on plan; verify your subscription supports external API access.
diff --git a/skills/odoo-sales-crm-expert/SKILL.md b/skills/odoo-sales-crm-expert/SKILL.md
new file mode 100644
index 00000000..b498abac
--- /dev/null
+++ b/skills/odoo-sales-crm-expert/SKILL.md
@@ -0,0 +1,109 @@
+---
+name: odoo-sales-crm-expert
+description: "Expert guide for Odoo Sales and CRM: pipeline stages, quotation templates, pricelists, sales teams, lead scoring, and forecasting."
+risk: safe
+source: "self"
+---
+
+# Odoo Sales & CRM Expert
+
+## Overview
+
+This skill helps you configure and optimize Odoo Sales and CRM. It covers opportunity pipeline setup, automated lead assignment, quotation templates, pricelist strategies, sales team management, and the sales-to-invoice workflow.
+
+## When to Use This Skill
+
+- Designing CRM pipeline stages for your sales process.
+- Creating a quotation template with optional products and bundles.
+- Setting up pricelists with customer-tier pricing.
+- Configuring automated lead assignment by territory or salesperson.
+
+## How It Works
+
+1. **Activate**: Mention `@odoo-sales-crm-expert` and describe your sales scenario.
+2. **Configure**: Receive step-by-step Odoo setup instructions.
+3. **Optimize**: Get recommendations for improving pipeline velocity and deal closure rate.
+
+## Examples
+
+### Example 1: Configure CRM Pipeline Stages
+
+```text
+Menu: CRM → Configuration → Stages → New
+
+Typical B2B Pipeline:
+ Stage 1: New Lead (probability: 10%)
+ Stage 2: Qualified (probability: 25%)
+ Stage 3: Proposal Sent (probability: 50%)
+ Stage 4: Negotiation (probability: 75%)
+ Stage 5: Won (is_won: YES — marks opportunity as closed-won)
+ Stage 6: Lost (mark as lost via the "Mark as Lost" button)
+
+Tips:
+ - Enable "Rotting Days" in CRM Settings to flag stale deals in red
+ - In Odoo 16+, Predictive Lead Scoring (AI) auto-updates probability
+ based on historical data. Disable it in Settings if you prefer manual
+ stage-based probability.
+```
+
+### Example 2: Create a Quotation Template
+
+```text
+Menu: Sales → Configuration → Quotation Templates → New
+(Requires the "Sales Management" module — enabled in Sales Settings)
+
+Template Name: SaaS Annual Subscription
+Valid for: 30 days
+
+Lines:
+ 1. Platform License | Qty: 1 | Price: $1,200/yr | (required)
+ 2. Onboarding Package | Qty: 1 | Price: $500 | Optional
+ 3. Premium Support | Qty: 1 | Price: $300/yr | Optional
+ 4. Extra User License | Qty: 0 | Price: $120/user | Optional
+
+Signature & Payment:
+ ☑ Online Signature required before order confirmation
+ ☑ Online Payment (deposit) — 50% upfront
+
+Notes section:
+ "Prices valid until expiration date. Subject to Schedule A terms."
+```
+
+### Example 3: Customer Tier Pricelist (VIP Discount)
+
+```text
+Menu: Sales → Configuration → Settings
+ ☑ Enable Pricelists
+
+Menu: Sales → Configuration → Pricelists → New
+
+Name: VIP Customer — 15% Off
+Currency: USD
+Discount Policy: Show public price & discount on quotation
+
+Rules:
+ Apply To: All Products
+ Compute Price: Discount
+ Discount: 15%
+ Min. Quantity: 1
+
+Assign to a customer:
+ Customer record → Sales & Purchase tab → Pricelist → VIP Customer
+```
+
+## Best Practices
+
+- ✅ **Do:** Use **Lost Reasons** (CRM → Configuration → Lost Reasons) to build a dataset of why deals are lost — invaluable for sales coaching.
+- ✅ **Do:** Enable **Sales Teams** with revenue targets so pipeline forecasting is meaningful per team.
+- ✅ **Do:** Set **Expected Revenue** and **Closing Date** on every opportunity — these feed the revenue forecast dashboard.
+- ✅ **Do:** Use **Quotation Templates** to standardize offers and reduce quoting time across the team.
+- ❌ **Don't:** Skip the CRM opportunity when selling — going directly from lead to invoice breaks pipeline analytics.
+- ❌ **Don't:** Manually edit prices on quotation lines as a workaround — set up proper pricelists instead.
+- ❌ **Don't:** Ignore the **Predictive Lead Scoring** feature in v16+ — configure it with historical data for accurate forecasting.
+
+## Limitations
+
+- **Commission rules** are not built into Odoo CRM out of the box — they require custom development or third-party modules.
+- The **Quotation Template** optional product feature requires the **Sale Management** module; it is not available in the base `sale` module.
+- **Territory-based lead assignment** (geographic routing) requires custom rules or the Enterprise Leads module.
+- Odoo CRM does not have native **email sequence / cadence** automation — use the **Email Marketing** or **Marketing Automation** modules for drip campaigns.
diff --git a/skills/odoo-security-rules/SKILL.md b/skills/odoo-security-rules/SKILL.md
new file mode 100644
index 00000000..c14d0a1b
--- /dev/null
+++ b/skills/odoo-security-rules/SKILL.md
@@ -0,0 +1,92 @@
+---
+name: odoo-security-rules
+description: "Expert in Odoo access control: ir.model.access.csv, record rules (ir.rule), groups, and multi-company security patterns."
+risk: safe
+source: "self"
+---
+
+# Odoo Security Rules
+
+## Overview
+
+Security in Odoo is managed at two levels: **model-level access** (who can read/write which models) and **record-level rules** (which records a user can see). This skill helps you write correct `ir.model.access.csv` entries and `ir.rule` domain-based record rules.
+
+## When to Use This Skill
+
+- Setting up access rights for a new custom module.
+- Restricting records so users only see their own data or their company's data.
+- Debugging "Access Denied" or "You are not allowed to access" errors.
+- Implementing multi-company record visibility rules.
+
+## How It Works
+
+1. **Activate**: Mention `@odoo-security-rules` and describe the access scenario.
+2. **Generate**: Get correct CSV access lines and XML record rules.
+3. **Debug**: Paste an access error and get a diagnosis with the fix.
+
+## Examples
+
+### Example 1: ir.model.access.csv
+
+```csv
+id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
+access_hospital_patient_user,hospital.patient.user,model_hospital_patient,base.group_user,1,0,0,0
+access_hospital_patient_manager,hospital.patient.manager,model_hospital_patient,base.group_erp_manager,1,1,1,1
+```
+
+> **Note:** Use `base.group_erp_manager` for ERP managers, not `base.group_system` — that group is reserved for Odoo's technical superusers. Always create a custom group for module-specific manager roles:
+>
+> ```xml
+>
+> Hospital Manager
+>
+>
+> ```
+
+### Example 2: Record Rule — Users See Only Their Own Records
+
+```xml
+
+ Hospital Patient: Own Records Only
+
+ [('create_uid', '=', user.id)]
+
+
+
+
+
+
+```
+
+> **Important:** If you omit `
`, the rule becomes **global** and applies to ALL users, including admins. Always assign a group unless you explicitly intend a global restriction.
+
+### Example 3: Multi-Company Record Rule
+
+```xml
+
+ Hospital Patient: Multi-Company
+
+
+ ['|', ('company_id', '=', False),
+ ('company_id', 'in', company_ids)]
+
+
+
+```
+
+## Best Practices
+
+- ✅ **Do:** Start with the most restrictive access and open up as needed.
+- ✅ **Do:** Use `company_ids` (plural) in multi-company rules — it includes all companies the user belongs to.
+- ✅ **Do:** Test rules using a non-admin user in debug mode — `sudo()` bypasses all record rules entirely.
+- ✅ **Do:** Create dedicated security groups per module rather than reusing core Odoo groups.
+- ❌ **Don't:** Give `perm_unlink = 1` to regular users unless deletion is explicitly required by the business process.
+- ❌ **Don't:** Leave `group_id` blank in `ir.model.access.csv` unless you intend to grant public (unauthenticated) access.
+- ❌ **Don't:** Use `base.group_system` for module managers — that grants full technical access including server configurations.
+
+## Limitations
+
+- Does not cover **field-level access control** (`ir.model.fields` read/write restrictions) — those require custom OWL or Python overrides.
+- **Portal and public user** access rules have additional nuances not fully covered here; test carefully with `base.group_portal`.
+- Record rules are **bypassed by `sudo()`** — any code running in superuser context ignores all `ir.rule` entries.
+- Does not cover **row-level security via PostgreSQL** (RLS) — Odoo manages all security at the ORM layer.
diff --git a/skills/odoo-shopify-integration/SKILL.md b/skills/odoo-shopify-integration/SKILL.md
new file mode 100644
index 00000000..1f368363
--- /dev/null
+++ b/skills/odoo-shopify-integration/SKILL.md
@@ -0,0 +1,99 @@
+---
+name: odoo-shopify-integration
+description: "Connect Odoo with Shopify: sync products, inventory, orders, and customers using the Shopify API and Odoo's external API or connector modules."
+---
+
+# Odoo ↔ Shopify Integration
+
+## Overview
+
+This skill guides you through integrating Odoo with Shopify — syncing your product catalog, real-time inventory levels, incoming orders, and customer data. It covers both using the official Odoo Shopify connector (Enterprise) and building a custom integration via Shopify REST + Odoo XMLRPC APIs.
+
+## When to Use This Skill
+
+- Selling on Shopify while managing inventory in Odoo.
+- Automatically creating Odoo sales orders from Shopify purchases.
+- Keeping Odoo stock levels in sync with Shopify product availability.
+- Mapping Shopify product variants to Odoo product templates.
+
+## How It Works
+
+1. **Activate**: Mention `@odoo-shopify-integration` and describe your sync scenario.
+2. **Design**: Receive the data flow architecture and field mapping.
+3. **Build**: Get code snippets for the Shopify webhook receiver and Odoo API caller.
+
+## Data Flow Architecture
+
+```
+SHOPIFY ODOO
+-------- ----
+Product Catalog <──────sync────── Product Templates + Variants
+Inventory Level <──────sync────── Stock Quants (real-time)
+New Order ───────push──────> Sale Order (auto-confirmed)
+Customer ───────push──────> res.partner (created if new)
+Fulfillment <──────push────── Delivery Order validated
+```
+
+## Examples
+
+### Example 1: Push an Odoo Sale Order for a Shopify Order (Python)
+
+```python
+import xmlrpc.client, requests
+
+# Odoo connection
+odoo_url = "https://myodoo.example.com"
+db, uid, pwd = "my_db", 2, "api_key"
+models = xmlrpc.client.ServerProxy(f"{odoo_url}/xmlrpc/2/object")
+
+def create_odoo_order_from_shopify(shopify_order):
+ # Find or create customer
+ partner = models.execute_kw(db, uid, pwd, 'res.partner', 'search_read',
+ [[['email', '=', shopify_order['customer']['email']]]],
+ {'fields': ['id'], 'limit': 1}
+ )
+ partner_id = partner[0]['id'] if partner else models.execute_kw(
+ db, uid, pwd, 'res.partner', 'create', [{
+ 'name': shopify_order['customer']['first_name'] + ' ' + shopify_order['customer']['last_name'],
+ 'email': shopify_order['customer']['email'],
+ }]
+ )
+
+ # Create Sale Order
+ order_id = models.execute_kw(db, uid, pwd, 'sale.order', 'create', [{
+ 'partner_id': partner_id,
+ 'client_order_ref': f"Shopify #{shopify_order['order_number']}",
+ 'order_line': [(0, 0, {
+ 'product_id': get_odoo_product_id(line['sku']),
+ 'product_uom_qty': line['quantity'],
+ 'price_unit': float(line['price']),
+ }) for line in shopify_order['line_items']],
+ }])
+ return order_id
+
+def get_odoo_product_id(sku):
+ result = models.execute_kw(db, uid, pwd, 'product.product', 'search_read',
+ [[['default_code', '=', sku]]], {'fields': ['id'], 'limit': 1})
+ return result[0]['id'] if result else False
+```
+
+### Example 2: Shopify Webhook for Real-Time Orders
+
+```python
+from flask import Flask, request
+app = Flask(__name__)
+
+@app.route('/webhook/shopify/orders', methods=['POST'])
+def shopify_order_webhook():
+ shopify_order = request.json
+ order_id = create_odoo_order_from_shopify(shopify_order)
+ return {"odoo_order_id": order_id}, 200
+```
+
+## Best Practices
+
+- ✅ **Do:** Use Shopify's **webhook system** for real-time order sync instead of polling.
+- ✅ **Do:** Match products using **SKU / Internal Reference** as the unique key between both systems.
+- ✅ **Do:** Validate Shopify webhook HMAC signatures before processing any payload.
+- ❌ **Don't:** Sync inventory from both systems simultaneously without a "master system" — pick one as the source of truth.
+- ❌ **Don't:** Use Shopify product IDs as the key — use SKUs which are stable across platforms.
diff --git a/skills/odoo-upgrade-advisor/SKILL.md b/skills/odoo-upgrade-advisor/SKILL.md
new file mode 100644
index 00000000..c8279b4b
--- /dev/null
+++ b/skills/odoo-upgrade-advisor/SKILL.md
@@ -0,0 +1,123 @@
+---
+name: odoo-upgrade-advisor
+description: "Step-by-step Odoo version upgrade advisor: pre-upgrade checklist, community vs enterprise upgrade path, OCA module compatibility, and post-upgrade validation."
+risk: safe
+source: "self"
+---
+
+# Odoo Upgrade Advisor
+
+## Overview
+
+Upgrading Odoo between major versions (e.g., v15 → v16 → v17) requires careful preparation, testing, and validation. This skill provides a structured pre-upgrade checklist, guides you through the upgrade tools (Odoo Upgrade Service and OpenUpgrade), and gives you a post-upgrade validation protocol.
+
+## When to Use This Skill
+
+- Planning a major Odoo version upgrade.
+- Identifying which custom modules need to be migrated.
+- Running the upgrade on a staging environment before production.
+- Validating the system after an upgrade.
+
+## How It Works
+
+1. **Activate**: Mention `@odoo-upgrade-advisor`, state your current and target version.
+2. **Plan**: Receive the full upgrade roadmap and risk assessment.
+3. **Execute**: Get a step-by-step upgrade command sequence.
+
+## Upgrade Paths
+
+| From | To | Supported? | Tool |
+|---|---|---|---|
+| v16 | v17 | ✅ Direct | Odoo Upgrade Service / OpenUpgrade |
+| v15 | v16 | ✅ Direct | Odoo Upgrade Service / OpenUpgrade |
+| v14 | v15 | ✅ Direct | Odoo Upgrade Service / OpenUpgrade |
+| v14 | v17 | ⚠️ Multi-hop | v14→v15→v16→v17 (cannot skip) |
+| v13 or older | any | ❌ Not supported | Manual migration required |
+
+## Examples
+
+### Example 1: Pre-Upgrade Checklist
+
+```text
+BEFORE YOU START:
+ ☑ 1. List all installed modules (Settings → Technical → Modules)
+ Export to CSV and review for custom/OCA modules
+ ☑ 2. Check OCA compatibility matrix for each community module
+ https://github.com/OCA/maintainer-tools/wiki/Migration-Status
+ ☑ 3. Take a full backup (database + filestore) — your restore point
+ ☑ 4. Clone production to a staging environment
+ ☑ 5. Run the Odoo Upgrade pre-analysis:
+ https://upgrade.odoo.com/ → Upload DB → Review breaking changes report
+ ☑ 6. Review custom modules against migration notes
+ (use @odoo-migration-helper for per-module analysis)
+ ☑ 7. Upgrade and test in staging → Fix all errors → Re-test
+ ☑ 8. Schedule a production maintenance window
+ ☑ 9. Notify users of scheduled downtime
+ ☑ 10. Perform production upgrade → Validate → Go/No-Go decision
+```
+
+### Example 2: Community Upgrade with OpenUpgrade
+
+```bash
+# Clone OpenUpgrade for the TARGET version (e.g., upgrading to v17)
+git clone https://github.com/OCA/OpenUpgrade.git \
+ --branch 17.0 \
+ --single-branch \
+ /opt/openupgrade
+
+# Run the migration against your staging database
+python3 /opt/openupgrade/odoo-bin \
+ --update all \
+ --database odoo_staging \
+ --config /etc/odoo/odoo.conf \
+ --stop-after-init \
+ --load openupgrade_framework
+
+# Review the log for errors before touching production
+tail -200 /var/log/odoo/odoo.log | grep -E "ERROR|WARNING|Traceback"
+```
+
+### Example 3: Post-Upgrade Validation Checklist
+
+```text
+After upgrading, validate these critical areas before going live:
+
+Accounting:
+ ☑ Trial Balance totals match the pre-upgrade snapshot
+ ☑ Open invoices, bills, and payments are accessible
+ ☑ Bank reconciliation can be performed on a test statement
+
+Inventory:
+ ☑ Stock valuation report matches pre-upgrade (run Inventory Valuation)
+ ☑ Open Purchase Orders and Sale Orders are visible
+
+HR / Payroll:
+ ☑ All employee records are intact
+ ☑ Payslips from the last 3 months are accessible and correct
+
+Custom Modules:
+ ☑ Every custom module loaded without ImportError or XML error
+ ☑ Run the critical business workflows end-to-end:
+ Create sale order → confirm → deliver → invoice → payment
+
+Users & Security:
+ ☑ User logins work correctly
+ ☑ Access rights are preserved (spot-check 3-5 users)
+```
+
+## Best Practices
+
+- ✅ **Do:** Always upgrade on a **copy of production** (staging) first — never the live instance.
+- ✅ **Do:** Keep the old version running until the new version is **fully validated and signed off**.
+- ✅ **Do:** Check OCA's migration status page: [OCA Migration Status](https://github.com/OCA/maintainer-tools/wiki/Migration-Status)
+- ✅ **Do:** Use the [Odoo Upgrade Service](https://upgrade.odoo.com/) pre-analysis report to get a list of breaking changes **before writing any code**.
+- ❌ **Don't:** Skip intermediate versions — Odoo requires sequential upgrades (v14→v15→v16→v17).
+- ❌ **Don't:** Upgrade custom modules and Odoo core simultaneously — adapt Odoo core first, then fix custom modules.
+- ❌ **Don't:** Run OpenUpgrade against production directly — always test on a staging copy first.
+
+## Limitations
+
+- Covers **v14–v17** only. Versions v13 and older have a fundamentally different module structure and require manual migration.
+- **Enterprise-exclusive module changes** (e.g., `sign`, `account_accountant`) may have undocumented breaking changes not included in OpenUpgrade.
+- The **Odoo.sh** automated upgrade path has a separate workflow (managed from the Odoo.sh dashboard) not covered here.
+- OWL JavaScript component migration (legacy widget → OWL v16+) is a complex front-end topic beyond the scope of this skill.
diff --git a/skills/odoo-woocommerce-bridge/SKILL.md b/skills/odoo-woocommerce-bridge/SKILL.md
new file mode 100644
index 00000000..24f0dbd3
--- /dev/null
+++ b/skills/odoo-woocommerce-bridge/SKILL.md
@@ -0,0 +1,129 @@
+---
+name: odoo-woocommerce-bridge
+description: "Sync Odoo with WooCommerce: products, inventory, orders, and customers via WooCommerce REST API and Odoo external API."
+---
+
+# Odoo ↔ WooCommerce Bridge
+
+## Overview
+
+This skill guides you through building a reliable sync bridge between Odoo (the back-office ERP) and WooCommerce (the WordPress online store). It covers product catalog sync, real-time inventory updates, order import, and customer record management.
+
+## When to Use This Skill
+
+- Running a WooCommerce store with Odoo for inventory and fulfillment.
+- Automatically pulling WooCommerce orders into Odoo as sale orders.
+- Keeping WooCommerce product stock in sync with Odoo's warehouse.
+- Mapping WooCommerce order statuses to Odoo delivery states.
+
+## How It Works
+
+1. **Activate**: Mention `@odoo-woocommerce-bridge` and describe your sync requirements.
+2. **Design**: Get the field mapping table between WooCommerce and Odoo objects.
+3. **Build**: Receive Python integration scripts using the WooCommerce REST API.
+
+## Field Mapping: WooCommerce → Odoo
+
+| WooCommerce | Odoo |
+|---|---|
+| `products` | `product.template` + `product.product` |
+| `orders` | `sale.order` + `sale.order.line` |
+| `customers` | `res.partner` |
+| `stock_quantity` | `stock.quant` |
+| `sku` | `product.product.default_code` |
+| `order status: processing` | Sale Order: `sale` (confirmed) |
+| `order status: completed` | Delivery: `done` |
+
+## Examples
+
+### Example 1: Pull WooCommerce Orders into Odoo (Python)
+
+```python
+from woocommerce import API
+import xmlrpc.client
+
+# WooCommerce client
+wcapi = API(
+ url="https://mystore.com",
+ consumer_key="ck_xxxxxxxxxxxxx",
+ consumer_secret="cs_xxxxxxxxxxxxx",
+ version="wc/v3"
+)
+
+# Odoo client
+odoo_url = "https://myodoo.example.com"
+db, uid, pwd = "my_db", 2, "api_key"
+models = xmlrpc.client.ServerProxy(f"{odoo_url}/xmlrpc/2/object")
+
+def sync_orders():
+ # Get unprocessed WooCommerce orders
+ orders = wcapi.get("orders", params={"status": "processing", "per_page": 50}).json()
+
+ for wc_order in orders:
+ # Find or create Odoo partner
+ email = wc_order['billing']['email']
+ partner = models.execute_kw(db, uid, pwd, 'res.partner', 'search',
+ [[['email', '=', email]]])
+ if not partner:
+ partner_id = models.execute_kw(db, uid, pwd, 'res.partner', 'create', [{
+ 'name': f"{wc_order['billing']['first_name']} {wc_order['billing']['last_name']}",
+ 'email': email,
+ 'phone': wc_order['billing']['phone'],
+ 'street': wc_order['billing']['address_1'],
+ 'city': wc_order['billing']['city'],
+ }])
+ else:
+ partner_id = partner[0]
+
+ # Create Sale Order in Odoo
+ order_lines = []
+ for item in wc_order['line_items']:
+ product = models.execute_kw(db, uid, pwd, 'product.product', 'search',
+ [[['default_code', '=', item['sku']]]])
+ if product:
+ order_lines.append((0, 0, {
+ 'product_id': product[0],
+ 'product_uom_qty': item['quantity'],
+ 'price_unit': float(item['price']),
+ }))
+
+ models.execute_kw(db, uid, pwd, 'sale.order', 'create', [{
+ 'partner_id': partner_id,
+ 'client_order_ref': f"WC-{wc_order['number']}",
+ 'order_line': order_lines,
+ }])
+
+ # Mark WooCommerce order as on-hold (processed by Odoo)
+ wcapi.put(f"orders/{wc_order['id']}", {"status": "on-hold"})
+```
+
+### Example 2: Push Odoo Stock to WooCommerce
+
+```python
+def sync_inventory_to_woocommerce():
+ # Get all products with a SKU from Odoo
+ products = models.execute_kw(db, uid, pwd, 'product.product', 'search_read',
+ [[['default_code', '!=', False], ['type', '=', 'product']]],
+ {'fields': ['default_code', 'qty_available']}
+ )
+
+ for product in products:
+ sku = product['default_code']
+ qty = int(product['qty_available'])
+
+ # Update WooCommerce by SKU
+ wc_products = wcapi.get("products", params={"sku": sku}).json()
+ if wc_products:
+ wcapi.put(f"products/{wc_products[0]['id']}", {
+ "stock_quantity": qty,
+ "manage_stock": True,
+ })
+```
+
+## Best Practices
+
+- ✅ **Do:** Use **SKU** as the unique identifier linking WooCommerce products to Odoo products.
+- ✅ **Do:** Run inventory sync on a **schedule** (every 15-30 min) rather than real-time to avoid rate limits.
+- ✅ **Do:** Log all API calls and errors to a database table for debugging.
+- ❌ **Don't:** Process the same WooCommerce order twice — flag it as processed immediately after import.
+- ❌ **Don't:** Sync draft or cancelled WooCommerce orders to Odoo — filter by `status = processing` or `completed`.
diff --git a/skills/odoo-xml-views-builder/SKILL.md b/skills/odoo-xml-views-builder/SKILL.md
new file mode 100644
index 00000000..8da0977e
--- /dev/null
+++ b/skills/odoo-xml-views-builder/SKILL.md
@@ -0,0 +1,102 @@
+---
+name: odoo-xml-views-builder
+description: "Expert at building Odoo XML views: Form, List, Kanban, Search, Calendar, and Graph. Generates correct XML for Odoo 14-17 with proper visibility syntax."
+risk: safe
+source: "self"
+---
+
+# Odoo XML Views Builder
+
+## Overview
+
+This skill generates and reviews Odoo XML view definitions for Kanban, Form, List, Search, Calendar, and Graph views. It understands visibility modifiers, `groups`, `domain`, `context`, and widget usage across Odoo versions 14–17, including the migration from `attrs` (v14–16) to inline expressions (v17+).
+
+## When to Use This Skill
+
+- Creating a new form or list view for a custom model.
+- Adding fields, tabs, or smart buttons to an existing view.
+- Building a Kanban view with color coding or progress bars.
+- Creating a search view with filters and group-by options.
+
+## How It Works
+
+1. **Activate**: Mention `@odoo-xml-views-builder` and describe the view you want.
+2. **Generate**: Get complete, ready-to-paste XML view definitions.
+3. **Review**: Paste existing XML and get fixes for common mistakes.
+
+## Examples
+
+### Example 1: Form View with Tabs
+
+```xml
+
+ hospital.patient.form
+ hospital.patient
+
+
+
+
+```
+
+### Example 2: Kanban View
+
+```xml
+
+ hospital.patient.kanban
+ hospital.patient
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+## Best Practices
+
+- ✅ **Do:** Use inline `invisible="condition"` (Odoo 17+) instead of `attrs` for show/hide logic.
+- ✅ **Do:** Use `attrs="{'invisible': [...]}"` only if you are targeting Odoo 14–16 — it is deprecated in v17.
+- ✅ **Do:** Always set a `string` attribute on your view record for debugging clarity.
+- ✅ **Do:** Use `` (v17) or `` + field tags (v16 and below) for activity tracking.
+- ❌ **Don't:** Use `attrs` in Odoo 17 — it is fully deprecated and raises warnings in logs.
+- ❌ **Don't:** Put business logic in view XML — keep it in Python model methods.
+- ❌ **Don't:** Use hardcoded `domain` strings in views when a `domain` field on the model can be used dynamically.
+
+## Limitations
+
+- Does not cover **OWL JavaScript widgets** or client-side component development.
+- **Search panel views** (``) are not fully covered — those require frontend knowledge.
+- Does not address **website QWeb views** — use `@odoo-qweb-templates` for those.
+- **Cohort and Map views** (Enterprise-only) are not covered by this skill.