Launch Claude Code async in background with automatic delivery to Telegram/WhatsApp. Use for coding, refactoring, codebase research, file generation, and complex multi-step automations. NOT for quick one-off questions or real-time interactive tasks. Includes strict thread-safe routing + E2E operator validation workflow.
Run Claude Code in background — zero OpenClaw tokens while it works. Results delivered to WhatsApp or Telegram automatically.
Claude Code is NOT just a coding tool. It's a full-powered AI agent with web search, file access, and deep reasoning. Use it for ANY complex task:
Give it prompts the same way you'd talk to a smart human — natural language, focused on WHAT you need, not HOW to do it.
NOT for:
When user asks things like:
it means run the full E2E operator validation flow for run-task.py routing + notifications.
It does NOT mean pytest/unittest discovery by default.
Required behavior:
--validate-only).nohup and file-based prompt.Use the canonical protocol: references/testing-protocol.md and the section below Full E2E Test (reference).
INLINECODE5 is asynchronous orchestration.
After a successful nohup launch, the correct behavior is:
Do not keep waiting in the same turn for Claude Code completion.
Do not poll and then summarize in the same turn unless user explicitly asked for active live monitoring.
Anti-pattern:
run-task.py and keep responding as if completion should appear in this turn.Correct pattern:
run-task.py → acknowledge launch → stop → wait for wake.Never claim "launched" until you have positive launch proof.
Required proof checklist (all):
nohup command returned a PID,ps -p <PID>),🔧 Starting Claude Code... (or equivalent startup marker),--validate-only) for Telegram thread runs.If launch fails with ❌ Invalid routing:
sessions_list,--notify-channel telegram --notify-thread-id <id> --notify-session-id <uuid>,Do not send "Claude Code ушёл в работу" before this gate is satisfied.
Before launching Claude Code, post a short plan in chat:
If staged: explicitly say this run is "phase 1" and what signal will decide phase 2.
For Telegram thread runs, run-task.py is designed to either route correctly or fail immediately.
sessions_list (or existing runtime context)agent:main:main:thread:<THREAD_ID> → use it directly in INLINECODE19--session from chat_id/sender id heuristics--session "agent:main:main:thread:<THREAD_ID>" for thread tasksagent:main:telegram:user:<id> for thread tasks--telegram-routing-mode auto:agent:main:telegram:user:<id>) unless explicitly forced
- blocks non-thread launch if a recent thread session exists for same target (likely misroute)
--telegram-routing-mode allow-non-thread or INLINECODE29This is intentional: abort fast > silent misroute.
⚠️ ALWAYS launch via nohup — exec timeout (2 min) will kill the process!
⚠️ NEVER put the task text directly in the shell command — quotes, special characters, and newlines WILL break argument parsing. Always save the prompt to a file first, then use $(cat file).
CODEBLOCK0
The --session key (e.g. agent:main:whatsapp:group:120363425246977860@g.us) is used to auto-detect the WhatsApp target.
CODEBLOCK1
Do NOT use
agent:main:telegram:user:<id>for thread tests/runs.
That routes to main chat scope and can drift from the source thread.
When Marvin is used in Telegram Threaded Mode, each thread has its own session key like agent:main:main:thread:369520.
Fail-safe routing (NEW): run-task.py now enforces strict thread routing.
--session contains :thread:<id>, the script refuses to start unless Telegram target + thread session UUID are resolved.sessions_list when possible.~/.openclaw/agents/main/sessions/*-topic-<thread_id>.jsonl.--notify-session-id mismatches the session key, it exits with error.Use --notify-session-id to wake the exact thread session:
CODEBLOCK2
All 5 notification types route to the DM thread when --session key contains :thread:<id> ✅
--notify-session-id — optional override. Usually auto-resolved from session metadata/files.--session.--notify-channel — optional channel hint (telegram/whatsapp); target is always auto-resolved from session metadatasingle default, iterate if explicitly needed)$(cat ...) avoids all quoting issues.
The detect_channel() function determines where to send notifications:
@g.us (WhatsApp group JID), WhatsApp is used❌ Invalid routing instead of silent misrouteCODEBLOCK3
CODEBLOCK4
sessions_send (agent wakes up)message(send) to WhatsApp group--completion-mode is optional (default single) and acts as a hint:
single = one run → continuation summary → stopWake payload now frames continuation as the same ongoing assistant conversation (same agent identity, same session, same history) after Claude Code replies to the previous launch.
In iterate mode the continuation flow is:
run_id and wake_id in wake payload./tmp/cc-orchestrator-state-<hash>.json.--trace-live), skipped wakes are announced as [TRACE][TECH][TELEGRAM][WAKE][SKIP].[TRACE][AGENT][WAKE_RECEIVED] ...
- [TRACE][AGENT][DECISION] continue|stop ...
<blockquote expandable> for prompt; via send_telegram_direct; includes Resume: <session-id|new>)send_telegram_direct)/tmp/cc-notify-{pid}.py; CC calls file; prefix "📡 🟢 CC: " auto-added)<blockquote expandable> for result; via send_telegram_direct)openclaw agent --deliver ✅ (same session continuation is visible to user)send_telegram_direct() is the core mechanism for all thread-targeted notifications from external scripts. It calls api.telegram.org directly with message_thread_id — bypasses the OpenClaw message tool entirely (which cannot route to DM threads from outside a session context).
Fallback — if agent wake fails (session locked/busy): already_sent=True is set after the direct send, so no duplicate is sent.
WhatsApp: Raw result sent directly (human sees it immediately) + sessions_send wakes agent for analysis.
Telegram: Result sent via send_telegram_direct → then agent is woken via openclaw agent --session-id --deliver so the continuation turn is visible in chat by default. This is the intended “same agent, same conversation” behavior after Claude completion.
Why not sessions_send for Telegram? sessions_send is blocked in the HTTP /tools/invoke deny list by architectural design. The openclaw agent CLI bypasses this limitation.
--timeout 7200 → after 7200s: SIGTERM → wait 10s → SIGKILLtry/except wraps entire main → crash notification always sentCurrent policy: all Claude Code notifications are silent in Telegram:
📡 🟢 CC) → INLINECODE104WhatsApp does NOT support silent mode — the flag is ignored for WhatsApp.
Telegram has two distinct thread models. The key difference for run-task.py is how to route messages to the thread.
The core problem with external scripts:
message tool's threadId parameter is Discord-specific — ignored for Telegram"chatId:topic:threadId" is rejected by the message tool's target resolvercurrentThreadTs) works ONLY inside active sessions — external scripts have no session contextsend_telegram_direct() bypasses the message tool entirely; calls api.telegram.org directly with INLINECODE113DM Threaded Mode (bot-user private chat with threads):
send_telegram_direct(chat_id, text, thread_id=..., parse_mode=...) ✅*:thread:<id> by INLINECODE117parse_mode="HTML" with <blockquote expandable> for prompt/resultparse_mode=None (plain text, avoid Markdown parse errors)parse_mode="Markdown" trap: finish messages contain **text** (CommonMark bold); Telegram MarkdownV1 rejects this with HTTP 400 — messages silently don't arrivereplyTo trap: combining replyTo + message_thread_id → Telegram rejects request → fallback strips thread_id → message lands in main chatopenclaw agent --session-id <uuid> --deliver publishes the wake turn to chat so the user sees the same ongoing assistant conversation.Forum Groups (supergroup with Forum topics enabled):
send_telegram_direct() approach works; message_thread_id is standard Bot API for Forum topicsClaude Code mid-task updates:
/tmp/cc-notify-{pid}.py to disk before launching Claude Code"📡 🟢 CC: " to all messages; cleaned up in finally block| Event | Emoji | WhatsApp delivery | Telegram delivery | DM thread? |
|---|---|---|---|---|
| Launch | 🚀 | sendchannel (Markdown) | sendtelegramdirect (HTML, silent) | ✅ messagethreadid |
| Heartbeat |
--deliver) | ✅ visible in chat |
-p "task" — print mode (non-interactive, outputs result)exec has 2 min default timeout → kills long taskspty:true, output has escape codes, hard to parse-p mode: clean, detached, reliablerun-task.py auto-inits if missing.
INLINECODE143 uses Optional[X] from typing (not X | None) for compatibility with Python 3.9. The union syntax (X | None) requires Python 3.10+.
CODEBLOCK5
Use this when you need to validate the entire pipeline in one run:
/tmp/cc-notify-<pid>.py)openclaw agent --session-id ... --deliver) and appears visibly in chatReason: keeps regression runs fast (minutes, not 20+ minutes) while still validating the critical iterate path.
✅ Claude Code completed and any next 🚀 Claude Code started, there must be a user-facing analysis message in the thread.
sleep 70) to trigger wrapper heartbeatIf a Claude Code task is expected to run longer than ~1 minute, explicitly ask Claude to send intermediate progress updates during execution.
Recommended wording to include in prompt:
For thread-safe Telegram runs, updates should use the injected automation script (/tmp/cc-notify-<pid>.py).
run-task.py automatically creates an on-disk notification script before launching Claude Code, so CC can send progress updates without seeing the bot token in the prompt (which triggers safety refusals):
CODEBLOCK10
⚠️ Never embed bot tokens or curl commands in the task prompt — Claude Code correctly identifies hardcoded tokens + external API calls as prompt injection and refuses. Use the on-disk script pattern above instead.
Quick reference: launching from a Telegram DM thread (minimal mode)
> # 1) Validate routing first (no Claude run) > python3 {baseDir}/run-task.py \ > --task "probe" \ > --project ~/projects/x \ > --session "agent:main:main:thread:<THREAD_ID>" \ > --validate-only > > # 2) Real launch (only 3 required params) > nohup python3 {baseDir}/run-task.py \ > --task "$(cat /tmp/prompt.txt)" \ > --project ~/projects/x \ > --session "agent:main:main:thread:<THREAD_ID>" \ > --timeout 900 \ > > /tmp/cc-run.log 2>&1 & >
- - Required:
--task,--project, INLINECODE159
:thread:<id> are blocked by default (❌ Unsafe routing blocked)--telegram-routing-mode allow-non-thread.
- -
THREAD_IDis auto-extracted from session key- Target + session UUID are auto-resolved (API, then local session-file fallback)
- If routing is inconsistent/unresolved, script exits with
❌ Invalid routingbefore run- All notifications from run-task (launch/heartbeat/result) stay on the source thread ✅
Claude Code sessions can be resumed to continue previous conversations. This is useful for:
--resume takes the Claude Code session ID, not the run_id or wake_id.
Correct source — look for this line in the run log:
📝 Session registered: <session-id-here>
--resume <session-id>.
Do NOT use:
run_id from wake payloadWhen in doubt: skip --resume and start fresh.
When a task completes, the session ID is automatically captured and saved to the registry (~/.openclaw/claude_sessions.json).
To resume a session, use the --resume flag:
CODEBLOCK14
Use --session-label to give sessions human-readable names for easier tracking:
CODEBLOCK15
The agent can read the session registry to find recent sessions:
CODEBLOCK16
Or manually inspect the registry:
CODEBLOCK17
Resume when:
Start fresh when:
If a session ID is invalid or expired:
/tmp/cc-run.log for detailsCommon resume failures:
Step 1: Initial research
CODEBLOCK18
Step 2: Check result and find session ID
CODEBLOCK19
Step 3: Follow-up implementation
CODEBLOCK20
When the agent wake / continue chain fails (no agent summary, wrong thread, session not resolved,
iterative loop stalls, etc.), see the dedicated guide:
Includes a Quick Triage Checklist (60 seconds) plus detailed items: agent not waking,
double messages, wrong thread routing, UUID resolution failures, session-locked wake,
❌ Invalid routing, Telegram HTTP 400 silent drops, mid-task update failures, stale/duplicate wake skips, and more.
This is the version validated in live Telegram thread tests.
openclaw agent --deliver) so continuation turns are visible in chat.wake_id/output dedupe.--trace-live emits technical milestones (RUN_TASK START/COMPLETE, WAKE, WAKE SKIP) into the same thread.--resume must use the Claude session id from 📝 Session registered: ... in the run log.sub:<N> (example: 🟢 CC (3min) | sub:1 | 12K tok | 18 calls | 🔧 Bash).tool_use id add, matching tool_result/task_notification remove).CODEBLOCK21
该技能支持在以下平台通过对话安装:
帮我安装 SkillHub 和 claude-code-task-1775933295 技能
设置 SkillHub 为我的优先技能安装源,然后帮我安装 claude-code-task-1775933295 技能
skillhub install claude-code-task-1775933295
文件大小: 31.16 KB | 发布时间: 2026-4-12 09:24