MoonshotAI / MoonshotAI/kimi-code
Hooks: opt-in `fail_mode = "closed"` for hooks that act as security gates
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 7.5k
- Forks
- 1.2k
- Avg merge
- 11h 53m
- Merged PRs (30d)
- 350
Description
Problem
Hooks currently fail open in every failure mode: if the hook script fails to spawn, crashes, times out, or exits with a code other than 0 or 2, the CLI resolves the result to allow and the gated operation proceeds. This is the right default for notifications and lightweight checks, and the docs are honest about the consequence: hooks "should not be used as the sole security barrier."
The gap is that for exactly the use case the docs call out (a PreToolUse hook gating dangerous shell commands), fail-open means the gate silently stops gating the moment the hook script breaks, hangs, or is removed. The agent sees no error and the user gets no signal that their guard is gone. A policy engine wired in through hooks cannot currently be made reliable, no matter how reliable the hook script itself is, because the runner's failure paths always allow.
Proposal
Add an optional per-hook fail_mode field to [[hooks]]:
"open"(default): today's behavior, unchanged. Existing configs are unaffected."closed": any failure to deliver a verdict (spawn failure, runtime error, timeout, exit code other than 0 or 2) blocks the operation, with an explicit reason string so the model can react.
Semantics that stay the same in both modes: exit 0 allows, exit 2 blocks with the stderr reason, structured stdout permissionDecision works as documented, and a user interrupt (Esc) resolves to allow, since the turn is being cancelled anyway.
One related edge: hook deduplication collapses identical (cwd, command) entries to a single run. With mixed modes on identical commands, the surviving entry should be the stricter one, otherwise config order silently weakens a gate.
Implementation
I have this working, with tests, on a branch: https://github.com/StressTestor/kimi-code/tree/feat/hook-fail-mode
It covers both agent-core (session/hooks) and agent-core-v2 (agent/externalHooks), including the config-shape difference between them (hook arrays reach agent-core's schema in raw snake_case because transformTomlData passes arrays through, while agent-core-v2's hooksFromToml camelizes entries before validation). Docs updated in en and zh, changeset included, verified end to end against a built CLI (a crashing PreToolUse hook with fail_mode = "closed" blocks the Bash call; the same hook without it fails open).
Happy to open the PR if this direction works for you.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reviewing the existing branch and the hook paths in agent-core (session/hooks) and agent-core-v2 (agent/externalHooks), including transformTomlData and hooksFromToml. Check the related tests, English and Chinese docs, and changeset; done means both hook implementations preserve default fail-open behavior and cover closed-mode failures, deduplication, and the described built-CLI flow.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- cli, security
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100