How Kimi Code Lifecycle Hooks Work: Events, Execution, and Configuration
Kimi Code lifecycle hooks map session events like SessionStart or PreToolUse to shell commands that receive JSON payloads via stdin, execute with configurable timeouts, and use exit codes (0 to allow, 2 to block) to control workflow flow without stopping execution on errors.
Kimi Code provides a generic hook system that allows you to intercept and react to key moments in an AI session's lifecycle. Implemented in packages/agent-core-v2/src/hooks.ts, these lifecycle hooks enable everything from audit logging to security blocking by running external scripts when specific events fire. Understanding how this system processes events and handles responses is essential for customizing your Kimi Code workflow safely.
What Are Lifecycle Hooks in Kimi Code?
A lifecycle hook is a rule that binds a specific event—such as SessionStart, UserPromptSubmit, or PreToolUse—to a shell command. When the event occurs, Kimi Code executes the command asynchronously, passing contextual data as JSON.
The core implementation resides in packages/agent-core-v2/src/hooks.ts, which exports OrderedHookSlot and createHooks to manage hook registration and execution. Hooks are defined in your ~/.kimi-code/config.toml under the [[hooks]] array, making them configurable without modifying the source code.
How Lifecycle Hooks Execute
When an event triggers, Kimi Code follows a strict execution protocol:
- Payload delivery – The CLI collects event-specific data (session ID, working directory, tool inputs) and writes it as JSON to the hook command's stdin.
- Timeout enforcement – Commands run with a configurable timeout that defaults to 30 seconds.
- Exit code interpretation:
0: Allow the operation to proceed2: Block the operation (for blockable events)- Any other non-zero: Allow (fail-open behavior)
- Stdout parsing – The CLI can read structured JSON responses from stdout to modify behavior.
Because the system is fail-open, timeouts or errors in hook scripts never halt the main Kimi Code session; they are logged and the workflow continues. This design prioritizes availability while still permitting security-oriented interception.
Available Lifecycle Events
Kimi Code supports distinct events categorized by whether they can block operations or only observe them:
UserPromptSubmit– Fires when text is entered. Blockable; use to amend or filter user input before the model processes it.PreToolUse– Fires before a tool executes. Blockable; use to validate dangerous operations like shell commands.Stop– Intercepts the model's stop signal. Blockable; allows injection of follow-up messages.SessionStart/SessionEnd– Fires on startup, resume, or exit. Observation-only; use for logging and resource initialization.PostToolUse/PostToolUseFailure– Fires after tool execution. Observation-only; use for telemetry and notifications.
Additional events like Notification (for background task state changes) are documented in docs/en/customization/hooks.md.
Configuring Lifecycle Hooks
Define hooks in ~/.kimi-code/config.toml using TOML array syntax. Each hook requires an event, optional matcher for filtering, command to execute, and timeout in seconds.
[[hooks]]
event = "SessionStart"
matcher = "startup"
command = "node ~/.kimi-code/hooks/log-session.mjs"
timeout = 30
The matcher field filters events when the event type supports it (e.g., matching specific tool names for PreToolUse). Omitting it catches all instances of that event.
Practical Lifecycle Hook Examples
Sending Desktop Notifications on Task Completion
Fire a macOS notification when background tasks complete using the Notification event:
[[hooks]]
event = "Notification"
matcher = "task\\.completed"
command = "terminal-notifier -title Kimi -message 'Task done'"
timeout = 30
Blocking Dangerous Shell Commands with PreToolUse
Create a security gate that prevents rm -rf execution by exiting with code 2:
[[hooks]]
event = "PreToolUse"
matcher = "Bash"
command = "node ~/.kimi-code/hooks/block-dangerous-bash.mjs"
timeout = 5
// block-dangerous-bash.mjs
let input = '';
process.stdin.on('data', chunk => (input += chunk));
process.stdin.on('end', () => {
const payload = JSON.parse(input);
const cmd = payload.tool_input?.command ?? '';
if (cmd.includes('rm -rf')) {
console.error('Dangerous command detected, blocked');
process.exit(2); // Block operation
}
process.exit(0); // Allow operation
});
Logging Session Start and End Events
The test suite in packages/agent-core/test/session/lifecycle-hooks.test.ts demonstrates logging by capturing JSON payloads:
// Helper script that records payloads to a file
const scriptPath = join(dir, 'record-hook.cjs');
await writeFile(
scriptPath,
[
"const { appendFileSync } = require('node:fs');",
"let input = '';",
"process.stdin.on('data', chunk => { input += chunk; });",
"process.stdin.on('end', () => {",
" appendFileSync(process.argv[2], input.trim() + '\\n');",
"});",
].join('\n'),
'utf-8',
);
// Session configuration with hooks
const session = new Session({
hooks: [
{ event: 'SessionStart', matcher: 'startup', command: scriptPath, timeout: 5 },
{ event: 'SessionEnd', matcher: 'exit', command: scriptPath, timeout: 5 },
],
});
The resulting JSON payload contains:
{
"hook_event_name": "SessionStart",
"session_id": "session-123",
"cwd": "/workspace",
"source": "startup"
}
When to Use Lifecycle Hooks
Choose hooks based on your operational requirements:
- Audit and logging – Use
SessionStartandPostToolUseto write immutable logs of all AI activity. - Security validation – Use
PreToolUsewith exit code2to block dangerous operations before execution. - Context enrichment – Use
UserPromptSubmitto inject Git branch names or environment metadata into prompts. - System integration – Use
Notificationto trigger external alerts when long-running tasks complete. - Resource management – Use
SessionEndto clean up temporary files or terminate background processes.
Summary
- Lifecycle hooks in Kimi Code connect session events to shell commands via
packages/agent-core-v2/src/hooks.ts. - Commands receive JSON payloads on stdin and communicate decisions through exit codes (
0allow,2block). - The system is fail-open; script failures or timeouts never crash the main session.
- Configure hooks in
~/.kimi-code/config.tomlusing the[[hooks]]array syntax. - Blockable events (
PreToolUse,UserPromptSubmit) can halt operations, while observation events provide telemetry without interrupting flow.
Frequently Asked Questions
What happens if a lifecycle hook script crashes or times out?
If a hook exits with a non-zero code other than 2, or exceeds its configured timeout (default 30 seconds), Kimi Code logs the failure and allows the operation to proceed. This fail-open design ensures that hook errors never disrupt your coding session.
Can I modify the JSON payload before it reaches the model?
Yes. The UserPromptSubmit event allows you to intercept user input via stdin, and you can write a modified JSON object to stdout. However, the specific implementation details for payload mutation depend on the event type; blocking events typically check exit codes while transformation events parse stdout.
Where are lifecycle hooks configured?
Hooks are defined in your user configuration file at ~/.kimi-code/config.toml under the [[hooks]] TOML array. This location keeps user customizations separate from the Kimi Code source code in packages/agent-core-v2/src/hooks.ts.
Which events can actually block operations versus just observe them?
According to the source code documentation in docs/en/customization/hooks.md, blockable events include UserPromptSubmit, PreToolUse, and Stop. Events like SessionStart, SessionEnd, PostToolUse, and PostToolUseFailure are observation-only and cannot halt execution.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →