MoonshotAI / MoonshotAI/kimi-code

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

Open
#3,699 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug
Dominant language
TypeScript
Stars
7.5k
Forks
1.2k
Avg merge
11h 53m
Merged PRs (30d)
350

Description

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)

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with packages/agent-core-v2/src/agent/prompt/promptService.ts and trace the blocked path, then inspect packages/node-sdk/src/v2/event-mapper.ts and apps/kimi-code/src/tui/controllers/session-event-handler.ts. Reproduce the denial with the provided hook configuration and follow the prompt completion events. Done means the displayed denial returns the TUI to idle and a subsequent prompt is processed without Ctrl-S.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
cli
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
75/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.