#Understand cron jobs configurations and delivery messages

1 messages · Page 1 of 1 (latest)

finite mica
#

Hey Krill!

I would like to understand how cron jobs work and how to configure them for the following usecases

Name Schedule Target Last Run Status
Memory Distillation 0 3 * * * (UTC) Isolated Feb 28, 03:00 âś… ok
Morning Tech & Global Pulse 0 8:00 (Cairo) Main Feb 28, 06:00 âś… ok
Daily Update (Cairo 8 AM) 0 8:00 (Cairo) Main Feb 28, 06:00 âś… ok
Evening Review & MENA News 21:00 (Cairo) Main Feb 27, 19:00 âś… ok
Weekly Reset - 2026 Res. Sun 10:00 (Cairo) Isolated Feb 22, 08:00 ❌ error*
Weekly Tech & Strategy Sun 10:00 (Cairo) Main Feb 22, 08:00 âś… ok
Monthly Finance Pulse 1st 11:00 (Cairo) Isolated - (Pending)
Luxor Marathon Planning Sept 1, 2026 Isolated - (One-shot)

My main issue. Is with delivery. When I attempted to configure a job to run in an isolated agent turn session. it caused the agent to run and do it but then in the main session it was asked to summerize the results in 2-3 sentences which is not ideal for some of these usecases. This was the case in a old version 2026.2.13. Not sure if anything has changed so far.

I changed all job to run within the main session to avoid this issue. But then I noticed that sometimes the main session is not delivering messages to telegram for some reason. Like the messages would appear in the web dashboard but was not sent to telegram.

I asked the agent to specifically send the job result to my telegram id. This solved the issue and was working great for a while until I started noticing that it sometimes sends the message twice. Once using the tool and the other as part of the chat.

Can you guide me to configure my jobs correctly?

nova pendantBOT
#

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

swift knotBOT
#

A bunch of what you’re seeing is expected routing + delivery-mode behavior, and it’s fixable once you separate:

  1. where the job runs (main vs isolated), and
  2. how results are delivered (announce vs none vs webhook vs “agent uses message tool”).

First: what version are you on now? (openclaw --version) — cron delivery behavior did change since early 2026.2.x.

Mental model: “Main” vs “Isolated”

Docs: https://docs.openclaw.ai/automation/cron-jobs

1) --session main (system event)

  • Cron enqueues a system event into the main session, then the next heartbeat processes it.
  • Delivery goes to the session’s “last route” (whatever you last talked to: Telegram, Dashboard, Discord, …).
  • So if you used the web dashboard recently, it’s totally plausible the result shows up there but not Telegram.

This matches your “it appears in the web dashboard but wasn’t sent to Telegram”.

#

2) --session isolated (agent turn in cron:<jobId>)

  • Cron runs a fresh isolated turn (no prior context).
  • You can set delivery explicitly via cron itself (recommended).

Your “2–3 sentence summary in main session” issue

For isolated jobs, if you omit delivery, it defaults to announce (and announce includes a short main-session summary by design).

From the docs:

  • announce: deliver to target channel and “post a brief summary to the main session”
  • none: internal only, no delivery and no main-session summary

So if you want isolated runs without that main-session summary, set no delivery:

openclaw cron edit <job-id> --no-deliver
#

Or when creating:

openclaw cron add ... --session isolated --no-deliver

CLI docs: https://docs.openclaw.ai/cli/cron

The “sometimes Telegram doesn’t get it” issue (main-session jobs)

This is almost always last-route vs explicit target.

If you need “always deliver to Telegram at 8am Cairo”, don’t rely on main-session routing. Use isolated + announce + explicit telegram target:

openclaw cron add \
  --name "Daily Update (Cairo 8 AM)" \
#
  --cron "0 8 * * *" \
  --tz "Africa/Cairo" \
  --session isolated \
  --message "..." \
  --announce \
  --channel telegram \
  --to "<your_telegram_chat_id>"

(Use your real chat id; topics look like -100...:topic:123 — see cron docs’ Telegram section.)

The “it sends twice” issue

That happens when you combine two delivery paths:

  • The agent prints the result (normal chat reply), and also
  • The agent uses the message tool to send the same content.
#

Pick one pattern:

Pattern A (recommended): cron does delivery (announce)

  • Use --session isolated --announce --channel telegram --to ...
  • In the job prompt: do NOT call message.send. Just write the final text normally.

Pattern B: agent does delivery (message tool), cron delivery disabled

  • Set --no-deliver (or delivery.mode=none)
  • In the prompt: call message.send and then make the run end with no chat output (otherwise you’ll get a second copy as the “assistant reply”).
    • In OpenClaw land that typically means: after the tool send, output NO_REPLY (so nothing else is posted).

If you do Pattern B without suppressing the normal reply, you’ll get duplicates exactly like you described.

Suggested mapping for your table

  • Memory Distillation → isolated + no-deliver (internal chore)
  • Morning/Daily/Evening briefings → isolated + announce to Telegram (explicit --channel/--to)
  • Weekly reset / monthly finance → isolated + announce (if you want it pushed) or no-deliver (if it’s internal)
#
  • One-shot (Luxor Marathon Planning) → --at "2026-09-01T…" + isolated + announce (or main if it must interact with main context)

Also: Cairo TZ should be Africa/Cairo (IANA name), not just “Cairo”.

Quick troubleshooting checklist (when something “ran ok” but didn’t show up)

Docs runbook: https://docs.openclaw.ai/gateway/troubleshooting#cron-and-heartbeat-delivery

Run:

openclaw cron status
openclaw cron list
openclaw cron runs --id <jobId> --limit 20
openclaw channels status --probe
openclaw logs --follow
#

Two important nuances from the docs:

  • A cron run ok means the agent turn finished, not necessarily that delivery succeeded (depending on bestEffort).
  • If you used --session main, results may go to the dashboard if that’s the last route.

If you paste:

  1. openclaw --version, and
  2. one problematic job definition (openclaw cron list entry or the exact cron add command you used),
    I can tell you the exact “best” setting (announce vs no-deliver vs message-tool) for each of your usecases and how to prevent duplicates 100%.
finite mica
#

The issue with announce is that it's hardcoded to generate a 2-3 sentence summary? right? I want the full job results.

Is this still the case?

swift knotBOT
#

No — announce is not hardcoded to “2–3 sentences” for what gets sent to Telegram.

What is short (by design) is the extra main-session note that OpenClaw posts about the isolated run when delivery.mode="announce":

  • Delivery content (to Telegram/Slack/etc): uses the isolated run’s actual outbound payloads (i.e., whatever the agent produced as its final output, chunked normally).
  • Main-session post: a short summary is posted to main only when announce is used.
    Source: https://docs.openclaw.ai/automation/cron-jobs (see “Announce delivery flow” + the bullet “A short summary is posted to the main session only when delivery.mode = "announce".”)

So if you want the full report in Telegram, you can absolutely use isolated+announce — just make your cron prompt produce the full report (not “summarize”).

If you want full report in Telegram AND zero main-session summary, then you currently can’t do that with announce (since that main-summary is tied to announce). The workaround is:

  • --session isolated --no-deliver
  • inside the job: message.send to Telegram
  • then end with NO_REPLY so you don’t get a second “chat” copy.

If you paste one of your cron job definitions (or the exact openclaw cron add ... you used), I’ll suggest the cleanest setup for that specific job (and eliminate the double-send).

finite mica
#

Here is an example of a job I have configured now:

    {
      "id": "0e3eedf7-40f4-4f37-84ca-0ade8a59d119",
      "agentId": "main",
      "name": "Morning Tech & Global Pulse (8 AM Cairo)",
      "enabled": true,
      "createdAtMs": 1771361711693,
      "updatedAtMs": 1772251243770,
      "schedule": {
        "tz": "Africa/Cairo",
        "expr": "0 6 * * *",
        "kind": "cron"
      },
      "sessionTarget": "main",
      "wakeMode": "now",
      "payload": {
        "kind": "systemEvent",
        "text": "ACTION: News Pulse - Morning Edition\n\n1. Information Gathering (Direct Fetching):\n   - Hacker News (Top Tech): \n     - curl -s \\\"https://hn.algolia.com/api/v1/search?tags=front_page&hitsPerPage=10\\\"\n   - Global News:\n     - firecrawl_scrape \\\"https://apnews.com/world-news\\\"\n     - firecrawl_scrape \\\"https://www.reuters.com/world/\\\"\n   - Egypt/MENA Economy:\n     - firecrawl_scrape \\\"https://enterprise.press/category/egypt/economy/\\\"\n\n2. Analysis & Summarization:\n   - Tech: Identify the top 3 high-signal tech stories.\n   - Global: Identify the top 2 major global stories.\n   - Regional: Extract the primary economic theme for Egypt/MENA.\n\n3. Presentation & Delivery:\n   - Tone: Sharp, direct, and helpful (per SOUL.md).\n   - Target: Send to Telegram ID 1359334095.\n   - Format: Telegram-optimized (Bold headings, bullet points).\n   - Delivery: Use the message tool to send results to 1359334095.\n\n4. Failure Protocol:\n   - If a source fetch fails, proceed and note it."
      },
      "state": {
        "nextRunAtMs": 1772337600000,
        "lastRunAtMs": 1772251200010,
        "lastStatus": "ok",
        "lastDurationMs": 43760,
        "consecutiveErrors": 0,
        "lastRunStatus": "ok",
        "lastDeliveryStatus": "not-requested"
      }
    },

Here is one of my cron job definitions. What do you think can be improved to make it send the full results and no summary to telegram?

swift knotBOT
#

A few concrete improvements jump out from that definition — and they map directly to the “full results / no unwanted summaries / no duplicates” goals.

1) Your schedule is currently 6:00 Cairo, not 8:00

You have:

"schedule": { "tz": "Africa/Cairo", "expr": "0 6 * * *" }

When you set tz, the cron expression is interpreted in that timezone. So for 8:00 Cairo, make it:

  • expr: "0 8 * * *"
  • tz: "Africa/Cairo"

(Using 0 6 only makes sense if you were thinking “6 UTC = 8 Cairo”, but with tz set you don’t need to do that conversion.)

2) The biggest reliability problem: sessionTarget: "main" + “send via message tool”

#

Main-session cron jobs (payload.kind="systemEvent") run through the main session/heartbeat machinery, which means:

  • routing can follow the session’s “last route” (dashboard vs telegram), and
  • if you also use message.send, you can get double sends (tool-send + normal assistant reply) depending on routing.

If your goal is “always deliver to Telegram, consistently”, the clean solution is: run isolated + let cron deliver (don’t ask the agent to call message.send).

Option A (recommended): Isolated + announce to Telegram (full report to Telegram)

This gives you:

  • full output delivered to Telegram (not “2–3 sentences”, unless your prompt asks for that)
  • no dependence on “last route”
  • no duplicate message-tool vs chat reply confusion

Example shape:

{
#
name: "Morning Tech & Global Pulse (8 AM Cairo)",
schedule: { kind: "cron", expr: "0 8 * * *", tz: "Africa/Cairo" },
sessionTarget: "isolated",
payload: {
kind: "agentTurn",
message: "Write the FULL morning report... (don’t summarize to 2-3 lines)."
},
delivery: {
mode: "announce",
channel: "telegram",
to: "<your_telegram_chat_id>"
},
wakeMode: "next-heartbeat" // optional: delays the tiny main-session note
}
#

Tradeoff: announce will still create a short main-session note (“job ran…”) by design — but that’s in the main session/dashboard, not Telegram. (Telegram still gets the full content.)

Docs: https://docs.openclaw.ai/automation/cron-jobs (Announce delivery flow)

Option B (if you want zero main-session note): Isolated + no-deliver + message.send + NO_REPLY

If you absolutely don’t want any main-session summary/note, do:

  • sessionTarget: "isolated"
  • delivery.mode = "none" (CLI: --no-deliver)
  • inside the prompt: send via message tool
  • end with NO_REPLY so there’s no second “assistant reply” payload

That looks like:

{
#
sessionTarget: "isolated",
payload: {
kind: "agentTurn",
message: `
Generate the full report.

Then send it via the message tool to Telegram chat id <id>.
After the message tool succeeds, output exactly: NO_REPLY
`
},
delivery: { mode: "none" }
}

This is the “no cron delivery, agent-only delivery” pattern. It’s also the pattern that prevents the double-send you observed.

#

3) Prompt/content: you’re asking for a short summary right now

Your current systemEvent says:

  • “top 3 tech stories”
  • “top 2 global stories”
  • “extract the primary theme”

That will inevitably produce something compact. If you want “full results”, change the requirements (e.g., top 10 + 2–3 bullets each + links + why it matters + “what to watch today”, etc.).

4) Tooling nit: curl ... / firecrawl_scrape ... inside the text isn’t automatically executed

Unless you have a custom setup, those lines are just instructions. In stock OpenClaw you’d typically use web_fetch / web_search (or exec if you’ve allowed it). So you’ll get better consistency if the prompt names the tools you actually have enabled.


If you tell me which outcome you want:

  1. OK with a tiny main-session note (Option A) vs no main-session note at all (Option B), and
  2. whether you want one Telegram message or multiple sections/messages,
#

…I can rewrite your exact job payload text to produce the “full report” format you want (and not accidentally re-introduce duplicates).

finite mica
#

I love you krill. You are the best!

swift knotBOT
#

Appreciate it — I’m here for it.

If you want, we can lock this down so your cron jobs are “boring reliable”:

  1. Paste openclaw --version
  2. Tell me which you prefer for these report-style jobs:
  • A) Isolated + announce to Telegram (full report to Telegram, tiny main-session note), or
  • B) Isolated + no-deliver + message.send + NO_REPLY (full report to Telegram, zero main-session note)

Then I’ll give you the exact openclaw cron edit/add commands (and a cleaned-up prompt template) so you get full results and no duplicates.