[Feature Request] PreToolUse/PostToolUse hooks lack access to live background task registry

Status Open
Reported on v2.1.233
Maintainer reply None cached
Activity 0 comments · opened Aug 16, 2026

Feature request

Related issues

  1. https://github.com/anthropics/claude-code/issues/48657

## Summary

Feature request: PreToolUse/PostToolUse hooks have no way to observe a background Bash task's
completion, so custom tooling built on them can only learn a task finished by an explicit blocking
TaskOutput call or by waiting for the next Stop event — both of which a normal working turn may
avoid for many tool calls in a row.

Desired state

as a suggested design, either of the following:

  1. a dedicated hook event fires when a background Bash task transitions to a terminal state
  2. the live background-task registry that Stop already receives (background_tasks

in its payload) is also included in the PreToolUse/PostToolUse payload, so tooling built on
those hooks can reconcile a task's real status without waiting for Stop or issuing an explicit
blocking wait.

Current state

A background Bash task's completion is only visible to the agent as an in-context notification
(the <task-notification> block delivered mid-turn) — this is not itself a hook event, so no hook
fires when it happens. Custom hook-based tooling that tracks a background task's status locally
(e.g. to warn if a turn is about to end while work is still live) has exactly two ways to learn a
task reached a terminal state: an explicit blocking TaskOutput(task_id=..., block=true) call, or
the next Stop event, whose payload is the only one of the three (PreToolUse/PostToolUse/
Stop) that carries the live task registry.

Practical effect: if the agent doesn't proactively call TaskOutput on a task it already knows
(from the notification) is done, any PreToolUse/PostToolUse-based tooling keeps treating that
task as live for every subsequent tool call in the same turn, producing stale "still pending"
signals even though the task completed and the agent has already seen so.

Minimal reproduction

  1. Register a PreToolUse hook script that reads a small local JSON marker file per

in-flight background task (created from an earlier PostToolUse observing a Bash tool call
with run_in_background: true).

  1. Launch a Bash tool call with run_in_background: true. Let it run to completion — a

<task-notification> for it appears in the transcript mid-turn once it finishes.

  1. Without calling TaskOutput on that task's ID, make another tool call in the same turn.
  2. Observed: the PreToolUse hook fires again with no signal that the task already completed —

its payload contains no live task-status registry, only whatever the hook script itself
persisted locally from step 1 (which nothing updated between steps 2 and 3).

  1. The same local marker only updates via an explicit TaskOutput(block=true) call reconciling

against its response, or at the next Stop event, whose payload does include a live
background_tasks registry with each task's current status.

Diagnostics

Payload shape observed for each hook:

  • Stop: includes background_tasks — a list of {id, type, status, description, ...} for

every task tracked this session, live at the moment Stop fires.

  • PreToolUse / PostToolUse: no equivalent field. The only background-task-shaped data present

is whatever the specific tool call in question concerns (e.g. a Bash call's own
backgroundTaskId in its response, or a TaskOutput call's own resolved status) — never the
full live registry.

Regression and controls

  • Fresh process/session: Reproduces — confirmed on a fresh session, not tied to session age or

compaction history.

  • Last known good version: Unknown — this appears to be the payload shape's design, not a

regression from a prior version.

  • Relevant control: Calling TaskOutput(task_id=..., block=true) explicitly after a task

notification does correctly resolve the task's status (confirms the registry data exists and is
reachable via that one specific tool call — just not proactively via the hooks that would need
it to avoid a stale-state window).

Environment

  • Product and version: Claude Code CLI 2.1.233
  • OS and version: macOS 26.6.1 (build 25G76), Darwin 25.6.0, arm64
  • Model / resolved model ID: Not model-specific — hook payload shape is independent of the active

model.

  • Runtime context: Interactive terminal session (tmux-managed), PreToolUse/PostToolUse/Stop

hooks configured via project-level Claude Code settings.

  • Authentication/provider path: Claude subscription (OAuth), interactive CLI.

View original on GitHub ↗