MoonshotAI / MoonshotAI/kimi-code

Hook command spawn failures are completely silent — no log, no diagnostic, kimi doctor reports OK

Open
#2,766 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

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

Description

Version: kimi-code 0.34.0 (Windows 11, x64) — code paths verified in both agent-core (session/hooks/runner.ts) and agent-core-v2 (agent/externalHooks/runner.ts).

Summary

When a [[hooks]] command in config.toml cannot be spawned or exits non-zero, kimi-code gives the user zero feedback anywhere: no log line in logs/kimi-code.log, no stderr warning, no event in the session wire.jsonl, and kimi doctor validates the TOML schema only, so it reports everything OK. The hook then silently never contributes context, which for UserPromptSubmit-based workflows means the injected content just never appears and the user has no way to notice except by absence.

In our case this turned a trivial quoting mistake into days of debugging that initially looked like an injection regression in the 0.33 engine migration — because there was no way to distinguish "the hook ran and its output was lost" from "the hook never ran".

Repro

  1. config.toml:

    [[hooks]]
    event = "UserPromptSubmit"
    command = "C:/Program Files/Git/bin/bash.exe C:/some/hook.sh"
    timeout = 15
    

    Note the unquoted interpreter path. Since hooks are spawned with spawn(command, [], { shell: true })cmd.exe /d /s /c "<command>" on Windows, cmd splits at the first space and fails with 'C:/Program' is not recognized as an internal or external command.

  2. Run any surface (kimi, kimi -p "hi", kimi acp).

  3. Observed: the hook never runs; nothing is logged anywhere; kimi doctor says all config files are valid.

  4. Control: with the interpreter path quoted —

    command = "\"C:/Program Files/Git/bin/bash.exe\" \"C:/some/hook.sh\""
    

    — everything works on every surface we tested (interactive TUI, -p, acp): the hook runs, receives the full JSON payload on stdin (including session_id), and its stdout is injected into context as a hook_result message. So the 0.34.0 hook pipeline itself is fine; only the failure reporting is missing.

Why it's silent (code)

  • runHook maps spawn errors to allowResult({ stderr }); that stderr is never surfaced to any log or UI.
  • resultFromExitCode(1, stdout, stderr) returns an allow result whose stderr is dropped by every consumer (userPromptHookMessage filters out non-zero exit codes and returns nothing).
  • ExternalHooksRunnerService.trigger() wraps everything in try { ... } catch { return [] }, and loadSafe() swallows config-load errors the same way.

Ask

  1. Log hook spawn failures / non-zero exits (event name, command, exit code, first stderr line) at WARN in the session log.
  2. Optionally: have kimi doctor attempt to resolve the command executable — or at least flag unquoted paths containing spaces on Windows, which is a classic trap for any hook written as <interpreter> <script>.

Related

Adjacent but distinct: #2455, #2107, #1896, #2070 report hook stdout/injection gaps on earlier versions. For 0.34.0 we specifically verified that UserPromptSubmit stdout is injected as hook_result on shell, print and ACP surfaces once the command actually spawns — so at least some of what gets reported as "stdout not injected" may in fact be this silent spawn failure, which is invisible to the reporter.

Happy to provide the full probe transcripts (isolated KIMI_CODE_HOME, per-event payload dumps, wire.jsonl evidence) if useful.

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 agent-core/session/hooks/runner.ts and agent-core-v2/agent/externalHooks/runner.ts, then trace ExternalHooksRunnerService.trigger(), loadSafe(), and userPromptHookMessage(). Reproduce the unquoted Windows command from the issue and verify that spawn failures and non-zero exits produce the requested WARN details in the session log without changing successful hook output handling.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
cli, devtools
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.