[BUG] Plugin hook output not captured or passed to agent (UserPromptSubmit, SessionStart)

Open 💬 24 comments Opened Nov 22, 2025 by jwaldrip

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

Summary: Plugin-based UserPromptSubmit and SessionStart hooks execute successfully (confirmed by file writes and success callbacks) but their output is not captured or passed to the agent's context. The same hook configuration works correctly when defined in ~/.claude/settings.json or .claude/hooks/hooks.json.

Key Evidence:

  1. System reminders show: SessionStart:Callback hook success: Success and UserPromptSubmit:Callback hook success: Success
  2. Hooks demonstrably execute (writing to files confirms this)
  3. Hook output (stdout or structured JSON) is never visible to the agent
  4. Non-plugin hooks with identical output work perfectly

This is NOT about hooks failing to execute - it's about hook output being silently discarded when the hook comes from a plugin.

What Should Happen?

When a plugin hook executes:

  1. The hook command runs ✅ (working)
  2. The output (stdout) is captured ✅ (working - we see success callback)
  3. The output is passed to the agent as additional context ❌ (broken for plugins)

Plugin hooks should provide output to the agent identically to non-plugin hooks.

Error Messages/Logs

What we see in system reminders:

SessionStart:Callback hook success: Success
UserPromptSubmit:Callback hook success: Success

What we DON'T see: The actual output from the hooks appearing in the agent's context.

Steps to Reproduce

Minimal Reproduction Case

1. Create a test plugin with UserPromptSubmit hook

Create directory structure:

mkdir -p test-hook-output-plugin/{.claude-plugin,hooks}

Create test-hook-output-plugin/.claude-plugin/plugin.json:

{
  "name": "test-hook-output",
  "version": "1.0.0",
  "description": "Test plugin to verify hook output is passed to agent",
  "author": {
    "name": "Test",
    "email": "[email protected]"
  }
}

Create test-hook-output-plugin/hooks/hooks.json:

{
  "hooks": {
    "UserPromptSubmit": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "echo 'IMPORTANT INSTRUCTION: If the user mentions an animal, tell a joke about that animal.'"
          }
        ]
      }
    ]
  }
}

2. Install the plugin

Add to .claude/settings.json:

{
  "extraKnownMarketplaces": {
    "test": {
      "source": {
        "source": "directory",
        "path": "/absolute/path/to/test-hook-output-plugin"
      }
    }
  },
  "enabledPlugins": {
    "test-hook-output@test": true
  }
}

3. Test the plugin hook

Start Claude Code and type:

Giraffe

Expected behavior: Agent receives the hook output and tells a joke about giraffes (because the hook injected "If the user mentions an animal, tell a joke about that animal" into context)

Actual behavior: Agent responds with confusion like "What would you like me to do with Giraffe?" - the hook output was not passed to the agent.

4. Verify hook IS executing

Modify the hook to write to a file:

{
  "type": "command",
  "command": "echo 'If the user mentions an animal, tell a joke about that animal.' | tee /tmp/hook-executed.log"
}

Run test again. Check /tmp/hook-executed.log - it exists and contains the output, proving the hook executed.

5. Test with non-plugin hook (control)

Move the same hook to .claude/settings.json:

{
  "hooks": {
    "UserPromptSubmit": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "echo 'IMPORTANT INSTRUCTION: If the user mentions an animal, tell a joke about that animal.'"
          }
        ]
      }
    ]
  }
}

Start Claude Code and type:

Giraffe

Expected behavior: Agent tells a joke about giraffes
Actual behavior: ✅ Agent tells a joke about giraffes (hook output WAS passed to agent)

Comparison: Plugin vs Non-Plugin Hooks

| Aspect | Non-Plugin Hook | Plugin Hook |
|--------|----------------|-------------|
| Hook registers | ✅ Yes | ✅ Yes |
| Hook executes | ✅ Yes | ✅ Yes (confirmed by file writes) |
| Success callback shown | ✅ Yes | ✅ Yes (Callback hook success: Success) |
| Output captured | ✅ Yes | ❓ Unknown |
| Output passed to agent | ✅ Yes | ❌ No |

Affected Hook Types

Confirmed affected:

  • UserPromptSubmit
  • SessionStart

Likely affected (untested):

  • Notification
  • Possibly others

Claude Model

Sonnet (default)

Is this a regression?

I don't know

Last Working Version

Unknown - possibly never worked

Claude Code Version

2.0.50 (and likely earlier versions)

Platform

Anthropic API

Operating System

macOS (Darwin 25.1.0)

Terminal/Shell

iTerm2.app (macOS)

Additional Information

Related but distinct issues:

  • #10225 - UserPromptSubmit hooks never execute (closed as duplicate, but about execution not output)
  • #11509 - SessionStart hooks never execute for local file-based plugins (about execution not output)
  • #9708 - Notification hooks don't execute (different hook type, about execution not output)

Key distinction: This issue is NOT about hooks failing to execute. The hooks ARE executing. The bug is that plugin hook output is silently discarded instead of being passed to the agent.

Impact: This makes it impossible to use plugins to:

  • Inject context based on user input (UserPromptSubmit)
  • Inject session-level instructions (SessionStart)
  • Provide dynamic context from plugin hooks
  • Build plugins that augment agent behavior via hook output

Workaround: Define hooks in ~/.claude/settings.json instead of plugin hooks/hooks.json, but this defeats the purpose of plugin-based hooks and isn't distributable.

Root cause hypothesis: The plugin hook execution pipeline may be missing the step that captures stdout/stderr or passes the captured output to the agent's context, even though it correctly:

  1. Discovers and registers plugin hooks
  2. Executes plugin hook commands
  3. Reports success callbacks

The output capture/injection step appears to only work for non-plugin hooks.

View original on GitHub ↗

24 Comments

informal-stripes-condo · 7 months ago

I'm also getting this

crsmithdev · 7 months ago

Experiencing similar behavior with SessionStart hooks defined in ~/.claude/settings.json (not plugin-based).

Hook configuration passes schema validation and script executes successfully when run manually with correct stdout output. However, on session start, no output appears in context - either the hook doesn't execute or output is silently discarded.

This suggests the output capture issue may not be limited to plugin-based hooks.

RevPalSFDC · 7 months ago

Confirming this bug with additional testing details.

Environment

  • Claude Code (Opus 4.5, model ID: claude-opus-4-5-20251101)
  • Linux 6.14.0-36-generic
  • Hook defined in project .claude/settings.json (not plugin hooks.json)

Reproduction

Hook configuration:

{
  "hooks": {
    "UserPromptSubmit": [{
      "matcher": "*",
      "hooks": [{
        "type": "command",
        "command": "echo '[TEST] If you see this, context injection works!'",
        "timeout": 5000
      }]
    }]
  }
}

Result:

  • ✅ Hook executes (Claude sees <system-reminder>UserPromptSubmit hook success: Success</system-reminder>)
  • ❌ stdout content is NOT injected into Claude's context

Formats tested (all failed to inject context)

  1. Plain stdout: echo "text" - documented as "easiest way to inject information"
  2. JSON hookSpecificOutput:
{
  "hookSpecificOutput": {
    "hookEventName": "UserPromptSubmit",
    "additionalContext": "text"
  }
}

Both formats execute successfully but Claude never receives the content.

What still works

  • Exit code 1 correctly blocks execution (useful for preventing dangerous operations)
  • Hook execution itself runs and completes

Impact

This breaks the primary use case for UserPromptSubmit hooks - injecting dynamic context (routing suggestions, safety warnings, compliance reminders) into Claude's reasoning before it responds.

Workaround

Currently using static instructions in CLAUDE.md instead of dynamic hook-based injection. This is not fully reliable - Claude may not consistently follow static instructions, whereas dynamic per-message injection would ensure the context is always present and actionable.

fmunteanu · 7 months ago

This is a must have feature, what's the point of having a hook if instructions cannot be passed to agent, or command output is not added to context? I should be able to use a hook like:

    "SessionStart": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "cat ${CLAUDE_PLUGIN_ROOT}/skills/framework-initialization/resources/instructions.md",
            "timeout": 10
          }
        ]
      }
    ]

Or:

    "SessionStart": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "echo 'Use `Read` tool with `${CLAUDE_PLUGIN_ROOT}/skills/framework-initialization/resources/instructions.md` path'",
            "timeout": 10
          }
        ]
      }
    ]

The only reliable solution I have now is to use a /framework:init switch that I pass to Claude. Really not elegant, it defeats the hooks purpose.

sonicdan · 6 months ago

Encountered into the same issue! The plugin system seems very buggy till now...fix it please!!!

pro-vi · 6 months ago

Ran into exact issue today:

 ⎿  UserPromptSubmit:Callback hook succeeded: Success  # this is plugin version of the hook
 ⎿  UserPromptSubmit hook succeeded: [Expected stdout]  # this is same hook but local 
schrockn · 6 months ago

Also ran into the same issue. Prevents me from using the plugin system which is painful.

rpolitex · 6 months ago

I have the same issue with PreCompact hook.

  • Static hook in project's .claude/settings.json works, stdout injected as custom compact instructions
  • Plugin hook executes (callback shows "Success"), but stdout is empty/not captured

Same hook, different location - different behaviour.

ShaneDugas · 6 months ago

I'm experiencing the same issue with UserPromptSubmit hooks not executing in Cursor. Here's my detailed findings:

Problem Summary

  • UserPromptSubmit hooks configured in settings.json do not execute in Cursor
  • Same configuration works perfectly in Claude CLI
  • Messages only saved when session ends (not in real-time)

Evidence & Test Results

Hook Configuration

"UserPromptSubmit": [
  {
    "hooks": [
      {
        "type": "command",
        "command": ".claude/hooks/capture-all-events.ts --event-type UserPromptSubmit"
      },
      {
        "type": "command",
        "command": ".claude/hooks/capture-conversation-to-markdown.ts"
      }
    ]
  }
]

Test Results

Claude CLI:

  • ✅ UserPromptSubmit hooks execute immediately
  • ✅ Real-time conversation capture works
  • ✅ Messages saved to disk as they're sent
  • ✅ UserPromptSubmit events successfully logged

Cursor IDE:

  • ❌ UserPromptSubmit hooks do NOT execute
  • ❌ No debug logs created (added extensive logging)
  • ❌ No UserPromptSubmit events in raw-outputs JSONL files
  • ❌ Messages only saved when session ends

Debugging Attempts

  1. Added debug logging to capture-all-events.ts:
  • Logs to temporary debug files
  • No logs created when messages sent in Cursor
  1. Verified hook configuration:
  • Hooks are executable
  • Configuration syntax is correct
  • Same config works in Claude CLI
  1. Checked other hooks:
  • PostToolUse hooks DO execute
  • Stop hooks DO execute
  • SessionStart hooks DO execute
  • Only UserPromptSubmit fails
  1. Verified data structure:
  • In Claude CLI, hooks receive full event data including prompt field
  • In Cursor, hooks never execute, so data structure cannot be verified

Impact

  • Workflow Disruption: Cannot use Cursor for real-time conversation logging
  • Inconsistent Behavior: Same configuration behaves differently in Cursor vs Claude CLI
  • Cross-Platform Issues: Cannot seamlessly switch between Cursor and Claude CLI

Use Case

I need real-time conversation capture for:

  1. Cross-platform workflows (switching between Cursor and Claude CLI)
  2. Session continuity and conversation history
  3. Real-time logging and monitoring

Additional Context

I've documented this issue in detail, including:

  • Complete test results and evidence
  • Comparison with Claude CLI behavior
  • Impact analysis on data persistence
  • Full technical analysis of hook execution differences

The core issue is that UserPromptSubmit hooks are configured but never execute in Cursor, preventing real-time conversation capture.

Related Issues:

  • Issue #10225 was marked as duplicate (also about UserPromptSubmit hooks)
  • Multiple forum posts report hooks not working in Cursor

---

sarahwooders · 6 months ago

We are also facing this issue. The SessionStart hook executes successfully, but Claude never sees it. Are there any plans to fix this?

TakumiOkayasu · 6 months ago

Coming from #16326 (marked as duplicate), I want to highlight a related user experience issue that stems from this bug:

The Cognitive Disconnect Problem

When hooks execute but their output isn't captured, Claude not only lacks context—it actively claims ignorance of hooks that are observably running.

Example conversation:

User: “Did you check the hooks?”
Claude: “I was aware of Claude Code’s hooks feature, but I didn’t check
if hooks were configured in this project.”

[Meanwhile, terminal shows: “Running PostToolUse hooks… (1/3 done)”]

This creates a trust problem where Claude contradicts observable system behavior.

Root Cause (Same as This Issue)

The problem is identical to what's described here: hooks execute successfully at the system level, but their output never reaches Claude's context. In my case:

  • Hooks configured in ~/.claude/settings.json (global, not plugin-based)
  • All hooks execute correctly (verified by file writes and terminal output)
  • Claude has zero awareness of their existence

Suggested Enhancement

Beyond fixing the output capture bug, consider session initialization context injection:

At session start, Claude should acknowledge configured hooks even before they execute:

System reminder: The following hooks are configured for this session:

- SessionStart: session-start-reminder.sh
- PreToolUse[Bash]: git-commit-push-block.sh
- PostToolUse[Bash]: git-post-command-reminder.sh
  (Hooks will execute at appropriate lifecycle events)

This would:

  1. Make Claude aware of its runtime configuration
  2. Prevent the "I don't know what hooks are active" problem
  3. Bridge the gap between mechanical execution and cognitive awareness

The output capture fix is critical, but initialization context would make Claude's behavior consistent with its actual configuration—even if specific hook output later fails to capture.

---

Environment from #16326:

  • Claude Code 2.0.76
  • Platform: Linux
  • Hook type: Global settings (~/.claude/settings.json)
  • Model: Opus
jdsumsion · 6 months ago

Wow, this is a pretty big bug to remain unresolved so long. On a pretty central feature.

WeaverDev · 6 months ago

+1, also running into this in vscode, both via terminal and claude code plugin.

attac-t · 6 months ago

this seems to be fixed on v2.1.3

jantic · 6 months ago
this seems to be fixed on v2.1.3

Same here. Using 2.1.5.

mstrausz · 5 months ago

+1, can't use my auto-injecting memory system due to this issue.

sstraus · 5 months ago

Still experiencing this issue. Created a minimal reproduction case that confirms plugin UserPromptSubmit hooks execute but output is not captured.

Test:

  1. Plugin hook outputs simple message: console.log('🔔 TEST HOOK EXECUTED');
  2. Asked Claude: "Did you see a message TEST HOOK EXECUTED?"
  3. Claude response: "No, I did not see that message"

However:

Moving the identical hook configuration from plugin hooks/hooks.json to ~/.claude/settings.json works perfectly - Claude sees the output in context.

Diagnosis:

The hook executes successfully (can verify with file write) but the stdout capture mechanism appears broken for plugin-based UserPromptSubmit hooks specifically.

Environment:

  • macOS (Darwin 25.2.0)
  • Plugin installed via symlink to ~/.claude/plugins/

Workaround:

Use ~/.claude/settings.json instead of plugin hooks.json, though this requires manual user configuration.

Full reproduction: https://github.com/Lansweeper/wiz-agents

greghughespdx · 5 months ago

I'm hitting this same issue with non-plugin hooks defined in ~/.claude/settings.json.

Setup:

  • macOS, Claude Code latest
  • UserPromptSubmit hook in ~/.claude/settings.json (not a plugin)
  • Hook outputs JSON with hookSpecificOutput.additionalContext per docs

Behavior:

  • Hook executes successfully (confirmed via curl side effects)
  • System shows "UserPromptSubmit hook success: Success"
  • But the additionalContext content never appears in Claude's context

What I tried:

  1. Plain text stdout → not injected
  2. JSON with hookSpecificOutput.additionalContext and hookEventName → not injected
  3. Various exit codes (0, 2) → no difference

The hook runs, the JSON is valid, but the context injection step seems to be skipped entirely. This blocks a key use case: injecting dynamic context (like notifications from other systems) into the conversation.

Would love to see this fixed - it's a significant limitation for automation workflows.

prodan-s · 5 months ago

Native hook workaround + hookEventName is silently required

We spent ~60 min debugging this on v2.1.42 and ran 5 format probes on a native UserPromptSubmit hook (in ~/.claude/settings.json, not a plugin). Sharing results because @greghughespdx's comment (Jan 31) hit the same native-hook failure we did.

Probe results (native UserPromptSubmit hook, v2.1.42)

| # | Output format | Result |
|---|--------------|--------|
| 1 | {"systemMessage":"..."} | ❌ Content dropped, shows "hook success: Success" only |
| 2 | {"hookSpecificOutput":{"additionalContext":"..."}} | ❌ Silently dropped |
| 3 | stderr (with exit 0) | ❌ Not injected |
| 4 | Plain text stdout | ✅ Injected as "hook success: [text]" |
| A | {"hookSpecificOutput":{"hookEventName":"UserPromptSubmit","additionalContext":"..."}} | ✅ Injected as "hook additional context: [text]" |

Key finding: hookEventName is silently required

Probe 2 and Probe A are identical except Probe A includes "hookEventName": "UserPromptSubmit" inside hookSpecificOutput. Without it, the entire JSON output is silently dropped — no error, no warning, just "Success."

The docs show hookEventName in the example JSON but never call it out as required. This likely explains @greghughespdx's report — native hooks DO work, but only with the exact documented format including hookEventName.

What this means for this issue

The plugin hook bug (original report) is still real — plugin hooks' output is dropped regardless of format. But some reports in this thread about "native hooks also broken" may actually be the missing hookEventName problem, not the plugin bug.

Working native hook example

#!/bin/bash
# UserPromptSubmit hook that injects context — working on v2.1.42
INPUT=$(cat)
PROMPT=$(printf '%s' "$INPUT" | python3 -c "import sys,json; print(json.load(sys.stdin).get('prompt',''))" 2>/dev/null)

# Example: keyword-filtered context injection
if printf '%s' "$PROMPT" | grep -qiE '(finance|health|tax)'; then
    MESSAGE="Remember to verify numbers before presenting"
    ESCAPED=$(printf '%s' "$MESSAGE" | python3 -c "import sys,json; print(json.dumps(sys.stdin.read()))")
    printf '{"hookSpecificOutput":{"hookEventName":"UserPromptSubmit","additionalContext":%s}}\n' "$ESCAPED"
fi
exit 0

Hope this helps others hitting the native-hook side of this issue. The plugin bug is separate and still needs fixing.

wayne5w · 5 months ago

Real-world impact: forced to build file-based workaround

We're building a hook-based integration that needs to inject contextual information into Claude's conversation via UserPromptSubmit hooks. The documented additionalContext field in stdout would be the clean solution, but any stdout output triggers "UserPromptSubmit hook error" — even valid JSON with exit code 0.

What we tried (all failed)

| Approach | Result |
|----------|--------|
| echo '{"hookSpecificOutput":{"additionalContext":"..."}}' + exit 0 | ❌ Hook error |
| printf '{"decision":"continue"}' + exit 0 | ❌ Hook error |
| Any non-empty stdout + exit 0 | ❌ Hook error |
| Empty stdout echo '{}' + exit 0 | ✅ Works (but no context injected) |

Additional finding: stderr sensitivity

CC CLI also treats any stderr output as a hook error, even with exit code 0. Tools like npx, jq, and other CLI utilities often write to stderr (progress bars, warnings, deprecation notices). We had to add exec 2>>debug.log at the top of every hook script to redirect all stderr to a file.

Workaround we had to build

Since hooks can't inject context via stdout, we built a file-based workaround:

  1. Hook writes context to a known file path
  2. Added a CLAUDE.md instruction telling Claude to read the file at the start of each response
  3. Claude reads the file (user sees Read 1 file) and deletes it (user sees Bash rm)

This works but the UX is poor — users see tool call noise instead of clean context injection. The additionalContext field would eliminate all of this.

Environment

  • macOS 14.x, bash 3.2 (system default)
  • Claude Code latest (as of Feb 2026)
  • Hooks registered in .claude/settings.json (project-level)

Priority request

This is a blocking issue for anyone building hook-based integrations that need to enrich Claude's context. The documented API (additionalContext in stdout) simply doesn't work for UserPromptSubmit. Fixing this would eliminate the need for file-based workarounds and significantly improve the developer experience for hook authors.

jpicklyk · 5 months ago

Potential Resolution: Missing hookEventName Property

The official hooks documentation has been updated (as of Feb 2026) to explicitly state that hookEventName is required in all hookSpecificOutput responses:

hookEventName | string | All | Required. Use input.hook_event_name to match the current event

Issue Analysis

Looking at the reproduction examples in this issue, the hook commands output plain text:

echo 'IMPORTANT INSTRUCTION: If the user mentions an animal, tell a joke about that animal.'

Without hookEventName, hook output is silently dropped regardless of whether it's from a plugin or native hook.

Suggested Test

Please test your plugin hooks with properly formatted JSON output including hookEventName:

For UserPromptSubmit hook:

#!/bin/bash
cat <<'EOF'
{
  "hookSpecificOutput": {
    "hookEventName": "UserPromptSubmit",
    "additionalContext": "IMPORTANT INSTRUCTION: If the user mentions an animal, tell a joke about that animal."
  }
}
EOF

For SessionStart hook:

#!/bin/bash
cat <<'EOF'
{
  "hookSpecificOutput": {
    "hookEventName": "SessionStart",
    "additionalContext": "Session started with custom plugin context."
  }
}
EOF

Hypothesis

The difference you observed between plugin hooks and native hooks may have been:

  1. Plugin hooks: Missing hookEventName → output silently dropped
  2. Native hooks: Happened to include hookEventName (or used plain text stdout format) → worked correctly

If adding hookEventName resolves the issue, this would indicate plugin hooks work correctly and the problem was the undocumented format requirement.

References

Can you test with the corrected format and report back? This may resolve the plugin hook output issue entirely.

prodan-s · 4 months ago

Confirming @jpicklyk's findings on v2.1.45 (latest). Our native hooks with hookEventName work correctly for:

  • UserPromptSubmit: additionalContext injected as "hook additional context: [text]" ✅
  • SessionStart: same format, works ✅
  • PostToolUse (Write|Edit|Grep|Glob|WebSearch matcher): additionalContext injected ✅

All use {"hookSpecificOutput":{"hookEventName":"<event>","additionalContext":"..."}} in ~/.claude/settings.json (non-plugin).

Gotcha for PostToolUse hook authors: tool_response in the hook's stdin JSON is a structured object (e.g., {"numFiles":0,"filenames":[]} for Grep), NOT the display string "No files found". If your hook pattern-matches against the string, it will silently fail to match. Use jq '.tool_response.numFiles' instead.

Plugin hooks remain broken for output injection — same hooks moved to a plugin's hooks/hooks.json produce "Success" with no context injected.

yurukusa · 3 months ago

This is a known gap — plugin-delivered hooks execute but their output isn't injected into the conversation context the same way user-level hooks are.
Workaround 1 — Move hooks from plugin to user settings:
Copy the hook configuration from your plugin to ~/.claude/settings.json directly:

// ~/.claude/settings.json (not via plugin)
{
  "hooks": {
    "UserPromptSubmit": [
      {
        "matcher": "",
        "hook": "bash -c 'your hook command here'"
      }
    ]
  }
}

Hooks in user-level settings have their output properly captured and injected into context.
Workaround 2 — Write output to a file, read via CLAUDE.md:
If you want to keep hooks in a plugin, have them write to a file instead:

// Plugin hook
{
  "hook": "bash -c 'echo \"context info\" > /tmp/claude-hook-output.txt'"
}

Then in CLAUDE.md:

At the start of each session, read /tmp/claude-hook-output.txt for context.

Workaround 3 — Use project-level settings instead of plugin:

// .claude/settings.local.json (project-level)
{
  "hooks": {
    "UserPromptSubmit": [
      {
        "matcher": "",
        "hook": "your command"
      }
    ]
  }
}

Project-level hooks (not via plugin) should have their output captured properly.
The root issue is that plugin-delivered hooks go through a different execution path than user/project-level hooks, and the output capture isn't wired up for the plugin path.

ssilvius · 3 months ago

Adding data from our investigation (filed separately as #45438 before finding these dupes):

This regressed in v2.1.97 (released 2026-04-08). Plugin SessionStart additionalContext was working correctly on v2.1.96 earlier today. Same plugin, same hooks.json, same machine.

Confirmed: hook executes (side effects work), stdout JSON with hookSpecificOutput.additionalContext is silently discarded in interactive terminal mode. --print mode may still work. Stop hooks in the same plugin/hooks.json work correctly. Tested across 5 agents in different project directories.