Files
odoo-ai/CLAUDE.md
2026-05-20 21:26:34 +00:00

10 KiB

CLAUDE.md — odoo-ai

This file gives Claude Code the context it needs to work effectively on this project. Read this before making any changes.


What This Project Is

odoo-ai is a multi-agent AI system that integrates with Odoo 18 Community Edition. It consists of two main components that work together:

  1. agent_service/ — FastAPI service (port 8001) — the AI brain. Hosts MasterAgent + 8 specialist agents, all LLM backends, memory tiers, and tool layers.
  2. addons/activeblue_ai/ — Odoo 18 module — the Odoo-side integration. OWL2 chat panel, webhook controllers, approval workflows, and cron jobs.

These are deployed as two separate Docker Compose stacks on the same host (192.168.2.9).


Deployment Context

Item Value
Agent service URL http://192.168.2.9:8001 (internal)
Odoo URL http://192.168.2.9:8069
Ollama http://192.168.2.9:11434
LLM model activeblue-chat (llama-based, ~124s cold-start from disk)
Postgres Two separate DBs — one for Odoo, one for agent service

HIPAA constraint: HIPAA-locked agents (finance_agent, accounting_agent, employees_agent, expenses_agent) must always use Ollama. Ollama is to have the ability to call out to Claude or any other cloud AI solution for assistance on completing a task if Ollama has not been able to resolve the request after 5 tries, no personal data is to be leaked out of the environment.


Project Structure

odoo-ai/
├── agent_service/
│   ├── agents/          # MasterAgent, 8 specialist agents, PeerBus, SweepCoordinator
│   ├── llm/             # OllamaBackend, ClaudeBackend, LLMRouter, ToolCallValidator
│   ├── memory/          # ConversationStore, OperationalStore, KnowledgeStore, MemoryManager
│   ├── tools/           # OdooClient + per-domain tool files
│   ├── routers/         # FastAPI routers: dispatch, approval, registry, sweep, health
│   ├── prompts/         # System prompts — one per agent
│   ├── mcp/             # MCP gateway (SSE, 14 tools, all forced local)
│   ├── migrations/      # Alembic — 7 tables
│   ├── logging_utils/   # Structured JSON logging + Loki push
│   ├── config.py        # pydantic-settings — all config lives here
│   ├── app_state.py     # Global singletons (MasterAgent, LLMRouter, etc.)
│   └── main.py          # FastAPI app + lifespan startup (prewarm + auto-heal)
├── addons/
│   └── activeblue_ai/
│       ├── models/      # ab.ai.bot, ab.ai.directive, ab.ai.log, ab.ai.agent.registry
│       ├── controllers/ # /ai/chat, /ai/webhook/callback, /ai/health, /ai/approval/*
│       ├── views/       # XML views + menus
│       ├── security/    # groups + ACL
│       ├── data/        # cron jobs
│       └── static/      # OWL2 JS + CSS + XML templates (systray brain icon + chat panel)
├── tests/               # 433 pytest tests — run before committing
├── research/            # Per-domain research notes — read before touching a domain
├── debian/              # .deb packaging
├── docker-compose.yml        # Agent service + its Postgres
├── docker-compose.odoo.yml   # Odoo 18 + Odoo Postgres
├── Dockerfile
├── traefik_dynamic_ai.yml    # Traefik dynamic config for ai.activeblue.net
├── setup.sh                  # Detects stale DB volume, runs Alembic on startup
├── build_deb.sh / publish_repo.sh
├── .env.example
└── VERSION

Key Architectural Rules

Agent constraints

  • Max 8 tools per specialist agent — enforced by ToolCallValidator at startup; AgentConfigError is raised if exceeded. Do not add tools without removing others.
  • Agents are stateless — no instance state between requests. All state lives in the 3-tier memory tables.
  • MasterAgent is a singleton — instantiated once in app_state.py, shared across all requests.

Memory tiers

Tier Table TTL Scope
1 ab_conversation_memory 200 rows/user hard cap Per user
2 ab_operational_memory 90 days Per agent + scope
3 ab_knowledge_store Permanent Entity-keyed

LLM routing

  • LLMRouter selects backend: Ollama or Claude, based on LLM_PRIVACY_MODE env + per-agent DB overrides
  • Privacy modes: local (Ollama only) / hybrid (per-agent override) / cloud (Claude for non-HIPAA agents)
  • HIPAA agents are always Ollama — this is hardcoded, not just config

Auto-RAG

All agents automatically call odoo_doc_agent to fetch Odoo 18 workflow guidance before answering. Don't remove this.

Auto-heal loop

main.py lifespan starts a background task that calls sysops_agent.auto_heal() every 2 minutes if any system is degraded. If all systems are running properly, then the MasterAgent which is seen by the user in the Discuss tab of odoo will be seen as Online denoted by a green icon that odoo uses to show user's online. The MasterAgent is a user in odoo with the email of activeblue_ai_bot@local

Key workflows

The user will be able to drop a zip file into the MasterAgent, the MasterAgent has the ability to extract this file, examine the contents and proceed to ask on what to do with the files. The MasterAgent has OCR capability and has recently been updated to Llama Vision. The MasterAgent is to route the information with the customer's request to the correct Agent. As an example of workflows that have worked in the past; User drops receipts zip file in the chat; MasterAgent extracts and reads the files with OCR and asks what to do with them. Customer states; create an expense report. MasterAgent routes the information to the responsible agent. The responsible agent creates the expense report and then confirms when complete. MasterAgent replies to the customer that the report is complete.

Ollama cold-start

activeblue-chat takes ~124s to load from disk. _prewarm_ollama() runs as a background task at startup. OllamaBackend enforces _MIN_TIMEOUT=300s regardless of env var — do not lower this.


Coding Conventions

  • Python async throughout — all agent methods, tool calls, DB access are async
  • asyncpg for direct Postgres — not SQLAlchemy ORM, not psycopg2
  • pydantic-settings in config.py — all configuration comes from here, not hardcoded
  • Structured JSON logging via logging_utils/ — use this, not print() or raw logging
  • Conventional commits: feat:, fix:, chore:, docs:, refactor:, test:
  • Feature branches per agent or feature — don't commit directly to main for large changes
  • Alembic for all DB schema changes — never modify tables directly

Adding a new specialist agent

  1. Create agent_service/agents/<name>_agent.py — extend base agent class
  2. Create agent_service/tools/<name>_tools.py — max 8 tools
  3. Create agent_service/prompts/<name>_agent.txt
  4. Register in AgentRegistry
  5. Add tests in tests/test_<name>_agent.py and tests/test_<name>_tools.py
  6. If HIPAA-sensitive, hardcode Ollama in LLMRouter

Modifying the Odoo module

  • Odoo module lives in addons/activeblue_ai/ — copy this into the Odoo container's addons volume to deploy
  • After any model change: increment version in __manifest__.py and run module upgrade in Odoo
  • OWL2 components are in static/src/ — Odoo bundles JS at runtime, no separate build step needed
  • XML IDs must be globally unique — prefix everything with activeblue_ai.

Running Locally (Dev)

# 1. Copy and fill .env
cp .env.example .env

# 2. Start Odoo stack
docker compose -f docker-compose.odoo.yml up -d

# 3. Start agent service (dev mode with reload)
pip install -r requirements.txt
uvicorn agent_service.main:app --reload --port 8001

# 4. Run Alembic migrations
cd agent_service/migrations && alembic upgrade head

# 5. Install Odoo module
# Odoo → Settings → Apps → search "ActiveBlue AI" → Install

Tests

Always run tests before committing.

# Preferred: use the project test venv
.venv-test/bin/python -m pytest tests/ -q

# Or manually
pip install -r requirements-test.txt
pytest tests/ -v

433 tests covering all 8 agents, all tool layers, PeerBus, AgentRegistry, ToolCallValidator, memory, dispatch router, and LLM router. All tests run in local mode (Ollama mocked) — no cloud LLM calls in tests.


Environment Variables

See .env.example for full list. Critical ones:

Variable Notes
ODOO_URL http://ai.activeblue.net
ODOO_API_KEY Odoo user API key — get from Odoo user settings
OLLAMA_URL http://192.168.2.9:11434 — use this IP, not .2.10 or .2.47
LLM_PRIVACY_MODE local / hybrid / cloud — default local
ANTHROPIC_API_KEY Only needed for hybrid or cloud mode
POSTGRES_PASSWORD No default — must be set
WEBHOOK_SECRET Shared between Odoo and agent service

Common Issues & Gotchas

  • Ollama timeout errors on first request: model is still warming. Check /health/detailed — if it says warming, wait. Do not lower _MIN_TIMEOUT.
  • AgentConfigError at startup: a specialist agent has > 8 tools. Remove tools before adding new ones.
  • Alembic "table already exists": stale DB volume. setup.sh detects this — check its logic before manually dropping tables.
  • OWL2 chat panel not loading: JS bundle cache in Odoo. Run Assets → Clear cache in debug mode, or restart Odoo.
  • PeerBus routing loops: depth parameter limits recursion. Don't increase MAX_PEER_DEPTH without understanding call-log tracking.
  • Traefik ACME for ai.activeblue.net: config is in traefik_dynamic_ai.yml — copy to Traefik CT's dynamic config directory on 192.168.1.53.
  • Two separate Postgres instances: agent service DB ≠ Odoo DB. Alembic only manages the agent service DB. Never run Alembic against the Odoo DB.

What's Out of Scope for This Repo

  • Axolotl / QLoRA fine-tuning pipeline → /opt/axolotl on 192.168.2.9 (separate)
  • IRC bot → tocmo0nlord/irc-bot (separate repo)
  • Traefik main config → managed on CT 112 directly
  • Odoo HIPAA training eLearning module → different Odoo addon, different repo