ODXPilot · Request a demo →

Ask in plain language. Approve before it posts.

ODXPilot is an AI assistant for day-to-day Odoo administration. Your team asks for the work; ODXPilot prepares it in Odoo as a plan of drafts, checks it against your roles and procedures, and waits for a person to approve.

PlanPT A

request

“bill the PO we received from PT Contoh Logistik”

SOP · vendor-bill-from-po · a41c07e2…

  1. 1readpurchase.order — received vs. invoiced
  2. 2checkvendor NPWP on file, period open
  3. 3createaccount.move — vendor bill, draft
  4. 4postaction_post — needs finance_manager

Requested by Rina (accountant)

Send for approval

Illustration of the planned interface.

The problem

AI can do the back-office work. Plugging it straight into Odoo isn’t safe.

Recording vendor bills, drafting invoices, matching payments, reconciling bank lines: routine work that still needs someone who knows Odoo, where a mistake is expensive. A general-purpose agent with an Odoo key can do it quickly — and gets it wrong in ways accounting can’t accept.

It guesses the schema

Model and field names differ per Odoo version, per installed app and per Studio customisation. A guessed field name is a failed write — or a wrong one.

The prompt is the only guard

“Don't post payments” in a system prompt is a suggestion, not a control. Text inside a PDF or an email can talk the model out of it.

It runs with a big key

Agents are usually wired up with an Odoo admin key, so one bad plan can touch anything in the database.

Odoo can't tell people apart

Teams share Odoo users, so Odoo's groups and history describe the shared user — not the person who asked the agent to act.

No segregation of duties

Nothing stops the same person, or the agent, from adding a vendor's bank account and then paying it.

Your way of working isn't in the model

Every company has its own procedures, localisation and chart of accounts. Best practice for VAT in one country isn't in the next.

How it works

The model plans. Deterministic code decides.

ODXPilot keeps the model’s job small — understand the request, propose a plan — and puts every decision that matters in code it can’t talk its way around.

  1. 1

    Ask

    In plain language, in a chat pinned to one company.

  2. 2

    Map to an SOP

    One of your own procedures from ODXDocs, filtered to this Odoo instance and company. No confident match: ODXPilot stops and asks.

  3. 3

    Plan

    Each step validated against the live fields of your instance, and dry-run through your role policy.

  4. 4

    Approve

    The right person, in the right company, re-authenticates and reviews the diff.

  5. 5

    Execute

    Through ODXProxy, as drafts by default, with the company context set by ODXPilot — not by the model.

  6. 6

    Record

    Audit log plus a chatter note on the Odoo record: who asked, who approved, which SOP.

The modelODXPilot — deterministic
Understands the requestYes—
Picks the procedure (SOP)Describes the taskMaps it to one published SOP version — or stops
Writes the planYesValidates every model and field against live fields_get
Decides permissionsNeverRole policy, default deny
Sees bank numbers, salaries, keysNeverMasked before the data reaches the model
Posts, pays, reconcilesNever on its ownOnly after a person with the right role approves

Where it fits

Built on ODXProxy, ODXBrain and ODXDocs. One stack per Odoo instance.

ODXPilot asks ODXBrain which Odoo model holds the data and which of your SOPs applies, fetches that SOP from ODXDocs, then reads live fields and records through ODXProxy — the only component that talks to Odoo. Odoo stays the engine and the gatekeeper.

Each Odoo instance gets its own ODXPilot, ODXProxy and ODXBrain, serving every company in that database. Nothing is shared between customers, so one company’s procedures never leak into another’s.

Your people

sign in with your identity provider

ODXPilot

plans · policy · approvals · audit

which model? which SOP?

ODXBrain

model names · SOP ids

ODXDocs

your SOPs, exact versions

fields_get · read · drafts

ODXProxy

one safe JSON-RPC seam

Odoo

the engine & gatekeeper

SOP mapping · with ODXDocs

Every request mapped to a procedure your people wrote.

ODXPilot doesn’t improvise accounting. Your accountants and developers write each procedure once in ODXDocs, the SOP manager that comes with ODXBrain: the business rules, the technical steps, and the phrases people use to ask for it. ODXPilot maps every request to exactly one published version of one SOP — or stops and asks.

vendor-bill-from-po.mdan SOP in ODXDocs
+++
id = "vendor-bill-from-po"
title = "Record a vendor bill from a received purchase order"
intents = [
  "create a bill from a purchase order",
  "record a supplier invoice against a PO",
  "enter a vendor bill after goods are received",
]

[applies_to]
odoo_min = "17.0"
edition = "enterprise"
modules = ["account", "purchase"]
+++

## Business rules (Accountant)

- Only bill what was received.
- Bills above IDR 50,000,000 need CFO approval
  before they are posted.
- The vendor's NPWP must be on the partner record.
  If it is missing, stop and ask Finance.
- Never post a bill dated in a closed period.

## Technical notes (Developer)

- Create it with purchase.order.action_create_invoice.
- Compare qty_received with qty_invoiced first.
- Post with account.move.action_post.
  Ask the user to confirm before posting.

How a request finds its SOP

  1. 1

    Describe

    ODXPilot turns the request into a short task description: “record a vendor bill for a received purchase order”.

  2. 2

    Rank

    ODXBrain ranks your published SOPs by their titles and intents, filtered to this instance: Odoo version, edition, installed modules — localisation included — and company.

  3. 3

    Stop if unsure

    No confident match means ODXPilot stops and asks you. It never runs the nearest procedure instead.

  4. 4

    Check the operation

    The chosen SOP's title is checked against the task, because “cancel a bill” and “record a bill” look alike to a search.

  5. 5

    Fetch that exact version

    The procedure comes from ODXDocs by id and version. There is no “latest”, so a publish mid-task can't swap it.

  6. 6

    Plan and log

    The plan follows the SOP's rules, and the run records the SOP id, its version and the hash of the published set.

Written by accountants and developers

Each SOP has two parts: the business rules, owned by an accountant, and the technical notes, owned by a developer. Both kinds of expertise, in one file.

Plain Markdown in git

One file per procedure. Review changes in a pull request, see every edit in a diff, and undo by publishing an earlier commit.

Self-tested before it goes live

Every phrase people use to ask for an SOP is held out in turn and must still find that SOP. A failing set can't be published — there is no override.

Every version kept

An SOP's version is the hash of its content, and every version ever published stays available. Any run can be replayed against exactly what the agent followed.

Scoped to your instance

An SOP declares the Odoo versions, edition, modules and companies it applies to. A procedure that doesn't fit this instance is never offered.

Yours alone

We ship no SOP library. Your procedures are your company's, live in your own stack and never mix with another customer's.

Bodies stay with ODXDocs

ODXBrain only ever sees an SOP's title and intents, to find it. The procedure itself is stored on your premises and handed out by ODXDocs.

A browser editor

See which SOPs are live, changed or new, try how a draft ranks before you save it, and publish through the same self-test.

ODXDocs exists today: SOPs are written, self-tested, published and served from the command line or its browser editor. Connecting it to ODXPilot is on the roadmap. How SOPs work →

Designed for accounting

The AI does the prep work. Your people keep the signature.

Draft by default

Accounting records are created as drafts. The agent prepares the work; a person posts it. Posting, payments and reconciliation each need an explicit approval.

Segregation of duties, on the person

Whoever asked for a change can't approve it — checked on the real person, not the shared Odoo user. The approver must hold the approver role in that company.

Permissions in code, not in the prompt

A policy engine checks every tool call against the person's role before anything leaves ODXPilot. Default deny. A denied call never reaches ODXProxy.

People, not Odoo users

Roles live in ODXPilot per person and per company, optionally synced from your identity provider. A few least-privilege Odoo users can serve the whole team, and every action is still attributed to a person.

Live schema, every time

Fields come from fields_get on your instance and are re-checked right before every write, so a Studio field added since the plan is seen, not guessed.

Your SOPs, not its imagination

Every request is mapped to a procedure your accountants and developers published in ODXDocs. With no confident match, ODXPilot stops and asks instead of improvising.

Masked before the model sees it

Bank account numbers, salaries and keys are masked inside ODXPilot, so the AI provider never receives them — even when the Odoo user could read them.

Multi-company aware

A chat is pinned to one company. ODXPilot sets the company context itself, and every plan step and approval carries a company badge.

Your Odoo keys stay server-side

Write-only once entered: never in a token, the browser, a log, a URL or a prompt — not even visible to your own admins.

Roles

Roles per person, per company.

The same person can be finance manager for one subsidiary and accountant for another in the same Odoo database. Roles are defined in ODXPilot — assigned there or mapped from your identity provider’s groups — and they can only narrow what the agent may do, never widen it.

Never through the agent, for any role: managing Odoo users and groups, or deleting accounting records.

auditor
Reads accounting data, bank numbers masked. No writes.
billing_clerk
Drafts customer invoices and vendor bills, edits partners (not bank fields).
accountant
Adds draft journal entries and reconciliation. No bank changes, no posting payments, no taxes or lock dates.
finance_manager
Posts, registers payments, approves bank account changes, sets lock dates. Still bound by segregation of duties.
tenant_admin
Manages users, roles, connections, policies and SOPs. No accounting rights unless also given a finance role.

Best practices

Putting AI on Odoo? Twelve rules we build ODXPilot by.

They hold whether you use ODXPilot or build your own agent on ODXProxy.

  1. 01

    Never give an agent an admin key

    Create one Odoo user per role tier — read-only, bookkeeper, manager — with the narrowest groups that work, and let the agent act through the tier that matches the person. Odoo's own access rules then stay a real backstop.

  2. 02

    Draft first, post by hand

    Let the agent create drafts and prepare reconciliations. Posting, paying, reconciling and resetting to draft are separate, explicitly approved steps.

  3. 03

    Enforce permissions in code

    A rule in the prompt can be argued away — by a user, or by text hidden in an invoice PDF or an email. A check in front of the API can't. Allow-list models and methods per role, default deny, fail closed.

  4. 04

    Read the schema live — and again before writing

    Call fields_get on the instance instead of trusting a field list. Re-fetch it right before a write that was approved hours later. On an unknown-field error, re-plan; never retry blindly.

  5. 05

    Maker ≠ checker, per company

    The person who asked can't approve. The approver needs the approver role in the company the change belongs to, and must have signed in again recently.

  6. 06

    Treat vendor bank changes as a fraud signal

    Changing a partner's bank account always needs a second person, and payments to that vendor are flagged for a while afterwards. It's the classic payment-fraud path.

  7. 07

    Set the company context yourself

    Send allowed_company_ids from the person's access, not from what the model suggests, and check company_id on every write. Pin each conversation to one company.

  8. 08

    Mask before inference

    Strip bank numbers, IBANs, salaries and tokens from tool results before they enter the model's context. What the provider never receives, it can't leak.

  9. 09

    Follow a written procedure, or stop

    Map each request to one approved, versioned procedure and log which one ran. When nothing matches confidently, ask a person — never run the nearest procedure.

  10. 10

    Cancel or reverse, never delete

    Keep unlink on accounting records out of the agent's reach entirely. Corrections go through cancellation, credit notes and reversals, like an accountant would do them.

  11. 11

    Attribute every write to a person

    Log who asked, under which role and connection, in which company, with which SOP and approver — and leave a chatter note on the Odoo record so the trail lives in Odoo too.

  12. 12

    Keep Odoo keys server-side

    Odoo API keys belong in a vault on the server: never in a browser, a token, a log line or a prompt. Short-lived tokens for people, and keys rotated before they expire.

The detailed version, with ODXProxy examples →

Status

Early. Here’s exactly what exists.

Everything above is how ODXPilot is designed to work. Today it’s a model you can talk to, running on the architecture the rest will be built on. It doesn’t do Odoo work yet.

Built today

  • ODXDocs: write, self-test, publish and serve SOPs, from the command line or a browser editor
  • Chat pipeline end to end: an orchestrator that streams replies, an MCP server, a terminal client
  • Claude (Anthropic) and Gemini on Google Vertex AI behind one router, chosen per chat

Roadmap

Odoo tools through ODXProxy

Reading and drafting in Odoo through the same JSON-RPC seam every ODXProxy client uses.

Roadmap

ODXBrain integration

Finding the right Odoo model for a request before reading its live fields.

Roadmap

Policy engine & approvals

Roles per person and company, segregation of duties, masking, the approval queue.

Roadmap

Sign-in with your identity provider

OIDC and SAML, AD / LDAP through a broker, MFA for anyone who writes or approves.

Roadmap

Web app

One question box; answers come back as plan cards with an approve step.

Roadmap

SOP mapping in every request

ODXPilot resolving each request through ODXBrain and following the exact SOP version from ODXDocs.

Roadmap

Local inference

Run the AI model on your own hardware, so your Odoo data doesn't go to a hosted AI provider.

FAQ

Will ODXPilot post or pay anything on its own?
No. It is designed to create drafts and prepare work; posting, payments and reconciliation each need approval from a person with the right role in that company.
Does the AI decide what I'm allowed to do?
No. Permissions are checked by a policy engine in code, against roles you define, before any call is sent to Odoo. The model only proposes a plan.
Which AI models does it use, and what do they see?
Claude (Anthropic) or Gemini on Google Vertex AI, chosen per chat. Your request and the Odoo data the task needs are sent to that provider; fields your policy masks — bank numbers, salaries, keys — are not.
Can it run fully on-premises or air-gapped?
Not yet. Today ODXPilot uses hosted AI models. Support for local inference — running the model on your own hardware — is next on the roadmap. ODXBrain, which ODXPilot uses to find Odoo models, already runs fully offline.
Where do the SOPs come from?
From your own team. Accountants and developers write them in ODXDocs, test them and publish them. We don't ship an SOP library: every company's way of working is its own.
What happens when no SOP matches a request?
ODXPilot stops and asks. It shows the closest procedures for a person to look at, but never runs one that isn't a confident match.
Does every person need their own Odoo user?
No. People sign in to ODXPilot with your identity provider and get roles there. ODXPilot acts through a small set of least-privilege Odoo users you register, and still records the real person on every action. Per-person Odoo users work too.
Does it know our custom fields and Studio changes?
Yes — it reads them live with ODXProxy's fields_get on your instance, and re-checks right before every write.
Is it shared between customers?
No. Each Odoo instance gets its own ODXPilot, ODXProxy and ODXBrain. Your SOPs, policies and history never mix with anyone else's.
Does ODXPilot change ODXProxy?
No. ODXPilot is a client of ODXProxy like any other. The proxy stays a fast, thin forwarder, and existing ODXProxy users are unaffected.
How do I see it? What will it cost?
Request a demo and we'll walk you through it. Availability and pricing aren't decided yet.

Running your back office on Odoo?

See ODXPilot in a demo. Tell us which processes eat your team’s week, or start building on ODXProxy today.