| name | vnclaw-odoo-skill |
| description | Integrate with Odoo 17 via XML-RPC API. Use when: managing projects, tasks, calendar events, time off requests, helpdesk tickets, knowledge articles, documents, or timesheets in Odoo 17. Supports read, create, and update operations only. No delete allowed. |
| argument-hint | Describe what you want to do in Odoo 17 (e.g., 'list all open tasks in project X', 'create a time off request') |
VNClaw — Odoo 17 Integration Skill
Execution Rules (MUST follow)
- ALWAYS run the command immediately. Never ask the user to confirm or explain what the command does before running it. Translate the request → pick the command → execute it in one step.
- Never say "Would you like me to execute this?" — just execute it.
- Never ask "Do you want me to run this?" — just run it.
- If the command fails, show the error and try to fix it. Do not ask the user for help diagnosing unless you have exhausted all options.
- Credentials: If env vars are missing, inform the user which variable is missing and stop. Do not ask for the value interactively.
Path Resolution
IMPORTANT: All commands below use SKILL_SCRIPTS as shorthand for the absolute path to the scripts directory. The skill may be installed in two locations — resolve it by checking both:
SKILL_SCRIPTS="$(
# 1. Check workspace: .github/skills/vnclaw-odoo-skill/scripts
_ws_root="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
_ws_path="$_ws_root/.github/skills/vnclaw-odoo-skill/scripts"
# 2. Global fallback locations
_global_path="$HOME/.vnclaw/skills/vnclaw-odoo-skill/scripts"
_global_path2="$HOME/.openclaw/skills/vnclaw-odoo-skill/scripts"
if [ -d "$_ws_path" ]; then
echo "$_ws_path"
elif [ -d "$_global_path" ]; then
echo "$_global_path"
elif [ -d "$_global_path2" ]; then
echo "$_global_path2"
else
# Last resort: search filesystem
find "$HOME" /opt -type d -name vnclaw-odoo-skill -path '*/skills/*' 2>/dev/null | head -1 | sed 's|$|/scripts|'
fi
)"
echo "SKILL_SCRIPTS=$SKILL_SCRIPTS"
Possible install locations:
| Location type | Path |
|---|
| Workspace skill | <git-root>/.github/skills/vnclaw-odoo-skill/scripts/ |
| User global (vnclaw) | ~/.vnclaw/skills/vnclaw-odoo-skill/scripts/ |
| User global (openclaw) | ~/.openclaw/skills/vnclaw-odoo-skill/scripts/ |
Environment Variables (Required)
Credentials are loaded from environment variables. Never hardcode credentials.
| Variable | Description |
|---|
ODOO_URL | Base URL (e.g., https://mycompany.odoo.com) |
ODOO_DB | Database name |
ODOO_USERNAME | Login username (email) |
ODOO_API_KEY | API key or password |
Common Features (All Modules)
All module scripts share these capabilities:
--my — Filter to current authenticated user's records
- Name-based lookups — Use
--user "Alice", --project "Website" etc. instead of IDs
- Date shortcuts —
--today, --yesterday, --this-week, --last-week, --this-month, --last-month, --this-year
- Custom date range —
--date-from 2026-03-01 --date-to 2026-03-31
- Log notes —
log-note action to post internal notes on records (where supported)
- Notify —
notify action to schedule activity notifications by user name (where supported)
- JSON output — All scripts output JSON to stdout, logs go to stderr
DATE FIELD RULE for tasks.py: Date shortcuts filter date_deadline by default.
To filter by when a task was created, always add --date-field created.
To filter by when a task was last updated, use --date-field updated.
Natural Language → Command Mapping
Use this table to translate common user requests into the correct command:
| User says... | Command |
|---|
| "my tasks" | tasks.py list --my |
| "my tasks this week" / "tasks with deadline this week" | tasks.py list --my --this-week |
| "tasks I created this week" / "tasks created this week" | tasks.py list --my --this-week --date-field created |
| "tasks created today" | tasks.py list --my --today --date-field created |
| "tasks created this month" | tasks.py list --my --this-month --date-field created |
| "tasks updated today" / "recently modified tasks" | tasks.py list --my --today --date-field updated |
| "my timesheets this week" | timesheets.py list --my --this-week |
| "log 2 hours on project X" | timesheets.py log --project "X" --hours 2 --description "..." |
| "my timesheet summary this month" | timesheets.py summary --my --this-month |
| "my calendar today" / "my meetings today" | calendar_events.py list --my --today |
| "my tickets" / "tickets assigned to me" | helpdesk.py list --my |
| "my leave requests this year" | time_off.py list --my --this-year |
Quick Decision: Which Script to Use
| User wants to... | Script | Example |
|---|
| List/view/create/update tasks | tasks.py | python3 $SKILL_SCRIPTS/tasks.py list --my --this-week |
| List/view/create/update projects | projects.py | python3 $SKILL_SCRIPTS/projects.py list --my |
| Log/view/update timesheets | timesheets.py | python3 $SKILL_SCRIPTS/timesheets.py log --project "Website" --hours 2 --description "review" |
| List/view/create/update calendar events | calendar_events.py | python3 $SKILL_SCRIPTS/calendar_events.py list --my --today |
| List/view/create/update helpdesk tickets | helpdesk.py | python3 $SKILL_SCRIPTS/helpdesk.py list --my --this-week |
| List/view/create/update time off requests | time_off.py | python3 $SKILL_SCRIPTS/time_off.py list --my --this-year |
| List/view/create/update knowledge articles | knowledge.py | python3 $SKILL_SCRIPTS/knowledge.py list --my --published |
| List/view/create/update documents | documents.py | python3 $SKILL_SCRIPTS/documents.py list --folder "HR" |
| Access any user-defined / custom model | custom_app.py | python3 $SKILL_SCRIPTS/custom_app.py list crm.lead --my --this-month |
| Test connection to Odoo | odoo_core.py | python3 $SKILL_SCRIPTS/odoo_core.py test-connection |
Module: Tasks (tasks.py)
Manages project.task. Actions: list, get, create, update, log-note, notify, stages.
Date filter field — use --date-field to choose which date to filter on:
deadline (default) — filters by date_deadline
created — filters by create_date (when the task was created)
updated — filters by write_date (when the task was last modified)
python3 $SKILL_SCRIPTS/tasks.py list --my
python3 $SKILL_SCRIPTS/tasks.py list --my --this-week --date-field created
python3 $SKILL_SCRIPTS/tasks.py list --my --today --date-field created
python3 $SKILL_SCRIPTS/tasks.py list --my --this-month --date-field created
python3 $SKILL_SCRIPTS/tasks.py list --my --this-week
python3 $SKILL_SCRIPTS/tasks.py list --user "Alice" --this-week --date-field created
python3 $SKILL_SCRIPTS/tasks.py list --project "Website Redesign"
python3 $SKILL_SCRIPTS/tasks.py list --search "login bug"
python3 $SKILL_SCRIPTS/tasks.py list --overdue
python3 $SKILL_SCRIPTS/tasks.py list --stage "In Progress"
python3 $SKILL_SCRIPTS/tasks.py list --tag "urgent"
python3 $SKILL_SCRIPTS/tasks.py get 42
python3 $SKILL_SCRIPTS/tasks.py create --name "Fix login bug" --project "Website" --assign "Alice" --deadline 2026-04-01
python3 $SKILL_SCRIPTS/tasks.py update 42 --stage "Done" --assign "Bob"
python3 $SKILL_SCRIPTS/tasks.py log-note 42 --body "Waiting for client feedback"
python3 $SKILL_SCRIPTS/tasks.py notify 42 --user "Alice" --summary "Please review this task"
python3 $SKILL_SCRIPTS/tasks.py stages
Module: Projects (projects.py)
Manages project.project. Actions: list, get, create, update, log-note, notify, stages.
python3 $SKILL_SCRIPTS/projects.py list --my
python3 $SKILL_SCRIPTS/projects.py list --manager "Alice"
python3 $SKILL_SCRIPTS/projects.py list --search "Website"
python3 $SKILL_SCRIPTS/projects.py list --active-only --favorites
python3 $SKILL_SCRIPTS/projects.py get 1
python3 $SKILL_SCRIPTS/projects.py create --name "Website Redesign" --manager "Alice"
python3 $SKILL_SCRIPTS/projects.py update 1 --stage "In Progress" --date-start 2026-04-01 --date-end 2026-06-30
python3 $SKILL_SCRIPTS/projects.py log-note 1 --body "Kickoff meeting completed"
python3 $SKILL_SCRIPTS/projects.py notify 1 --user "Alice" --summary "Budget review needed"
python3 $SKILL_SCRIPTS/projects.py stages
Module: Timesheets (timesheets.py)
Manages account.analytic.line. Actions: list, summary, log, update.
python3 $SKILL_SCRIPTS/timesheets.py list --my --this-week
python3 $SKILL_SCRIPTS/timesheets.py list --user "Alice" --this-month
python3 $SKILL_SCRIPTS/timesheets.py list --employee "Alice Smith"
python3 $SKILL_SCRIPTS/timesheets.py list --project "Website Redesign"
python3 $SKILL_SCRIPTS/timesheets.py list --date-from 2026-03-01 --date-to 2026-03-31
python3 $SKILL_SCRIPTS/timesheets.py summary --my --this-month
python3 $SKILL_SCRIPTS/timesheets.py log --project "Website Redesign" --hours 2.5 --description "Code review"
python3 $SKILL_SCRIPTS/timesheets.py log --project "Website" --hours 3 --description "Dev" --date 2026-03-17
python3 $SKILL_SCRIPTS/timesheets.py update 15 --hours 4 --description "Updated"
Module: Calendar Events (calendar_events.py)
Manages calendar.event. Actions: list, get, create, update.
python3 $SKILL_SCRIPTS/calendar_events.py list --my --today
python3 $SKILL_SCRIPTS/calendar_events.py list --my --this-week
python3 $SKILL_SCRIPTS/calendar_events.py list --attendee "Alice"
python3 $SKILL_SCRIPTS/calendar_events.py list --organizer "Bob"
python3 $SKILL_SCRIPTS/calendar_events.py list --search "Sprint"
python3 $SKILL_SCRIPTS/calendar_events.py list --date-from 2026-03-20 --date-to 2026-03-25
python3 $SKILL_SCRIPTS/calendar_events.py get 10
python3 $SKILL_SCRIPTS/calendar_events.py create --name "Sprint Planning" --start "2026-03-20 09:00:00" --stop "2026-03-20 10:00:00" --attendees "Alice, Bob, Carol" --location "Room A"
python3 $SKILL_SCRIPTS/calendar_events.py update 10 --start "2026-03-20 14:00:00" --stop "2026-03-20 15:00:00"
Module: Helpdesk (helpdesk.py)
Manages helpdesk.ticket. Actions: list, get, create, update, log-note, notify, stages.
python3 $SKILL_SCRIPTS/helpdesk.py list --my
python3 $SKILL_SCRIPTS/helpdesk.py list --user "Alice"
python3 $SKILL_SCRIPTS/helpdesk.py list --customer "Acme Corp"
python3 $SKILL_SCRIPTS/helpdesk.py list --search "login" --this-week
python3 $SKILL_SCRIPTS/helpdesk.py list --priority 2 --team "Support"
python3 $SKILL_SCRIPTS/helpdesk.py list --stage "In Progress"
python3 $SKILL_SCRIPTS/helpdesk.py get 5
python3 $SKILL_SCRIPTS/helpdesk.py create --name "Login page broken" --team "Support" --assign "Alice" --customer "Acme Corp"
python3 $SKILL_SCRIPTS/helpdesk.py update 5 --stage "Solved" --assign "Bob"
python3 $SKILL_SCRIPTS/helpdesk.py log-note 5 --body "Escalated to engineering"
python3 $SKILL_SCRIPTS/helpdesk.py notify 5 --user "Alice" --summary "Please investigate"
python3 $SKILL_SCRIPTS/helpdesk.py stages
Module: Time Off (time_off.py)
Manages hr.leave. Actions: list, get, create, update, leave-types.
python3 $SKILL_SCRIPTS/time_off.py list --my
python3 $SKILL_SCRIPTS/time_off.py list --user "Alice"
python3 $SKILL_SCRIPTS/time_off.py list --employee "Alice Smith"
python3 $SKILL_SCRIPTS/time_off.py list --state validate
python3 $SKILL_SCRIPTS/time_off.py list --leave-type "Sick Time Off"
python3 $SKILL_SCRIPTS/time_off.py list --my --this-year
python3 $SKILL_SCRIPTS/time_off.py leave-types
python3 $SKILL_SCRIPTS/time_off.py create --date-from "2026-03-25 08:00:00" --date-to "2026-03-26 17:00:00" --leave-type "Paid Time Off" --name "Personal day"
python3 $SKILL_SCRIPTS/time_off.py get 12
Module: Knowledge (knowledge.py)
Manages knowledge.article. Actions: list, get, create, update.
python3 $SKILL_SCRIPTS/knowledge.py list --my
python3 $SKILL_SCRIPTS/knowledge.py list --author "Alice"
python3 $SKILL_SCRIPTS/knowledge.py list --published
python3 $SKILL_SCRIPTS/knowledge.py list --root-only
python3 $SKILL_SCRIPTS/knowledge.py list --search "onboarding"
python3 $SKILL_SCRIPTS/knowledge.py list --category workspace
python3 $SKILL_SCRIPTS/knowledge.py get 5
python3 $SKILL_SCRIPTS/knowledge.py create --name "Setup Guide" --parent-name "Engineering" --body "<h1>Getting Started</h1>"
python3 $SKILL_SCRIPTS/knowledge.py update 5 --body "<p>Updated content</p>"
Module: Documents (documents.py)
Manages documents.document. Actions: list, get, create, update, folders.
python3 $SKILL_SCRIPTS/documents.py list --my
python3 $SKILL_SCRIPTS/documents.py list --owner "Alice"
python3 $SKILL_SCRIPTS/documents.py list --folder "HR Documents"
python3 $SKILL_SCRIPTS/documents.py list --search "invoice"
python3 $SKILL_SCRIPTS/documents.py list --type binary --this-month
python3 $SKILL_SCRIPTS/documents.py list --tag "contracts"
python3 $SKILL_SCRIPTS/documents.py folders
python3 $SKILL_SCRIPTS/documents.py get 3
python3 $SKILL_SCRIPTS/documents.py create --name "Design Spec" --folder "Engineering" --owner "Alice" --url "https://example.com/spec"
python3 $SKILL_SCRIPTS/documents.py update 3 --folder "Archive"
Module: Custom App (custom_app.py)
For any Odoo model not covered by the dedicated scripts — CRM, Sales, Purchase, Inventory, Manufacturing, Accounting, or any custom app installed in the Odoo instance.
Recommended workflow:
- Discover the model technical name with
models
- Inspect available fields with
fields
- Then
list, get, create, update as needed
python3 $SKILL_SCRIPTS/custom_app.py models --search "CRM"
python3 $SKILL_SCRIPTS/custom_app.py models --search "Sale Order"
python3 $SKILL_SCRIPTS/custom_app.py models --module crm
python3 $SKILL_SCRIPTS/custom_app.py fields crm.lead
python3 $SKILL_SCRIPTS/custom_app.py fields crm.lead --search "stage"
python3 $SKILL_SCRIPTS/custom_app.py fields sale.order --type many2one
python3 $SKILL_SCRIPTS/custom_app.py list crm.lead
python3 $SKILL_SCRIPTS/custom_app.py list crm.lead --my --this-month
python3 $SKILL_SCRIPTS/custom_app.py list crm.lead --search "Acme" --user "Alice"
python3 $SKILL_SCRIPTS/custom_app.py list sale.order \
--domain '[["state","=","sale"]]' \
--fields '["id","name","partner_id","amount_total","date_order"]' \
--order "date_order desc" --limit 20
python3 $SKILL_SCRIPTS/custom_app.py list sale.order --date-field date_order --this-month
python3 $SKILL_SCRIPTS/custom_app.py get crm.lead 42
python3 $SKILL_SCRIPTS/custom_app.py count crm.lead --domain '[["stage_id.name","=","Won"]]'
python3 $SKILL_SCRIPTS/custom_app.py create crm.lead \
--values '{"name":"New Opportunity","partner_id":5,"expected_revenue":10000}'
python3 $SKILL_SCRIPTS/custom_app.py update crm.lead 42 \
--values '{"stage_id":3,"priority":"1"}'
python3 $SKILL_SCRIPTS/custom_app.py update crm.lead --ids '[42,43,44]' \
--values '{"user_id":7}'
python3 $SKILL_SCRIPTS/custom_app.py log-note crm.lead 42 --body "Called the client, follow up next week"
python3 $SKILL_SCRIPTS/custom_app.py notify crm.lead 42 \
--user "Alice" --summary "Please follow up with this lead"
Generic Client (odoo_core.py)
For raw low-level access or testing the connection:
python3 $SKILL_SCRIPTS/odoo_core.py test-connection
python3 $SKILL_SCRIPTS/odoo_core.py search-read res.partner --fields '["name","email","phone"]' --limit 20
python3 $SKILL_SCRIPTS/odoo_core.py fields res.partner
Security Rules
- No delete —
unlink is blocked in all scripts.
- Sensitive models blocked —
ir.rule, ir.model.access, ir.config_parameter, etc.
- Read-only models —
res.users, hr.employee, stage/type models cannot be modified.
- Credentials from environment only — Never pass credentials as arguments.
- Audit logging — All operations are logged to stderr with timestamps.
Troubleshooting
| Issue | Solution |
|---|
Access Denied | Check all 4 env vars: ODOO_URL, ODOO_DB, ODOO_USERNAME, ODOO_API_KEY |
Model not found | Module may not be installed in your Odoo instance |
No module named odoo_core | Run the script from the scripts directory or use absolute path |
| Script not found | Resolve SKILL_SCRIPTS path as shown in Path Resolution above |
Field Reference
See Odoo Models Reference for detailed field lists per model.