[BUG] A plugin's `prompt.submit` module hook never sees prompts the same plugin submits, contrary to the `$.prompt.submit` docs

Status Open
Reported on v2.1.299
Maintainer reply None cached
Activity 0 comments · opened Oct 14, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report
  • [x] I am using the latest version of Claude Code (reproduced on CLI 2.1.299, and earlier on 2.1.296 and on the desktop app bundling 2.1.295)

What's Wrong?

$.prompt.submit's doc says: "It goes through every hook but the calling one (the plugin's others see it)". In practice, no prompt.submit hook in the calling plugin's module runs, even when the submit comes from a different hook's frame. The debug log says:

hooks module <plugin>@inline prompt.submit skipped: re-entry (the plugin's own code raised it; origin <plugin>)

Reproduced with the submit called from a $.clock.after callback started in session.start, from $.clock.every, and from setTimeout. A different plugin's prompt.submit hook does see the submission (it can rewrite text and attach context). A classic UserPromptSubmit command hook in the same plugin's hooks.json also runs on it.

What Should Happen?

Either the plugin's other hooks see its own submissions, as the doc says, letting a plugin attach context to the prompts it submits, or the doc should say that the whole plugin's hooks are skipped. Today the documented pattern ("the plugin's others see it") silently does nothing.

Steps to Reproduce

export const register: Register = (on) => {
  on('session.start', async ($, e, next) => {
    const r = await next(e)
    $.clock.after(4000, () => void $.prompt.submit({ text: '[probe]' }))
    return r
  })
  on('prompt.submit', async ($, e, next) => {
    if (e.origin?.kind === 'plugin' && e.origin.name === '<this plugin>') {
      return next({ ...e, text: `${e.text} [HOOK_RAN]`, context: [...(e.context ?? []), 'PROBE_CONTEXT'] })
    }
    return next(e)
  }).catch(($, e, next) => next(e))
}
  1. Load the plugin; wait for [probe] to arrive.
  2. Expected: [probe] [HOOK_RAN], and the model receives PROBE_CONTEXT. Observed: [probe] unchanged, no context. The debug log shows the skipped: re-entry line.
  3. Add a second plugin with the same prompt.submit hook matching the first plugin's name. Its rewrite and context do apply.

Environment

CLI 2.1.299 (claude -p --plugin-dir, fresh process), debug log line from that run:

2026-10-14T14:44:27.305Z [DEBUG] hooks module reentry-probe@inline prompt.submit skipped: re-entry (the plugin's own code raised it; origin reentry-probe)

Also reproduced on 2.1.296 (CLI) and on the desktop app bundling 2.1.295, macOS.

View original on GitHub ↗