Unified health scoring for Odoo custom addons
Project description
Odoo Doctor 🩺
Unified health scoring for Odoo custom addons.
Combines confidence-aware static analysis with optional external linters (Ruff, Pylint-Odoo) to produce a single 0–100 score per addon — designed for CI pipelines and AI coding agents.
Quick Start
# 1. Chạy ngay (không cần install)
pipx run odoo-doctor scan .
# 2. Install global
pip install odoo-doctor
odoo-doctor scan .
# 3. JSON output cho CI / agents
odoo-doctor scan . --json
# 4. Fail nếu score < 80
odoo-doctor scan . --min-score 80
# 5. Chỉ scan file đã thay đổi (PR review)
odoo-doctor scan . --diff main --json
What it checks
| Rule | Tier | Category |
|---|---|---|
raw-sql-string-interpolation |
P0 | Security |
missing-access-csv |
P0 | Security |
unknown-model-in-access-csv |
P1 | Correctness |
duplicate-xml-id |
P1 | Correctness |
view-field-not-in-model |
P1 | Correctness |
button-method-not-found |
P1 | Correctness |
missing-xml-ref |
P1 | Correctness |
manifest-missing-dependency |
P1 | Module Hygiene |
manifest-missing-required-fields |
P2 | Module Hygiene |
search-in-loop |
P1 | Performance |
public-controller-sudo-risk |
P1 | Security |
unbounded-search |
P2 | Performance |
manifest-data-order-risk |
P2 | Module Hygiene |
override-missing-super |
P1 | Correctness |
compute-missing-depends |
P2 | Correctness |
Plus Ruff and Pylint-Odoo findings when those tools are installed.
Score explained
Each category score starts at 100 and loses points per high-confidence
finding, where each finding deducts tier_impact × category_weight
(default weight 1.0; override via [category_weights]). The overall score
blends only in-scope categories (those with at least one active rule):
category_score = max(0, 100 − Σ(tier_impact × category_weight))
overall = 0.4 × min(in_scope_category_scores)
+ 0.6 × avg(in_scope_category_scores)
Tier impacts: P0 = 25, P1 = 10, P2 = 4, P3 = 1.
| Label | Range |
|---|---|
| Excellent | 90–100 |
| Good | 75–89 |
| Needs work | 50–74 |
| Critical | 0–49 |
Each finding deducts points by tier: P0 = −25, P1 = −10, P2 = −4, P3 = −1.
Only high confidence findings count toward the score.
Configuration
odoo-doctor init # creates odoo-doctor.toml
[odoo-doctor]
odoo_version = "17.0"
addons_paths = ["."]
odoo_source_path = "/path/to/odoo/source"
capabilities = ["enterprise", "owl"]
min_score = 75
[adapters]
ruff = true
pylint_odoo = false
[severity]
"search-in-loop" = "warning"
[ignore]
rules = []
files = ["**/migrations/**"]
modules = []
[category_weights]
Security = 1.5
[surfaces.pr_comment]
min_confidence = "all"
categories = []
[surfaces.ci_failure]
min_confidence = "high"
categories = []
CI Integration
GitHub Actions
The easiest way to integrate Odoo Doctor into GitHub Actions is using our official composite action. See .github/workflows/odoo-doctor.example.yml for a full example.
- name: Odoo Doctor Scan
uses: minhhq-a1/odoo-doctor@v0.3.1
with:
fail-on: warning
min-score: 75
diff-base: main
pr-comment: true
paths: "."
If you prefer pip install, you can run it directly:
- name: Odoo Doctor (pip)
run: |
pip install odoo-doctor
odoo-doctor scan . --format github --min-score 75 --fail-on error
SARIF & Baseline Mode
For GitHub Code Scanning and IDE integration:
odoo-doctor scan . --format sarif > results.sarif
# Then upload via github/codeql-action/upload-sarif
To capture current debt and block only new findings in CI:
odoo-doctor scan . --write-baseline .odoo-doctor-baseline.json
# Commit the baseline, then in CI:
odoo-doctor scan . --baseline .odoo-doctor-baseline.json --fail-on warning
CI/PR Surfaces
--format github: Emits GitHub Actions annotations inline.--score-delta <base-ref>: Opt-in PR score delta. It does a worktree-isolated second scan and needs git history (fetch-depth: 0in Actions).- Sticky PR comment: Posted/updated via
ghwhen--format githubruns in a PR with a validGH_TOKEN. Idempotent via a hidden marker.
pre-commit
# .pre-commit-config.yaml
repos:
- repo: local
hooks:
- id: odoo-doctor
name: Odoo Doctor
language: system
entry: odoo-doctor scan --diff HEAD --fail-on error
pass_filenames: false
types: [python]
Agent Usage
Odoo Doctor is designed for AI coding agents. Install the SKILL.md files:
odoo-doctor install # installs to .odoo-doctor/skills/
Then in your agent workflow:
# After editing Odoo code
odoo-doctor scan . --diff main --json
# Fix P0/P1 findings with confidence: "high"
# Re-scan to verify fixes
odoo-doctor scan . --diff main --json
Use odoo-doctor rules explain <rule-name> to understand any finding.
Generating stubs for your Odoo version
Bundled stubs cover 17.0, 18.0, 19.0 (core models only).
For full accuracy, generate from source or a live instance:
# From Odoo source checkout
python -m odoo_doctor.graph.stubs.build_stubs source \
--odoo-path /path/to/odoo \
--version 17.0
# From a live Odoo instance (no source needed)
python -m odoo_doctor.graph.stubs.build_stubs rpc \
--rpc-url http://localhost:8069 \
--rpc-db mydb \
--rpc-password admin \
--version 17.0
The generated JSON is written to src/odoo_doctor/graph/stubs/data/<version>.json
(or --output <path> for a custom location).
Inline suppression
x = self.env.cr.execute(f"SELECT ...") # odoo-doctor: disable=raw-sql-string-interpolation
<record id="my_record" model="ir.ui.view"> <!-- odoo-doctor: disable=duplicate-xml-id -->
Exit codes
| Code | Meaning |
|---|---|
0 |
Clean — no triggered thresholds |
1 |
Findings at or above --fail-on severity |
2 |
One or more modules score below --min-score |
3 |
Invalid argument, out-of-range --min-score, or git/ref failure |
Development
git clone https://github.com/minhhq-a1/odoo-doctor
cd odoo-doctor
pip install -e ".[dev]"
pytest # 324+ test cases
pytest --cov=odoo_doctor # with coverage
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file odoo_doctor-0.3.1.tar.gz.
File metadata
- Download URL: odoo_doctor-0.3.1.tar.gz
- Upload date:
- Size: 66.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
706a15ccc857837442fb6608bbfdad151ba15bcd9005375b40258d19b8b3b757
|
|
| MD5 |
6c50bafaa150ec78b5dc23889526f8c0
|
|
| BLAKE2b-256 |
0ead5a7334a1580c7b6037a94e2c4188312cc2778240c1d5d6b7bca17f6ff6d7
|
Provenance
The following attestation bundles were made for odoo_doctor-0.3.1.tar.gz:
Publisher:
publish.yml on minhhq-a1/odoo-doctor
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
odoo_doctor-0.3.1.tar.gz -
Subject digest:
706a15ccc857837442fb6608bbfdad151ba15bcd9005375b40258d19b8b3b757 - Sigstore transparency entry: 1975681932
- Sigstore integration time:
-
Permalink:
minhhq-a1/odoo-doctor@df2d603b435166519ec1d3ebdab263ffcf4a1c60 -
Branch / Tag:
refs/tags/v0.3.1 - Owner: https://github.com/minhhq-a1
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@df2d603b435166519ec1d3ebdab263ffcf4a1c60 -
Trigger Event:
release
-
Statement type:
File details
Details for the file odoo_doctor-0.3.1-py3-none-any.whl.
File metadata
- Download URL: odoo_doctor-0.3.1-py3-none-any.whl
- Upload date:
- Size: 104.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8770c029ac1b1e4eee507f276e4743cdf1b7404f24afc40b9b6786e30dc054ab
|
|
| MD5 |
639393f4a5a326a4400f8c408810345f
|
|
| BLAKE2b-256 |
0505f47f367c58066600bbeb86516e971df0af08329f10ab6d2ad4e6ec480476
|
Provenance
The following attestation bundles were made for odoo_doctor-0.3.1-py3-none-any.whl:
Publisher:
publish.yml on minhhq-a1/odoo-doctor
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
odoo_doctor-0.3.1-py3-none-any.whl -
Subject digest:
8770c029ac1b1e4eee507f276e4743cdf1b7404f24afc40b9b6786e30dc054ab - Sigstore transparency entry: 1975682013
- Sigstore integration time:
-
Permalink:
minhhq-a1/odoo-doctor@df2d603b435166519ec1d3ebdab263ffcf4a1c60 -
Branch / Tag:
refs/tags/v0.3.1 - Owner: https://github.com/minhhq-a1
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@df2d603b435166519ec1d3ebdab263ffcf4a1c60 -
Trigger Event:
release
-
Statement type: