Skip to content

fix(integration): run the Kimi Code hook on Windows - #8

Draft
paulork wants to merge 1 commit into
fix/windows-hook-quotingfrom
fix/windows-kimi-hook
Draft

paulork wants to merge 1 commit into
fix/windows-hook-quotingfrom
fix/windows-kimi-hook

Conversation

@paulork

@paulork paulork commented Oct 16, 2026 •

Copy link
Copy Markdown
Owner

Summary

On Windows, luvus integration install kimi now installs a hook that actually runs, so Kimi Code reports its exact session to Luvus. This holds for a home directory with spaces, and the hook no longer needs python3. Unix behavior is unchanged.

Closes RizRiyz#510

This PR depends on RizRiyz#511, the fix for RizRiyz#509 (fix/windows-hook-quoting), and reuses its shared PowerShell helpers. It targets that branch so the diff shows only the Kimi change, and will be retargeted to main after RizRiyz#511 merges.

What

  • src/agent/kimi/integration.rs:
    • On Windows, install writes luvus-agent-hook.ps1 next to config.toml and registers the encoded PowerShell command from Claude and Codex integration hooks never run on Windows RizRiyz/luvus#509 (integration::powershell_hook_command) for SessionStart, Notification and Stop. config.toml is still edited in place with toml_edit, so API keys, comments and the user's own hooks survive. Earlier Luvus entries, including the raw .sh path that never ran, are replaced, and the old .sh script is removed. A malformed config is refused before anything is written.
    • On Windows, is_installed reports installed only when the script exists and every event runs exactly the command this install writes. A raw-path install from an earlier release therefore shows as not installed, and re-enabling it replaces it.
    • Luvus entries are recognized by the raw script path or by the script path inside a PowerShell -EncodedCommand (via Claude and Codex integration hooks never run on Windows RizRiyz/luvus#509's encoded_command_texts). Uninstall also removes the .ps1.
    • Kimi gets its own luvus integration hook kimi, following the other adapters: pane.report_event for Notification and Stop, and pane.report_session otherwise. It runs only inside a Luvus pane, reads at most 256 KiB, and caps the forwarded message at 200 characters.
    • Unix still installs and registers the existing shell script. The install code is only split into read_config and register, with the same order of operations.
  • src/agent/kimi/hook.ps1: the Windows script. It hands the payload on stdin to luvus integration hook kimi.
  • src/integration.rs: tests only. The existing Kimi test now expects the script and command for each OS, and its helper recognizes encoded commands.
  • Docs: the Kimi entry in the agents guide notes the Windows behavior and says to re-enable an integration installed by an earlier release.

Why

The adapter registered script.to_string_lossy(), an unquoted Windows path such as C:\Users\<name>\.kimi-code\luvus-agent-hook.sh.

Kimi Code runs hook commands with Node's spawn(command, [], {shell: true}) (packages/agent-core-v2/src/features/externalHooks/internal/runHook.ts in MoonshotAI/kimi-code), which is cmd.exe /d /s /c on Windows.

  • With a space in the path, cmd.exe breaks the path at the space.
  • Without one, cmd.exe hands the .sh file to its file association (for example git-bash.exe), which opens a separate window without the payload.
  • Kimi logs nothing for a failed non-blocking hook, so the failure is silent.

The payload is snake_case (hook_event_name, session_id), so it can be parsed in Luvus, and no python3 is needed.

Screenshots

The same setup in both images: an isolated LUVUS_HOME, and a temporary KIMI_CODE_HOME under C:\luvus-wtkimi-home\shots\…\Jane Doe\.kimi-code, a path with a space, with a dummy model at 127.0.0.1:9. luvus integration install kimi was run with the binary under test, and a findstr probe hook next to the Luvus entries records the SessionStart payload Kimi sends. Kimi Code 2.2.0 is on the left, after its first message (the turn was then interrupted, since the dummy model never answers). On the right are the probe output and luvus agent list, filtered to agent, pane and session.

Before, on main (0062178): Kimi fired SessionStart (the probe has the payload, and Kimi's banner shows its session), but the Luvus script never ran, and the pane has no session.

pr-510-before

With this PR: the pane is bound to the same session_… id Kimi reports. That id exists only in the temporary KIMI_CODE_HOME, not in the ~/.kimi-code the server reads, so the binding comes from the hook.

pr-510-after
CLI output, before and after
# BEFORE: main 0062178 (unfixed), Windows 11, Kimi Code 2.2.0
# Isolated LUVUS_HOME; KIMI_CODE_HOME = 'C:\luvus-wtkimi-home\shots\before\Jane Doe\.kimi-code' (dummy model at 127.0.0.1:9)

## Installed hook command (KIMI_CODE_HOME\config.toml, same for SessionStart / Notification / Stop)
command = 'C:\luvus-wtkimi-home\shots\before\Jane Doe\.kimi-code\luvus-agent-hook.sh'

## probe.txt: a findstr SessionStart hook next to the Luvus entries (proves Kimi fired SessionStart)
{"hook_event_name":"SessionStart","session_id":"session_5a85c952-5773-41f9-a25a-e2606fb95802","cwd":"C:/luvus-wtkimi-work","client_type":"kimi_code_cli","source":"startup","model":"__kimi_env_model__","profile":"agent"}

## Kimi pane (after the first message, then Esc)
 ╭────────────────────────────────────────────────────────╮
 │                                                        │
 │  ▐█▛█▛█▌  Welcome to Kimi Code!                        │
 │  ▐█████▌  Send /help for help information.             │
 │                                                        │
 │  Directory: C:\luvus-wtkimi-work                       │
 │  Session:   session_5a85c952-5773-41f9-a25a-e2606fb958…│
 │  Model:     dummy-model                                │
 │  Version:   2.2.0                                      │
 │                                                        │
 ╰────────────────────────────────────────────────────────╯
 ✦ Kimi Code Desktop is here — Everything you love about
                             Kimi Code, now on desktop
   Run /desktop or visit https://www.kimi.com/code to
   install
   No session yet — one will be created on your first
 message.
 ❯ Reply with the single word: ok
   Interrupted by user
 ╭────────────────────────────────────────────────────────╮
 │ >                                                      │
 ╰────────────────────────────────────────────────────────╯
 dummy-model thinking  C:\luvus-wtkimi-work  master [±]
                                        context: 1% (63/8k)

## luvus agent list
        "agent": "kimi",
        "authority": "process_tree",
        "pane": "1",
        "session": null,


# AFTER: this PR (c2b6479), Windows 11, Kimi Code 2.2.0
# Isolated LUVUS_HOME; KIMI_CODE_HOME = 'C:\luvus-wtkimi-home\shots\after\Jane Doe\.kimi-code' (dummy model at 127.0.0.1:9)
# The session id exists only in that temporary KIMI_CODE_HOME, not in the ~/.kimi-code the server reads, so the binding comes from the hook.

## Installed hook command (KIMI_CODE_HOME\config.toml, same for SessionStart / Notification / Stop)
command = "powershell.exe -NoProfile -NonInteractive -ExecutionPolicy Bypass -EncodedCommand JgAgACcAQwA6AFwAbAB1AHYAdQBzAC0AdwB0AGsAaQBtAGkALQBoAG8AbQBlAFwAcwBoAG8AdABzAFwAYQBmAHQAZQByAFwASgBhAG4AZQAgAEQAbwBlAFwALgBrAGkAbQBpAC0AYwBvAGQAZQBcAGwAdQB2AHUAcwAtAGEAZwBlAG4AdAAtAGgAbwBvAGsALgBwAHMAMQAnAA=="

## probe.txt: a findstr SessionStart hook next to the Luvus entries
{"hook_event_name":"SessionStart","session_id":"session_b3b74240-5041-4c9b-91d8-8d5bff495e23","cwd":"C:/luvus-wtkimi-work","client_type":"kimi_code_cli","source":"startup","model":"__kimi_env_model__","profile":"agent"}

## Kimi pane (after the first message, then Esc)
 ╭────────────────────────────────────────────────────────╮
 │                                                        │
 │  ▐█▛█▛█▌  Welcome to Kimi Code!                        │
 │  ▐█████▌  Send /help for help information.             │
 │                                                        │
 │  Directory: C:\luvus-wtkimi-work                       │
 │  Session:   session_b3b74240-5041-4c9b-91d8-8d5bff495e…│
 │  Model:     dummy-model                                │
 │  Version:   2.2.0                                      │
 │                                                        │
 ╰────────────────────────────────────────────────────────╯
 ✦ Kimi Code Desktop is here — Everything you love about
                             Kimi Code, now on desktop
   Run /desktop or visit https://www.kimi.com/code to
   install
   No session yet — one will be created on your first
 message.
 ❯ Reply with the single word: ok
   Interrupted by user
 ╭────────────────────────────────────────────────────────╮
 │ >                                                      │
 ╰────────────────────────────────────────────────────────╯
 dummy-model thinking  C:\luvus-wtkimi-work  master [±]
                                        context: 1% (63/8k)

## luvus agent list
        "agent": "kimi",
        "authority": "process_tree",
        "pane": "1",
        "session": "session_b3b74240-5041-4c9b-91d8-8d5bff495e23",

Verification

Windows 11, base 9a01839 (RizRiyz#509 on 0062178), Kimi Code 2.2.0.

  • cargo fmt --all --check (Rust 1.99.0)
  • cargo clippy --all-targets -- -D warnings (Rust 1.99.0, Windows)
  • New tests in agent::kimi::integration::tests:
    • kimi_windows_install_replaces_raw_path_entries (Windows only): under a home with a space, $HOME, a backtick, ' and %PATH%, a raw-path install shows as not installed. Two installs leave exactly one Luvus entry per event with the encoded command, after the user's own hook, and remove the old .sh. Uninstall removes the script.
    • kimi_windows_hook_command_runs_under_cmd_with_a_spaced_home (Windows only): runs the installed command the way Kimi does, cmd.exe /d /s /c "<command>", and checks that the payload on stdin reaches the program the script starts.
    • hook_reports_kimi_sessions_and_lifecycle_events: the real Kimi 2.2.0 SessionStart payload, Notification and Stop, message truncation, and rejected payloads, including an oversized one.
    • hook_runs_only_in_a_luvus_pane
    • luvus_entries_are_recognised_raw_and_encoded
    • foreign_encoded_hooks_are_not_ours
    • windows_script_hands_the_payload_to_luvus_without_python
  • Updated test: integration::tests::kimi_hook_preserves_config_and_is_reversible now asserts the exact command for each OS, and that only the user's hook remains after uninstall.
  • cargo test --bin luvus -- integration::tests agent::: 133 passed, 3 failed. They are the same 3 CRLF-sensitive failures as on Claude and Codex integration hooks never run on Windows RizRiyz/luvus#509's base: integration::tests::installing_replaces_only_the_legacy_managed_hook and two agent::opencode::integration tests. None of them touches the changed code.
  • End to end with the debug binary and real Kimi Code 2.2.0, in an isolated LUVUS_HOME and named session. The production server and the real ~/.kimi-code were not touched. Each run used a temporary KIMI_CODE_HOME and a dummy model at 127.0.0.1:9.
    • Home with a space (C:\luvus-wtkimi-kimi home) and without one: the pane bound to the new session_… id. That id existed only in the temporary KIMI_CODE_HOME, and the server reads the real ~/.kimi-code, so the binding came from the hook.
    • Control home with only a probe hook and no Luvus hook: the pane stayed with session: null.

Notes

  • Kimi Code 2.2.0 fires SessionStart on the first message, not when it starts.
  • Stop and Notification weren't exercised live: they need a working model and an account. A failed model turn fires no Stop. Their payload handling is covered by the unit tests.
  • Unix and macOS weren't run here. Their install path is unchanged, and CI covers them.
  • Copilot and Grok also register the raw .sh path and are likely affected on Windows. I couldn't test them (not installed), so they are out of scope.

Kimi Code runs hook commands through cmd.exe on Windows, which split the
raw luvus-agent-hook.sh path at spaces or handed the .sh file to its file
association, so the hook never ran. On Windows, register the encoded
PowerShell hook command and report the payload through
`luvus integration hook kimi`, without python3. Re-enabling replaces the
old raw-path entries; Unix is unchanged.

Closes RizRiyz#510
@paulork
paulork force-pushed the fix/windows-kimi-hook branch from c2b6479 to 7997b73 Compare October 16, 2026 21:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant