Updated on 2026-07-30 GMT+08:00

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.

Table 1 Plug-in file loading paths

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.

Table 2 Supported hook events

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.

  1. 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 {}
        },
      }
    }

  2. 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

  3. 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

  4. 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