[FEATURE] A hook event when a background task ends
Preflight Checklist
- [x] I have searched existing requests and this feature hasn't been requested yet
- [x] This is a single feature request (not multiple features)
Problem Statement
I build Multishell (https://github.com/KieranP/multishell), a macOS terminal that shows each agent session's status (working, waiting, done) from hooks. "Done" has to wait until the background work the turn started has finished, so we need to know what is still running.
Today the only source is the background_tasks field on Stop. That works when Claude is idle at the moment a task ends: the task's notice wakes the model, a turn runs, and its Stop lists the task no longer. It fails in two cases.
- A task that ends mid-turn
The task's notice is queued until the turn can take it, and no hook fires. The next background_tasks arrives at the turn's own Stop, so for the rest of the turn any status display still counts the finished task.
- A task the user stops
In 2.1.292 a stop from the tasks dialog marks the task {status: "killed", notified: true, ...}. Because notified is already true, no notice is queued, so the model is never woken and no Stop fires. A hook consumer keeps counting the task as running until the user's next turn ends, which may be hours later.
SubagentStop covers a subagent's end. Nothing covers the other task types, and nothing covers a stop that skips the notice.
Proposed Solution
Add a hook event that fires whenever a background task stops running: a shell or Monitor, a subagent, a workflow, an MCP task or a cloud session. It should fire for every cause, including a task that ends mid-turn and a task the user stops from the tasks dialog.
A new event, say BackgroundTaskEnd. The name should not reuse TaskCompleted, which is about TaskCreate list items.
- When it fires: every time a background task leaves the running state: completed, failed or stopped, whether by the user, by
TaskStop, or by its parent subagent exiting. It fires whether or not a turn is running and whether or not the model will be notified. - Payload: the common fields, plus:
task_id, the same idbackground_tasksusestask_type, such asshell,subagent,workflow,MCP taskor
cloud session
status:completed,failedorkillednotifies_model: whether a task notice will reach the model, which tells a
consumer whether a turn is about to follow
agent_idof the subagent that launched it, where one diddescription- Matcher:
task_type.
A matching BackgroundTaskStart would let consumers track tasks without waiting for the next Stop, but the end event is what we are missing.
Alternative Solutions
- Polling process ids. Hooks expose no pid for a task. Finding the shells means scanning the process table, which is a recurring cost for every session.
- Reading the transcript. The queue entries show a task's notice being enqueued, but the transcript format is not a documented contract.
background_taskson every hook. That would fix case 1 at the next tool call, but not case 2: after a user stop while Claude is idle, no hook fires at all.
Priority
Medium - Would be very helpful
Feature Category
Developer tools/SDK
Use Case Example
_No response_
Additional Context
_No response_