openclaw - 💡(How to fix) Fix [discord] Discord-originated subagent tasks default to done_only, leaving channel stuck on typing indicator

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

Root Cause

In the bundled chunk task-registry-CU9A1ECz.js (likely source src/tasks/task-registry.ts):

function ensureNotifyPolicy(params) {
    if (params.notifyPolicy) return params.notifyPolicy;
    return (params.deliveryStatus ?? ensureDeliveryStatus({
        ownerKey: params.ownerKey,
        scopeKind: params.scopeKind
    })) === "not_applicable" ? "silent" : "done_only";
}

When no explicit notifyPolicy is passed (typical for ACP spawns and @openclaw/discord/dist/subagent-hooks-DHA_1pBI.js's handleDiscordSubagentSpawning path), the parent task defaults to done_only. Combined with:

  • shouldAutoDeliverTaskStateChange only firing on state_changes policy (task-registry-CU9A1ECz.js:89-91)
  • shouldAutoDeliverTaskTerminalUpdate only firing at terminal status (:83-87)
  • Discord typing module being a fixed 5s start with no task-state link (@openclaw/discord/dist/typing-BhIpRSfR.js) and a 20-min wall-clock cap (message-handler.process-DO17vBlT.js:1003-1016)

…the operator sees a typing indicator with no payload for the duration of the run.

Fix Action

Fix / Workaround

Workaround until merged

Sites that can patch the dist directly can apply the diff above plus requesterOrigin pass-through at both call sites as a local mitigation.

Code Example

function ensureNotifyPolicy(params) {
    if (params.notifyPolicy) return params.notifyPolicy;
    return (params.deliveryStatus ?? ensureDeliveryStatus({
        ownerKey: params.ownerKey,
        scopeKind: params.scopeKind
    })) === "not_applicable" ? "silent" : "done_only";
}

---

function ensureNotifyPolicy(params) {
     if (params.notifyPolicy) return params.notifyPolicy;
-    return (params.deliveryStatus ?? ensureDeliveryStatus({
+    const deliveryStatus = params.deliveryStatus ?? ensureDeliveryStatus({
         ownerKey: params.ownerKey,
         scopeKind: params.scopeKind
-    })) === "not_applicable" ? "silent" : "done_only";
+    });
+    if (deliveryStatus === "not_applicable") return "silent";
+    if (params.requesterOrigin?.channel === "discord") return "state_changes";
+    return "done_only";
 }

---

openclaw tasks notify <taskId> state_changes
RAW_BUFFERClick to expand / collapse

Symptom

A Discord-originated session that spawns a subagent / child task shows only the Discord typing indicator with no visible progress or state updates. The operator has no visibility into long-running work until terminal status.

Concrete repro (local, OpenClaw 2026.5.26 + @openclaw/discord 2026.5.26 + @openclaw/codex 2026.5.26):

  1. In a Discord channel routed to an OpenClaw agent, send a message that triggers the agent to spawn a subagent (e.g. ask Codex to run a child task).
  2. Discord shows the typing indicator for the agent.
  3. No progress messages appear; the channel sits silently until the parent task reaches terminal status (often minutes later).
  4. openclaw tasks list shows notifyPolicy=done_only for the parent and notifyPolicy=silent for the child CLI task.

Root cause

In the bundled chunk task-registry-CU9A1ECz.js (likely source src/tasks/task-registry.ts):

function ensureNotifyPolicy(params) {
    if (params.notifyPolicy) return params.notifyPolicy;
    return (params.deliveryStatus ?? ensureDeliveryStatus({
        ownerKey: params.ownerKey,
        scopeKind: params.scopeKind
    })) === "not_applicable" ? "silent" : "done_only";
}

When no explicit notifyPolicy is passed (typical for ACP spawns and @openclaw/discord/dist/subagent-hooks-DHA_1pBI.js's handleDiscordSubagentSpawning path), the parent task defaults to done_only. Combined with:

  • shouldAutoDeliverTaskStateChange only firing on state_changes policy (task-registry-CU9A1ECz.js:89-91)
  • shouldAutoDeliverTaskTerminalUpdate only firing at terminal status (:83-87)
  • Discord typing module being a fixed 5s start with no task-state link (@openclaw/discord/dist/typing-BhIpRSfR.js) and a 20-min wall-clock cap (message-handler.process-DO17vBlT.js:1003-1016)

…the operator sees a typing indicator with no payload for the duration of the run.

Proposed fix

ensureNotifyPolicy should default to state_changes (not done_only) when the task carries a Discord origin marker, so Discord-originated work surfaces progress and state-change events:

 function ensureNotifyPolicy(params) {
     if (params.notifyPolicy) return params.notifyPolicy;
-    return (params.deliveryStatus ?? ensureDeliveryStatus({
+    const deliveryStatus = params.deliveryStatus ?? ensureDeliveryStatus({
         ownerKey: params.ownerKey,
         scopeKind: params.scopeKind
-    })) === "not_applicable" ? "silent" : "done_only";
+    });
+    if (deliveryStatus === "not_applicable") return "silent";
+    if (params.requesterOrigin?.channel === "discord") return "state_changes";
+    return "done_only";
 }

Both ensureNotifyPolicy call sites (mergeExistingTaskForCreate and the main task-create path) need to pass requesterOrigin: params.requesterOrigin. requesterOrigin is already available in the surrounding params at both call sites; this is a pure pass-through.

Side-effect surface

  • Non-Discord callers (cron, system, ACP from other channels): unchanged — fallback still done_only or silent.
  • Tasks with an explicit notifyPolicy (codex native subagents at silent): unchanged — the early-return if (params.notifyPolicy) return params.notifyPolicy still wins.
  • Discord channels will see more messages per task (the goal).

Related / follow-up

  1. Discord typing watchdog. typing-BhIpRSfR.js is a one-shot 5s start; the 20-min wall-clock cap lives in message-handler.process-DO17vBlT.js:1003-1016. A task-state-driven watchdog that posts an explicit "still working" message after N seconds of no state event would close the residual case where a task is genuinely silent (e.g. tool with no progress emit). Worth a separate issue.
  2. Codex child task visibility. Filed separately — the @openclaw/codex native subagent mirror is silent/not_applicable. Will link companion issue after filing.
  3. CLI documentation. openclaw subagents … does not exist (No built-in command or plugin CLI metadata owns "subagents"); the real surface is openclaw tasks {cancel, flow cancel, notify}. Consider an alias or a doc clarification.

Workaround until merged

Operators can manually promote a silent / done_only task with:

openclaw tasks notify <taskId> state_changes

…which works via the existing updateTaskNotifyPolicyById runtime override (task-registry-CU9A1ECz.js:2446).

Sites that can patch the dist directly can apply the diff above plus requesterOrigin pass-through at both call sites as a local mitigation.


Environment: macOS, OpenClaw 2026.5.26, @openclaw/discord 2026.5.26, @openclaw/codex 2026.5.26, node 22.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING