Odoo 17.0 Development Skill
A comprehensive skill set for building production-quality Odoo 17.0 custom modules. Covers the full development lifecycle: module structure, ORM, views, actions, performance, and testing — following official Odoo coding guidelines.
When to Apply
Reference these rules when:
- Creating or extending a custom Odoo 17.0 module
- Defining models, fields, or compute methods
- Writing
@apidecorators, constraints, or onchange handlers - Building XML views, menus, and actions
- Optimizing queries or processing large recordsets
- Writing unit tests, integration tests, or UI tours
- Adding chatter, sequences, ratings, or portal access to a model
Rule Categories by Priority
| Priority | Category | Impact | Prefix |
|---|---|---|---|
| 1 | Module Manifest | HIGH | manifest- |
| 2 | ORM Models | HIGH | models- |
| 3 | ORM Fields | HIGH | fields- |
| 4 | API Decorators | HIGH | decorators- |
| 5 | Recordset & Domains | MEDIUM | recordsets- |
| 6 | Actions | MEDIUM | actions- |
| 7 | Performance | MEDIUM | performance- |
| 8 | Testing | MEDIUM | testing- |
| 9 | Mixins | LOW | mixins- |
Quick Reference
1. Module Manifest (HIGH)
manifest-required-keys— Every module must havename,version,depends,license,installablemanifest-data-order— Security CSV always first indata, menus always lastmanifest-assets-bundle— Register JS/OWL/SCSS files underassets.web.assets_backendmanifest-version-format— Use{odoo}.{major}.{minor}.{patch}e.g.17.0.1.0.0manifest-dependencies— Missing or wrongdependsprevents module installation
2. ORM Models (HIGH)
models-class-order— Follow canonical attribute → field → constraint → compute → CRUD → action → helper ordermodels-type-selection— UseModelfor persistence,TransientModelfor wizards,AbstractModelfor mixinsmodels-inherit-modes— Know the 4_inheritmodes: extend, copy, compose, delegatemodels-sql-constraints— Prefer_sql_constraintsover Python for uniqueness checksmodels-required-attributes—_nameand_descriptionare required on every new model
3. ORM Fields (HIGH)
fields-monetary-currency—Monetaryfields always require a pairedcurrency_fieldfields-many2one-index— Always setindex=TrueonMany2onefields used in searchesfields-store-decision— Usestore=Trueonly when field needs to be searched or sortedfields-m2m-commands— Use ORM write commands(0,0,v)(4,id)(6,0,ids)for relational writesfields-selection-add— When extending aSelection, always defineondeletefor new keys
4. API Decorators (HIGH)
decorators-depends-completeness— List ALL fields that affect the computed resultdecorators-depends-assign-all-branches— Always assign computed field in every code pathdecorators-constrains-exception—@api.constrainsmust raiseValidationError, neverUserErrordecorators-constrains-loop— Always loopfor rec in selfinside@api.constrainsdecorators-onchange-not-enforced—@api.onchangedoes not run on programmatic create/writedecorators-onchange-newid—self.idinside@api.onchangeis aNewId, not an integerdecorators-create-multi— Always use@api.model_create_multiforcreate()overrides in 17.0decorators-depends-context-no-store— Fields with@api.depends_contextcannot bestore=True
5. Recordset & Domains (MEDIUM)
recordsets-search-count— Usesearch_count()instead oflen(search())for countingrecordsets-batch-write— Callwrite()on the whole recordset, never inside a looprecordsets-batch-create— Pass a list tocreate([...])instead of calling it in a looprecordsets-domain-operators—|and&are prefix operators applying to the next two conditionsrecordsets-sudo-comment— Always add a comment explaining whysudo()is usedrecordsets-raw-sql-params— Never format SQL strings; always use%sparameterized queries
6. Actions (MEDIUM)
actions-window-menu— Always bind leaf<menuitem>to anir.actions.act_windowrecordactions-data-order— Declare actions in view XML, menus in a separatemenus.xmlloaded lastactions-python-return— Return action dicts from Python methods to open views or wizardsactions-cron-method— Cron methods must be decorated with@api.modeland handle their own errorsactions-server-binding— Usebinding_model_idto add server actions to the Action dropdown
7. Performance (MEDIUM)
performance-prefetch— Rely on ORM prefetch; usemapped()to extract cross-record field valuesperformance-no-loop-write— Never callwrite()orcreate()inside aforloopperformance-index-searched-fields— Addindex=Trueon fields used insearch()domains orORDER BYperformance-read-group— Useread_group()for aggregations instead of loading full recordsetsperformance-invalidate-after-sql— Callinvalidate_model()after any raw SQL write
8. Testing (MEDIUM)
testing-setup-class— UsesetUpClassfor shared fixtures;setUponly when full isolation is neededtesting-post-install-tag— Tag tests with@tagged('post_install', '-at_install')testing-constrains-coverage— Every@api.constrainsmethod must have a test that triggers ittesting-wizard-pattern— Test wizards by creating them with context, then calling the action methodtesting-tour-js— UI tours must be registered in theweb_tour.toursregistry and tested viaHttpCase
9. Mixins (LOW)
mixins-mail-thread— Add_inherit = ['mail.thread', 'mail.activity.mixin']for chatter + activitiesmixins-tracking— Usetracking=Trueon fields to log changes in the chatter automaticallymixins-sequence— Useir.sequence+next_by_code()in fielddefault=for auto-numberingmixins-portal— Implement_compute_access_urlwhen usingportal.mixinmixins-message-post— Usemessage_post()for programmatic chatter messages
How to Use
Read individual skill files for detailed explanations, correct and incorrect code examples, and gotchas:
odoo-manifest.md
odoo-orm-models.md
odoo-orm-fields.md
odoo-orm-decorators.md
odoo-orm-recordsets.md
odoo-actions.md
odoo-performance.md
odoo-testing.md
odoo-mixins.md
Each file contains:
- Why it matters in Odoo 17.0
- Incorrect code examples with explanation (
# ❌ WRONG) - Correct code examples with explanation (
# ✅ CORRECT) - Decision trees and edge cases
Full Compiled Document
For the complete guide with all rules, patterns, and examples expanded,
including global coding guidelines and skill routing table: AGENTS.md