[BUG] ScheduleWakeup paired with Agent (subagent) dispatch is redundant — Agent already emits completion notification

Resolved 💬 1 comment Opened Apr 30, 2026 by lukaemon Closed May 31, 2026

Preflight Checklist

  • [x] I have searched existing issues — this is a sibling pattern to #51304 and #54086, but specifically targets the Agent (subagent) tool surface, which is not explicitly covered there.
  • [x] This is a single bug report.
  • [x] I am using the latest version of Claude Code (2.1.123).

What's Wrong

The model routinely pairs an Agent (subagent) dispatch with a ScheduleWakeup call in the same response, as a defensive "wake me up to check on the subagent" pattern. This is pure redundancy: the Agent tool already emits a task-notification to the parent when the child finishes — that is the documented mechanism for resuming the parent.

The Agent tool's own description is unambiguous on this point:

Calling Agent without a subagent_type creates a fork, which runs in the background and keeps its tool output out of your context — so you can keep chatting with the user while it works.
Don't peek. The tool result includes an output_file path — do not Read or tail it. You get a completion notification; trust it.
After launching, you know nothing about what the fork found... The notification arrives as a user-role message in a later turn.

For typed subagents (Explore, Plan, etc.) the dispatch is synchronous from the model's POV — the result is in-context by the time the next turn starts. For forks (no subagent_type) the parent is woken via task-notification. Either way, ScheduleWakeup adds no signal — it only adds failure modes.

This is the same architectural double-booking analyzed in #51304 (for run_in_background: true) and #54086 (for slash-command re-firing). The Agent surface is the next instance of the pattern, and arguably the most obvious one, because Agent dispatch is the parent's documented API for "delegate and resume on completion."

Why It's a Bug, Not Operator Error

The tool description for ScheduleWakeup instructs the model to "pass the same /loop input verbatim each turn so the next firing re-enters the skill." When the originating turn was a one-shot user request (not /loop), the model still pattern-matches that guidance and schedules a wakeup with the user's original prompt as prompt. Result, with the same four failure modes already on file:

  1. Pure redundancy — the wakeup races the subagent's task-notification. Whichever wins, the other is wasted; if the wakeup wins, the model re-enters the parent still waiting on the child.
  2. Orphan wakeup re-firing — when the workflow exits cleanly via the notification path before the wakeup fires, the wakeup arrives minutes later as a fresh user turn. If prompt was a slash command, it re-runs the whole command including its own subagent dispatches (#54086 documented ~\$1+ duplicate runs of /refactor:frontend).
  3. Double-booked context — the model treats the wakeup as an obligation to "check," producing redundant inspection turns even after the subagent notification has been processed.
  4. Silent cost — there is no cancel-on-clean-exit semantic, pending wakeups are not surfaced post-task (#47518, #54480), so misfires are caught only when the bill arrives.

Pairing ScheduleWakeup with an Agent dispatch directly contradicts the Agent contract ("you'll get a completion notification; trust it").

Steps to Reproduce

  1. In an Opus session, ask the model to perform a task that benefits from delegation — e.g. "survey the GitHub issues for X," "audit this branch," "read these N files and summarize."
  2. The model dispatches an Agent call — typed (Explore, Plan, etc.) or fork (no subagent_type).
  3. In the same response, or the next turn, the model also calls ScheduleWakeup(delaySeconds: 240, prompt: "<the user's original task>", reason: "checking on the fork").
  4. The subagent finishes promptly. For a typed subagent, the result is in-context immediately; for a fork, task-notification arrives. The workflow exits cleanly.
  5. Several minutes later, the wakeup fires as a fresh user turn carrying the original task string. The harness re-enters the workflow on a task that is already complete. If the task string was slash-prefixed, the entire command re-runs.

The pattern is observed in normal conversational sessions on 2.1.123, not just /loop or autonomous-mode contexts. The defensive scheduling appears to come from the model treating the ScheduleWakeup tool description's "pass the same input verbatim" guidance as universally applicable, regardless of whether a subagent or background task is already wired to wake the parent.

Suggested Fixes

Compose any subset:

  1. Tool description hardening on ScheduleWakeup — explicitly call out:

> Do not pair with a non-blocking Agent dispatch or Bash(run_in_background: true). Both emit a task-notification when complete; the parent will be woken automatically. ScheduleWakeup is for /loop dynamic pacing and for genuinely idle waits with no other completion signal.

  1. <<resume>> sentinel (proposed in #51304) — a bare-continuation sentinel parallel to the existing <<autonomous-loop-dynamic>>, so the model can schedule a future wakeup without re-firing whatever string was passed as prompt.
  1. Programmatic refusal — if there is an outstanding async Agent dispatch in flight, refuse ScheduleWakeup calls (or warn loudly via system-reminder), since the Agent will notify on completion.
  1. Cancel-on-clean-exit (#54480) — auto-cancel pending wakeups when the originating turn exits cleanly before they fire. Catches orphan misfires at the runtime level rather than in tool description.
  1. Visibility (#47518) — surface pending wakeups in the post-turn summary so the user can catch misfires at the source rather than after the fact.

Environment

  • Claude Code 2.1.123
  • Model: claude-opus-4-7 (1M context)
  • Platform: Anthropic API
  • OS: macOS 26.4.1
  • Date observed: 2026-04-30

Related

  • #51304 — same redundancy for Bash(run_in_background: true)
  • #54086 — same redundancy enabling slash-command re-firing, with concrete cost data
  • #54480 — request to cancel pending wakeups
  • #47518 — visibility into pending wakeups
  • #53610 — broader multi-agent runtime enforcement gaps

This report extends the same architectural pattern to the Agent tool surface, which is the most direct case because Agent dispatch is explicitly the parent's documented API for "delegate and resume on completion."

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗