- Intercept dangerous operations before a tool call.
- Automatically run a linter after every file write to keep code style consistent.
- Get a desktop notification when the Agent finishes a task—no need to watch the IDE.
Supported events
Qoder CN IDE supports five hook events:
| Event name | Trigger | Blockable |
|---|---|---|
| UserPromptSubmit | After the user submits a prompt, before the Agent processes it | Yes |
| PreToolUse | Before a tool call is executed | Yes |
| PostToolUse | After a tool call succeeds | No |
| PostToolUseFailure | After a tool call fails | No |
| Stop | When the Agent completes its response | No |
Quick start
The following example intercepts dangerous commands like rm -rf to demonstrate the hook configuration flow.
Step 1: Create the script
Step 2: Add the configuration
Add the following to ~/.lingma/settings.json:
Step 3: Verify
Restart the IDE. In the Qoder CN panel, ask the Agent to run a command containing rm -rf. The hook blocks execution and reports the error back to the Agent.
Common scenarios
| Scenario | Event | Description |
|---|---|---|
| Block dangerous commands | PreToolUse | Block Agent from running commands like rm -rf, DROP TABLE, etc. |
| Validate file paths | PreToolUse | Restrict Agent file writes to designated directories |
| Auto-lint / format | PostToolUse | Automatically run ESLint / Prettier after each file write |
| Audit logging | PostToolUse | Log all Agent tool calls for security auditing |
| Failure monitoring / alerts | PostToolUseFailure | Send alerts or log errors when tool calls fail |
| Prompt content review | UserPromptSubmit | Detect sensitive information (passwords, keys, etc.) in user input |
| Auto-inject context | UserPromptSubmit | Append project guidelines or coding conventions to prompts |
| Desktop notification | Stop | Show a system notification when the Agent completes |
How it works
Using hooks boils down to three steps: write a script → register the configuration → run automatically.
When the Agent reaches a lifecycle point (e.g., before a tool call), the plugin checks whether a hook is registered for that event:
- The IDE loads all hook configurations at startup.
- During Agent execution, a specific event (e.g., PreToolUse) is reached.
- All hook groups for that event are traversed, and each matcher is compared against the current context.
- Matched hooks execute their shell scripts in order.
- Each script reads event context (JSON) from stdin and returns decisions via exit code and stdout.
- The IDE decides subsequent behavior (allow or block) based on the return values.
Prerequisites
- jq: Example scripts depend on jq to parse JSON. On macOS, run
brew install jq. On Linux, runapt install jq. - Script permissions: All hook scripts must be executable (
chmod +x).
Creating hooks
Step 1: Determine the requirements—pick an event and matcher
First, decide where to intercept and what to match:
Requirement | Event | matcher |
Check before Agent runs any shell command | PreToolUse | "Bash" |
Process after Agent writes or edits a file | PostToolUse | "Write | Edit" |
Log when an Agent tool call fails | PostToolUseFailure | "Bash" or omit |
Screen all user-submitted prompts | UserPromptSubmit | Omit (matches all) |
Trigger a notification when the Agent stops | Stop | Omit (matches all) |
Intercept MCP tools only | PreToolUse | "mcp__.*" |
Step 2: Write the hook script
A hook script is a standard shell script that follows this protocol:
- Input: Receive event context as JSON via stdin.
- Output: Control behavior via exit code.
Step 3: Register in the configuration file
Write the script path under the corresponding event:
Step 4: Test and debug
You can pipe a fake payload to the script for testing:
Configuring hooks
Configuration file locations
Hook configuration is loaded from the following files. Multiple configurations are merged and executed (priority from lowest to highest):
| Location | Scope | Priority | Shareable | Description |
|---|---|---|---|---|
| ~/.lingma/settings.json | User | 1 (Lowest) | No | Personal configuration; applies to all projects |
| .lingma/settings.json | Project | 2 | Yes | Committable to Git for team sharing |
| .lingma/settings.local.json | Project (Local) | 3 | No | Personal dev overrides; add to .gitignore |
Configuration format
| Field | Required | Description |
|---|---|---|
| type | Yes | Must be "command" |
| command | Yes | The shell command or script path to execute |
| timeout | No | Timeout in seconds. Default: 30 |
| matcher | No | Filter for triggering. If omitted, matches all invocations of the event |
matcher rules
A matcher narrows when a hook fires. Matched fields vary by event (see per-event descriptions).
Syntax | Meaning | Example |
Omit or "*" | Match all | Triggers for all tools |
Exact value | Exact match | "Bash" triggers only for the Bash tool |
| separated | Match multiple values | "Write | Edit" triggers for Write or Edit |
Regular expression | Regex match | "mcp__.*" matches all MCP tools |
Tool name mapping
Qoder CN supports two sets of tool names—native and compatible. Either can be used when configuring hooks; they are normalized at runtime for matching. For example, matcher: "Bash" and matcher: "run_in_terminal" are equivalent.
| Native name | Compatible name | Description |
|---|---|---|
| run_in_terminal | Bash | Execute a shell command |
| read_file | Read | Read file content |
| create_file | Write | Create or write to a file |
| search_replace | Edit | Edit a file |
| delete_file | - | Delete a file |
| grep_code | Grep | Search file content |
| search_file | Glob | Match file names |
| list_dir | LS | List directory contents |
| task | Task | Start a subtask / sub-agent |
| mcp__<server>__<tool> | Same as native | An MCP tool |
Writing hook scripts
Hook scripts receive JSON via stdin and control behavior through exit code and stdout. This section describes the input/output format shared by all events; per-event fields appear in the Event reference.
Input
Hook scripts receive JSON via stdin. All events include these common fields:
| Field | Description |
|---|---|
| session_id | Current session ID |
| cwd | Current working directory |
| hook_event_name | Name of the triggered event |
| transcript_path | File path to the session context JSON |
Output
Hooks signal decisions via exit code and stdout.
Exit code determines basic behavior:
| Exit Code | Meaning | Behavior |
|---|---|---|
| 0 | Success | Continues execution; parses stdout JSON |
| 2 | Block | Stops the operation; stderr is injected into the conversation (blockable events only) |
| Other | Error | Continues execution; stderr is shown to the user only |
Event reference
UserPromptSubmit
- Trigger: After the user submits a prompt, before the Agent processes it
- Blockable: Yes (exit 2 cancels the request)
- Additional fields: prompt (the raw text entered by the user)
PreToolUse
- Trigger: Before the Agent executes a tool call
- Blockable: Yes (exit 2 rejects the tool call)
- Matcher field: tool_name
- Additional fields: tool_name, tool_input
PostToolUse
- Trigger: After a tool call succeeds
- Blockable: No
- Matcher field: tool_name
- Additional fields: tool_name, tool_input, tool_response
PostToolUseFailure
- Trigger: After a tool call fails
- Blockable: No
- Matcher field: tool_name
- Additional fields: tool_name, tool_input, error
Stop
- Trigger: When the Agent completes its response
- Blockable: No
- Additional fields: stop_hook_active, last_assistant_message

