# AGENTS.md — Odoo OCR Project This file provides context and rules for AI agents working on `odoo_ocr`, a local-first invoice OCR pipeline that reads scanned, printed, handwritten, and native-PDF invoices and produces Odoo Enterprise-ready XML. ## Mandatory First Step for Agents Before starting any work on this project, inspect `.agents/skills/` and load every skill whose description applies to the task at hand. The skills contain project-specific rules, prompts, templates, and checklists that take precedence over general instructions. Available project skills: - `odoo-ocr-pipeline` — when implementing classifier, branches, OCR, extraction, or review. - `odoo-xml-import` — when generating or validating Odoo XML. - `local-vlm-client` — when writing model clients or prompts. - `review` — when reviewing code, tests, or design decisions before approving changes. If the requested change touches more than one skill, load all of them. If a task is ambiguous or conflicts with the local-only / privacy constraint, stop and consult the user before proceeding. ## Mandatory Development Workflow All non-trivial implementation tasks follow this workflow. Trivial tasks (e.g., a single typo fix or one-line import correction) may skip straight to implementation, but they still require validation. ### 1. Understand Before changing anything: - Read the relevant parts of the codebase. - Load all applicable skills from `.agents/skills/`. - Identify the schemas, modules, tests, and config that the change will touch. - Confirm the goal and constraints with the user if anything is unclear. **Do not modify files during this phase.** ### 2. Plan Produce a concise implementation plan that includes: - What files will be created, modified, deleted, or renamed. - Which schemas or public interfaces change. - How the change fits existing tests and what new tests are needed. - Any risks, assumptions, or open questions. ### 3. Wait for Approval **STOP after presenting the plan.** Do not create, modify, delete, or rename files until the user explicitly approves the plan. Questions and clarification are allowed during this phase. ### 4. Implement Once the plan is approved: - Make the smallest changes that satisfy the approved plan. - Follow project conventions (schemas first, type hints, error handling, logging). - If implementation reveals that the approved plan is materially wrong or incomplete, **stop and explain the discrepancy** rather than silently expanding scope. ### 5. Validate Run appropriate tests and checks. At minimum: - `python -m pytest tests/` - `ruff check src tests` - `mypy src/odoo_ocr --ignore-missing-imports --strict` (if feasible for the change) Fix issues caused by the change. Report any pre-existing failures clearly. ### 6. Review Before finishing, review your own changes: - Does the code match the approved plan? - Are there unintended changes or debug code left behind? - Are tests meaningful and not just mocks of themselves? - Would the next agent understand what you did? Load the `review` skill and use its checklist for any non-trivial change. ## Project Goal Build a Python application that: 1. Classifies incoming invoice files by type (native PDF, scanned print, handwritten, mixed image). 2. Routes each file to a specialized processing branch. 3. Runs OCR using local vision-language models (Ollama or llama.cpp). 4. Extracts a structured invoice representation. 5. Reviews extracted data against the original image using a second vision model. 6. Emits valid Odoo XML for import into Odoo Enterprise. ## Tech Stack - **Language**: Python 3.11+ - **Dependency management**: `pyproject.toml` (PEP 621); use `uv` or `pip`. - **Core libraries**: - `pydantic` v2 for all data schemas and settings. - `pymupdf` and `pdf2image` for PDF ingestion. - `Pillow` and `opencv-python-headless` for image preprocessing. - `httpx` for HTTP model clients. - `lxml` for XML generation and validation. - `pytest` and `pytest-asyncio` for tests. - **Local inference**: - Primary runtime: **Ollama** for fast iteration. - Optimized/runtime path: **llama.cpp server** (custom GGUF quants). - **Models**: - Document classifier: `Qwen2.5-VL-3B` or heuristics. - OCR / extraction: `Qwen2.5-VL-7B` or `GLM-OCR` (preferred for handwriting). - Review / validation: `Qwen2.5-VL-7B` or larger (`72B` if available). ## Architecture ``` Input File → Classifier (heuristic + small VLM) → Branch: digital_pdf → text/layout extraction → Branch: scanned_print → preprocess → VLM OCR → Branch: handwritten → preprocess → GLM-OCR / handwriting OCR → Branch: mixed_unknown → preprocess → ensemble OCR → Structured Extraction VLM → Review VLM (image vs extracted JSON) → Confidence check → XML Builder → Odoo XML + sidecar JSON ``` ## Code Conventions 1. **Project layout**: keep application code under `src/odoo_ocr/`. 2. **Schemas first**: define Pydantic models before writing business logic. 3. **Type hints**: use `typing` everywhere; run `mypy` in strict mode where practical. 4. **Error handling**: never swallow exceptions; return structured `Result` objects or raise domain exceptions. 5. **Configuration**: use `pydantic-settings` with `config.yaml` and env var overrides. 6. **Logging**: use Python standard `logging`; log every model call latency and token usage. 7. **No hardcoded secrets**: model endpoints, credentials, and paths come from settings. 8. **Tests**: every module must have tests under `tests/`. Use fixtures from `tests/fixtures/`. ## Model Client Rules 1. Support both Ollama and llama.cpp with a unified interface (`BaseVLMClient`). 2. Always emit JSON from VLMs when doing extraction/review. Use constrained prompts, not regex scraping. 3. Retry on transient failures with exponential backoff. 4. Cache model responses by content hash to avoid re-running expensive inference during development. 5. Record per-call metrics (model name, tokens, latency, prompt hash). ## Data Flow Rules 1. Every invoice must pass through the **review stage** before XML generation. The review model compares the original image with the extracted JSON and produces a `ReviewResult`. 2. Every invoice must produce: - A Pydantic `ExtractedInvoice` object. - A review result (`ReviewResult`) with confidence score and issue list. - An Odoo XML file (unless blocked by low confidence). - A sidecar JSON file with metadata, timings, and confidence. 3. If review confidence is below the configured threshold, mark the invoice for human review and do not generate final XML (or generate a draft with a warning flag). 4. Never send invoice data outside the local model endpoints. For production, "local" means a model endpoint reachable on the same host or within a trusted, on-premise runtime. A shared LAN endpoint (e.g. a dedicated Ollama server on the local network) is acceptable for integration testing and staging, but production deployments should keep invoice data on the same host as the model runtime unless explicitly approved. ## Review Stage Rules 1. The review stage is **mandatory**, not optional. 2. The review VLM must receive both the original invoice image and the extracted `ExtractedInvoice` JSON. 3. The review prompt asks the model to verify field presence, arithmetic, and consistency. 4. The `ReviewResult` must include a confidence score between 0.0 and 1.0 and a list of issues. 5. XML generation must respect the confidence thresholds in `config.yaml`: - `confidence >= 0.90`: generate final XML. - `0.75 <= confidence < 0.90`: generate XML with a human-review flag. - `confidence < 0.75`: do not generate final XML; emit sidecar JSON only. 6. See skill `review` for the full review checklist. ## Odoo XML Target Generate Odoo data-import XML compatible with Odoo Enterprise vendor bills: - `res.partner` (vendor) - `account.move` (vendor bill header) - `account.move.line` (invoice lines) - `account.tax` references by percentage/name See skill `odoo-xml-import` for detailed field mapping and a sample XML template. ## When to Ask the User Ask for clarification when: - The requested change would alter the model stack. - The change affects the Odoo target schema or import method. - You are unsure whether a file should be committed or a dependency added. - A requested feature conflicts with the local-only / privacy constraint. - Any project rule, skill instruction, or requirement is unclear or ambiguous.