#openclaw message send wrapper pattern for multi-recipient cron jobs

1 messages Β· Page 1 of 1 (latest)

sleek sapphire
#

Hi Krill,
Following your earlier advice β€” for cron jobs that need to fan out to multiple WhatsApp recipients from a single Python script, you recommended calling openclaw message send directly from the script rather than using isolated + announce.
Could you sketch the exact wrapper pattern for that? Specifically:

Does openclaw message send work correctly when called from inside a Python script running within the OpenClaw Docker container?
For same message to multiple recipients β€” do you call it once with repeated --target flags, or once per recipient?
For different message per recipient β€” one call per recipient, each with its own --target and --message?
Any gotchas with env/PATH inside the container when calling the CLI from Python (e.g. subprocess.run)?

Running OpenClaw v2026.4.15.

past saddleBOT
versed wraithBOT
#

To help others find answers, you can mark your question as solved via Right click solution message -> Apps -> βœ… Mark Solution

woeful sundialBOT
#

Yep, that pattern should work fine on v2026.4.15, as long as the Python script runs in the same OpenClaw container context and can see the same config/state.

Short answers:

  • Inside Python in the Docker container? Yes.
  • Same message to multiple recipients? Use one broadcast call with --targets ..., not repeated --target.
  • Different message per recipient? Use one send call per recipient.
  • Gotchas? Mostly PATH, HOME, and state/config env.

Recommended pattern

import json
import os
import subprocess
#
ENV = os.environ.copy()
ENV.setdefault("HOME", "/home/node")
ENV.setdefault("OPENCLAW_STATE_DIR", "/home/node/.openclaw")
ENV.setdefault("OPENCLAW_CONFIG_PATH", "/home/node/.openclaw/openclaw.json")

def oc(args):
    cp = subprocess.run(
        ["openclaw", *args, "--json"],
        env=ENV,
        text=True,
        capture_output=True,
        check=True,
        timeout=60,
    )
    return json.loads(cp.stdout)
#

def whatsapp_send(target, message, account=None):
    args = [
        "message", "send",
        "--channel", "whatsapp",
        "--target", target,
        "--message", message,
    ]
    if account:
        args += ["--account", account]
    return oc(args)

def whatsapp_broadcast(targets, message, account=None):
    args = [
        "message", "broadcast",
#
        "--channel", "whatsapp",
        "--targets", *targets,
        "--message", message,
    ]
    if account:
        args += ["--account", account]
    return oc(args)

Usage

Same message to many:

whatsapp_broadcast(
#
    ["+15551234567", "+447700900123"],
    "Daily report is ready"
)

Different message per recipient:

for target, msg in [
    ("+15551234567", "Alice report ready"),
    ("+447700900123", "Bob report ready"),
]:
    whatsapp_send(target, msg)

Important gotchas

#
  1. send is single-target.
    openclaw message send takes one --target. For fanout, use openclaw message broadcast --targets ....

  2. Use E.164 / WhatsApp IDs.
    WhatsApp targets should be phone numbers like +15551234567 or a group JID.

  3. Keep the same user/env as the gateway.
    In Docker, state is usually under /home/node/.openclaw. If your Python process runs with a different HOME, the CLI can look in the wrong place.

  4. Pass argv list, not shell=True.
    It avoids quoting bugs.

  5. broadcast is best-effort.
    It can partially succeed. If you want strict per-recipient retry/accounting, looping over send is cleaner.

If you want, paste your current Python wrapper and I’ll tighten it up against the exact Docker layout you’re using.