Hooks run custom scripts at key points in the Qoder CN CLI agent lifecycle—such as blocking dangerous commands, sending notifications on task completion, or auto-linting written files.
Hooks are defined in a JSON configuration file and take effect immediately—no code changes required.
This example blocks the Agent from running
Step 2: Edit the configuration file
Add the following to
Step 3: Verify the result
Start Qoder CN CLI and ask the Agent to run a command containing
Hook configurations are loaded from the following three files. The settings from all three levels are merged and executed:
Fields:
A single event supports multiple matcher groups, each containing multiple hook commands.
The
Hook scripts receive a JSON payload on stdin and use exit codes and stdout to control behavior. Each event adds its own fields to the common structure below.
All events include the following fields on stdin:
Parse the input with
A hook controls behavior through its exit code: 0 for success, 2 to block the operation (supported events only), and any other non-zero value for a non-blocking error. Some events also parse a JSON object on stdout for fine-grained control when the exit code is 0.
Hook scripts can access the following environment variables:
Qoder CN CLI supports the following hook events across the session lifecycle.
Triggers when a session starts.
Matcher field: Session source
Additional input fields:
Triggers when a session ends.
Matcher field: End reason
Additional input fields:
Triggers after a user submits a prompt but before the Agent processes it.
Additional input fields:
Triggers before a tool runs. This hook can block tool execution.
matcher: Tool name (such as
Block tool execution: Exit with code 2. Content on stderr is sent to the Agent as an error message.
Triggers after a tool executes successfully.
Matcher field: Tool name
Additional input fields:
Triggers after a tool fails to execute.
Matcher field: Tool name
Additional input fields:
Triggers when the Agent finishes its response with no pending tool calls. Use this hook to prevent the Agent from stopping and prompt it to continue.
Prevent the Agent from stopping: Exit with code 2. Content from stderr is injected into the conversation, prompting the Agent to continue.
Triggers when a subagent starts or stops. SubagentStop works like Stop and can prevent a subagent from stopping.
Matcher field: Agent type name
Additional input fields:
Triggers before context compaction.
Matcher field: Trigger method
Additional input fields:
Triggers on notification events such as permission requests or task completions.
Matcher field: Notification type
Additional input fields:
Triggers when a tool requires user authorization to run.
Matcher field: Tool name
Additional input fields:
Send a macOS desktop notification when the Agent completes a task or requests authorization. Save the following script to
Configuration:
Auto-lint JavaScript and TypeScript files after the Agent writes or edits them. Save the following script to
Set event to
Check for uncommitted Git changes when the Agent stops, and prompt it to continue if any exist. Save the following script to
Set event to
Quick start
This example blocks the Agent from running rm -rf commands.
Step 1: Create the script
~/.qoder-cn/settings.json:
rm -rf. The hook blocks execution and notifies the Agent.
Configuration
Configuration file locations
Hook configurations are loaded from the following three files. The settings from all three levels are merged and executed:
Configuration format
| Field | Required | Description |
|---|---|---|
type | Yes | Must be set to "command". |
command | Yes | The shell command to run. |
timeout | No | The timeout in seconds. Default: 60. |
matcher | No | Match condition. If omitted, the hook applies to all instances. |
Matcher rules
The matcher field determines when a hook triggers. Each event matches against a different field.
Syntax | Description | Example |
Leave blank or | Matches all. | Triggers for all tools. |
Exact value | Exact match. |
|
| Matches multiple values. |
|
Regular expression | Regular expression match. |
|
Writing hook scripts
Hook scripts receive a JSON payload on stdin and use exit codes and stdout to control behavior. Each event adds its own fields to the common structure below.
Input
All events include the following fields on stdin:
| Field | Description |
|---|---|
session_id | The ID of the current session. |
cwd | The current working directory. |
hook_event_name | The name of the event that triggered the hook. |
jq:
Output
A hook controls behavior through its exit code: 0 for success, 2 to block the operation (supported events only), and any other non-zero value for a non-blocking error. Some events also parse a JSON object on stdout for fine-grained control when the exit code is 0.
Environment variables
Hook scripts can access the following environment variables:
| Variable | Description |
|---|---|
QODERCN_PROJECT_DIR | The working directory of the current project. |
Supported events
Qoder CN CLI supports the following hook events across the session lifecycle.
SessionStart
Triggers when a session starts.
Matcher field: Session source
| Matcher value | Trigger scenario |
|---|---|
startup | A new session starts. |
resume | An existing session is resumed. |
compact | Context compaction is complete. |
SessionEnd
Triggers when a session ends.
Matcher field: End reason
| Matcher value | Trigger scenario |
|---|---|
prompt_input_exit | The user closes the prompt (e.g., by pressing Ctrl+D). |
other | The session ends for other reasons. |
UserPromptSubmit
Triggers after a user submits a prompt but before the Agent processes it.
Additional input fields:
PreToolUse
Triggers before a tool runs. This hook can block tool execution.
matcher: Tool name (such as Bash, Write, Edit, Read, Glob, Grep, or an MCP tool name such as mcp__server__tool)
Additional input fields:
PostToolUse
Triggers after a tool executes successfully.
Matcher field: Tool name
Additional input fields:
PostToolUseFailure
Triggers after a tool fails to execute.
Matcher field: Tool name
Additional input fields:
Stop
Triggers when the Agent finishes its response with no pending tool calls. Use this hook to prevent the Agent from stopping and prompt it to continue.
Prevent the Agent from stopping: Exit with code 2. Content from stderr is injected into the conversation, prompting the Agent to continue.
SubagentStart / SubagentStop
Triggers when a subagent starts or stops. SubagentStop works like Stop and can prevent a subagent from stopping.
Matcher field: Agent type name
Additional input fields:
PreCompact
Triggers before context compaction.
Matcher field: Trigger method
| Matcher value | Trigger scenario |
|---|---|
manual | The user manually executes /compact. |
auto | Compaction is triggered automatically when the context window is full. |
Notification
Triggers on notification events such as permission requests or task completions.
Matcher field: Notification type
| Matcher value | Trigger scenario |
|---|---|
permission | A permission request notification. |
result | A notification for a result generated by the Agent. |
PermissionRequest
Triggers when a tool requires user authorization to run.
Matcher field: Tool name
Additional input fields:
Use cases
Send desktop notifications
Send a macOS desktop notification when the Agent completes a task or requests authorization. Save the following script to ~/.qoder-cn/hooks/notify.sh:
Automatically lint modified files
Auto-lint JavaScript and TypeScript files after the Agent writes or edits them. Save the following script to ${project}/.qoder-cn/hooks/auto-lint.sh:
PostToolUse, matcher to Write|Edit, and command to .qoder/hooks/auto-lint.sh.
Keep the Agent running
Check for uncommitted Git changes when the Agent stops, and prompt it to continue if any exist. Save the following script to ~/.qoder-cn/hooks/check-continue.sh:
Stop and command to ~/.qoder-cn/hooks/check-continue.sh.