claude-code - 💡(How to fix) Fix [FEATURE] Expose background tasks (and tools-called-this-turn) to hooks — re-raise of #23386 with agent-teams use cases

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

Re-raising #23386 (auto-closed for inactivity, then locked, no maintainer engagement). The original ask — make running background tasks visible to hooks via input JSON — is still valid, and the agent-teams primitive landed in the interim has made it strictly more useful. I'd also push the ask one step broader: expose agent execution state to hooks, of which background_tasks is one slice and "tools called this turn" is another (motivated below).

Root Cause

Re-raising #23386 (auto-closed for inactivity, then locked, no maintainer engagement). The original ask — make running background tasks visible to hooks via input JSON — is still valid, and the agent-teams primitive landed in the interim has made it strictly more useful. I'd also push the ask one step broader: expose agent execution state to hooks, of which background_tasks is one slice and "tools called this turn" is another (motivated below).

Fix Action

Fix / Workaround

Current workaround (still bad)

Per-session sidecar state files keyed off session_id work for background_tasks but require user code to mirror what the harness already tracks. For "tools called this turn" the workaround is re-parsing the session's JSONL transcript on every hook fire — expensive and brittle.

  • #23386 — original request for background_tasks (auto-closed for inactivity, locked).
  • #4321 — Session-Scoped In-Memory State for Hooks (broader framing).
  • #50779 — agent-teams inbox delivery deferred until end_turn; the workarounds in the comments there would benefit from background-task visibility for similar reasons.

Code Example

{
  "session_id": "abc123",
  "hook_event_name": "TeammateIdle",
  "teammate_name": "researcher",
  "team_name": "infra",
  "background_tasks": [
    {
      "task_id": "task-xyz",
      "tool_name": "Bash",
      "started_at": "2026-05-12T10:30:00Z",
      "description": "Running test suite"
    },
    {
      "task_id": "agent-abc",
      "tool_name": "Agent",
      "subagent_type": "Explore",
      "started_at": "2026-05-12T10:31:00Z",
      "description": "Exploring codebase"
    }
  ],
  "tools_called_this_turn": [
    {"tool_name": "Read", "count": 4},
    {"tool_name": "Edit", "count": 1}
  ]
}
RAW_BUFFERClick to expand / collapse

Summary

Re-raising #23386 (auto-closed for inactivity, then locked, no maintainer engagement). The original ask — make running background tasks visible to hooks via input JSON — is still valid, and the agent-teams primitive landed in the interim has made it strictly more useful. I'd also push the ask one step broader: expose agent execution state to hooks, of which background_tasks is one slice and "tools called this turn" is another (motivated below).

Original use cases (from #23386, still apply)

  1. Prevent duplicate work — a PreToolUse hook can block starting a second build/test run if one is already in progress.
  2. Resource management — limit concurrent background tasks to avoid overwhelming the system.
  3. Stop-hook coordination — check if background work is still pending before allowing the agent to finish.
  4. Debugging / observability — log or display what's currently running.

New: agent-teams use cases

The TeammateIdle hook exists but is partially blind to the state of the teammate it's gating.

  1. TeammateIdle gate on in-flight background work. A teammate that still has a long-running Bash run_in_background:true or background Agent shouldn't be allowed to idle yet, but the hook can't see what's still running. Without background-task visibility, the hook either over-blocks (forces wake-ups just to "check on something") or under-blocks (lets the teammate idle while a build/eval/job is still in flight). Either pattern degrades how the team-lead reasons about teammate state.

  2. Catch teammates that finished without calling SendMessage. A teammate ending a turn without SendMessage AND with no background tasks pending is almost certainly stuck — they did the work but never told the lead. A TeammateIdle hook with visibility into (a) tools called this turn and (b) running background tasks could implement:

    "no SendMessage called this turn AND no background work pending → block idle, prompt the teammate to send a message to the lead before stopping."

    This is a real recurring failure mode that the lead currently has to detect after the fact (or never).

    This is the case that motivates the broader framing: background_tasks alone isn't enough. Tools-called-this-turn is the adjacent field that closes the loop.

  3. Lead-side stall detection. A Stop hook on the lead could check whether any teammate has background work pending before allowing the lead's turn to end. Less critical, same pattern.

Proposed input shape

Same shape as #23386 proposed, plus a sibling field for the per-turn tool calls:

{
  "session_id": "abc123",
  "hook_event_name": "TeammateIdle",
  "teammate_name": "researcher",
  "team_name": "infra",
  "background_tasks": [
    {
      "task_id": "task-xyz",
      "tool_name": "Bash",
      "started_at": "2026-05-12T10:30:00Z",
      "description": "Running test suite"
    },
    {
      "task_id": "agent-abc",
      "tool_name": "Agent",
      "subagent_type": "Explore",
      "started_at": "2026-05-12T10:31:00Z",
      "description": "Exploring codebase"
    }
  ],
  "tools_called_this_turn": [
    {"tool_name": "Read", "count": 4},
    {"tool_name": "Edit", "count": 1}
  ]
}

Exact shape is a strawman — what matters is exposing these two pieces of state.

Current workaround (still bad)

Per-session sidecar state files keyed off session_id work for background_tasks but require user code to mirror what the harness already tracks. For "tools called this turn" the workaround is re-parsing the session's JSONL transcript on every hook fire — expensive and brittle.

Related

  • #23386 — original request for background_tasks (auto-closed for inactivity, locked).
  • #4321 — Session-Scoped In-Memory State for Hooks (broader framing).
  • #50779 — agent-teams inbox delivery deferred until end_turn; the workarounds in the comments there would benefit from background-task visibility for similar reasons.

🤖 Generated with Claude Code

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING