[FEATURE] A hook event when a background task ends

Status Open
Reported on v2.1.292
Maintainer reply None cached
Activity 0 comments · opened Oct 7, 2026

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.

  1. 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.

  1. 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 id background_tasks uses
  • task_type, such as shell, subagent, workflow, MCP task or

cloud session

  • status: completed, failed or killed
  • notifies_model: whether a task notice will reach the model, which tells a

consumer whether a turn is about to follow

  • agent_id of the subagent that launched it, where one did
  • description
  • 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_tasks on 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_

View original on GitHub ↗