MoonshotAI / MoonshotAI/kimi-code

feat(hooks): let hooks participate in the approval decision (blocking PermissionRequest, or an "allow" decision on PreToolUse)

Open
#1,326 4 comments 3 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

Context

I build Clawd, a desktop pet that visualizes coding-agent activity and surfaces permission prompts as desktop bubbles. I recently integrated Kimi Code's hooks (0.22.0) and want to say the permission events are genuinely well designed: PermissionRequest fires exactly when the approval panel blocks (no guessing from PreToolUse timing), the display block carries the real command and cwd for UI to show, and PermissionResult makes "the user answered" a clean, immediate signal. My integration uses all three and they work great for notifying.

The gap

External UIs can only observe an approval — they cannot answer it:

  • PermissionRequest is fired via fireAndForgetTrigger (packages/agent-core/src/agent/permission/index.ts), so nothing a hook returns is read; the decision lives exclusively inside the TUI reverse-RPC approval flow.
  • PreToolUse is blockable, but only with deny semantics (exit 2 / permissionDecision: "deny"). An allow simply means "this hook doesn't object" — the permission policy chain continues and the TUI panel still pops. So a hook-driven UI can implement "reject from the bubble", but never "approve from the bubble"; users would face a double prompt.

This blocks a whole class of integrations: one-click approval from a desktop companion, remote/mobile approval (approve from your phone while away from the keyboard), or an org-side policy gateway that auto-approves vetted commands.

I'm aware the daemon/server modes (kimi server / kimi web) expose an approval broker over WS/REST for Kimi's own web and desktop frontends — but that only covers sessions running under those modes. The interactive TUI is a single process (the SDK RPC pair is in-memory), so for people who run kimi in a terminal — which is who a companion tool sees — hooks are the only integration surface, and asking them to switch how they launch Kimi just so an external tool can answer approvals isn't realistic.

Proposal

Either of these would unlock it (option A feels cleanest):

A. A blocking variant of PermissionRequest. Run it through the blocking path (like Stop/PreToolUse) before falling back to the TUI panel. A hook that prints a structured decision, e.g.

{ "hookSpecificOutput": { "permissionDecision": "approve", "scope": "once" } }

resolves the approval; no output / exit 0 / timeout falls through to the normal TUI panel. That keeps it fully backward compatible — every existing PermissionRequest hook today exits without a decision and would behave exactly as before — and preserves the fail-open philosophy (hook crash → TUI panel, never a hang or an implicit approval).

B. An "allow" decision on PreToolUse. Today only "deny" is honored; honoring "allow" as "skip the ask, treat as approved" (short-circuiting the ask policy the way a session approval rule does) would achieve the same with the existing event, at the cost of deciding before the approval context (action/display) exists.

Prior art in the ecosystem: Claude Code's PreToolUse hooks accept allow/deny/ask decisions, and Codex's PermissionRequest hook is blocking with a decision output — third-party approval surfaces (remote approval bots, desktop companions) are built on exactly this. Kimi Code already has the cleanest event model of the three; this is the one missing piece.

I'd be happy to contribute a PR for option A if the direction sounds acceptable to you.

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 in packages/agent-core/src/agent/permission/index.ts, then trace the existing blocking paths for Stop and PreToolUse and the fire-and-forget PermissionRequest flow. Compare the proposed blocking PermissionRequest and PreToolUse allow semantics, and define completion as an external hook being able to resolve approval while preserving TUI fallback, timeout, and failure behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
authorization, cli
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.