Repository navigation
Releases: asao-vn/asao-odoo-tools
Release list
v0.17.1
-
Fixed, operation packs (found in a review of packs on 2026-10-18):
- Crash. A
WIZARDoperation without itswizardcrashed odoo-cli when the pack was read: on
pack add, or onpack syncfrom a module that ships the mistake. It is now refused with a reason. - Reaching outside the company. A pack could open a wizard that reaches outside the company or grants
access. Packs now refuse what odoo-cli leaves out on purpose:- e-mail and SMS composers, and mailings;
- sending an invoice (
account.move.send) and post; - portal access, and invitations.
- Money rated too low. Every accounting and payment model is HIGH risk at least, matched by prefix.
account.payment.registerwas MEDIUM.
- Crash. A
-
Changed: at data level operate,
resolvefinds what is named and cannot count.mcp serve --data-access operateruns it strictly:- conditions on a name, a reference, a state or the partner, by
=,!=,inorilike; - no range on a date, an amount or an id;
- at most 5 ids, with no count;
- 30 calls a session.
As 0.17.0 shipped it, an agent at operate counted 54 invoices by paging ids. Measured again with the
strict build: every write that names its record is done (5 of 5), and no figure is read (0 of 6). - conditions on a name, a reference, a state or the partner, by
This release's rehearsal
Before the tag, the public workflows ran on this release's commit, f91a10f:
- Conformance (run 39102583899):
- 19.0: 1252 of 1301 re-agreed, 0 regressed;
- 20.0: 1161 of 1187 re-agreed, 0 regressed;
- K01 to K11 AGREE on both series.
- Packs proof (run 39102587608):
19 of 19 checks agree on Odoo 19.0. It covers packs, data levels, the secret page, and the pack fixes of
this release.
The privacy-cost pilot measured strict resolve at operate: 5 of 5 writes that name their record, and 0 of
6 figures read.
This release's own conformance
The tag ran the conformance workflow again
(run 39104322319):
- 19.0: 1253 of 1301 re-agreed, and 0 regressed;
- 20.0: 1161 of 1187 re-agreed, and 0 regressed;
- Controls and alerts: K01 to K11 AGREE on both series.
Its evidence, conformance-19.0.tar.gz and conformance-20.0.tar.gz, is attached below.
v0.17.0
1368 operations: 1301 verified on 19.0, and 1187 of the 1306 that 20.0 can run. The Python companion asao-erp 0.4.0 is released with it (pip install asao-erp).
-
New: bounds on an agent, and a stop switch (DEC-2026-0182).
agents stop --profile Prefuses every call of everymcp serveon that profile, from its next
call, with the reason you give. It also stopsroutines runandroutines due.agents resume
lifts it.mcp serve --max-calls N --max-writes Nbound a session.--rate Ncaps the calls in a minute (60 by default), since each call takes one of Odoo's workers
while it runs.- Every refusal is in the trace, and nothing runs.
-
New:
--accept, a write judged at three levels (DEC-2026-0183).ODOO_VALID: Odoo answered, the operation is verified, and its postcondition held.INTENT_VERIFIED: every value asked for, read back, is what Odoo holds.RESULT_ACCEPTED: the review checks over the weeks around the record find nothing that names it, for
example an invoice made twice or a tax rate that is not the product's.- The result says the level reached, and why it stopped there.
-
New:
resolve, find records without seeing them. It answers ids only, at most 20, from a filter on
plain fields. A filter on personal data or free text is refused. It is offered at data level operate, so
an agent that may not see the data can still find the customer's latest draft and act on it. -
Settings:
stock_text_confirmation(text the customer when a delivery is done, Odoo's paid SMS) can
be switched off. While it is on, validating a delivery for a customer with a phone opens a blocking
dialog. It was verified on 19.0 and 20.0, read through the CLI and through an independent oracle. -
Fixed: a line could not be added to a quotation or an RFQ.
--order, the order a line belongs to,
was refused as a read's sort order. An agent in the privacy-cost experiment found it. -
New: review checks as files (DEC-2026-0181). A check can be a file,
odoo-cli.check/v1, run by one
engine.- What a file holds: the read operation it needs, how records match (
pairsorgroups), how a
finding reads, and its own cases, at least one to flag and one to leave alone. - Commands:
review test-checkchecks a file and runs its cases;review add-checkandremove-checkkeep a team's own checks per profile. These run beside the
built-in ones, and their cases run again each time they load.
- Two built-in checks moved: O22 and O23 are now files. Both versions gave byte-identical findings
on 786 random cases before the Go code was removed. Guide: docs/checks.md.
- What a file holds: the read operation it needs, how records match (
-
New: verdicts and precision.
- Every finding has a stable
key. review verdict --finding KEY --real|--false-alarmkeeps the person's judgement, which later runs show
on the finding.review precisiongives each check's share of real findings, and lists the false alarms to turn into
cases.
- Every finding has a stable
-
The review simulation runs every week, on a new seed: 12 months, with noise and the held-out set.
-
New: a trace of what agents did. Every tool call an agent makes through
mcp serveis appended
to a local journal of the profile it ran against, chained by hashes. An entry holds:- when, which agent host, and the command line you saw;
- whether you confirmed it, its status and error code, and the record it wrote;
- the data level the server ran at.
It never holds what a read returned.
- Commands:
trace listshows the entries, andtrace verifyfinds an entry that was removed or
changed. Both are yours alone, never an agent's. - Turning it off:
ODOO_CLI_TRACE=off. - Not traced: an agent that runs odoo-cli in a shell.
-
Review, measured on a bigger and messier business. The
review-simworkflow can now run 12 months
or more, with a real shop's everyday noise and three kinds of business (--profile trader|retail|service).- Four checks fixed: a year with that noise found four formulas that only held on a small, clean
business: O25 (round claims), O19 (below cost), O21 (refund after payment) and O02 (an invoice twice).
All four were fixed, and the invoice read gainedinvoice_origin, re-verified on 19.0 and 20.0. - The held-out set: 18 cases and 13 look-alikes written after the fixes (
--fresh). On all three
kinds of business, every case was found and no look-alike was flagged
(run 38995070451).
- Four checks fixed: a year with that noise found four formulas that only held on a small, clean
-
The secret page's code moved to a package of its own (
agentkit/secretpage), beside the trace
(agentkit/trace). Neither knows Odoo.
Install
curl -fsSL https://raw.githubusercontent.com/asao-vn/asao-odoo-tools/main/scripts/install.sh | sh
pip install asao-erp # the Python companion, for analysisThis release's rehearsal
Before the tag, the public conformance workflow ran on this release's commit, bcc7b9c
(run 39042150205).
- 19.0: 1251 of 1301 verified operations re-agreed, and 0 regressed. Two were unstable:
people.expense.submitandmanufacturing.order.mark_done_confirm_consumption_with_backorder. - 20.0: 1161 of 1187 re-agreed, 0 regressed, and 12 new agreements.
event.lead_rule.execute_rule
was unstable. - Controls and alerts: K01 to K11 AGREE on both series.
The review's measurements, in the public review-sim workflow:
- The held-out set, written after the last change to the checks: 19/19 cases caught and 13/13
look-alikes left alone, on three kinds of business. - Real sales from UCI Online Retail II, with nothing planted in them: every planted case was still
caught. O21 raised 4 alarms on 59 real returns from customers it had not seen, down from 36 alarms on
79 returns.
This release's own conformance
The tag ran the conformance workflow again
(run 39044236011):
- 19.0: 1253 of 1301 re-agreed, and 0 regressed.
people.expense.submitwas unstable, as before. - 20.0: 1161 of 1187 re-agreed, 0 regressed, and 12 new agreements.
event.lead_rule.execute_rule
was unstable, as before. - Controls and alerts: K01 to K11 AGREE on both series.
Its evidence, conformance-19.0.tar.gz and conformance-20.0.tar.gz, is attached below.
v0.16.0
1368 operations, unchanged: 1301 verified on 19.0, and 1187 of the 1306 that 20.0 can run.
-
New: operation packs (DEC-2026-0176). A custom module brings its own operations as a pack, a
JSON file it ships asstatic/odoo-cli/pack.jsonthat names its reads, writes, object buttons,
wizards and reports. It holds data, never code.- Commands:
pack syncfinds the packs of the installed custom modules and keeps them for the profile;pack addkeeps one from a file, for Studio or Odoo Online;pack list,pack showandpack removemanage them;pack generatewrites a first pack for a module's author.
- Checks against your Odoo before a pack is kept:
- the module is installed;
- its models and fields exist;
- every method is an object button of the model's views;
- every wizard is a wizard;
- every report exists.
- Never allowed: a pack never names users, rights, company settings, code, mail or a credential,
never deletes, and never calls a private or ORM method. - Running them:
- a pack's operations are commands and MCP tools of the profile, and need
--allow-unverified; - an agent's write through a pack always asks the person, even under
--confirm-writes=false; - risk floors: a button or a wizard is MEDIUM at least, and a write to a payment, a journal
entry or a bank account is HIGH.
- a pack's operations are commands and MCP tools of the profile, and need
- Documentation and proof: docs/packs.md is the guide. The
packsworkflow
(conformance/packs/prove.sh) proves it on a demo module: on Odoo 19.0, 15 of 15 checks agree
(run 38981143110). The
checks cover generate, sync, the MCP access, the list, a create by customer name, an update,
three buttons, a wizard, Odoo's own refusal, a PDF, and a method the pack does not name.
- Commands:
-
New: how much of the data an agent sees (DEC-2026-0178).
mcp serve --data-accesssets the
level, and odoo-cli enforces it in every result and error it gives the agent:act, the default: personal data, free text and files are withheld from every record;operate: no read tool but discovery, and status, ids, verdicts and error codes only;full: what 0.15 gave.
profile set --agent-data-accessrecords a profile's level, and a server can lower it, never
raise it.mcp tools --data-accessshows what each level offers. This changes the default:
pass--data-access fullfor what 0.15 gave. Proven live by a scripted MCP host on the pack lab
(run 38981985013):- at act, a customer's email, phone and comment were withheld, and the name was kept;
- at operate, there was no read tool, and a create gave the agent its id only.
-
New: a secret is typed on a one-time local page, never in the chat (DEC-2026-0179).
- The commands:
credential set --browserstores an Odoo password or API key.secret env --file .env --name KEY --browserwrites one line of a.envfile, kept at mode 600. - The page: it is served on 127.0.0.1 under a random path, takes one submission, lasts 5
minutes, and loads nothing from elsewhere. It refuses a form without its own token, or from
another origin. - The agent: it may call both as CONFIRM tools and gets only "stored". The value never passes
through it. - Settings:
ODOO_CLI_SECRET_INPUT=offrefuses the page, andODOO_CLI_THEME=plaindrops its
colours.credential setnow takes--password-stdinor--browser, exactly one. - Proven live in the
packsworkflow
(run 38983358156, 19 of 19):
an agent asked over MCP, and a second process stood in for the person and typed on the page.
The.envfile got its line at mode 600, and the agent gotstoredwithout the value.
- The commands:
-
MCP:
pack listandpack showare read tools: 619 by default, and 1390 with--allow-writes
(771 CONFIRM). At--data-access operate, 10 read tools remain, all discovery.
mcp toolstakes--profile, so its listing has that profile's packs, asserve's does. -
JSON-2:
get_viewsgoes by name, so its views are never taken for record ids. -
exploreand packs share one list of the models and fields that hold credentials. -
Conformance: the write runner gives an attendance the date of its check-in where the employee works,
so a run near midnight in that time zone agrees. The 0.15.0 release run did not.
Install
curl -fsSL https://raw.githubusercontent.com/asao-vn/asao-odoo-tools/main/scripts/install.sh | shThis release's rehearsal
Before the tag, the public conformance workflow ran on this release's commit, 0818168
(run 38984549949).
- 19.0: 1252 of 1301 verified operations re-agreed, and 0 regressed. Two were unstable:
people.expense.submit, as since 0.11, andmanufacturing.workorder.start, whose twins differ in
a date and time field. - 20.0: 1160 of 1187 re-agreed, 0 regressed, and 12 new agreements. Two were unstable:
event.lead_rule.execute_rule, as before, andmanufacturing.workorder.start. - Controls and alerts: K01 to K11 AGREE on both series.
- The new features were proven in the
packsworkflow on Odoo 19.0, 19 of 19 checks
(run 38983358156), as each
section above says.
This release's own conformance
The tag ran the conformance workflow again
(run 38987004391):
- 19.0: 1251 of 1301 re-agreed, and 0 regressed.
people.expense.submitwas unstable, as before. - 20.0: 1161 of 1187 re-agreed, 0 regressed, and 12 new agreements.
event.lead_rule.execute_rule
was unstable, as before. - Controls and alerts: K01 to K11 AGREE on both series.
Its evidence, conformance-19.0.tar.gz and conformance-20.0.tar.gz, is attached below.
v0.15.0
1368 operations, unchanged: 1301 verified on 19.0, and 1187 of the 1306 that 20.0 can run.
-
New:
odoo-cli upgrade check --to 20.0. Before an upgrade, it says which customizations people
made in the database will stop working on 20.0, and why.- What it reads: saved filters, automation rules, server actions, custom fields, email templates,
views, record rules, access rights, export templates, default values and window actions. - How it checks them: it resolves every model and field they reference against a map made from
the 19.0 and 20.0 conformance labs. A renamed field gets its probable new name. A module the map
does not cover, such as an Enterprise or a third-party one, gets UNKNOWN. - What it never does: it reads only, and never prints the code or the templates it reads.
- Options:
--markdown-filewrites a report in Vietnamese.upgrade mapslists the pairs this
build can check.
- What it reads: saved filters, automation rules, server actions, custom fields, email templates,
-
What 20.0 changes for customizations. Record rules and access rights move into one new model,
ir.access, so every custom one has to be written again. 44 models and 618 fields are gone, and 56
selection fields lose values. -
Measured on real Odoo, in the open. The new
upgrade-checkworkflow
(run 38968869331) used 23
customizations, written after the check was finished:- it made them on a throwaway 19.0 and ran the check there;
- it made them again on a throwaway 20.0, which refused 13; the check had flagged all 13;
- among the 10 that still work there was no false alarm, and one CHECK: a filter on a value 20.0
dropped; - it found nothing on the 56 customizations the lab makes itself.
The people who wrote the set knew what 20.0 changes. So the run shows that the map holds on a real
20.0, not how much of a real database the check can read. -
MCP:
upgrade_checkandupgrade_mapsare read tools: 617 by default, 1386 with--allow-writes. -
An Odoo on a private address can be allowed by name.
ASAO_PRIVATE_PROVIDER_ENDPOINTStakes exact
host:port pairs, such as192.168.1.10:8069. Only those skip the refusal of private addresses.
ASAO_ALLOW_PRIVATE_PROVIDER_ENDPOINTS=truestill allows them all.
Install
curl -fsSL https://raw.githubusercontent.com/asao-vn/asao-odoo-tools/main/scripts/install.sh | shThis release's rehearsal
Before the tag, the public conformance workflow ran on main at f6a4460
(run 38969032952). The tagged
commit, 652934b, changes only the wording of the Vietnamese report (with its test), the README and the
CHANGELOG.
- 19.0: 1251 of 1301 verified operations re-agreed, and 0 regressed. Two were unstable:
people.expense.submit, the flake seen since 0.11;manufacturing.order.mark_done_confirm_consumption_with_backorder. Its twins differed once, only in
date_start, a date and time field, and the recheck agreed.
- 20.0: 1161 of 1187 re-agreed, 0 regressed, and 12 new agreements. One was unstable:
event.lead_rule.execute_rule, the flake seen in 0.13.1. - Controls and alerts: K01 to K11 AGREE on both series.
This release's own conformance
The release's own conformance
(run 38971763212) failed on one
operation, on both series: workforce.attendance_log.create disagreed on date. The cause was the
conformance runner, not odoo-cli:
- Odoo computes an attendance's date from its check-in, in the employee's time zone (Europe/Brussels
in the demo data). The runner wrote today's date by its own UTC clock. - That write pass ran at 22:03 to 22:10 UTC, just after midnight in Brussels, so Odoo stored the next
day. The rehearsal had written at 21:33 UTC and agreed. - Nothing else regressed in that run. On 19.0, 1253 of 1301 re-agreed; on 20.0, 1160 of 1187. K01 to
K11 AGREE.
The fix. The runner now writes the date in the employee's time zone, by each series' own rule
(public cb94469 and 82da99c). The first fix read a calendar time zone, which Odoo 20 no longer has.
The re-run. Conformance then ran again on main, with the same odoo-cli code and the fixed runner
(run 38977694022). Its writes
again came after midnight in Brussels.
- 19.0: 1254 of 1301 re-agreed, and 0 regressed.
people.expense.submitwas unstable, as
before. - 20.0: 1160 of 1187 re-agreed, 0 regressed, and 12 new agreements. Two were unstable:
event.lead_rule.execute_rule, as before;manufacturing.workorder.start, whose twins differed once, only inproduction_date, a date and
time field. The recheck agreed.
- Controls and the attendance:
workforce.attendance_log.createagreed on both series, and K01
to K11 AGREE on both.
Its evidence, conformance-19.0.tar.gz and conformance-20.0.tar.gz, is attached below.
v0.14.0
1368 operations, unchanged: 1301 verified on 19.0, and 1187 of the 1306 that 20.0 can run.
- Every write an agent asks for needs your confirmation.
mcp serve --allow-writesnow asks you in
the agent host before every write, not only before the 61 high-risk, destructive and bank-account
operations. Almost any text an agent reads in Odoo can be written outside the company (a website
form, an email that became a lead or a task, a sign-up), and such text can carry instructions. A host
that cannot ask gets a refusal with theodoo-cli ...command line for you to run yourself.
mcp tools --allow-writesshows 769 CONFIRM. --confirm-writes=falsegives back what 0.13 did, for an agent that reads no such text: the low-
and medium-risk writes run without asking, and the 61 still ask.--confirm-writes, added in 0.13.1,
is now the default and is still accepted.- Fixed:
explorerefusesir.accesson Odoo 20. Odoo 20 mergesir.model.accessandir.rule
into one model,ir.access, whichexploreread although it refuses the two models it replaces. - Conformance: a lab no longer fails to start one time in 64. Its random database password could
begin with-, which the Odoo image'swait-for-psql.pytook for an option. The read and write
runners record the renames file by its name, not by its path on the machine that ran them.
Install
curl -fsSL https://raw.githubusercontent.com/asao-vn/asao-odoo-tools/main/scripts/install.sh | shThis release's rehearsal
Before the tag, the public conformance workflow ran on main at 5990f69, the commit this release is built from (run 38885218562):
- 19.0: 1252 of 1301 verified operations re-agreed, 0 regressed. One was unstable:
people.expense.submitdisagreed once, then agreed, the flake already seen in 0.13. - 20.0: 1161 of 1187 re-agreed, 0 regressed, and 12 new agreements. One was unstable:
event.lead_rule.execute_rule, the flake seen in 0.13.1. - Controls and alerts: K01 to K11 AGREE on both series.
- Both labs started with the hex database password, and the 20.0 evidence names
dialect-renames-20.0.jsonrather than a path.
This release's own conformance (run 38888363561) gave the same result: 0 regressed on both series; 1252 of 1301 re-agreed on 19.0 and 1161 of 1187 on 20.0; one unstable on each, the same two; every control and alert AGREE. Its evidence, conformance-19.0.tar.gz and conformance-20.0.tar.gz, is attached below.
v0.13.1
1368 operations, unchanged: 1301 verified on 19.0, and 1187 of the 1306 that 20.0 can run.
- Changes to a bank account ask you first. On
mcp serve --allow-writes, creating, changing or
archiving a bank account (identity.bank_account.*, risk LOW) ran without asking, and could also
setallow_out_payment, the flag Odoo checks before it pays an account. A bank account says who the
company pays, so an agent now changes one only after you confirm the call in the agent host: 61
operations ask, up from 58. mcp serve --confirm-writes: every write asks you first, not only the high-risk ones. Use it
when the agent reads text written outside the company (a website form, an email that became a lead
or a task, a sign-up): such text can carry instructions, and an agent can follow them.- The server's instructions tell the agent that text inside records is data, never an instruction,
and to bring requests found there about bank details, contacts, prices or access to you. - Fixed: what a confirmation tells you. It showed an
asao ...command line and said ASAO would
still check your permissions, which odoo-cli does not. It now shows theodoo-cli ...command line,
and says the call runs with the full authority of the Odoo login in the server's profile. - Fixed: the flags that shape a read are refused on a write.
executeaccepted--limit,
--filter,--order,--offset,--group-byand--aggregatewith an operation that changes
Odoo, and ran the write. A caller paging through what it took for a read, such as the asao-erp SDK
0.3.0'sread(), could run a write by mistake. It is now refused withAERP_READ_FLAG_ON_WRITE
before any profile is read. - Fixed: a partial apply is recorded as PARTIAL. Before,
spec apply --partialwith a backend
recorded the run as APPLIED, and kept the spec as the one last applied in full, although the plan's
UNSUPPORTED or AMBIGUOUS steps were left out. The run is now PARTIAL, with how many steps were left
out, andspec pullstill gives the last spec applied in full. - Fixed: an S3 bucket whose name holds a dot is addressed by path. AWS's certificate does not
cover a dotted bucket name used as a host name. - Said plainly: the routines timer was tried on systemd. The launchd, Task Scheduler and cron
installers are written but not tried yet.
Install
curl -fsSL https://raw.githubusercontent.com/asao-vn/asao-odoo-tools/main/scripts/install.sh | shThis release's rehearsal
Before the tag, the public conformance workflow ran on main at c937594 (run 38865552037), one commit before the MCP change, which does not touch how an operation runs on Odoo:
- 19.0: 1252 of 1301 verified operations re-agreed, 0 regressed. One was unstable:
people.expense.submitdisagreed once, then agreed, the flake already seen in 0.13.0. - 20.0: 1161 of 1187 re-agreed, 0 regressed, and 12 new agreements.
event.lead_rule.execute_ruleandpeople.expense.approvedisagreed once and were sampled again: 0 regressed, one unstable. - Controls and alerts: AGREE on both series.
This release's own conformance (run 38869034604) gave the same result: 0 regressed on both series; 1251 of 1301 re-agreed on 19.0 and 1161 of 1187 on 20.0; one unstable on each, people.expense.submit on 19.0 and event.lead_rule.execute_rule on 20.0, the flakes seen in 0.13.0; every control and alert AGREE. Its evidence, conformance-19.0.tar.gz and conformance-20.0.tar.gz, is attached below.
v0.13.0
1368 operations, unchanged: 1301 verified on 19.0, and 1187 of the 1306 that 20.0 can run.
-
odoo-cli routines: a business's daily, weekly and monthly checks, with no Python. The routines
theasao-erpSDK introduced now run in the command line itself:templates: ten starter routines (sales yesterday, overdue receivables, money in and out, late
transfers, late tasks, last week's and last month's books review, stalled opportunities, monthly
revenue, recurring tasks);init,list,run,dueandstatus;install: a timer on systemd, launchd, Task Scheduler or cron.
Each run is kept in a folder: what Odoo answered, a computed summary, and the reading of the agent
you chose (Claude Code, Codex, Gemini CLI, agy, any command, or none). The same file format as the
SDK (TOML, and now YAML or JSON).What changed on the way:
- a read or group step can only run a read operation;
- a routine changes Odoo only through steps that say so, never by installing a module;
- a run that reached Odoo at no step leaves the slot open for the next timer tick;
- one
dueruns at a time.
An agent over MCP may list the starter routines and read a file's routines and their latest runs
(three read tools, from the file the server was started with); running routines, writing a file
and installing a timer stay with you. -
A team on one Odoo:
odoo-cli spec --backend.spec planandapplycan share a backend:- where: an S3 bucket (or Cloudflare R2, MinIO, Backblaze B2), signed by odoo-cli itself with no
SDK, or a shared folder; - the lock: one apply at a time, and
spec unlockfor an apply that died; - the plans: each one is saved under its hash with the spec as written, so a colleague can review
it (spec pull --plan); - the record: every apply is recorded as REFUSED, FAILED or APPLIED, with plan and report
(spec runs); - the spec last applied in full, which anyone can pull back (
spec pull); spec stateshows it all.
With a backend, apply needs the reviewed plan's hash (or
--auto-approve). A backend belongs to
one Odoo, and another one is refused before it is read. There is no state file: every plan reads
Odoo itself. "Who" is a label (user and host); the bucket's permissions decide who writes, and
odoo-cli trustsays so. For approval by a colleague whose identity is checked, see
docs/team-spec.md. - where: an S3 bucket (or Cloudflare R2, MinIO, Backblaze B2), signed by odoo-cli itself with no
-
Proof:
- Routines on an Odoo 19 lab: all ten templates ran; the recurring-task routine created its
tasks once and found them on the next run; a timer ran the due routines. - The backend against MinIO: the signature matches AWS's published example; plan, review, apply
and pull round-trip the spec byte for byte; five concurrent applies gave one APPLIED and four
SPEC_LOCKED.
- Routines on an Odoo 19 lab: all ten templates ran; the recurring-task routine created its
Install
curl -fsSL https://raw.githubusercontent.com/asao-vn/asao-odoo-tools/main/scripts/install.sh | shThis release's rehearsal
Before the tag, the public conformance workflow ran on main (run 38856361228) and was green on both series:
- 19.0: 1252 of 1301 verified operations re-agreed, 0 regressed. One was unstable:
people.expense.submitdisagreed once, then agreed, a flake already seen before 0.11.0. - 20.0: 1161 of 1187 re-agreed, 0 regressed, and 12 new agreements. One was unstable:
event.lead_rule.execute_ruledisagreed once, then agreed with no change, because of the order of its twins. - Controls K01-K08 and alerts K09-K11: AGREE on both series.
This release's own conformance (run 38858980412) gave the same result: 0 regressed on both series, the same two flakes, and every control and alert AGREE. Its evidence, conformance-19.0.tar.gz and conformance-20.0.tar.gz, is attached below.
v0.12.0
1368 operations: 1301 verified on 19.0, and 1187 of the 1306 that 20.0 can run.
-
Alerts: K09-K11 in
odoo-cli controls. Notify-only Odoo automation rules (module
base_automation, which you install) whose only action schedules an activity for the person you name:- K09: a bank account is added, or its number, holder or trusted flag changes;
- K10: a posted entry is reset to draft (posting it again adds nothing);
- K11: a partner that has invoices changes its tax number or name (one that never traded is not
reported).
Plan and apply them like any control:
--param K09.user="Ngọc Lan"(or the user's id) and
K09.lang=vi|enfor the activity's summary. A plan of an alert already on is NO_CHANGE. There is no
alert for a changed lock date: Odoo cannot schedule an activity on a company, and the change history
shows it. -
Eleven operations under them, all verified:
- rules (
structure.alert_rule.list|describe|create|update) held to names that start withodoo-cli:; - their actions (
structure.alert_action.*), whose type is forced to an activity; - three reads that resolve what a rule names (
structure.registry_model.list,
structure.registry_field.list,structure.activity_type.list).
A rule or action you made is out of their reach. An action that runs code, writes records, sends a
message or calls a webhook is refused before Odoo is reached; so is an action without its rule, and a
rule or action on a model that cannot carry activities (neverbase, which every model inherits).
Proven by
conformance/odoo-alerts-conformance.py, now part of the lab run; the labs installbase_automation. - rules (
-
Fixed: an archived record of an operation's own subset can be updated. The check that a target
belongs to an operation's subset ran with Odoo's default active test, so an archived record (an alert
rule switched off) could never be brought back. It now sees archived records; the subset still decides. -
Fixed: a plan compares lists of ids as sets. A list of two ids was read as a many2one's
[id, name], so a record with a two-record many2many was planned as a change on every run. -
Conformance: the action runner leaves a payment transaction's state-change stamp out of the twin
comparison. It is a clock stamp to the second, and it failed 0.11.0's release run on 19.0.- The lab seeder no longer makes automation rules or server actions. Its generic rules on the model
basemade every model run them inside its own create, and creating a bank account with K09 on then
failed in the rehearsal before this release.
- The lab seeder no longer makes automation rules or server actions. Its generic rules on the model
This release's rehearsal
Before this tag, the full conformance ran on main twice. The first run caught a real failure, which
was fixed before the tag: with K09 on, creating a bank account was refused, caused by automation rules
the lab seeder had made on the model base (see Conformance above). The second run was green on 19.0
and 20.0. Every control and alert agreed, with 0 regressed operations.
Install: curl -fsSL https://raw.githubusercontent.com/asao-vn/asao-odoo-tools/main/scripts/install.sh | sh
v0.11.0
1357 operations: 1290 verified on 19.0, and 1176 of the 1295 that 20.0 can run.
-
odoo-cli controls: Odoo's own switches that stop what the review finds. Eight controls:
purchase approval from an amount, locked purchase and sales orders, lock dates, the restrictive
audit trail, hashed entries, customer credit limits and two-step sign-in for employees. Each says
what Odoo does once it is on (read in Odoo's source), where Odoo enforces it (server, web client
only, or a warning) and whether it can be undone.controls statusreads them;controls planandcontrols apply --plan-hashturn the reversible
ones on through the spec engine and the catalog's verified operations.- It never moves a lock date back, never sets the hard lock date, never hashes a journal (Odoo never
lets that be undone) and never weakens a stronger setting already on. - Odoo Community has no screen for lock dates: odoo-cli sets them.
- Agents may list, read and plan; applying stays with the person.
review checksand the markdown
report name the control that would have prevented a finding. - Proven on 19.0 and 20.0 by
conformance/odoo-controls-conformance.py: each control turned on
through the CLI, then what Odoo does exercised through an independent oracle (an order over the
amount waits for approval, an entry of a locked period cannot be reset to draft, a posted bill
cannot be deleted, an employee's password is refused over RPC), then everything restored. - Two things the run found in Odoo itself are now in the controls' text. A document dated in a
locked period is posted with its accounting date moved after the lock, not refused. Once two-step
sign-in is required of employees, their passwords no longer work over RPC.
-
Saving the Settings page is verified.
structure.settings.updatehad no runner: it has no
record and no button.conformance/odoo-settings-conformance.pysets every setting through the
CLI, reads it back as the page opens it, and restores it. Verified on 19.0 and 20.0; the two
settings 20.0 removed are left out of the read and refused on write.- New settings: the purchase approval amount, the restrictive audit trail, the customer credit
limit and its default. - The timesheet reminders are gone: Community declares them but keeps neither.
- Company reads and writes take the four soft lock dates. Reads also show the hard lock date and a
journal's hash switch, which the catalog never writes. - The labs install
hr_timesheet, whose settings the page offers, and run both new workflows.
- New settings: the purchase approval amount, the restrictive audit trail, the customer credit
-
Agents can report a fault in odoo-cli, and you decide whether it is filed.
odoo-cli report draftbuilds a scrubbed report on your machine and sends nothing; you file it through a prefilled
GitHub link. Internal errors and the MCP server's instructions point agents at it. -
Six more review checks, 20 in all. Each was planted, with a look-alike it must leave alone, in the
simulated business the review is proven on:O02a customer invoiced twice for one sale (the same lines are XEM_NGAY);O07a payment cut into pieces under the approval limit: parts of one bill, or no bill at all;O26documents dated back into a month that had ended: customer invoices, credit notes and manual
journal entries, with a closing allowance;O27revenue booked in the last days of a month and credited early in the next;O28andO29, Vietnam: purchases of 5 million đồng or more paid in cash, alone or as several bills of
one seller on one day, lose their input VAT deduction (Nghị định 181/2025/NĐ-CP, Điều 26, read in the
Official Gazette).
A check whose read does not return a field it needs is reported as not run, with the reason, never as
clean. -
The change history, read.
structure.field_change.list|describe(old and new values) and
structure.change_note.list|describe(who changed which record, when), held to the fields a review
needs: payee bank accounts, partners' tax numbers, document states and dates, lock dates, prices.
Odoo shows them to administrators only. On 20.0 they need themail_trackingmodule (Discuss
Tracking), which 20.0 split out ofmail; the check before a call says so. -
Payments and journal entries say more.
finance.payment.listreturns the bank account paid into, the
bills and invoices a payment settles, and who made it when;finance.journal_entry.list|describe, who made
an entry when and whether a payment or a bank statement line made it. All verified again on 19.0 and 20.0. -
conformance/odoo-read-conformance.py --onlyruns a few reads;odoo-conformance-lab.sh --setup-onlybuilds
a lab and keeps it, without a pass. -
Recurring tasks.
work.task.createandwork.task.updatetakerecurring,repeat_every,
repeat_unit(day, week, month, year),repeat_type(forever, until) andrepeat_until, with
due_on,priority(low, medium, high, urgent),tags(by name or id) anddescription;
work.task.listandwork.task.describereturn them. Odoo makes the next occurrence when the
current one is closed (done or cancelled), not on a calendar date. -
Verified as a workflow, on 19.0 and 20.0. A new conformance pass
(conformance/odoo-task-recurrence-conformance.py, part of the weekly lab run) creates a recurring
task with every new field, reads it back through an independent JSON-RPC oracle and through the
CLI, changes its recurrence, closes it, and checks that Odoo opened exactly one next occurrence a
month later.
This release's conformance
The release's own run on 19.0 flagged finance.payment_transaction.capture. Its two twins both went
from authorized to done and differed only in last_state_change, a timestamp Odoo stamps to the
second, so a twin captured in the second it was authorized looked unchanged. The runner now leaves
that stamp out, as it already did for opportunities and orders (commit b1bbcdd); odoo-cli's code is
this release's own. The conformance-19.0 evidence attached here is from the re-run on that commit
(0 regressed, 1241 of 1290 agreed again, people.expense.submit unstable); conformance-20.0 is
from the release run. Both include the controls workflow: K01 to K08 agreed.
Install: curl -fsSL https://raw.githubusercontent.com/asao-vn/asao-odoo-tools/main/scripts/install.sh | sh
v0.10.0
Install: curl -fsSL https://raw.githubusercontent.com/asao-vn/asao-odoo-tools/main/scripts/install.sh | sh