Feature Request: Add `last_assistant_message` to PostToolUse and PostToolUseFailure hook inputs

Resolved 💬 2 comments Opened Feb 22, 2026 by rinoshiyo Closed Mar 22, 2026

Preflight Checklist

  • [x] I have searched existing issues and this is not a duplicate
  • [x] I have read the documentation for hooks
  • [x] This is a feature request, not a bug report

---

Problem Statement

When using hooks to retrieve the assistant's text, the behavior depends on whether the assistant's response includes a tool_use block:

  1. If the assistant's response does not contain a tool_use block → Stop hook fires, and last_assistant_message provides the assistant's text.
  2. If the assistant's response does contain a tool_use block → Stop hook does not fire; instead, PostToolUse / PostToolUseFailure hooks fire. However, these hook inputs do not include last_assistant_message.

An assistant response can contain both text blocks and tool_use blocks in the same message. In this case, because tool_use is present, the Stop hook does not fire — and there is no way to retrieve the text block content via hooks. This co-occurrence of text and tool_use in a single response is a common pattern (e.g., the assistant writes an explanation while calling a tool), making these turns completely invisible to hook-based integrations.

In other words, there is no way to retrieve the assistant's text via hooks for turns that involve tool use (see #15250 for related context).

The last_assistant_message field currently exists only on Stop and SubagentStop hook inputs (as documented in #26710). It is absent from PostToolUse and PostToolUseFailure.

Any developer who wants to relay assistant text to an external system via hooks runs into this exact wall. The pattern is:

  1. Wire up the Stop hook to capture last_assistant_message.
  2. Discover that tool-use turns never trigger Stop.
  3. Try PostToolUse as a fallback—only to find last_assistant_message is missing there too.

---

Proposed Solution

Add last_assistant_message to the PostToolUse and PostToolUseFailure hook input payloads.

Current PostToolUse input:

{
  "hook_event_name": "PostToolUse",
  "tool_name": "...",
  "tool_input": "...",
  "tool_response": "...",
  "tool_use_id": "..."
}

Proposed PostToolUse input:

{
  "hook_event_name": "PostToolUse",
  "tool_name": "...",
  "tool_input": "...",
  "tool_response": "...",
  "tool_use_id": "...",
  "last_assistant_message": "..."
}

Similarly for PostToolUseFailure:

{
  "hook_event_name": "PostToolUseFailure",
  "tool_name": "...",
  "tool_input": "...",
  "error": "...",
  "tool_use_id": "...",
  "last_assistant_message": "..."
}

The Stop hook already contains logic to build last_assistant_message. Applying the same approach to PostToolUse and PostToolUseFailure is straightforward:

// The same idea already used in the Stop hook:
// find the last assistant message in the conversation history
// and extract only the text blocks.

function getLastAssistantMessage(messages) {
  const lastAssistant = [...messages]
    .reverse()
    .find(msg => msg.role === "assistant");

  if (!lastAssistant) return undefined;

  return lastAssistant.content
    .filter(block => block.type === "text")
    .map(block => block.text)
    .join("\n")
    .trim() || undefined;
}

// Add to the PostToolUse input builder
function buildPostToolUseInput(toolName, toolInput, toolResponse, toolUseId, messages) {
  return {
    hook_event_name: "PostToolUse",
    tool_name: toolName,
    tool_input: toolInput,
    tool_response: toolResponse,
    tool_use_id: toolUseId,
    last_assistant_message: getLastAssistantMessage(messages),  // NEW
  };
}

// Same for PostToolUseFailure
function buildPostToolUseFailureInput(toolName, toolInput, error, toolUseId, messages) {
  return {
    hook_event_name: "PostToolUseFailure",
    tool_name: toolName,
    tool_input: toolInput,
    error: error,
    tool_use_id: toolUseId,
    last_assistant_message: getLastAssistantMessage(messages),  // NEW
  };
}

---

Alternative Solutions

Parsing the transcript file directly

Claude Code writes a transcript JSONL to disk that contains the full conversation history, including assistant messages. Hook scripts can read this file at runtime to extract the latest assistant text.

This works today, but it relies on an internal format that is not part of the official hook API. Any change to the transcript schema can silently break integrations built on top of it. It is not a stable API surface.

Relying solely on the Stop hook

Developers can wire everything to Stop and accept that assistant text is unavailable for tool-use turns. This is the current fallback, but it means hook-based integrations are completely blind to tool-use turns.

---

Priority

High — Significant impact on productivity

---

Feature Category

Developer tools / SDK

---

Use Case Example

Example: external notification integration via hooks

  1. Claude Code responds in an agentic workflow, using tools (file edits, shell commands, etc.) along the way.
  2. A developer wants to forward the assistant's text to an external system (chat tool, logging pipeline, monitoring dashboard, etc.) via hooks.
  3. Today: Stop does not fire for tool-use turns, and there is no way to retrieve the assistant's text for those turns.
  4. With this change: PostToolUse / PostToolUseFailure fire after every tool call and now include last_assistant_message, making it possible to relay assistant text to external systems even for tool-use turns.

This applies to any hook-based use case where assistant text is needed: logging pipelines, approval workflows, custom UIs, and more.

---

Additional Context

Related Issues

  • #15250 (closed): Background on why Stop hook behavior was changed for tool-use turns. This proposal addresses the collateral impact of that change.
  • #26710 (closed): Documentation fix for last_assistant_message on Stop / SubagentStop. This proposal extends that coverage to PostToolUse / PostToolUseFailure.
  • #24908 (open): PostToolUse not firing on tool_use_error. A related gap in PostToolUse coverage.

No breaking changes

This is an additive change only. Hook scripts that do not reference last_assistant_message are unaffected. Existing PostToolUse and PostToolUseFailure handlers continue to work without modification.

Low implementation cost

The Stop hook already implements the logic to build last_assistant_message. Applying the same logic to PostToolUse and PostToolUseFailure requires minimal additional code.

View original on GitHub ↗

This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗