Odoo xml conventions
Skill omas-odoo/odoo-superpowers/skills/odoo-xml-conventions
Use when writing, reviewing, or migrating any .xml file in an Odoo module — views, actions, menus, security records, data files, QWeb templates. Holds Odoo's naming, formatting, inheritance, and cross-version syntax conventions. Invoke before adding records to views/, security/, data/, or report/ directories.From its SKILL.md
npx -y skills add omas-odoo/odoo-superpowers --skill odoo-xml-conventionsAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
5.2 KB, ~1.2k tokens by cl100k_base, as published. Nobody here has run it
Odoo XML Conventions
Write the backend XML an experienced reviewer wouldn't comment on — so the review is about the design, not the naming. These are stances to carry, not a checklist to run: the exact patterns — naming tables, attribute order, xpath and version syntax — live in references/, pulled only when you need the fact. When a task skips the planning pass (odoo-grill), these reflexes carry the design alone.
Scope is backend XML — view, action, menu, security, and data records. OWL/QWeb client templates under static/src are odoo-js's domain — the inheritance instinct rhymes (extend, don't replace) but the directives and file conventions differ.
The stances
An external id is a contract, not a label
The XML id outlives the code that writes it: once a customer DB stores account_move_view_form, every ref=, every inheriting module, every Studio customization, and every migration script points at that string — renaming it isn't a rename, it's a break. So spend the naming thought up front, module-prefixed and descriptive, so the next person finds the record by guessing its id. The canonical patterns aren't aesthetics; they're the shared vocabulary reviewers and tooling (web_studio, OCA) parse. Legacy non-conforming ids you can't rename without a migration stay as-is — but new ids you add still follow the convention; don't let the exception spread. (Exact patterns: references/xml-naming.md.)
Inherit a view — never redefine it
When you need a field on someone else's form, your default is an xpath into their view, not a fresh copy: a copy forks the UI and silently drops every other module's contributions the day core changes the original. Anchor the xpath on something stable — a named field, a named page — never a position index, which shifts the moment any module inserts above you. An extension keeps the original's id and earns the .inherit.<module> name suffix; a primary view is a genuinely new record and takes a new id with no suffix. Get the suffix wrong (underscores where dots belong, or missing entirely) and the override loads silently wrong. (xpath, primary-vs-extension, suffix mechanics: references/xml-inheritance.md, references/xml-naming.md.)
The view is the UI — don't rebuild it in Python
Odoo's view layer already renders labels, formats, conditional visibility, and grouping; reaching into Python to assemble HTML, hardcode a layout, or compute what a <filter> or an invisible= expression states declaratively is fighting the framework — it won't theme, translate, or survive an upgrade. An empty <search> is the same mistake in miniature: it overrides the freebie Odoo generates with something worse, so give it the obvious search field, the lifecycle filters, and a group-by. Add a view type only when the model earns it — each one is surface area someone else maintains. (search and view-type forms: references/xml-format.md.)
Declare data with the narrowest semantics it needs
noupdate is a promise about who owns a record after install: noupdate="1" says "the customer may edit this and my next module update must not stomp it" (config seed, parameters), plain records say "this is mine, re-asserted on every upgrade" (views, actions, security). Decide per-record intent, not per-file habit — wrap only the locked records in <data noupdate="1">, and if the whole file is locked put it on <odoo> directly rather than a redundant <data>. Keep one concept per file (views / menus / security / data each their own) so review and demo-data loading stay predictable. (noupdate and data-tag forms: references/xml-format.md.)
Match the target version's era — a mismatch fails silent
XML doesn't reject an attribute from the wrong Odoo era, it ignores it: a v16 attrs= on a v17 DB simply never hides the field, no error to catch it. So before writing gating or inheriting a core view, know which major you target and which tag/attribute it actually renders — <tree> vs <list>, attrs=/states= vs inline invisible=/readonly=. When inheriting, your xpath must match the tag the target version renders, not the one you remember. (Era-by-era syntax: references/version-changes.md; the JS side of a port: odoo-js.)
References (consult for the fact, don't memorize)
| Need the exact... | Read |
|---|---|
| id / name pattern for a view, action, menu, group, or rule | references/xml-naming.md |
attribute order, <menuitem>/<template>, <search>, noupdate/<data> form | references/xml-format.md |
xpath anchor, primary-vs-extension, position= values | references/xml-inheritance.md |
pre/post-v17 gating, <tree>→<list>, column_invisible | references/version-changes.md |
At review time see also odoo-code-review; for where each XML file lives in the module, odoo-module-development.
What ships with it: 4 files
18.2 KB alongside SKILL.md
references/
- version-changes.md2.5 KB
- xml-format.md5.0 KB
- xml-inheritance.md3.7 KB
- xml-naming.md6.9 KB
Gives 0 of the 12 instructions most docs writing skills give in ~1.2k tokens
Counted across 1,637 of the 3,044 authors here whose files we hold, read 2026-08-07
- Announce the skill at startin 54 of 1637, across 26 files
- Convert legacy doc files before editingin 45 of 1637, across 7 files
- Predict questions readers might askin 42 of 1637, across 4 files
- Generate clarifying questions for initial contextin 42 of 1637, across 3 files
- Create document scaffold with placeholder textin 42 of 1637, across 3 files
- Brainstorm content options for each sectionin 42 of 1637, across 3 files
- Test the document with a fresh context-less instancein 42 of 1637, across 3 files
- Include exact file paths in every taskin 42 of 1637, across 15 files
- Ask interview questions one at a timein 42 of 1637, across 27 files
- Apply surgical edits during refinementin 41 of 1637, across 2 files
- Offer structured workflow or freeformin 40 of 1637, across 1 file
- Ask for document meta-contextin 40 of 1637, across 2 files
Grouped from the skills themselves: near-identical wordings counted once, and counted by distinct author, so one author publishing three of these counts once. Length counted with cl100k_base; the agent that loads this file may tokenize it differently.