[BUG] PreToolUse and PostToolUse hooks: all context-injection channels (additionalContext, systemMessage, plain stdout) dropped for Bash matcher in v2.1.123

Resolved 💬 3 comments Opened May 3, 2026 by MeetMartin Closed Jun 1, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported with this scope
  • [x] This is a single bug report
  • [x] I am using the latest version of Claude Code (v2.1.123)

What's Wrong?

Following up on #19432 (closed for inactivity, locked) — the same problem reproduces in v2.1.123, AND the scope is broader than that issue documented.

For Bash-matched hooks, none of the three documented context-injection channels reach the model:

| Hook event | Channel | Outcome in v2.1.123 |
|---|---|---|
| PreToolUse | hookSpecificOutput.additionalContext | dropped (matches #19432) |
| PreToolUse | top-level systemMessage | dropped |
| PreToolUse | plain stdout (text, not JSON) | dropped |
| PostToolUse | hookSpecificOutput.additionalContext | dropped (new finding — #19432 only documented PreToolUse) |

The hook scripts execute correctly. The JSON outputs are well-formed and produce the expected text. The harness receives the response (we verified via diagnostic stdin-tracing). But none of it surfaces in the model's view of the tool result.

Other hookSpecificOutput fields still work: permissionDecision: 'deny' blocks correctly, permissionDecisionReason reaches the model on deny.

What Should Happen?

Per the hooks reference:

Where the reminder appears depends on the event: * PreToolUse, PostToolUse, PostToolUseFailure, and PostToolBatch: next to the tool result

We expect the additionalContext to appear next to the tool result so the model can see and act on it. None of the three channels achieve this for Bash-matched hooks.

Reproduction

  1. Install code-nexus — or any project with a hook that returns additionalContext on Bash. Reduced repro:

.claude/settings.json:
``json
{
"hooks": {
"PreToolUse": [{ "matcher": "Bash", "hooks": [{ "type": "command", "command": "node /tmp/test-hook.mjs" }] }],
"PostToolUse": [{ "matcher": "Bash", "hooks": [{ "type": "command", "command": "node /tmp/test-hook.mjs" }] }]
}
}
``

/tmp/test-hook.mjs:
``js
import { readFileSync } from 'node:fs'
const input = JSON.parse(readFileSync(0, 'utf-8'))
const event = input.hook_event_name
const out = {
hookSpecificOutput: {
hookEventName: event,
additionalContext: 'XYZZY_TEST_MARKER: if you see this, say PRETOOL_OK or POSTTOOL_OK',
},
}
process.stdout.write(JSON.stringify(out) + '\n')
``

  1. In a Claude Code session, run any Bash command (e.g. \ls\).
  2. Observe: the model never references the marker text. Verified by adding diagnostic file-logging inside the hook script — the hook fires correctly and emits the JSON, but the model's response shows no awareness of the marker.

Environment

  • Claude Code Version: 2.1.123
  • Platform: macOS (CLI, not VSCode extension — distinguishing this from #20062 which was specific to the VSCode extension)
  • Settings: project-level \.claude/settings.json\
  • Verified hook executes by writing diagnostic to /tmp on each invocation

Why This Matters

Discoverability hooks for code-intelligence tooling (CodeNexus, similar) rely on this delivery channel to nudge the model toward graph-aware tools instead of grep. Without it, the hook architecture is purely cosmetic — the script runs, the JSON is correct, but the user gets zero behavior change.

Related: #19432 (closed stale, locked), #20062 (closed as duplicate of #19432), #15664 (feature claimed added in v2.1.9 but not actually wired up).

🤖 Generated with Claude Code

View original on GitHub ↗

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