Hooks
Hooks are the core mechanism of the CodeArts Agent CLI plugin system. They allow developers to inject custom logic during key phases such as tool execution, message processing, and permissions control. A plugin declares the lifecycle events it is interested in by returning a hook object. When an event is triggered, the custom function of the plugin is called.
Storage Paths for Plug-ins and Dependency Files
A plug-in is a JavaScript/TypeScript module that operates by exporting plug-in functions. Each function receives a context object and returns the corresponding hook object. If external packages are required within a plug-in file, you must create a package.json file in the configuration directory and configure the necessary dependencies. CodeArts Agent automatically installs these dependencies when it starts.
| Plug-in Type | Plug-in File Storage Path | Plug-in Dependency Storage Path | Description |
|---|---|---|---|
| Project | Root directory of the current project: ./codeartsdoer/plugin or ./codeartsdoer/plugins | Root directory of the current project: ./codeartsdoer/ | Valid only for the current project. |
| User | Local %USERPROFILE%/.codeartsdoer/plugin or %USERPROFILE%/.codeartsdoer/plugins | Local %USERPROFILE%/.codeartsdoer/ | Valid for all projects of the current user. |
Supported Hook Events
For details about the hook events supported by CodeArts Agent CLI, see Table 2. For details about the examples of each hook event, see Hook Event Reference.
| Event Category | Event Name | Trigger Time | Blockable | Typical Application Scenario | Description |
|---|---|---|---|---|---|
| Chat message | chat.message | Triggered after a user sends a message but before it enters the processing workflow. | Yes | Chat message processing | Automatically triggered when a new message arrives. Supports editing message content and parts. |
| Chat parameter | chat.params | Triggered before each LLM call. | Yes | Chat parameter modification | Supports dynamically adjusting LLM inference parameters (including temperature, topP, topK, etc.) to optimize model output as needed. |
| Chat request header | chat.headers | Triggered before each LLM call. | Yes | Chat request header modification | Supports customizing and modifying HTTP request header fields to adapt to complex requirements such as network proxies and interface authentication. |
| Chat response | chat.response | Triggered after the LLM returns a response. | No | Chat response logging | Automatically captures core metrics of the model response, such as tokens, cost, and duration, achieving precise billing statistics, efficient troubleshooting, and complete log retention. |
| Chat error | chat.error | Triggered when an error occurs during an LLM call. | No | Chat error logging | Logs error details when an LLM call fails. |
| Chat compression | chat.compression | Triggered during context compression. | No | Chat compression logging | Logs the token counts before and after context compression to assist in storage and performance tuning. |
| Chat end | chat.finished | Triggered when a chat ends. | No | Chat end logging | Logs the chat end event, including the token consumption and running information of the current run. |
| User approval | user.approval | Triggered when a user confirmation or approval action is required. | Yes | User approval logging | Intercepts high-risk operations and initiates manual confirmation and approval, controlling the execution permissions of sensitive operations. |
| Turn end | turn.end | Triggered when each chat turn ends. | No | Turn end logging | Logs the end of each chat turn, containing key information such as processing duration and termination reasons. |
| Command execution | command.execute.before | Triggered before a command is executed. | Yes | Command preprocessing | Supports custom configuration of parts to achieve command preprocessing and flexible adaptation. |
| Tool execution | tool.execute.before | Triggered before a tool is executed. | Yes | Tool execution pre-parameter adjustment | Supports customizing and modifying args before tool execution to achieve validation, dynamic rewriting, and service adaptation. |
| tool.execute.after | Triggered after a tool is executed. | Yes | Tool execution post-result processing | Supports customizing and modifying returned results, including the title, output, and metadata fields. | |
| Tool definition | tool.definition | Triggered before a tool definition is sent to the LLM. | Yes | Tool definition modification | Supports customizing configuration descriptions and parameters before tool definitions are pushed to the model, ensuring precise adaptation to service scenarios. |
| Shell environment | shell.env | Triggered when fetching Shell environment variables. | Yes | Shell environment variable configuration and management | Supports adding or modifying environment variables when Shell environment variables are fetched. |
| Permission request | permission.ask | Triggered when permission verification is required. | Yes | Permission request processing | Processes permission validation requests and supports configuring three strategies: allow, deny, and ask. |
| Message conversion | experimental.chat.messages.transform | Triggered before the message list is sent to the LLM. | Yes | Message conversion | Supports preprocessing the chat list before it is reported to the model. |
| System message conversion | experimental.chat.system.transform | Triggered before the system prompt is sent. | Yes | System message conversion | Supports optimizing prompt content before the prompt is sent. |
| Session compression | experimental.session.compacting | Triggered before context compression starts. | Yes | Chat compression | Supports customizing the compression prompt before context compression is executed. |
| Text completion | experimental.text.complete | Triggered when text completion finishes. | Yes | Text completion result customization | Supports modifying the output content after text completion is completed. |
| Configuration loading | config | Triggered when application startup configurations are loaded. | No | Configuration loading | Performs configuration initialization and dynamic parameter injection and is triggered during the loading of custom configurations. |
| Common event | event | Triggered when all Bus events are subscribed to. | No | Event processing | Processes common events. |
Writing an Example
This section describes how to create a user-level hook.
The following example shows how to create a JsonFormatPlugin. The plugin can automatically format a compressed JSON file in which the content is squeezed in one line. After that, the content in the file is indented by two spaces.
- Go to the ~\.codeartsdoer\plugin directory and create and edit the JsonFormatPlugin.ts file.
// Import the plugin type to define the plugin. import type { Plugin } from "@opencode-ai/plugin" // Import the file system module to read and write disk files. import { readFileSync, writeFileSync } from "fs" // Export the plugin implementation. Plugin is an asynchronous function that receives plugin input parameters and returns a hook object. export const JsonFormatPlugin: Plugin = async ({}) => { return { // Listen to the hook after the tool is executed. This function is triggered after the tool execution is complete. "tool.execute.after": async ( // Input parameters include the tool name, session ID, call ID, and other parameters. input: { tool: string; sessionID: string; callID: string; args: any }, // Output parameters include the title, output, and metadata of the tool execution result. output: { title: string; output: string; metadata: any }, ) => { if (input.tool !== "read") return // Obtain the file path. Only .json files are processed. const filePath = input.args?.filePath || input.args?.[0] || "" if (!filePath.endsWith(".json")) return try { const raw = readFileSync(filePath, "utf-8").trim() const parsed = JSON.parse(raw) const formatted = JSON.stringify(parsed, null, 2) + "\n" if (formatted === raw) return // Write the formatted content back to the disk file. writeFileSync(filePath, formatted, "utf-8") } catch {} }, } } - Go to the project folder, create and compile a compressed test file named test-plugin.json.
{"plugin":"JsonFormatPlugin","test":{"input":"Compressed single-line JSON file","output":"Formatted multi-line JSON file"}}Figure 1 Before formatting
- Run the required command based on the development mode:
- In TUI development mode, enter the following command in the TUI dialog box and press Enter:
Read test-plugin.json
- In CLI development mode, run the following command:
codearts run "Read test-plugin.json"
Figure 2 Command in CLI development mode
- In TUI development mode, enter the following command in the TUI dialog box and press Enter:
- After the command is executed, the test-plugin.json file is automatically formatted with proper line breaks and indentation. When the same file is read again, it will not be processed again because it has already been formatted.
Open the target JSON file. You will find that the JSON file has been formatted.
Figure 3 Formatted file
Feedback
Was this page helpful?
Provide feedbackThank you very much for your feedback. We will continue working to improve the documentation.See the reply and handling status in My Cloud VOC.
For any further questions, feel free to contact us through the chatbot.
Chatbot