Short answer, so you can leave if that is all you came for: nothing reads the row back. When a tool returns no value, Odoo composes a success sentence from what the action intended and hands that to the model. The agent then reports success because it was given a string, not because anyone checked the database.
Here is the longer version, with what I actually found.
First, the part most people get wrong
A lot of posts right now claim Odoo's AI is "just an API wrapper." That is false, and you can refute it with one screenshot of the source.
Odoo 19 Enterprise ships a genuine tool-calling agent loop. Up to 20 successive rounds of up to 20 parallel tool calls, with an injected termination protocol. Retrieval over an indexed corpus with a real vector field type. Unattended execution through cron. And real write capability, through server actions an administrator authors and marks for AI use.
That is an agent by any reasonable definition. It loops, it calls tools, it acts on its environment, and it runs without a human present. Odoo also made a defensible safety choice: there is no generic write tool. Writes travel only through actions a human wrote, and the ORM access rules still apply.
So the interesting question is not capability. It is what happens after it acts.
What Odoo says about that, in their own words
From the AI server actions documentation:
An AI server action acts as a decision maker, or a manager. It reads the record and its context. It interprets the AI prompt. And it decides which tool to call, and what arguments to use.
And, in the same documentation:
The server action does not enforce business rules, modify records directly, or guarantee the correctness of the operation. Its role is limited to decision-making.
Read that second one again if you are about to point this at a production database. Odoo is being straight with you. The agent decides. Everything else is yours to build.
Also, if you assumed the chat assistant could act:
The standard Ask AI agent cannot make changes to the database. As such, it can open views and display reports, but it cannot create leads or alter data.
The four things I found in the source
1. Nothing is read back. When a server action returns nothing, Odoo substitutes a static description assembled from the action's intent, along the lines of "Activity created for X." The model is told the write worked by a sentence Odoo composed. The database is never re-read to confirm it.
2. There is no savepoint in the module's tool execution. Picture a five-step action where step three is denied by a record rule. Steps one and two are already written and stay written. Steps four and five then run against a half-changed state. Nothing tells you the data is now inconsistent.
3. A denial becomes advice. The exception handler catches the error, converts it to a string, and returns it to the model as the tool result so the run can continue. Odoo's own code comment says this is intentional, so a prompt can say "do X, and if it fails, do Y." A permission error is a token the model can reason around rather than a wall.
4. The evidence is a chatter message. It records what was attempted, not the before and after state, and a mail.message can be edited or deleted like any other record.
Why this matters more in an ERP than anywhere else
If an agent gets a blog post wrong, you notice. If it writes to the wrong record in your ERP and reports success, nothing errors, nobody notices, and it compounds. A month later somebody is reconciling accounts and cannot work out why.
An enterprise prospect described this to me better than I could:
An agent does the wrong thing and reports success. Writes against the wrong person or record, or reads a truncated list and answers as if complete. Nothing errors. Nobody notices. It piles up. Checking the draft before it runs does not catch it, because the mistake happens during execution.
That last sentence is the one that matters. Reviewing what the agent proposed does not protect you, because the failure happens after approval.
What a write actually needs before you can leave it running
Four properties. None exotic, all checkable.
- Read-back. The result handed to the model is re-read from the database after the write, not composed from the request.
- Atomicity. A multi-step action completes fully or leaves no trace.
- Structured refusal. A denial returns a machine-readable code, not a sentence the model can reinterpret.
- Evidence. An append-only record of before and after values, independent of the record's own chatter.
If you are evaluating any AI-for-ERP tool, including mine, those four are a better test than any demo. Ask the vendor to show you the row, re-read from the database, after the write. Not the log of what it tried.
Disclosure, and my own score
I help build one of these (nanti.ai). So take the above as claims to verify rather than neutral reporting, and here is my own honest scoring against the same bar.
We do the four. Every write is re-read on an independent connection after commit and compared field by field against what the caller intended, proven by deliberately corrupting the stored value behind a write in the test suite to confirm the product refuses the happy echo. Refusals are committed on a separate transaction so the record of the denial survives the rollback of the action it denied.
Where we fall short, since a bar you only apply to other people is worth nothing:
- We have not commissioned a third-party penetration test, and will not claim one.
- Several of those properties are paid-tier only. A free-tier install genuinely has less.
- Until this week our own core advertised an idempotency key it did not honour on the free tier, so a client retry could create a second record. That was a real defect in shipped code. It is fixed, with a test that holds it closed.
- We claim tamper-evident, never tamper-proof. A database superuser who disables the trigger can still alter rows. The hash chain makes that evident rather than impossible.
None of this makes Odoo's engineering bad. It is a deliberate, bounded design and their documentation describes it accurately. It does mean that if you are about to let an agent write into your ERP, the question is not how capable it is.
It is: after it writes, where does the confirmation come from?
If the answer is that the model said so, you do not have a record. You have a rumour.
Odoo is a trademark of Odoo S.A. This is independent work, not affiliated with or endorsed by Odoo S.A.
If you have pointed an agent at your Odoo, I would like to know what it wrote that it should not have.
Top comments (0)