From basaltbytes-skills
Use when working on Odoo 19 web-client customizations in JavaScript or arch XML: assets, `@odoo-module`, registries, services, systray/client actions, browser state, `patch(...)`, view descriptors, `js_class`, `searchModel`, modifiers, `options=`, XPath inheritance, built-in/custom views, field/view widgets, `standardFieldProps`, or `extractProps`. Not for backend ORM, Hoot tests, Owl internals, or generic JS/Owl.
How this skill is triggered — by the user, by Claude, or both
Slash command
/basaltbytes-skills:odoo-frontendThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
> The skill is based on Odoo 19.0 documentation, source-verified view references, tutorial-derived frontend patterns, and local solved tutorial addons, then trimmed on 2026-04-22 to keep only high-signal Odoo-specific frontend guidance.
GENERATION.mdexamples/custom-view-minimal.mdexamples/field-widget.mdexamples/gallery-view-full.mdexamples/view-inheritance.mdexamples/view-widget.mdreferences/advanced-kanban-customization.mdreferences/arch-xml.mdreferences/built-in-views.mdreferences/core-assets-and-modules.mdreferences/core-registries-and-extension-points.mdreferences/features-client-actions-and-shared-state.mdreferences/features-patching-code.mdreferences/field-widgets.mdreferences/view-architecture.mdreferences/view-inheritance.mdreferences/view-registration.mdreferences/view-widgets.mdThe skill is based on Odoo 19.0 documentation, source-verified view references, tutorial-derived frontend patterns, and local solved tutorial addons, then trimmed on 2026-04-22 to keep only high-signal Odoo-specific frontend guidance.
Use this for Odoo-specific web-client wiring and arch parser quirks, not generic frontend theory. It intentionally skips generic Owl, JS, QWeb, editor/mobile APIs, and testing APIs.
Do not read every reference up front. Start from the slice that matches the task.
| If the task is about... | Read |
|---|---|
Asset bundles, manifest operations, lazy asset loading, named lazy bundles, LazyComponent, loadJS, @odoo-module, aliases, import rules | core-assets-and-modules |
Registry categories, sequence ordering, systray, main_components, command_provider, lazy_components, action registry | core-registries-and-extension-points |
Systray items, popover client actions, command-palette actions, shared service state, Reactive models, browser-backed persistence | features-client-actions-and-shared-state |
Safe, minimal use of patch(...) | features-patching-code |
View descriptor, Controller / Renderer / Model / ArchParser, or WithSearch resolution | view-architecture |
Build a brand-new view type or customize one via js_class | view-registration, then custom-view-minimal or gallery-view-full |
Extend a built-in kanban with a sidebar, searchModel, fuzzyLookup, or t-model | advanced-kanban-customization |
Built-in view archs for kanban, graph, pivot, calendar, search | built-in-views |
Root tags, modifiers, options=, groups=, or removed attrs= / states= patterns | arch-xml |
| Add, move, replace, or mutate nodes with XPath inheritance | view-inheritance, then view-inheritance example |
Author a custom <field widget="..."> | field-widgets, then field-widget example |
Author a custom <widget name="..."> | view-widgets, then view-widget example |
| Need a full custom-view scaffold instead of a minimal one | gallery-view-full |
A view is five pieces glued together by registry.category("views"):
| Piece | Role | Standard impl |
|---|---|---|
ArchParser | Reads XML into archInfo. Synchronous, no Owl. | Custom per view type |
Model | Data layer. | RelationalModel or a custom model |
Renderer | Pure Owl component. Draws model.root. Never fetches. | Custom per view type |
Controller | Root Owl component. Owns layout and wires Model to Renderer. | Custom per view type |
| View descriptor | Plain object with type, Controller, Renderer, Model, ArchParser, props, and optional extras | Required |
A sixth optional Compiler converts arch XML into Owl templates at runtime for views such as form and kanban. Use view-architecture for the full descriptor catalogue and runtime resolution path.
| Pattern | Status | Fix |
|---|---|---|
attrs="{'invisible': [...]}" | Removed in 17. Raises ValidationError. | Put invisible=, readonly=, or required= directly on the node |
states="draft,confirmed" | Removed in 17 | Rewrite as a direct expression, e.g. invisible="state not in ('draft', 'confirmed')" |
<tree> root | Removed in 17 | Use <list> |
JSON.parse(options) on <field> | Wrong. <field options> is py.js, not strict JSON. | Trust the parsed options in extractProps |
Skipping JSON.parse on <button options=...> | Wrong in the other direction | Parse button options as JSON |
Mutating record.data directly | Bypasses model machinery | Use record.update({...}) |
| Reading raw arch attrs inside a component | Leaks parsing concerns into rendering | Parse in extractProps and pass clean props |
| Custom widget without standard props | Breaks prop validation and runtime expectations | Spread standardFieldProps or standardWidgetProps |
New file under static/src/ not referenced in __manifest__.py | Loads 0 bytes at runtime | Add it to the right asset bundle in the same diff |
__manifest__.py, XML arch, and existing static/src files. In Odoo, most frontend bugs are wiring mistakes before they are logic mistakes.patch(...).js_class customizations, spread the built-in descriptor instead of copying it.extractProps; keep components ignorant of raw arch XML.mountWithCleanup, mountView, defineModels, or mock-server control.npx claudepluginhub basaltbytes/skills --plugin basaltbytes-skillsGuides completion of development work by verifying tests, detecting environment, and presenting structured options for merge, PR, or cleanup.
Enforces test-driven development: write failing test first, then minimal code to pass. Use when implementing features or bugfixes.
Guides creation and editing of skills using test-driven development with pressure scenarios and subagents to verify agent compliance.