npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

openclaw-channel-odoo

v0.4.3

Published

OpenClaw channel plugin for Odoo — receive webhooks and reply via configurable XML-RPC methods

Readme


An OpenClaw channel plugin that wires OpenClaw agents into Odoo. Any Odoo event — a button click, a chat input, a cron — can hand off to an agent, and the agent's output can flow back into Odoo as a chatter message, a newly created record, a field update, or anything else callable via XML-RPC.

  • 🪝 Inbound: any Odoo trigger → agent (auth'd, deduped, debounced)
  • 📤 Outbound: agent output → any Odoo method, configurable per model
  • 🔍 Tool: odoo_search_read — the agent reads Odoo data on demand
  • 🎯 Per-model routing: different methods, agents, prompts per Odoo record type

Heads up — the plugin is one half of the integration. You also need a small Odoo-side addon (an HTTP controller that POSTs to the webhook, and the method(s) the plugin calls back into). See the Odoo-side setup section of the configuration guide for a copy-paste minimal example.


Quick start

Install via OpenClaw:

openclaw plugins install openclaw-channel-odoo

Minimal openclaw.json:

{
  "channels": {
    "odoo": {
      "url": "https://myodoo.com",
      "db": "mydb",
      "uid": 2,
      "password": "<api-key>",
      "webhookSecret": "<shared-bearer-token>",
      "webhookPath": "/openclaw/inbound",

      // Optional inbox tunables (defaults shown):
      //   debounceMs:     window after the first inbound msg before
      //                   flushing the batch to the agent. Range [0, 60000].
      //   agentTimeoutMs: hard cap on one dispatch attempt (agent run +
      //                   delivery). Also the staleness boundary used by
      //                   boot recovery. Range [30000, 3600000].
      //   maxConcurrentDispatches:
      //                   max Odoo inbox batches allowed to dispatch at once.
      //                   Default 1 so Odoo bursts queue instead of starting
      //                   many agent runs in the OpenClaw process.
      //   minDispatchSpacingMs:
      //                   min spacing between dispatch starts. Default 5000.
      //   dispatchAdmissionRetryMs:
      //                   retry delay when the admission gate defers a batch.
      //                   Default 15000.
      //   maxProcessRssMb / maxEventLoopDelayMs:
      //                   optional process-health admission limits. Default 0
      //                   disables each check.
      "debounceMs": 3000,
      "agentTimeoutMs": 900000,
      "maxConcurrentDispatches": 1,
      "minDispatchSpacingMs": 5000,
      "dispatchAdmissionRetryMs": 15000,

      "routes": [
        {
          "match": "*",
          "reply": {
            "method": "message_post",
            "kwargs": {
              "body": "$body",
              "message_type": "comment"
            }
          }
        }
      ]
    }
  }
}

With the minimal Odoo-side controller (shown in the configuration guide), this config routes every inbound message through your agent and posts the reply back to the triggering record's chatter. No custom Odoo methods needed — message_post is built in.

For per-model routing, routing-key matching ({ routingKey: "<glob>" }), per-route agent overrides, custom reply methods, and the variable system — see the configuration guide.


How it works

┌──────────────┐   webhook   ┌─────────┐   dispatch   ┌───────┐
│  Odoo action │ ──────────► │  Plugin │ ───────────► │ Agent │
└──────────────┘             └─────────┘              └───────┘
       ▲                          │
       │    XML-RPC execute_kw    │
       └──────────────────────────┘
  1. Something happens in Odoo — a button press, a chat input, a workflow event
  2. Your Odoo-side controller POSTs the trigger to the plugin's webhook (Bearer-auth'd)
  3. Plugin routes the message to an agent (optionally per-model)
  4. Agent does its thing and produces output; plugin calls back into Odoo via the method configured for that model

Documentation

  • 📖 Configuration guide — Odoo-side setup, routes, matching, the variable system, worked examples, validation errors
  • 🐛 Issues — bug reports and feature requests
  • 📋 Changelog — version history

Telemetry

The plugin emits structured OTEL events at lifecycle transitions via openclaw's diagnostic-events SDK. When @openclaw/otel-diagnostics is installed and configured, these flow to your OTLP backend automatically:

| Event | Where | Produces | |---|---|---| | message.queued | After webhook persists a new batch | Counter openclaw.message.queued{channel,source} | | message.processed{outcome=completed} | After XML-RPC delivery succeeds | Counter + openclaw.message.duration_ms histogram | | message.processed{outcome=error} | After cap-exhaustion (scheduler) OR TTL expiry (recovery) | Counter + span with reason attribute | | run.attempt | Per recorded failure (scheduler) | Counter openclaw.run.attempt{attempt=N} | | inbox.failure (structured log) | Per recorded failure (scheduler) | OTLP log with failureClass, attempt counters, willAbandon, nextDelayMs |

Dependencies:

  • Telemetry is auto-collected by @openclaw/otel-diagnostics — install it and set config.diagnostics.otel.endpoint to ship events to your OTLP backend.
  • The plugin is safe to run without @openclaw/otel-diagnostics — the helpers are no-ops when no event listener is registered. No crash, no extra log noise on the gateway.
  • The inbox.failure structured log flows to OTEL only when config.diagnostics.otel.logs = true in the otel-diagnostics config (default OFF). Without this, the log line is still written to the gateway's local logs via diagnosticLogger.

Per-failure-class breakdown in Grafana. The reason field on message.processed{outcome=error} lives in span attributes (not metric labels). Query via TraceQL on a tracing backend (Tempo/Jaeger):

{ openclaw.outcome="error" } | count() by(openclaw.reason)

Two distinct reason values are emitted: cap_exhausted:<failureClass> (scheduler, when retries are exhausted) and ttl_expired (boot recovery, when a batch sat on disk longer than the 1-hour TTL).


License

MIT · © Monday Merch B.V.