| name | odoo-upgrade-executer |
| description | Implement the per-module task files produced by the odoo-upgrade-planner skill (tasks/NN-module.md) — apply mechanical fixes directly using the odoo-module-builder skill as the spec for correct target-version syntax, always pairing a model/field/table rename with its required openupgradelib migration script so no data is lost, stop and interview the user before any change that isn't a pure rename, then re-verify and test after each module. Never invents fixes outside the task files. Use when the user asks to implement/apply an Odoo upgrade plan, invokes /upgrade-execute, or has a tasks/ directory from a prior planning pass they want carried out. |
Odoo Upgrade Executer (/upgrade-execute)
You are implementing an Odoo module upgrade that was already planned.
This skill consumes the tasks/00-INDEX.md + tasks/NN-<module>.md files
produced by the odoo-upgrade-planner skill — it does not do its own
discovery. If no tasks/ directory exists yet, tell the user to run the
planner first; do not improvise an audit here.
Ground rule: this skill only acts on rows already logged in the task
files. If you notice something else while working (a new issue, a task
that turns out to be more/less involved than logged) you update that
module's task file to reflect it and tell the user — you do not silently
fix things that were never logged, and you do not silently expand scope.
Write the fix the way the target version expects. When a row calls for
new or rewritten code (a modernized view, a corrected cron record, a ported
_compute_display_name), use the odoo-module-builder skill's
reference files as the spec — they encode correct target-version shape
copied verbatim from shipped Odoo core. Don't reconstruct the correct
syntax from memory. If module-builder isn't installed, look the construct
up directly in the target branch per references/github-lookup.md.
0. Before starting
- Read
tasks/00-INDEX.md. Confirm the execution order with the user —
don't just start at row 1 without a nod, especially if cross-module
dependencies are noted.
- Confirm scope for this session: all modules in the index, or a subset?
A single upgrade-execute session doesn't have to cover every module.
- Establish a rollback point. Confirm the working tree is committed
(or stash/commit it) before the first edit, so every module's changes
land as a reviewable, revertable unit. Commit per module as you finish
it — not one giant commit at the end.
- Re-confirm
gh auth status if any module's task file references
Enterprise-verified findings — you'll re-verify before applying fixes
that touch Enterprise-dependent code (Step 2 below).
- If any row in scope has a
Data-safety action (any Models-section
rename), confirm a current database backup/restore point exists.
Migration scripts touch production data directly — see
references/data-safety-migrations.md. Do not proceed with a
data-affecting row without this confirmation. A git commit is not a
database backup.
Step 1 — Work one module at a time, in index order
For each module's task file, process sections in the order they appear —
Manifest → Models → Views → Data Records → Security → SCSS/CSS
→ JS — and within each section, in row order. Later rows often depend on
earlier ones (rows cross-reference by id, e.g. "depends on M1").
Within a section, prefer resolving install-blocker rows before
runtime-break before silent-regression — a module that won't install
can't be tested at all, so blockers first gets you to a testable state
soonest. Never let this reordering break a stated cross-reference.
Skip the ## Optional modernization section entirely unless the user
explicitly asks for it. Those rows are non-blocking by definition and
implementing them uninvited expands the diff the client has to review.
Each task is a - [ ] checkbox heading. Update the marker in the file
as you go — this is the audit trail, not your chat summary:
| Marker | Set it when |
|---|
- [x] | Implemented and its Verify by check passed |
- [-] | User decided to skip — add a **Skipped:** <reason> line |
- [ ] | Still open (leave it, and add a note if blocked) |
Keep the Progress: n / m done line at the top of the file current.
Never tick a box before the change is actually in the files.
For each task:
- Skip tasks already marked
- [x] or - [-].
- If
Needs decision: No (mechanical rename, or pure syntax
modernization):
- The task's
Action block is a list of imperative steps — file, line,
old value, new value, and any code to paste. Perform them as
written. Don't re-derive the fix or second-guess the mapping; the
planner already verified it against source. If a step is ambiguous or
doesn't match what's actually in the file, that's a real discrepancy —
stop and raise it (rule 4 below) rather than improvising.
- Re-verify the row's claim is still accurate — re-check the cited
source (
references/github-lookup.md) and confirm nothing you changed
earlier this session has superseded it (e.g. a field rename that a
later view-xpath row depends on).
- Where the Action block needs code the planner didn't paste, match
module-builder's reference for that construct —
cron-jobs.md for an
ir.cron record, views-search-filters.md/form-views.md for view
XML, models.md for Python, security.md for ACL/groups.
- If the task has a
Data-safety action entry, also write the
migration script it specifies — migrations/<new_version>/pre-migrate.py
using the exact openupgradelib call(s) named there
(references/data-safety-migrations.md). "Mechanical" describes the
rename mapping being unambiguous, not that the data side is optional —
never apply a rename in code without its paired migration script, or
the column/table/model's data is silently orphaned on upgrade.
- Run the task's Verify by check. Only then change
- [ ] to
- [x], and only once both the code change and (if applicable) the
migration script are in place.
- If
Needs decision: YES:
- Stop. Do not write code yet. These tasks have no Action block by
design — they carry a three-part briefing instead. Put it to the user:
- What this code does today — the business purpose in plain terms
(e.g. "this field tracks the alternate delivery address used when
invoicing and shipping differ"), not a restatement of the field name.
- Why it breaks — what specifically no longer exists/works, citing
the source in the task.
Step 2 — Re-verify before touching Enterprise-dependent code
If a row's Verified against cites odoo/enterprise, re-confirm gh auth status and repo access (references/github-lookup.md) immediately before
implementing that row — access can have changed since planning, and this
skill must not guess at Enterprise structure without a live check.
Step 3 — Post-module verification
After finishing all rows in one module's task file:
-
Re-run the planner's checks over the upgraded module only — manifest
depends resolve, models/fields exist, every inherit_id and xpath
resolves, every data record's refs resolve, ACL rows point at live
models, SCSS variables resolve, JS patch targets resolve. Any new
finding goes back into the task file as a fresh row rather than being
fixed ad hoc.
-
If a local/test Odoo instance is available, attempt the actual module
upgrade (-u <module> --stop-after-init or equivalent) and capture any
ir.ui.view xpath errors, missing-field/model errors, or invalid-field
errors from the log. Any such error means something was missed — log it
as a new task row; do not patch around it silently.
-
A clean install is not a pass. runtime-break rows — anything in
## Method Overrides, and JS/POS findings — do not surface at install
at all. The module loads fine and raises TypeError the first time
something exercises the code path, frequently on a screen that looks
unrelated to the module. Start the server and actually open:
- every screen named in a
runtime-break row,
- the form/list views of each model the module touches or overrides
a search on,
- Settings, and the partner and user forms — broad
_search/compute overrides commonly blow up there even when the
module is about something else entirely.
Watch the server log while clicking. A TypeError: ... got an unexpected keyword argument means an override signature is still
wrong; re-open that row rather than treating the module as done.
-
Commit this module's changes as its own commit.
-
Report to the user: what was applied mechanically, what needed a
decision (and what was decided), what's left open, and the verification
result — before moving to the next module in the index.
Step 4 — After all modules in scope are done
Update tasks/00-INDEX.md's status per module and give the user a final
summary: modules fully done, modules with open/skipped rows and why, any
new findings surfaced during execution that weren't in the original plan,
and anything left in ## Optional modernization they may want to schedule
separately.
Hard rules
- Never implement a row marked
Needs decision? = Yes without first
asking, using the three-part question shape in Step 1.3. This is the
single most important rule in this skill.
- Never invent work outside the task files. New findings get added as
new rows and are then subject to the same mechanical/decision rule — they
are not fixed in the same breath they're discovered.
- Never implement
## Optional modernization rows uninvited.
- Never silently change business logic. A "mechanical" fix is only ever
a rename/re-path/syntax swap with proven zero behavior change; anything
else is a decision row by definition, even if it looks small.
- Never rename a model/field/table in code without its migration
script. The ORM does not carry old data to a new column/table/model
name on its own — skipping the migration script is silent data loss, not
a shortcut. See
references/data-safety-migrations.md.
- Never run a data-affecting migration without a confirmed database
backup. A git commit does not protect data.
- Never write replacement syntax from memory when module-builder or the
target branch can tell you the correct shape.
- Don't reorder modules from the index without telling the user why
(e.g. you discovered a dependency the planner missed).
- Never tick a checkbox before the change is in the files and its
Verify by check passed. The markers are the audit trail; a wrong one
is worse than none.
- Never treat a clean install as proof for a
runtime-break task.
Those only surface when a screen is opened — open it.
- Keep the task files as the single source of truth — checkbox and
Progress: updates go into the actual tasks/*.md files, not just a
chat summary, so the audit trail survives the session.
Reference files
| Need | File |
|---|
| Correct target-version syntax for any construct you rewrite | the odoo-module-builder skill's references/ |
| Confirmed 19.0 changes with both-branch evidence and failure modes | references/verified-19-changes.md |
How to check odoo/odoo + odoo/enterprise on GitHub, gh auth flow | references/github-lookup.md |
| Data safety: writing the migration script a rename task requires | references/data-safety-migrations.md |
| The task file schema this skill reads and updates | references/task-file-format.md |