Use the mods API changedplugins/mods/api
Nearest release: v2.1.304, published 6 hours before upstream edited the page. Shown because the two are within 24 hours of each other. Nothing here says the release caused the edit.
Upstream edited this page at 20 Oct 2026 02:35 UTC, give or take a minute or two: the time comes from Anthropic’s own sitemap rather than from a commit. This site recorded the change at 20 Oct 2026 02:37 UTC.
Upstream edited
Recorded here
Lines+83added
Lines−0removed
From line
218
where the diff opens
First seen
1 Oct 2026
this site's first read of the page
Recorded edits12to this page, all time
### Calls and background work after the user interrupts a turn #### Retry a refused or dropped call #### What refused calls return #### Work your mod started before the interruption
The whole hunk
from line 218, old and new numbered
/
from line 218
218218
219219Timers stop when the module reloads. For long-running work inside a hook, [`next.signal`](/docs/en/plugins/mods/reference#the-hook-function) is an `AbortSignal` that aborts when the event your hook is handling is abandoned, for example when the user interrupts, so pass it to anything long-running.
220220
221### Calls and background work after the user interrupts a turn
222
223The reason `the session was stopped and nobody has sent input since` in a result or error means the user stopped a running turn, such as with Esc or **Stop**. After that interruption, calls that start new work in the session are refused until the user's next input, such as a message at the prompt.
224
225Apart from `$.prompt.submit` and `$.command.run`, this handling of calls and background work after an interruption requires Claude Code v2.1.304 or later.
226
227#### Retry a refused or dropped call
228
229Make a refused or dropped call again from a [`turn.complete`](/docs/en/plugins/mods/events#follow-a-turn) hook. Calls stay refused until the user's next input, and nothing queues or repeats them for you.
230
231When a call's result or error contains one of these strings, keep its arguments for a later retry:
232
233* **`the session was stopped and nobody has sent input since`**: the call was refused
234* **`was removed from the queue before it ran`**: the prompt or command left the queue without running and was dropped, for example when the user stopped the turn
235
236In this example, call `submitPrompt` from your background job in place of [`$.prompt.submit`](#start-a-turn-from-a-background-job). When the result or the error carries one of those strings, `submitPrompt` keeps the text in `pendingText` for the `turn.complete` hook to submit again:
237
238```javascript theme={null}
239// The text of the last refused or dropped prompt, or null
240let pendingText = null
241
242async function submitPrompt($, text) {
243 let reason
244 try {
245 const result = await $.prompt.submit({ text })
246 reason = result?.drop ?? ''
247 } catch (error) {
248 reason = String(error?.message ?? error)
249 }
250 if (reason.includes('the session was stopped and nobody has sent input since') ||
251 reason.includes('was removed from the queue before it ran')) {
252 pendingText = text
253 }
254 // Any other result or error isn't retried
255}
256
257on('turn.complete', async ($, e, next) => {
258 if (pendingText !== null) {
259 const text = pendingText
260 // Empty pendingText before retrying, so that a second run of this hook
261 // doesn't submit the same text.
262 pendingText = null
263 // Not awaited: the hook would stay open until the new turn starts
264 submitPrompt($, text)
265 }
266 return next(e)
267})
268```
269
270Before the user's next input, `turn.complete` can fire for the interrupted turn itself and for a subagent's turn, and calls made then are refused again. In that case `submitPrompt` keeps the text for a later `turn.complete`.
271
272For a call that rejects, such as `$.command.run`, catch the error and test its message the way `submitPrompt` tests `reason`.
273
274#### What refused calls return
275
276In the results, `<reason>` stands for `the session was stopped and nobody has sent input since`:
277
278| Some refused calls | Result until the user's next input |
279| :- | :- |
280| `$.prompt.submit` | Resolves with `{ drop: '<reason>' }` and queues no prompt |
281| `$.command.run` | Rejects with an error whose message ends with `<reason>` |
282| [`$.agent.spawn`](/docs/en/plugins/mods/reference#mods-api-methods) | Resolves with `{ deny: '<reason>' }` and starts no subagent |
283| `$.session.send` to a subagent that finished | Resolves with `{ isDelivered: false, reason: 'Agent "<id>" was not resumed: <reason>.' }`, where `<id>` is the subagent's id. A subagent that's still running receives the message. |
284| `$.session.send` to an [agent team](/docs/en/agent-teams) teammate | Resolves with `{ isDelivered: false, reason: 'Teammate "<name>" was not messaged: <reason>.' }`, where `<name>` is the teammate's name |
285| [`$.tool.call`](/docs/en/plugins/mods/reference#mods-api-methods) of Bash with `run_in_background: true`, Monitor, or CronCreate | Resolves with `{ deny: '<tool> was not run: it starts background work, a schedule or a goal, and <reason>' }`, where `<tool>` is the tool's name |
286
287Along with these `$.session.send` and `$.tool.call` results, the user can see the [`Stopped:` toast](/docs/en/plugins/mods/troubleshoot#stopped-type-a-message-to-continue).
288
289#### Work your mod started before the interruption
290
291After the user stops a running turn, for example with Esc, some work your mod had already started is dropped and some waits for the user's next input.
292
293| Work | What happens until the user's next input | What to do |
294| :- | :- | :- |
295| A prompt from `$.prompt.submit` still in the queue | Dropped. The call resolves with `{ drop: 'the prompt was removed from the queue before it ran' }`. | Submit it again as [Retry a refused or dropped call](#retry-a-refused-or-dropped-call) shows |
296| A command from `$.command.run` still in the queue | Dropped. The call rejects with an error whose message includes `the command was removed from the queue before it ran`. | Run it again as [Retry a refused or dropped call](#retry-a-refused-or-dropped-call) shows |
297| A one-time job scheduled with a tool such as CronCreate that comes due before the user's next input | Starts no turn then, and runs after that input | Nothing needed |
298| A recurring job scheduled with a tool such as CronCreate that comes due before the user's next input | Starts no turn then. The job loses that run and keeps its schedule. | Nothing needed |
299| An event from a monitor your mod started | The monitor keeps running. An event the monitor raises before the user's next input is dropped, except the notice that the monitor ended, which arrives after that input. | Nothing can be done |
300| A subagent your mod spawned and later resumed with `$.session.send` that finishes before the user's next input | Its finish notice waits, and reaches the conversation after that input | Nothing needed |
301
302When a scheduled job comes due or a monitor raises an event before the user's next input, the user can see the [`Stopped:` toast](/docs/en/plugins/mods/troubleshoot#stopped-type-a-message-to-continue).
303
221304## Send and receive messages between sessions
222305
223306A mod can send a plain-text message to another of your sessions, to one of this session's subagents, or to a teammate in its [agent team](/docs/en/agent-teams). It can also observe the messages that arrive and leave.
No line in this hunk matches that.