.claude/skills/openclaw-cron-double-delivery/SKILL.md
Fix OpenClaw cron jobs delivering messages multiple times (2x or 3x) to the recipient. Use when: (1) recipient reports receiving the same cron job output multiple times, (2) cron job shows status "error" with "Message failed" but delivery shows "delivered", (3) agent prompt instructs the agent to send messages directly (via message tool, imsg, or similar) AND the job has a delivery config — causing both the agent AND the cron delivery system to send separately, (4) gateway logs show "Unknown channel: bluebubbles" or "Unknown channel: imessage" errors from agent tool calls during cron execution.
npx skillsauth add Dbochman/dotfiles openclaw-cron-double-deliveryInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
A cron job delivers its output to the recipient multiple times per run. The job may also
report status: error with "Message failed" even though delivery succeeds, and
consecutiveErrors increments causing backoff delays.
"status":"error", "error":"Message failed", but
"delivered":true, "deliveryStatus":"delivered"[tools] message failed: Unknown channel: bluebubbles or
[tools] message failed: Unknown target "X" for imessageimsg send --to,
or instructs it to use the message tool)delivery config block in jobs.jsonOpenClaw cron jobs have two independent delivery paths:
message tool or imsg CLI during
execution to send messages directlydelivery config and sends the agent's final summary text to the specified targetWhen the prompt instructs the agent to send messages AND the job has a delivery config,
both paths fire. If the agent's message tool call also fails (e.g., channel mismatch),
the agent may retry, creating additional deliveries. Meanwhile the cron delivery system
still sends successfully, marking delivered: true.
The status: error comes from the agent's failed tool call, not from the cron delivery.
This is why the job shows "error" but "delivered" simultaneously.
The fix is simple: never have the agent send messages directly in cron job prompts. Let the cron delivery system handle all message delivery.
DELIVERY: Do NOT use the message tool or imsg. Your final text output IS the briefing
-- the cron system delivers it automatically.
imsg send --to ... commandsInstead of having the agent send error messages to a different person, just have it output the error text. The cron delivery will send it to the configured recipient. If you need errors routed to a different person, create a separate error-notification job or handle it at the gateway level.
j["state"]["consecutiveErrors"] = 0
j["state"]["lastRunStatus"] = "ok"
j["state"]["lastStatus"] = "ok"
del j["state"]["lastError"] # if present
updatedAtMs to int(time.time() * 1000) for gateway hot-reloadnextRunAtMs is correct (scp from dotfiles may overwrite Mini's live value)"message": "You are Dylan's morning briefing assistant...
...Compose Briefing\n\nFormat a concise iMessage-friendly summary:..."
No mention of sending, messaging, or delivery. The agent just outputs text, and the cron delivery config handles the rest.
"status":"ok" in the JSONL run history[tools] message failed errors in gateway log for that job's sessionBefore (broken):
If this fails with any auth error:
- Send error to Dylan via iMessage: imsg send --to [email protected] "AUTH ERROR..."
...
The briefing will be delivered to Julia via iMessage automatically.
After (fixed):
DELIVERY: Do NOT use the message tool or imsg. Your final text output IS the briefing
-- the cron system delivers it automatically.
If this fails with any auth error:
- Output: "Morning briefing skipped -- auth error. Dylan: re-auth and scp credentials."
...
Keep it brief and scannable.
delivery.mode: "announce" sends the agent's final summary text as a messagedelivery.channel: "bluebubbles" and delivery.to control where it goesmessage tool and the cron delivery are completely independent — there is
no deduplication between themopenclaw-cron-job-creation covers jobs.json schema and creationopenclaw-cron-ghost-jobs covers jobs running after removaldevelopment
Search the web for current information, news, facts, and answers. Use when asked questions about current events, needing to look something up, finding websites, researching topics, or when you need up-to-date information beyond your training data.
development
Summarize any URL, YouTube video, podcast, PDF, or file into concise text. Use when asked to read an article, summarize a link, get the gist of a video or podcast, extract content from a URL, or when you need to understand what a web page or document contains.
development
Play music via Spotify and control Google Home speakers. Use when asked to play music, songs, artists, playlists, podcasts, or control speakers/volume/audio.
testing
Create new OpenClaw skills, modify and improve existing skills, and measure skill performance with evals. Use when users want to create a skill from scratch, update or optimize an existing skill, run evals to test a skill, benchmark skill performance with variance analysis, or optimize a skill's description for better triggering accuracy. Also use when asked to "make a skill", "turn this into a skill", "improve this skill", or "test this skill".