# 3.3 Project Interface V2

> **Note:** This document is about the creation and usage of `ProjectInterface`.
>
> In this document, **PI** refers to `ProjectInterface` and **Client** refers to the tool that can process PI.

## Introduction

The so-called `ProjectInterface` is a standardized project structure declaration for MaaFramework. It currently consists of a single file, `interface.json`. By defining a PI, you can leverage various derivative tools of MaaFramework. Therefore, even if you intend to integrate solely using a general-purpose programming language, it is recommended to define a PI containing the basic information.

> [!TIP]
>
> You can find general UI and other tools that use PI in the [Community Projects](https://github.com/MaaXYZ/MaaFramework/blob/main/README_en.md#community-project) section.

### Version Notes

Due to the rapid iteration of business development, the release schedule of MaaFramework cannot be properly aligned with the iteration pace of the PI. Therefore, PI will have its own separate version control, and its version number will not be completely synchronized with the MaaFramework release version number.

We have designated the version number for the independent release (January 30, 2026) as `v2.1.0`. Subsequent additions and fixes will be marked with version numbers in the documentation.

| Date       | Version | Changes |
| ---------- | ------- | ------- |
| 2026-01-30 | v2.1.0  | Standalone release |
| 2026-01-30 | v2.2.0  | Added `attach_resource_path` and `import` fields |
| 2026-02-23 | v2.3.0  | Added `checkbox` multi-select type, `option.controller`, `option.resource`, global/resource/controller-level options, `focus.display` display channel tag, `preset` field, `import` supports importing `preset` |
| 2026-03-05 | v2.3.1  | Clarified option applicability filtering |
| 2026-03-09 | v2.4.0  | Added top-level `group` declarations and `task.group` task grouping |
| 2026-03-23 | v2.5.0  | Convention for `PI_*` environment variables when the Client starts Agent subprocesses (UI / Client metadata and the selected controller and resource with i18n resolved) |
| 2026-04-18 | v2.6.0  | Added `resource.hash` resource integrity check field |

## `interface.json`

> [!TIP]
>
> This file can be validated and receive hints via the [schema](https://github.com/MaaXYZ/MaaFramework/blob/main/tools/interface.schema.json) file.
>
> When opening the project template folder with VSCode, the schema and file will be automatically associated.

### Overall Structure

- **interface_version** `number`  
  The interface version number, currently 2, fixed and required. Identifies the **major JSON schema version** of `interface.json`. The PI documentation also uses an independent semantic version (e.g. v2.5.0 for the environment-variable convention); the two are not required to match.

- **languages** `object`  
  Multi-language support configuration. Keys are language codes, values are paths to corresponding translation files. If not specified, only Chinese is supported by default.  
  File paths are relative to the directory containing interface.json.

  ```jsonc
  "languages": {
      "zh_cn": "interface_zh.json",
      "en_us": "interface_en.json"
  }
  ```

- **name** `string`  
  The unique project identifier, used as the project ID.

- **label** `string`  
  The project display name, shown in the user interface. Supports internationalized strings (starting with `$`). If not set, the value of the `name` field is displayed. _Optional._

  ```jsonc
  {
    "name": "MyProject",
    "label": "$project_name"  // Internationalized project name
  }
  ```

- **title** `string`  
  The window title. The Client will display this content directly without additional decoration. _Optional_, defaults to a combination of `name` and `version`. Supports internationalization (starting with `$`).

- **icon** `string`  
  The application icon file path, relative to the project root directory. If not specified, the default icon is used. Supports internationalization (starting with `$`).

- **mirrorchyan_rid** `string`  
  MirrorChyan resource package identifier, used for resource management and distribution.

- **mirrorchyan_multiplatform** `boolean`  
  Whether multi-platform is supported, affecting resource package packaging and distribution strategies.

- **github** `string`  
  The project's GitHub repository URL, used for version update checking and issue feedback.  
  **Software Update Convention:**  
  ~~After painful lessons from version history,~~ we expect general-purpose UIs to only provide update functionality for this GitHub release, not separate updates for the UI itself or MaaFW.  
  Resource authors should package their specified UI/MaaFW when releasing, ensuring that a specific resource version on the user side corresponds to a unique UI and MaaFW version, avoiding various issues caused by version mixing.

- **version** `string`  
  The project version number. The Client can display it to users and use it for version update checking.

- **contact** `string`  
  Contact information, displayed on the "About" page. Supports file paths, URLs, or direct text. Content supports Markdown format. Supports internationalization (starting with `$`).

- **license** `string`  
  Project license information, displayed on the "About" page. Supports file paths, URLs, or direct text. Content supports Markdown format. Supports internationalization (starting with `$`).

- **welcome** `string`  
  Welcome message, displayed in a popup when the user first uses the application, can also be used as an announcement. Supports file paths, URLs, or direct text. Content supports Markdown format. The system records the displayed content and will show the popup again when the content is updated. Supports internationalization (starting with `$`).

- **description** `string`  
  Project description information, displayed on the "About" page. Supports file paths, URLs, or direct text. Content supports Markdown format. Supports internationalization (starting with `$`).

- **controller** `object[]`  
  Controller configuration, an array of objects containing preset controller information.

  - **name** `string`  
    Unique name identifier, used as the controller ID.

  - **label** `string`  
    Display name, shown in the user interface. Supports internationalized strings (starting with `$`). If not set, the value of the `name` field is displayed.

  - **description** `string`  
    Detailed controller description. Supports file paths, URLs, or direct text. Content supports Markdown format. _Optional._ Supports internationalization (starting with `$`).

  - **icon** `string`  
    Controller icon file path, relative to the project root directory. _Optional._ Supports internationalization (starting with `$`).

  - **type** `'Adb' | 'Win32' | 'MacOS' | 'PlayCover' | 'Gamepad' | 'WlRoots'`  
    Controller type; valid values are `Adb`, `Win32` (Windows only), `MacOS` (macOS only), `PlayCover` (macOS only), `Gamepad` (Windows only),
    and `WlRoots` (Linux only).

  - **display_short_side** `number`  
    The short side length of the default scaled resolution, used for screen adaptation. _Optional_, defaults to 720. Mutually exclusive with `display_long_side` and `display_raw`.

  - **display_long_side** `number`  
    The long side length of the default scaled resolution, used for screen adaptation. _Optional._ Mutually exclusive with `display_short_side` and `display_raw`.

  - **display_raw** `boolean`  
    Whether to use the original resolution for screenshots without scaling. _Optional_, defaults to false. Mutually exclusive with scaled resolution settings.

  - **permission_required** `boolean`  
    Whether this controller requires running with administrator privileges. _Optional_, defaults to false.  
    Before running tasks, if the current process is not elevated, it will prompt and try to restart itself as an administrator.

  - **attach_resource_path** `string[]` **💡 v2.2.0**  
    _Optional._ An array of additional resource paths. These paths will be loaded after `resource.path` has finished loading.

  - **option** `string[]` **💡 v2.3.0**  
    _Optional._ Controller-level option configuration, an array of strings. Array elements should correspond to the key names in the outer `option` configuration. The parameters generated by this option will participate in the pipeline override of all tasks that use this controller, serving as controller-level parameter passing.  
    If a referenced option does not satisfy the current controller/resource constraints, that option's `pipeline_override` (including nested `option.option`) must not be merged. **💡 v2.3.1**

  - **adb** `object`  
    Specific configuration for the `Adb` controller.

    > **Note:** In V2 protocol, the input/screencap methods for Adb controllers are automatically detected and selected by MaaFramework, no manual configuration required.

  - **win32** `object`  
    Specific configuration for the `Win32` controller.

    - **class_regex** `string`  
      _Optional._ The regular expression used to search for window class names by the Win32 controller.

    - **window_regex** `string`  
      _Optional._ The regular expression used to search for window titles by the Win32 controller.

    - **mouse** `string`  
      _Optional._ The mouse control method for the Win32 controller. If not provided, the default is used. See [Control Methods](2.4-ControlMethods.md#win32-input) for details.

    - **keyboard** `string`  
      _Optional._ The keyboard control method for the Win32 controller. If not provided, the default is used. See [Control Methods](2.4-ControlMethods.md#win32-input) for details.

    - **screencap** `string`  
      _Optional._ The screenshot method for the Win32 controller. If not provided, the default is used. See [Control Methods](2.4-ControlMethods.md#win32-screencap) for details.

  - **macos** `object`  
    Specific configuration for the `MacOS` controller.

    - **title_regex** `string`  
      _Optional._ The regular expression used to search for window titles by the MacOS controller.

    - **screencap** `string`  
      _Optional._ The screenshot method for the MacOS controller. If not provided, the default is used. See [Control Methods](2.4-ControlMethods.md#macos-screencap) for details.

    - **input** `string`  
      _Optional._ The input control method for the MacOS controller. If not provided, the default is used. See [Control Methods](2.4-ControlMethods.md#macos-input) for details.

  - **playcover** `object`  
    Specific configuration for the `PlayCover` controller (macOS only). Used to control iOS applications running via PlayCover. See [Control Methods](2.4-ControlMethods.md#playcover-macos) for details.

    - **uuid** `string`  
      Optional. The Bundle Identifier of the target application. If not provided, the default `maa.playcover` will be used. This is only used as a controller identifier and is unrelated to the application being controlled.

  - **gamepad** `object`  
    Specific configuration for the `Gamepad` controller (Windows only). Used to create a virtual gamepad for game control. Requires [ViGEm Bus Driver](https://github.com/ViGEm/ViGEmBus) to be installed. See [Control Methods](2.4-ControlMethods.md#gamepad-windows) for details.

    - **class_regex** `string`  
      _Optional._ The regular expression used to search for window class names by the Win32 controller.

    - **window_regex** `string`  
      _Optional._ The regular expression used to search for window titles by the Win32 controller.

    - **gamepad_type** `string`  
      _Optional._ The virtual gamepad type. Valid values are `Xbox360`, `DualShock4` (or `DS4`). If not provided, `Xbox360` is used by default.

    - **screencap** `string`  
      _Optional._ The screenshot method. If not provided, the default is used. Only effective when window regex is configured. See [Control Methods](2.4-ControlMethods.md#win32-screencap) for details.

  - **wlroots** `object`  
    Specific configuration for the `WlRoots` controller.

    - **use_win32_vk_code** `bool`
      _Optional._ When `true`, key codes are interpreted as Win32 Virtual-Key codes and translated to Linux evdev codes internally; when `false`, they are passed through as raw evdev codes. Default is `false`.

- **resource** `object[]`  
  Resource configuration, an array of objects containing information about resource loading.

  - **name** `string`  
    Unique name identifier, used as the resource package ID.

  - **label** `string`  
    Display name, shown in the user interface. Supports internationalized strings (starting with `$`). If not set, the value of the `name` field is displayed. _Optional._

  - **description** `string`  
    Detailed resource description. Supports file paths, URLs, or direct text. Content supports Markdown format. _Optional._

  - **icon** `string`  
    Resource icon file path, relative to the project root directory. _Optional._ Supports internationalization (starting with `$`).

  - **path** `string[]`  
    An array of paths to load. If multiple paths are provided, they will be loaded sequentially; resources loaded later will [override](#resource-override) those loaded earlier.  
    File paths are relative to the directory containing interface.json.  
    **Note:** Resources include not only `pipeline` but also `image` and `model`. Therefore, do not specify the `pipeline` directory directly.

  - **controller** `string[]`  
    _Optional._ Specifies the list of controller types supported by this resource package. Array elements should correspond to the `name` field in the `controller` configuration. If not specified, all controller types are supported.

    When a user selects a controller, only resource packages that support that controller will be displayed in the user interface for selection. This allows providing specially optimized resource packages for different controller types.
  
  - **option** `string[]`  
    _Optional._ Resource-level option configuration, an array of strings. Array elements should correspond to the key names in the outer `option` configuration. The parameters generated by this option will participate in the pipeline override of all tasks, serving as resource-level parameter passing.  
    If a referenced option does not satisfy the current controller/resource constraints, that option's `pipeline_override` (including nested `option.option`) must not be merged. **💡 v2.3.1**

  - **hash** `string` **💡 v2.6.0**  
    _Optional._ Resource integrity check value. This should be the hash string obtained via `MaaResourceGetHash` after loading only `path`.  
    Verification should occur after loading `path` but before loading `controller.attach_resource_path`.  
    If the actual hash does not match, a warning should be shown to the user (e.g. suggest re-downloading the resource package) without preventing continued use.  
    Debug builds (e.g. pre-release versions) may skip this check. If this field is not set, no verification is needed.

    ```jsonc
    "resource": [
        {
            "name": "AndroidSpecificResource",
            "label": "$AndroidSpecificResource",
            "controller": ["Android"],
            "path": ["resource_android"]
        },
        {
            "name": "GeneralResource",
            "label": "$GeneralResource",
            "path": ["resource"],
            "hash": "1a2b3c4d"
        }
    ]
    ```

- **agent** `object | object[]`  
  Agent configuration; it can be a single object or an array of objects, containing information about the subprocess(es) (AgentServer). Supports configuring multiple Agents simultaneously for more complex automation scenarios.  
  From **v2.5.0** onward, the Client should also inject environment variables with the `PI_` prefix when starting this subprocess, as described in [Agent subprocess environment variables](#agent-subprocess-env-v25) below.

  - **child_exec** `string`  
    The subprocess path, an executable file available in the system path. For example, if the Python path exists in the environment variables (system or user), you can simply write `"python"`.  
    CWD is the directory containing interface.json.

  - **child_args** `string[]`  
    _Optional._ An array of arguments for the subprocess.

  - **identifier** `string`  
    _Optional._ A connection identifier used to create a communication socket. If provided, it will be used; otherwise, one is created automatically.

  **Single Agent Example:**

  ```jsonc
  "agent": {
      "child_exec": "python",
      "child_args": [
          "./agent/main.py",              // Note: CWD is the directory containing interface.json
          "--test-mode"                   // Fixed string, passed as-is
      ]
  }
  ```

  **Multiple Agents Example:**

  ```jsonc
  "agent": [
      {
          "child_exec": "python",
          "child_args": ["./agent/recognition.py"]
      },
      {
          "child_exec": "python",
          "child_args": ["./agent/action.py"]
      }
  ]
  ```

<a id="agent-subprocess-env-v25"></a>

### Agent subprocess environment variables **💡 v2.5.0**

When the Agent runs in a separate process from the MaaFramework host, the child process has no automatic access to the general UI’s name and version, UI language, or which controller and resource package the user selected—information that is also not exposed through ordinary MaaFW C API callbacks. To let custom recognition/action logic read **Client-side context** and a **runtime snapshot of the current PI selection**, the **Client** should set the following environment variables when starting the `agent` subprocess (names in uppercase; values are strings).

| Variable | Description |
| -------- | ----------- |
| `PI_INTERFACE_VERSION` | Semantic version string of the PI **extension surface** implemented by the Client (e.g. `v2.5.0`). The child may use this to detect available variables or behaviors; **do not** confuse this with the numeric `interface_version` field in `interface.json` (currently fixed at `2`). |
| `PI_CLIENT_NAME` | Identifier of the general UI / Client, e.g. `MFAA`, `MXU`, `VSCODE`, `MPE`, `MaaDebugger`. |
| `PI_CLIENT_VERSION` | The Client’s own version (semantic version string as defined by the Client). |
| `PI_CLIENT_LANGUAGE` | Current UI language code, e.g. `zh_cn`, `en_us` (aligned with `languages` keys or Client convention). |
| `PI_CLIENT_MAAFW_VERSION` | MaaFramework library version bundled or used by the Client (semantic version string). |
| `PI_VERSION` | Same as the top-level `version` field in `interface.json` (resource project version). |
| `PI_CONTROLLER` | **Single-line JSON string**: the full object for the **currently selected** `controller` array entry. All i18n-capable fields (e.g. `label`, `description`) should already be resolved to **final display text**, without `$`-prefixed translation keys. |
| `PI_RESOURCE` | **Single-line JSON string**: the full object for the **currently selected** `resource` array entry, with i18n resolved likewise; use compact JSON (no newlines) so it fits environment variable limits. |

**Notes:**

- If a value is unavailable, the Client may omit the variable or set it empty; the child should tolerate missing variables.
- `PI_CONTROLLER` / `PI_RESOURCE` describe the **current selection** only. If the user switches controller or resource at runtime, the Client should update the environment when restarting the subprocess or at another agreed time (restart policy is implementation-defined).
- Values must respect OS limits on environment variable size and character set; JSON should be minified.

**Example (illustrative; actual values are single lines):**

```text
PI_INTERFACE_VERSION=v2.5.0
PI_CLIENT_NAME=MFAA
PI_CLIENT_VERSION=v1.0.0
PI_CLIENT_LANGUAGE=zh_cn
PI_CLIENT_MAAFW_VERSION=v5.9.0
PI_VERSION=v2.2.0
PI_CONTROLLER={"name":"Win32-Window","label":"Win32-默认","description":"默认控制器","type":"Win32","win32":{"class_regex":"UnityWndClass","window_regex":"Endfield","screencap":"Background","mouse":"SendMessageWithCursorPos","keyboard":"PostMessage"},"permission_required":true}
PI_RESOURCE={"name":"官服","label":"官服","path":["./resource"]}
```

- **group** `object[]` **💡 v2.4.0**  
  _Optional._ Task group declarations, an array of objects. Used to declare task groups and their display attributes.

  - **name** `string`  
    Unique group identifier, used as the group ID. Tasks will reference this name via `task.group`.

  - **label** `string`  
    Group display name, shown in the user interface. Supports internationalized strings (starting with `$`). If not set, the value of the `name` field is displayed. _Optional._

  - **description** `string`  
    Detailed group description to help users understand the purpose of this group. Supports file paths, URLs, or direct text. Content supports Markdown format. _Optional._

  - **icon** `string`  
    Group icon file path, relative to the project root directory. Used for display in the user interface. _Optional._ Supports internationalization (starting with `$`).

  - **default_expand** `boolean`  
    _Optional_, defaults to `true`. Whether this group is expanded by default in the Client.

  ```jsonc
  "group": [
      {
          "name": "daily",
          "label": "$DailyTasks",
          "description": "$DailyTasksDesc",
          "icon": "groups/daily.png",
          "default_expand": true
      },
      {
          "name": "battle",
          "label": "$BattleTasks"
      }
  ]
  ```

- **task** `object[]`  
  Task configuration, an array of objects containing information about executable tasks.

  - **name** `string`  
    Unique task identifier, used as the task ID.

  - **label** `string`  
    Task display name, shown in the user interface. Supports internationalized strings (starting with `$`). If not set, the value of the `name` field is displayed. _Optional._

  - **entry** `string`  
    The task entry, which is the name of the `Task` in the `pipeline`.

  - **default_check** `boolean`  
    Whether this task is selected by default. _Optional_, defaults to false. The Client will use this value to determine whether to check this task by default during initialization.

  - **description** `string`  
    Detailed task description to help users understand the task's functionality. Supports file paths, URLs, or direct text. Content supports Markdown format. _Optional._

  - **icon** `string`  
    Task icon file path, relative to the project root directory. Used for display in the user interface. _Optional._ Supports internationalization (starting with `$`).

  - **group** `string[]` **💡 v2.4.0**  
    _Optional._ Specifies the list of groups this task belongs to. Array elements should correspond to the `name` field in the top-level `group` configuration. If not specified, this task does not belong to any explicit group.

    A task may belong to multiple groups at the same time. Clients should treat these entries as group memberships only; task identity, enabled state, preset references, and option values are still keyed by `task.name`.

    ```jsonc
    "task": [
        {
            "name": "CollectReward",
            "label": "$CollectReward",
            "entry": "CollectReward",
            "group": ["daily"]
        },
        {
            "name": "FarmStage",
            "label": "$FarmStage",
            "entry": "FarmStage",
            "group": ["daily", "battle"]
        }
    ]
    ```

  - **resource** `string[]`  
    _Optional._ Specifies the list of resource packages supported by this task. Array elements should correspond to the `name` field in the `resource` configuration. If not specified, this task is available in all resource packages.

    When a user selects a resource package, the Client may hide tasks that do not support that resource package, or display them in a disabled (grayed-out) state to inform the user. This allows providing specialized task configurations for different resource packages, such as event tasks that are only available in specific resource packages.

    ```jsonc
    "task": [
        {
            "name": "EventTask",
            "label": "$EventTask",
            "entry": "ActivityTask",
            "resource": ["Official"],
            "description": "Event task only available in the Official resource package"
        },
        {
            "name": "CommonTask",
            "label": "$CommonTask",
            "entry": "CommonTask"
        }
    ]
    ```

  - **controller** `string[]`  
    _Optional._ Specifies the list of controller types supported by this task. Array elements should correspond to the `name` field in the `controller` configuration. If not specified, this task is available for all controller types.

    When a user selects a controller, the Client may hide tasks that do not support that controller, or display them in a disabled (grayed-out) state to inform the user. This allows providing specialized task configurations for different controller types, such as tasks that are only available for Adb controllers or Win32 controllers.

    ```jsonc
    "task": [
        {
            "name": "AndroidOnlyTask",
            "label": "$AndroidOnlyTask",
            "entry": "AndroidSpecificTask",
            "controller": ["Android"],
            "description": "Task only available for Android controllers"
        },
        {
            "name": "Win32OnlyTask",
            "label": "$Win32OnlyTask",
            "entry": "Win32SpecificTask",
            "controller": ["Win32Emulator"],
            "description": "Task only available for Win32 controllers"
        },
        {
            "name": "CommonTask",
            "label": "$CommonTask",
            "entry": "CommonTask"
        }
    ]
    ```

  - **pipeline_override** `pipeline`  
    _Optional._ Task parameters that [override](#resource-override) the loaded resources when executing the task. This structure is exactly the same as the JSON file in the `pipeline` and must include the task name part, for example:

    ```jsonc
    "pipeline_override": {
        "Quit": {
            "enabled": true
        }
    }
    ```

  - **option** `string[]`  
    _Optional._ Task configuration options, an array containing keys from subsequent `option` objects. The Client will prompt the user to make selections based on these.

    The Client can display the options in the order provided in the `option` array.

- **option** `record<string, object>`  
  Definition of configuration options, an object mapping containing information about each option.

  - _**key**_  
    Unique name identifier; tasks will reference this name.

  - **type** `string`  
    The option type. _Optional_, defaults to `"select"`. Valid values:  
    - `"select"`: Dropdown selection box, user selects one from predefined options  
    - `"checkbox"`: Multi-select box, user selects multiple from predefined options **💡 v2.3.0**  
    - `"input"`: User input field, allows manual input  
    - `"switch"`: Toggle switch, Yes or No

  - **controller** `string[]` **💡 v2.3.0**  
    _Optional._ Specifies the list of controller types this option applies to. Array elements should correspond to the `name` field in the `controller` configuration. If not specified, this option is available for all controller types.  
    When a user selects a controller, the Client may hide options that do not apply to that controller, or display them in a disabled (grayed-out) state to inform the user.  
    If the current controller is not in this list, the option is treated as inactive: all `pipeline_override` generated by this option and its sub-options (`option.option`) must be excluded from merging. **💡 v2.3.1**

  - **resource** `string[]` **💡 v2.3.0**  
    _Optional._ Specifies the list of resource packages this option applies to. Array elements should correspond to the `name` field in the `resource` configuration. If not specified, this option is available for all resource packages.  
    When a user selects a resource package, the Client may hide options that do not apply to that resource package, or display them in a disabled (grayed-out) state to inform the user.  
    If the current resource package is not in this list, the option is treated as inactive: all `pipeline_override` generated by this option and its sub-options (`option.option`) must be excluded from merging. **💡 v2.3.1**

  - **label** `string`  
    Option display label, shown in the user interface. Supports internationalized strings (starting with `$`). _Optional._

  - **description** `string`  
    Detailed option description to help users understand the option's purpose. Supports file paths, URLs, or direct text. Content supports Markdown format. _Optional._ Supports internationalization (starting with `$`).

  - **icon** `string`  
    Option icon file path, relative to the project root directory. _Optional._ Supports internationalization (starting with `$`).

  - **cases** `object[]`  
    Used only when `type` is `"select"`, `"checkbox"`, or `"switch"`. Available options, an array of objects containing information about each option.

    **Note:** When `type` is `"checkbox"`, the user can select multiple cases simultaneously. The `pipeline_override` of all selected cases will be merged in the order they appear in the `cases` array — regardless of the order in which the user checked them.

    **Note:** When `type` is `"switch"`, only two cases are supported, and the following rules must be followed:  
    - If `case.name` is one of `"Yes"`, `"yes"`, `"Y"`, or `"y"`, that case will be recognized as the **Yes option**  
    - If `case.name` is one of `"No"`, `"no"`, `"N"`, or `"n"`, that case will be recognized as the **No option**  
    - The Client will match the user's Y/N input based on the case's name, and other inputs will prompt the user to re-enter

    It is recommended to use `"Yes"` and `"No"` as the names of the two cases to ensure consistency across different Clients.

    The Client can display the options in the order provided in the `cases` array.

    - **name** `string`  
      Unique option identifier, used as the option ID.

    - **label** `string`  
      Option display name, shown in the user interface. Supports internationalized strings (starting with `$`). If not set, the value of the `name` field is displayed. _Optional._

    - **description** `string`  
      Detailed option description. Supports file paths, URLs, or direct text. Content supports Markdown format. _Optional._ Supports internationalization (starting with `$`).

    - **icon** `string`  
      Option icon file path, relative to the project root directory. _Optional._ Supports internationalization (starting with `$`).

    - **option** `string[]`  
      Sub-option list. _Optional._ These sub-options are only displayed when the user selects the current option. These sub-options are also defined in the outer `option` and support unlimited nesting.

    - **pipeline_override** `pipeline`  
      Same as the `pipeline_override` in the `task`. It takes effect when the option is activated.

  - **inputs** `object[]`  
    Used only when `type` is `"input"`. Input configuration, an array of objects defining user-inputtable fields.

    - **name** `string`  
      Unique input field identifier, used as the input field ID.

    - **label** `string`  
      Input field display name, shown in the user interface. Supports internationalized strings (starting with `$`). If not set, the value of the `name` field is displayed. _Optional._

    - **description** `string`  
      Detailed input field description to help users understand input requirements. Supports file paths, URLs, or direct text. Content supports Markdown format. _Optional._ Supports internationalization (starting with `$`).

    - **default** `string`  
      Default value for the input field. _Optional._

    - **pipeline_type** `string`  
      The data type of the input field in pipeline_override. Valid values: `"string"`, `"int"`, `"bool"`. When using variable substitution in pipeline_override, type conversion is performed according to this type.

    - **verify** `string`  
      Regular expression used to validate whether user input is valid. _Optional._

    - **pattern_msg** `string`  
      Message displayed when regex validation of user input fails. _Optional._ Supports internationalization (starting with `$`).

  - **pipeline_override** `pipeline`  
    Used when the option type is `"input"`, as a substitution template for user input content. Supports using `{name}` format in strings to reference input field values. _Optional._

  - **default_case** `string` | `string[]`  
    Default option name. _Optional._
    - When `type` is `"select"` or `"switch"`: provide a single string; the Client uses it as the initial selected value.
    - When `type` is `"checkbox"`: provide a string array; the Client uses it as the initial set of selected values. **💡 v2.3.0**

- **global_option** `string[]` **💡 v2.3.0**  
  _Optional._ Global option configuration, an array of strings. Array elements should correspond to key names in the `option` configuration.  
  The parameters generated by this option will participate in the pipeline override of all tasks, regardless of which resource package or controller the user has selected.  
  Unlike `resource.option` and `controller.option`, global options do not depend on any resource package or controller selection.  
  However, options referenced by `global_option` must still satisfy their own `resource` / `controller` constraints; otherwise, no `pipeline_override` is applied. **💡 v2.3.1**

  ```jsonc
  "global_option": [
      "BattleMode",
      "AutoDodge"
  ]
  ```

- **import** `string[]` **💡 v2.2.0**  
  _Optional._ An array of paths to other PI files to import. File paths are relative to the directory containing interface.json.  
  Supports importing `task`, `option`, and `preset` **💡 v2.3.0** fields from these files.  
  The Client will load these files sequentially and merge their contents with the current file, enabling configuration splitting and reuse.

- **preset** `object[]` **💡 v2.3.0**  
  _Optional._ Preset configurations, an array of objects. Each preset is a snapshot of predefined task checkbox states and option values. Users can apply a preset with a single click to quickly switch between different usage scenarios.

  - **name** `string`  
    Unique identifier, used as the preset ID.

  - **label** `string`  
    Display name, shown in the user interface. Supports internationalized strings (starting with `$`). If not set, the value of the `name` field is displayed. _Optional._

  - **description** `string`  
    Detailed preset description to help users understand the applicable scenario. Supports file paths, URLs, or direct text. Content supports Markdown format. _Optional._ Supports internationalization (starting with `$`).

  - **icon** `string`  
    Preset icon file path, relative to the project root directory. _Optional._ Supports internationalization (starting with `$`).

  - **task** `object[]`  
    List of task configurations included in this preset.

    - **name** `string`  
      Required. The task name corresponding to `task[].name` at the top level.

    - **enabled** `boolean`  
      _Optional_, defaults to `true`. Whether this task is checked in the preset.

    - **option** `record<string, OptionValue>`  
      _Optional._ Preset values for each option of this task. Keys are option key names from the top-level `option`. The `OptionValue` type depends on the corresponding `option.type`:

      | option.type | OptionValue type | Example |
      |---|---|---|
      | `select` / `switch` | `string` (`case.name`) | `"x3"` / `"Yes"` |
      | `checkbox` | `string[]` (array of `case.name`) | `["AutoBattle", "AutoPickup"]` |
      | `input` | `record<string, string>` (input field name → value) | `{ "ChapterNumber": "4" }` |

  **Preset Example:**

  ```jsonc
  "preset": [
      {
          "name": "DailyRoutine",
          "label": "$DailyRoutine",
          "description": "Daily routine: Wilderness + Insight + 3-9 + Claim Rewards",
          "icon": "preset_daily.png",
          "task": [
              { "name": "Collect Wilderness", "enabled": true },
              { "name": "Daily Insight (Will Analysis)", "enabled": true },
              {
                  "name": "Standard Combat",
                  "enabled": true,
                  "option": {
                      "BattleStage": "3-9 Dire (Lark)",    // select type: fill case.name
                      "RepeatCount": "x3",                  // select type: fill case.name
                      "DrainAllSanity": "No",               // switch type: fill case.name
                      "EnableFeatures": ["AutoBattle", "AutoPickup"]  // checkbox type: fill case.name array
                  }
              },
              { "name": "Claim Rewards", "enabled": true },
              { "name": "Event: Stage 17 Hard (Event Ended)", "enabled": false }
          ]
      },
      {
          "name": "RealtimeAssist",
          "label": "$RealtimeAssist",
          "description": "Background assist mode, only runs auto-assist tasks",
          "task": [
              {
                  "name": "Standard Combat",
                  "enabled": true,
                  "option": {
                      "EnableFeatures": ["AutoBattle", "AutoPickup", "AutoHeal"]
                  }
              }
          ]
      }
  ]
  ```

  **Managing presets across files via `import`:**

  Preset configurations can be split into separate files via `import` for easier management and reuse. For example:

  ```jsonc
  // interface.json
  {
      "import": [
          "preset_daily.json",
          "preset_realtime.json"
      ],
      "preset": [
          // Presets can also be defined directly in the main file and will be merged with imported presets
      ]
  }
  ```

  ```jsonc
  // preset_daily.json
  {
      "preset": [
          {
              "name": "DailyRoutine",
              "label": "$DailyRoutine",
              "description": "Daily routine package",
              "task": [
                  { "name": "Collect Wilderness", "enabled": true },
                  { "name": "Claim Rewards", "enabled": true }
              ]
          }
      ]
  }
  ```

### Option Override Order **💡 v2.3.0**

The `pipeline_override` generated by each level of option is merged in the following order — **later-merged fields override earlier ones with the same key name**:

1. `global_option` — global options, applied first, lowest priority
2. `resource.option` — resource-level options
3. `controller.option` — controller-level options
4. `task.option` — task-level options, applied last, highest priority

In other words: `task.option` > `controller.option` > `resource.option` > `global_option`.

Before applying the merge order above, inactive options must be filtered out. Any option that does not satisfy the current `controller` / `resource` constraints (including options referenced by `global_option`, `resource.option`, `controller.option`, `task.option`, and nested `option.option`) must not generate `pipeline_override`. **💡 v2.3.1**

The reasoning behind this design is that more specific configuration (task-level) should have higher priority, while more general configuration (global-level) serves as the fallback default.

**Example:**

If both `global_option` and a `task.option` reference the same option, and that option's cases make different overrides to the same pipeline node, the task-level override will take final effect.

### Option Examples

#### Select Type Option Example

```jsonc
{
  "option": {
    "BattleStage": {
      "type": "select",
      "label": "$SelectBattleStage",
      "description": "Select the stage to farm",
      "default_case": "3-9 Dire",
      "cases": [
        {
          "name": "3-9 Dire (Lark)",
          "label": "$3-9Dire",
          "description": "Farm Lark",
          "icon": "lark.png",
          "option": [
            "UseSanityPotion",
            "AfterFarmingXXX"
          ],
          "pipeline_override": {
            "EnterTheShow": {
              "next": "MainChapter_3"
            }
          }
        }
      ]
    }
  }
}
```

#### Input Type Option Example

```jsonc
{
  "option": {
    "CustomStage": {
      "type": "input",
      "label": "Custom Stage",
      "description": "Choose which stage to play",
      "icon": "wrench.png",
      "inputs": [
        {
          "name": "ChapterNumber",
          "label": "$ChapterNumber",
          "description": "Stage chapter number, use Arabic numerals",
          "default": "4",
          "pipeline_type": "string",
          "verify": "^\\d+$"
        },
        {
          "name": "Timeout",
          "label": "$Timeout",
          "description": "Wait timeout duration",
          "default": "20000",
          "pipeline_type": "int",
          "verify": "^\\d+$"
        }
      ],
      "pipeline_override": {
        "EnterTheShow": {
          "next": "MainChapter_{ChapterNumber}",
          "timeout": "{Timeout}"
        }
      }
    }
  }
}
```

#### Checkbox Type Option Example 💡 v2.3.0

```jsonc
{
  "option": {
    "BattleFeatures": {
      "type": "checkbox",
      "label": "$BattleFeatures",
      "description": "Select the battle features to enable, multiple selections allowed",
      "default_case": ["NormalStrike", "ChargedStrike"],
      "cases": [
        {
          "name": "NormalStrike",
          "label": "$NormalStrike",
          "description": "Enable normal strike",
          "pipeline_override": {
            "NormalMatch": {
              "enabled": true
            }
          }
        },
        {
          "name": "ChargedStrike",
          "label": "$ChargedStrike",
          "description": "Enable charged strike",
          "pipeline_override": {
            "ChargedMatch": {
              "enabled": true
            }
          }
        },
        {
          "name": "ComboStrike",
          "label": "$ComboStrike",
          "description": "Enable combo strike",
          "pipeline_override": {
            "ComboMatch": {
              "enabled": true
            }
          }
        }
      ]
    }
  }
}
```

> **Note:** In `checkbox` type, the `pipeline_override` of multiple selected cases is merged in the **definition order** of the `cases` array — regardless of the order in which the user checked them.

### Internationalization Support

For all string fields that support internationalization, if the string starts with `$`, it indicates that the string is an internationalized string. The Client needs to read the actual value from the translation file before displaying it.

For example:

```jsonc
{
  "name": "MyDemo3",
  "label": "$MyDemo3",
  "controller": [
    {
      "name": "Android",
      "label": "$Android"
    }
  ]
}
```

Corresponding translation file (e.g., `interface_en.json`):

```jsonc
{
  "MyDemo3": "My Demo 3",
  "Android": "Android Device"
}
```

### Resource Override

If a later-loaded resource contains a task with the same name as one already loaded, the tasks will be merged. Generally, the top-level keys of the new task will replace those of the old task. For example:

Old Task

```jsonc
{
    "task1": {
        "enabled": false,
        "recognition": "DirectHit",
        "next": [ "T1", "T2" ]
    }
}
```

New Task

```jsonc
{
    "task1": {
        "enabled": true,
        "action": "Click",
        "next": [ "T2", "T3" ]
    }
}
```

Merged Task

```jsonc
{
    "task1": {
        "enabled": true,
        "recognition": "DirectHit",
        "action": "Click",
        "next": [ "T2", "T3" ]       // Direct replacement; inner arrays/lists are not merged.
    }
}
```

### Node Notification Handling

MaaFramework sends node notifications via callback functions during task execution. The Client needs to implement the corresponding handling logic to display task execution status to users.

#### Callback Function Signature

The Client needs to register a callback function to receive notifications. For the function signature, refer to [MaaDef.h](https://github.com/MaaXYZ/MaaFramework/blob/main/include/MaaFramework/MaaDef.h):

```c
typedef void(MAA_CALL* MaaEventCallback)(
    void* handle,
    const char* message,
    const char* details_json,
    void* trans_arg
);
```

- **message**: Message type identifier (e.g., `Node.Action.Starting`, `Node.Recognition.Succeeded`, etc.)
- **details_json**: JSON string containing specific data

#### Message Template Mechanism

Resource authors can configure message templates in the Pipeline using the `focus` field. The `focus` field is a dictionary where keys are message types and values are template strings or template objects. Template strings support file paths, URLs, or direct text, content supports Markdown format, and support internationalization (starting with `$`). When the Client receives a callback, it should perform placeholder replacement based on the template and display the result to users via the specified channel.

##### Two Forms of `focus` Values

**Shorthand (plain string):** Equivalent to `display: "log"` — content is only shown in the run log.

```jsonc
"focus": {
    "Node.Action.Starting": "{name} starts execution"
}
```

**Full form (object):** Use the `display` field to specify the display channel. **💡 v2.3.0**

```jsonc
"focus": {
    "Node.Action.Starting": {
        "content": "{name} starts execution",
        "display": "toast"
    }
}
```

##### `display` Values **💡 v2.3.0**

| Value | Description | Behavior |
|----|------|----------|
| `"log"` | Run log (**default**) | Appended to the log stream, non-interrupting |
| `"toast"` | In-app lightweight notification | Briefly appears then auto-dismisses, non-blocking |
| `"notification"` | System-level notification | Pushed to OS notification center, received even when app is in background |
| `"dialog"` | Non-blocking dialog | Popup message box, task pipeline **continues running** in the background |
| `"modal"` | Blocking popup | Task is **paused** until the user confirms — suitable for scenarios requiring manual intervention |

`display` supports arrays so the same message can be pushed to multiple channels simultaneously:

```jsonc
"focus": {
    "Node.Action.Succeeded": {
        "content": "✅ {name} executed successfully",
        "display": ["log", "toast"]
    },
    "Node.Action.Failed": {
        "content": "❌ Execution failed, please check the environment",
        "display": ["log", "modal"]
    }
}
```

**Complete Pipeline Configuration Example:**

```jsonc
{
  "NodeA": {
    "focus": {
      "Node.Recognition.Succeeded": "{name} recognition hit, ready to start execution",
      "Node.Action.Starting": {
        "content": "{name} starts execution, task ID: {task_id}",
        "display": ["log", "toast"]
      },
      "Node.Action.Failed": {
        "content": "{name} execution failed",
        "display": "modal"
      }
    }
  }
}
```

**Callback Function Parameters Example:**

```c
// message parameter:
"Node.Action.Starting"

// details_json parameter (after parsing):
{
    "task_id": 12345,
    "action_id": 11111,
    "name": "NodeA",
    "focus": {
        "Node.Recognition.Succeeded": "{name} recognition hit, ready to start execution",
        "Node.Action.Starting": {
            "content": "{name} starts execution, task ID: {task_id}",
            "display": ["log", "toast"]
        },
        "Node.Action.Failed": {
            "content": "{name} execution failed",
            "display": "modal"
        }
    }
}
```

#### Client Processing Flow

1. Parse the `details_json` parameter in the callback function
2. Check if the parsed object contains a `focus` field
3. If present, find the corresponding template (string or object) in `focus` based on the `message` parameter
4. If the template is a string, treat it as `content` and set `display` to `["log"]`; if it is an object, read `content` and `display` separately
5. Replace placeholders in `content` (e.g., `{name}`, `{task_id}`) with data from `details_json`
6. Display the processed text to the user via the channel(s) specified in `display` (may be multiple) **💡 v2.3.0**

Using the example above, upon receiving `Node.Action.Starting`, the Client should append to the log and show a toast: `NodeA starts execution, task ID: 12345`

#### More Message Types

For a complete list of callback messages and detailed descriptions, please refer to [Callback Protocol](2.3-CallbackProtocol.md) and [MaaMsg.h](https://github.com/MaaXYZ/MaaFramework/blob/main/include/MaaFramework/MaaMsg.h).
