odoo-managerManage Odoo (contacts, any business objects, and metadata) via the official External XML-RPC API. Supports generic CRUD operations on any model using execute_kw, with ready-made flows for res.partner and model introspection. Features dynamic instance and database switching with context-aware URL, database, and credential resolution.
Install via ClawdBot CLI:
clawdbot install willykinfoussia/odoo-managerOdoo server URL precedence (highest to lowest):
temporary_url — one-time URL for a specific operationuser_url — user-defined URL for the current sessionODOO_URL — environment default URLThis allows you to:
Examples (conceptual):
```text
// Default: uses ODOO_URL from environment
{{resolved_url}}/xmlrpc/2/common
// Override for one operation:
temporary_url = "https://staging.mycompany.odoo.com"
{{resolved_url}}/xmlrpc/2/common
// Override for session:
user_url = "https://client-xyz.odoo.com"
{{resolved_url}}/xmlrpc/2/common
```
Database name (db) precedence:
temporary_dbuser_dbODOO_DBUse this to:
Username precedence:
temporary_usernameuser_usernameODOO_USERNAMESecret (password or API key) precedence:
temporary_api_key or temporary_passworduser_api_key or user_passwordODOO_API_KEY (if set) or ODOO_PASSWORDImportant:
Environment variables are handled via standard OpenClaw metadata: requires.env declares required variables (ODOO_URL, ODOO_DB, ODOO_USERNAME, ODOO_PASSWORD). ODOO_API_KEY is an optional environment variable used instead of the password when present; it is not listed in metadata and should simply be set in the environment when needed.
At runtime the skill always works with:
{{resolved_url}} — final URL{{resolved_db}} — final database name{{resolved_username}} — final login{{resolved_secret}} — password or API key actually used to authenticateThese are computed using the precedence rules above.
Thetemporary_anduser_names are runtime context variables used by the skill logic, not OpenClaw metadata fields. OpenClaw does not have anoptional.contextmetadata key; context is resolved dynamically at runtime as described below.
User examples:
odoo_demo juste pour cette opération"Behavior:
temporary_* (url, db, username, api_key/password)This is ideal for:
User examples:
clientx_prod pour cette session"Behavior:
user_* (url, db, username, api_key/password)temporary_ or by clearing user_User examples:
Action:
user_url, user_db, user_username, user_password, user_api_keyODOO_URL, ODOO_DB, ODOO_USERNAME, ODOO_PASSWORD / ODOO_API_KEY)User examples:
Response should show (never full secrets):
```text
Current Odoo Context:
```
Odoo exposes part of its server framework over XML-RPC (not REST).
The External API is documented here: https://www.odoo.com/documentation/18.0/fr/developer/reference/external_api.html
Two main endpoints:
{{resolved_url}}/xmlrpc/2/common — authentication and meta calls{{resolved_url}}/xmlrpc/2/object — model methods via execute_kwCall version() on the common endpoint to verify URL and connectivity:
```python
common = xmlrpc.client.ServerProxy(f"{resolved_url}/xmlrpc/2/common")
version_info = common.version()
```
Example result:
```json
{
"server_version": "18.0",
"server_version_info": [18, 0, 0, "final", 0],
"server_serie": "18.0",
"protocol_version": 1
}
```
Use authenticate(db, username, password_or_api_key, {}) on the common endpoint:
```python
uid = common.authenticate(resolved_db, resolved_username, resolved_secret, {})
```
uid is an integer user ID and will be used in all subsequent calls.
If authentication fails, uid is False / 0 — the skill should:
ODOO_URL, ODOO_DB, username, and secretBuild an XML-RPC client for the object endpoint:
```python
models = xmlrpc.client.ServerProxy(f"{resolved_url}/xmlrpc/2/object")
```
Then use execute_kw with the following signature:
```python
models.execute_kw(
resolved_db,
uid,
resolved_secret,
"model.name", # e.g. "res.partner"
"method_name", # e.g. "search_read"
[positional_args],
{keyword_args}
)
```
All ORM operations in this skill are expressed in terms of execute_kw.
Domains are lists of conditions:
```python
domain = [["field_name", "operator", value], ...]
```
Examples:
[['is_company', '=', True]][['country_id', '=', france_id]][['probability', '>', 50]]Common operators:
"=", "!=", ">", ">=", "<", "<=""like", "ilike" (case-insensitive)"in", "not in""child_of" (hierarchical relations)YYYY-MM-DD or ISO 8601 format.int) when writing; reads often return [id, display_name].Each subsection below shows typical user queries and the corresponding
execute_kw usage. They are applicable to any model (not only res.partner).
User queries:
Action (generic):
```python
ids = models.execute_kw(
resolved_db, uid, resolved_secret,
"model.name", "search",
[domain],
{"offset": 0, "limit": 80}
)
```
Notes:
domain is a list (can be empty [] to match all records).offset and limit for pagination.User queries:
Action:
```python
count = models.execute_kw(
resolved_db, uid, resolved_secret,
"model.name", "search_count",
[domain]
)
```
User queries:
Action:
```python
records = models.execute_kw(
resolved_db, uid, resolved_secret,
"model.name", "read",
[ids],
{"fields": ["name", "country_id", "comment"]}
)
```
If fields is omitted, Odoo returns all readable fields (often a lot).
Shortcut for search() + read() in a single call.
User queries:
Action:
```python
records = models.execute_kw(
resolved_db, uid, resolved_secret,
"model.name", "search_read",
[domain],
{
"fields": ["name", "country_id", "comment"],
"limit": 5,
"offset": 0,
# Optional: "order": "name asc"
}
)
```
User queries:
Action:
```python
new_id = models.execute_kw(
resolved_db, uid, resolved_secret,
"model.name", "create",
[{
"name": "New Partner"
# other fields...
}]
)
```
Returns the newly created record ID.
User queries:
Action:
```python
success = models.execute_kw(
resolved_db, uid, resolved_secret,
"model.name", "write",
[ids, {"field": "new value", "other_field": 123}]
)
```
Notes:
ids is a list of record IDs.ids receive the same values.User queries:
Action:
```python
success = models.execute_kw(
resolved_db, uid, resolved_secret,
"model.name", "unlink",
[ids]
)
```
Useful for quick lookup on models with a display name (e.g. partners, products).
User queries:
Action:
```python
results = models.execute_kw(
resolved_db, uid, resolved_secret,
"res.partner", "name_search",
["Agrolait"],
{"limit": 10}
)
```
Result is a list of [id, display_name].
res.partner is the core model for contacts, companies, and many business relations in Odoo.
User queries:
Action:
```python
companies = models.execute_kw(
resolved_db, uid, resolved_secret,
"res.partner", "search_read",
[[["is_company", "=", True]]],
{"fields": ["name", "country_id", "comment"], "limit": 80}
)
```
User queries:
Action:
```python
[partner] = models.execute_kw(
resolved_db, uid, resolved_secret,
"res.partner", "read",
[[7]],
{"fields": ["name", "country_id", "comment"]}
)
```
User queries:
Minimal body:
```python
partner_id = models.execute_kw(
resolved_db, uid, resolved_secret,
"res.partner", "create",
[{
"name": "New Partner",
"is_company": True
}]
)
```
Additional fields examples:
street, zip, city, country_idemail, phone, mobilecompany_type ("person" or "company")User queries:
Action:
```python
models.execute_kw(
resolved_db, uid, resolved_secret,
"res.partner", "write",
[[7], {
"street": "New street 1",
"phone": "+33 1 23 45 67 89"
}]
)
```
User queries:
Action:
```python
models.execute_kw(
resolved_db, uid, resolved_secret,
"res.partner", "unlink",
[[999]]
)
```
User queries:
Action:
```python
fields = models.execute_kw(
resolved_db, uid, resolved_secret,
"res.partner", "fields_get",
[],
{"attributes": ["string", "help", "type"]}
)
```
The result is a mapping from field name to metadata:
```json
{
"name": {"type": "char", "string": "Name", "help": ""},
"country_id": {"type": "many2one", "string": "Country", "help": ""},
"is_company": {"type": "boolean", "string": "Is a Company", "help": ""}
}
```
User queries:
Action:
```python
models_list = models.execute_kw(
resolved_db, uid, resolved_secret,
"ir.model", "search_read",
[[]],
{"fields": ["model", "name", "state"], "limit": 200}
)
```
state indicates whether a model is defined in code ("base") or created dynamically ("manual").
User queries:
Action (simplified):
```python
partner_model_ids = models.execute_kw(
resolved_db, uid, resolved_secret,
"ir.model", "search",
[[["model", "=", "res.partner"]]]
)
fields_meta = models.execute_kw(
resolved_db, uid, resolved_secret,
"ir.model.fields", "search_read",
[[["model_id", "in", partner_model_ids]]],
{"fields": ["name", "field_description", "ttype", "required", "readonly"], "limit": 500}
)
```
authenticate returns False or later calls fail.xmlrpc/2/common or xmlrpc/2/object.The skill should:
limit / offset on search and search_read to handle large datasets.limit to a reasonable value (e.g. 80).fields list for read / search_read when possible.=, in) for large datasets.{{resolved_url}}, {{resolved_db}}, {{resolved_username}}, {{resolved_secret}}version() on {{resolved_url}}/xmlrpc/2/commonuidexecute_kw on res.partner with search_read and domain [['is_company', '=', True]]common.authenticatecreate a new res.partner with {"name": "New Partner", "is_company": True}read that ID with fields ["name", "is_company", "country_id"]temporary_url and/or temporary_db to point to another Odoo environment.This skill can:
search, search_count, read, search_read, create, write, unlink) on any Odoo model via execute_kw.res.partner (contacts / companies).fields_get, ir.model, and ir.model.fields.Generated Mar 1, 2026
A consulting firm uses the skill to manage contacts and sales pipelines across multiple client Odoo instances. They switch between client-specific URLs and databases using session context, ensuring data isolation and efficient client servicing without manual reconfiguration.
An online retailer integrates Odoo with their e-commerce platform to sync inventory levels and orders. They use temporary context to test updates on a staging database before applying changes to production, minimizing disruption to live operations.
A manufacturing company tracks production orders and material usage in Odoo. The skill enables dynamic database switching between test and production environments for quality checks and reporting, using generic CRUD operations on manufacturing models.
A non-profit organization manages donor records and fundraising campaigns in Odoo. They utilize the skill to introspect models and perform CRUD operations on res.partner for donor updates, with secure credential resolution for volunteer access.
A real estate agency maintains property listings and client inquiries in Odoo. They leverage context-aware URL resolution to work with different regional instances, allowing agents to quickly switch between databases for property data management.
Offers integration services to connect Odoo with other business systems like ERP or CRM platforms. Revenue is generated through subscription fees for API management and support, leveraging the skill's dynamic instance switching for multi-tenant deployments.
Provides consulting to customize Odoo modules and workflows for clients. Revenue comes from project-based fees and hourly rates, using the skill to test configurations across different environments before deployment to ensure compatibility.
Hosts and maintains Odoo instances for businesses, offering uptime guarantees and technical support. Revenue is derived from monthly hosting fees and premium support packages, utilizing the skill for automated monitoring and database management across client instances.
💬 Integration Tip
Ensure environment variables are securely set for default credentials, and use temporary context for one-off operations to avoid persistent changes to session settings.
Manage Trello boards, lists, and cards via the Trello REST API.
Sync and query CalDAV calendars (iCloud, Google, Fastmail, Nextcloud, etc.) using vdirsyncer + khal. Works on Linux.
Manage tasks and projects in Todoist. Use when user asks about tasks, to-dos, reminders, or productivity.
Master OpenClaw's timing systems. Use for scheduling reliable reminders, setting up periodic maintenance (janitor jobs), and understanding when to use Cron v...
Calendar management and scheduling. Create events, manage meetings, and sync across calendar providers.
Kanban-style task management dashboard for AI assistants. Manage tasks via CLI or dashboard UI. Use when user mentions tasks, kanban, task board, mission con...