Hooks let you inject custom logic at key points in the Qoder CN IDE lifecycle without modifying any code. By editing a JSON configuration file, you can:
Qoder CN IDE supports five hook events:
The following example intercepts dangerous commands like rm -rf to demonstrate the hook configuration flow.
Add the following to
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.
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:
First, decide where to intercept and what to match:
A hook script is a standard shell script that follows this protocol:
Script template:
Beyond exit codes, you can output JSON on exit 0 for finer control:
Write the script path under the corresponding event:
You can pipe a fake payload to the script for testing:
Check stderr output (block message):
Hook configuration is loaded from the following files. Multiple configurations are merged and executed (priority from lowest to highest):
A single event can have multiple matcher groups, and each group can contain multiple hook commands.
A matcher narrows when a hook fires. Matched fields vary by event (see per-event descriptions).
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,
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.
Hook scripts receive JSON via stdin. All events include these common fields:
Different events add additional fields (see the Event reference). Parse input with jq:
Hooks signal decisions via exit code and stdout.
Exit code determines basic behavior:
stdout JSON (optional; only takes effect on exit 0):
Hot reloading is not supported. Restart the IDE after modifying settings.json.
The default timeout is 30 seconds. A timeout is treated as an error (execution continues; stderr is shown to the user).
Same-event hooks run in declared order. Across files, priority applies: user (lowest) → project → project-local (highest).
Hooks run in the project root (cwd) as the current user, inheriting the IDE process environment.
Hook stderr output is sent back to the Agent or user. For detailed logs, search Qoder CN runtime logs for entries prefixed with [hook].
- 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 |
The current version does not support hot reloading. Restart the IDE after modifying configuration.
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