Skip to content

UserPromptSubmit denial displays the hook result but leaves the TUI pending until Ctrl-S #3699

Description

@aldanux

What version of Kimi Code is running?

0.42.0

Which open platform/subscription were you using?

Kimi Platform (API key · platform.kimi.ai)

Which model were you using?

kimi-k3

What platform is your computer?

Darwin 25.6.0 arm64 arm

What issue are you seeing?

A UserPromptSubmit hook that denies submission (to display a result and skip the model call) shows the result, but the TUI never finishes the pending interaction on its own. A following prompt stays queued until I press Ctrl-S ("steer immediately"). Both exit-0 structured denial and exit-2 denial reproduce it; changing the hook output form does not resolve the stall.

Source-level findings (verified against 0.42.0 commit 6954d2c8bf94a5c7fc29cc6ae35b15d042cc4dcb and current main d3dc5945548d3353a5e6cfc457a3a8cf84d7da71):

  • The engine does emit prompt.completed with reason: "blocked", but the SDK filters it out before it reaches the TUI: prompt.completed is in DROPPED_DOMAIN_EVENT_TYPES (packages/node-sdk/src/v2/event-mapper.ts, entry at L38 on main, filter at L68).
  • The blocked path publishes completion and returns before loop.submit, so no engine turn starts or ends (packages/agent-core-v2/src/agent/prompt/promptService.ts L547–552).
  • The TUI finalizes an interaction on turn.ended (apps/kimi-code/src/tui/controllers/session-event-handler.ts L369–391); the hook.result handler (L594–617) renders the result without finalizing.

Net: on the hook-denial path the TUI gets the display event but neither a forwarded prompt.completed nor a turn.ended, so it never returns to idle.

What steps can reproduce the bug?

  1. Add this rule to ~/.kimi-code/config.toml, then start a new interactive kimi session:
[[hooks]]
event = "UserPromptSubmit"
matcher = "^hook-stall$"
command = "printf '%s\\n' 'Hook handled this prompt; model submission skipped.' >&2; exit 2"
  1. Submit hook-stall. The hook result is displayed and model submission is denied.
  2. Submit a nonmatching prompt, such as Reply with OK. It stays pending instead of being processed.
  3. Press Ctrl-S (“steer immediately”); the following prompt can then proceed.

For the exit-0 variant, replace only command with:

command = '''
printf '%s\n' '{"message":"Hook handled this prompt; model submission skipped.","hookSpecificOutput":{"permissionDecision":"deny","permissionDecisionReason":"Handled by hook"}}'
exit 0
'''

Use one variant at a time. The explicit message avoids conflating this with raw JSON display when that field is absent.

What is the expected behavior?

After displaying the hook result and denying submission, the TUI should finish the interaction cleanly, return to idle, and process the next prompt normally without ctrl-s.

Additional information

Related: #3464 (client stalls / invisible completed work, but for compaction/rendering and queueing, not this hook-denial path), #3568 (raw hook JSON when no message field — here the result displays fine; completion stalls with either output form), #3536 (proposed model-visible/terminal-hidden context), PR #929 (suppress allowed hook output while keeping blocking output visible — this is about finishing after that visible blocking result).

Contribution

  • I am willing to submit a PR for this bug fix myself (please wait for maintainer approval in this issue first)

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions