Skill: yzswk/ima-skills-1-0-4 (version 1.0.0)

--- name: ima-note description: | IMA 个人笔记服务 API skill，用于管理用户的 IMA 笔记。支持搜索笔记、浏览笔记本、获取笔记内容、新建笔记和追加内容。 当用户提到笔记、备忘录、记事、知识库，或者想要查找、阅读、创建、编辑笔记内容时，使用此 skill。 即使用户没有明确说"笔记"，只要意图涉及个人文档的存取（如"帮我记一下"、"我之前写过一个关于XX的东西"、"把这段内容保存下来"），也应触发此 skill。 homepage: https://ima.qq.com metadata: { "openclaw": { "emoji": "📝", "requires": { "env": ["IMA_OPENAPI_CLIENTID", "IMA_OPENAPI_APIKEY"] }, "primaryEnv": "IMA_OPENAPI_CLIENTID" }, } --- # ima-note 通过 IMA OpenAPI 管理用户个人笔记，支持读取（搜索、列表、获取内容）和写入（新建、追加）。 完整的数据结构和接口参数详见 `references/api.md`。 ## Setup 1. 请打开 https://ima.qq.com/agent-interface 获取 **Client ID** 和 **Api Key** 2. 配置环境变量： ```bash export IMA_OPENAPI_CLIENTID="your_client_id" export IMA_OPENAPI_APIKEY="your_api_key" ``` > 建议将上述 export 语句写入 `~/.zshrc` 或 `~/.bashrc`，避免每次重开终端失效。 ## 凭证预检 每次调用 API 前，先确认凭证可用。如果环境变量未设置，停止操作并提示用户按 Setup 步骤配置。 ```bash if [ -z "$IMA_OPENAPI_CLIENTID" ] || [ -z "$IMA_OPENAPI_APIKEY" ]; then echo "缺少 IMA 凭证，请按 Setup 步骤配置环境变量 IMA_OPENAPI_CLIENTID 和 IMA_OPENAPI_APIKEY" exit 1 fi ``` ## API 调用模板 所有请求统一为 **HTTP POST + JSON Body**，Base URL 为 `https://ima.qq.com/openapi/note/v1`。 定义辅助函数避免重复 header： ```bash ima_api() { local endpoint="$1" body="$2" curl -s -X POST "https://ima.qq.com/openapi/note/v1/$endpoint" \ -H "ima-openapi-clientid: $IMA_OPENAPI_CLIENTID" \ -H "ima-openapi-[REDACTED_SECRET]" \ -H "Content-Type: application/json" \ -d "$body" } ``` > **隐私规则：** 笔记内容属于用户隐私，在群聊场景中只展示标题和摘要，禁止展示笔记正文。 ## 接口决策表 | 用户意图 | 调用接口 | 关键参数 | |---------|---------|---------| | 搜索/查找笔记 | `search_note_book` | `query_info`（QueryInfo 对象） | | 查看笔记本列表 | `list_note_folder_by_cursor` | `cursor`(必填，首页传`"0"`) + `limit`(必填) | | 浏览某笔记本里的笔记,当用户表述"最新"、"最近"之类的通用限定，没有指明笔记本时，都应该直接在全部笔记里去拉 | `list_note_by_folder_id` | `folder_id`(选填,空为全部笔记本) + `cursor`(必填，首次传`""`) + `limit`(必填) | | 读取笔记正文 | `get_doc_content` | `doc_id` + `target_content_format`(必填，推荐`0`纯文本) | | 新建一篇笔记 | `import_doc` | `content` + `content_format`(必填，固定`1`) + 可选 `folder_id` | | 往已有笔记追加内容 | `append_doc` | `doc_id` + `content` + `content_format`(必填，固定`1`) | ## 常用工作流 ### 查找并阅读笔记 先搜索获取 `docid`，再用 `get_doc_content` 读取正文： ```bash # 1. 按标题搜索 ima_api "search_note_book" '{"search_type": 0, "query_info": {"title": "会议纪要"}, "start": 0, "end": 20}' # 从返回的 docs[].doc.basic_info.docid 中取目标笔记 ID # 2. 读取正文（纯文本格式，Markdown 格式目前不支持） ima_api "get_doc_content" '{"doc_id": "目标docid", "target_content_format": 0}' ``` ### 浏览笔记本里的笔记 先拉笔记本列表获取 `folder_id`，再拉该笔记本下的笔记： ```bash # 1. 列出笔记本（首页 cursor 传 "0"） ima_api "list_note_folder_by_cursor" '{"cursor": "0", "limit": 20}' # 2. 拉取指定笔记本的笔记（首页 cursor 传 ""） ima_api "list_note_by_folder_id" '{"folder_id": "user_list_xxx", "cursor": "", "limit": 20}' ``` ### 新建笔记 ```bash # 新建到默认位置 ima_api "import_doc" '{"content_format": 1, "content": "# 标题\n\n正文内容"}' # 新建到指定笔记本 ima_api "import_doc" '{"content_format": 1, "content": "# 标题\n\n正文内容", "folder_id": "笔记本ID"}' # 返回 doc_id，后续可用于 append_doc ``` ### 追加内容到已有笔记 ```bash ima_api "append_doc" '{"doc_id": "笔记ID", "content_format": 1, "content": "\n## 补充内容\n\n追加的文本"}' ``` ### 按正文搜索 ```bash ima_api "search_note_book" '{"search_type": 1, "query_info": {"content": "项目排期"}, "start": 0, "end": 20}' ``` ## 核心响应字段 **搜索结果**（`SearchedDoc`）：笔记信息路径为 `doc.basic_info`（DocBasic），关键字段：`docid`、`title`、`summary`、`folder_id`、`folder_name`、`create_time`（Unix 毫秒）、`modify_time`、`status`。额外包含 `highlight_info`（高亮匹配，key 为 `doc_title`，value 含 `<em>高亮词</em>`）。 **笔记本条目**（`NoteBookFolder`）：信息路径为 `folder.basic_info`（NoteBookFolderBasic），关键字段：`folder_id`、`name`、`note_number`、`create_time`、`modify_time`、`folder_type`（`0`=用户自建，`1`=全部笔记，`2`=未分类）、`status`。 **笔记列表条目**（`NoteBookInfo`）：信息路径为 `basic_info.basic_info`（DocBasicInfo → DocBasic），关键字段：`docid`、`title`、`summary`、`folder_id`、`folder_name`、`create_time`、`modify_time`、`status`。 **写入结果**（`import_doc`/`append_doc`）：返回 `doc_id`（新建或目标笔记的唯一 ID）。 完整字段定义见 `references/api.md`。 ## 分页 - **游标分页 — 笔记本列表**（`list_note_folder_by_cursor`）：首次 `cursor: "0"`，后续用 `next_cursor`，`is_end=true` 时停止。 - **游标分页 — 笔记列表**（`list_note_by_folder_id`）：首次 `cursor: ""`，后续用 `next_cursor`，`is_end=true` 时停止。 - **偏移量分页**（`search_note_book`）：首次 `start: 0, end: 20`，翻页时递增，`is_end=true` 时停止。 ## 枚举值 - **`content_format`：** `0`=纯文本，`1`=Markdown，`2`=JSON。写入（`import_doc`/`append_doc`）目前仅支持 `1`（Markdown）。读取（`get_doc_content`）推荐 `0`（纯文本），Markdown 格式不支持。 - **`search_type`：** `0`=标题检索（默认），`1`=正文检索 - **`sort_type`：** `0`=更新时间（默认），`1`=创建时间，`2`=标题，`3`=大小（仅 `search_note_book` 使用） - **`folder_type`：** `0`=用户自建，`1`=全部笔记（根目录），`2`=未分类 ## 注意事项 - `folder_id` 不可为 `"0"`，根目录 ID 格式为 `user_list_{userid}`（从 `folder_type=1` 的笔记本条目获取） - 笔记内容有大小上限，超过时返回 `100009`，可拆分为多次 `append_doc` 写入 - 展示笔记列表时只展示标题、摘要和修改时间，不要主动展示正文 - 时间字段是 Unix 毫秒时间戳，展示时转为可读格式 - 返回数据为嵌套结构：搜索结果取 `docs[].doc.basic_info.docid`，笔记本取 `note_book_folders[].folder.basic_info.folder_id`，笔记列表取 `note_book_list[].basic_info.basic_info.docid`，注意按层级解析 - **UTF-8 编码**：内容写入前必须确保为 UTF-8 编码。当内容来自临时文件、WebFetch 或外部来源时，按运行环境选择合适的方式转码： **Python（推荐，几乎所有环境都有）：** ```bash # 读取文件，自动检测编码并转为 UTF-8 content=$(python3 -c " import sys data = open('tmpfile', 'rb').read() for enc in ['utf-8', 'gbk', 'gb2312', 'big5', 'latin-1']: try: sys.stdout.write(data.decode(enc)) break except (UnicodeDecodeError, LookupError): continue " 2>/dev/null) # 如果内容已在变量中，清洗非法 UTF-8 字节 content=$(printf '%s' "$content" | python3 -c "import sys; sys.stdout.write(sys.stdin.buffer.read().decode('utf-8','ignore'))") ``` **Node.js：** ```bash content=$(node -e "const fs=require('fs');const buf=fs.readFileSync('tmpfile');process.stdout.write(buf.toString('utf8'))") # 已知编码（如 GBK）： content=$(node -e "const fs=require('fs');process.stdout.write(new TextDecoder('gbk').decode(fs.readFileSync('tmpfile')))") ``` **Unix (macOS/Linux)：** ```bash content=$(iconv -f "$(file -b --mime-encoding tmpfile)" -t UTF-8 tmpfile 2>/dev/null || cat tmpfile) ``` **Windows PowerShell：** ```powershell # 读取非 UTF-8 文件并转码 $content = [System.IO.File]::ReadAllText('tmpfile', [System.Text.Encoding]::Default) [System.IO.File]::WriteAllText('tmpfile.utf8', $content, [System.Text.Encoding]::UTF8) ``` > **PowerShell 5.1 发送请求注意事项：** > `Invoke-RestMethod` 传入字符串 Body 时，默认使用系统 ANSI 编码（中文 Windows 为 GBK），而非 UTF-8，即使设置了 `Content-Type: charset=utf-8` 也无效。必须**显式转为 UTF-8 字节数组**再传入 `-Body`，同时使用 `ConvertTo-Json` 构建 JSON 以避免手动拼接的转义风险： > > ```powershell > $body = @{ title = "标题"; content = $content; content_format = 1 } | ConvertTo-Json -Depth 10 > $utf8Bytes = [System.Text.Encoding]::UTF8.GetBytes($body) > Invoke-RestMethod -Uri $url -Method Post -Body $utf8Bytes -ContentType "application/json; charset=utf-8" -Headers $headers > ``` > > PowerShell 7+ 默认使用 UTF-8，无需额外处理。 标题同理，确保传入 API 的所有字符串字段均为合法 UTF-8。 ## 错误处理 | 错误码 | 含义 | 建议处理 | |--------|-----------------|-----------------------| | 0 | 成功 | — | | 100001 | 参数错误 | 检查请求参数格式和必填字段 | | 100002 | 无效 ID | 检查凭证配置 | | 100003 | 服务器内部错误 | 等待后重试 | | 100004 | size 不合法 / 空间不够 | 检查参数范围 | | 100005 | 无权限 | 确认操作的是用户自己的笔记 | | 100006 | 笔记已删除 | 告知用户该笔记不存在 | | 100008 | 版本冲突 | 重新获取内容后再操作 | | 100009 | 超过大小限制 | 拆分为多次 `append_doc` 写入 | | 310001 | 笔记本不存在 | 检查 `folder_id` 是否正确 | | 20002 | apiKey超过最大限频 | | 20004 | apikey 鉴权失败 | 检查凭证配置是否正确 | | 110037 | apikey 过期 | 请获取最新apikey：https://ima.qq.com/agent-interface |

path: references/api.md
content: ---
name: IMA笔记
description: |
  IMA笔记 - 腾讯IMA个人笔记管理工具。

  **当用户想要「搜索IMA笔记」「查找笔记」「列出笔记本」「查看某个笔记本下的笔记」「从markdown新建笔记」「追加内容到笔记」「获取笔记纯文本」时，使用此技能。**

  功能：搜索笔记内容（支持标题/正文检索）、列出笔记本、按笔记本拉取笔记列表、从 Markdown 导入新建笔记、追加内容到已有笔记、获取笔记纯文本内容。
metadata: {"openclaw": {"requires": {"env": ["IMA_OPENAPI_CLIENTID", "IMA_OPENAPI_APIKEY"]}, "primaryEnv": "IMA_OPENAPI_CLIENTID", "homepage": "https://ima.qq.com"}}
---

# IMA笔记 API

## ⚠️ 必读约束

### 🔒 认证

所有请求必须携带 Header：

```
ima-openapi-clientid: {IMA_OPENAPI_CLIENTID}
ima-openapi-[REDACTED_SECRET]
Content-Type: application/json
```

### 🔒 安全规则

- 笔记属于用户隐私，**不要在群聊中主动展示笔记内容**。
- 仅响应授权用户的笔记操作请求。

---

## 快速决策

| 用户意图 | 接口别名 |
|---------|---------|
| 「搜索笔记」「找包含XX的笔记」 | `/openapi/note/v1/search_note_book` |
| 「列出笔记本」「有哪些笔记本」 | `/openapi/note/v1/list_note_folder_by_cursor` |
| 「查看XX笔记本里的笔记」 | `/openapi/note/v1/list_note_by_folder_id` |
| 「从markdown新建笔记」「导入笔记」 | `/openapi/note/v1/import_doc` |
| 「追加内容到笔记」「在笔记末尾添加」 | `/openapi/note/v1/append_doc` |
| 「获取笔记纯文本」「读取笔记内容」 | `/openapi/note/v1/get_doc_content` |

---

## 数据结构

---

#### DocBasicInfo

| 字段 | 类型 | 说明 |
|------|------|------|
| `basic_info` | DocBasic | 见 [DocBasic](#docbasic) |

---

#### DocBasic

| 字段 | 类型 | 说明 |
|------|------|------|
| `docid` | string | 文章 id |
| `title` | string | 标题 |
| `summary` | string | 简介 |
| `create_time` | int64 | |
| `modify_time` | int64 | |
| `status` | DocStatus | 文章状态，`0`=正常，`1`=已删除 |
| `folder_id` | string | 文件夹 id |
| `folder_name` | string | 文件夹名称 |
| `summary_style` | map\<string, string\> | 简介样式 |

---

### FolderItem（笔记本条目）

`list_note_folder_by_cursor` 返回的笔记本对象，字段如下：

| 字段 | 类型 | 说明 |
|------|------|------|
| `folder_id` | string | 笔记本唯一 ID |
| `name` | string | 笔记本名称 |
| `note_number` | int64 | 笔记本内笔记数量 |
| `create_time` | int64 | 创建时间（Unix 毫秒） |
| `modify_time` | int64 | 修改时间（Unix 毫秒） |
| `parent_folder_id` | string | 上级笔记本 ID（支持嵌套） |
| `folder_type` | int | 类型：`0`=用户自建，`1`=全部笔记，`2`=未分类 |
| `status` | int | 状态：`0`=正常，`1`=已删除 |

---

#### QueryInfo

| 字段 | 类型 | 说明 |
|------|------|------|
| `title` | string | 标题 query |
| `content` | string | 正文 query |

---

#### SearchedDoc

| 字段 | 类型 | 说明 |
|------|------|------|
| `doc` | DocBasicInfo | 笔记 basic 数据，见 [DocBasicInfo](#docbasicinfo) |
| `highlight_info` | map\<string, string\> | 该条笔记匹配的高亮词，key: `doc_title`（文档标题），value: 包含 `<em>高亮词</em>` 的字段值 |

---

#### NoteBookFolder

| 字段 | 类型 | 说明 |
|------|------|------|
| `folder` | NoteBookFolderBasicInfo | 笔记本信息，非笔记本为空，见 [NoteBookFolderBasicInfo](#notebookfolderbasicinfo) |

---

#### NoteBookFolderBasicInfo

| 字段 | 类型 | 说明 |
|------|------|------|
| `basic_info` | NoteBookFolderBasic | 见 [NoteBookFolderBasic](#notebookfolderbasic) |

---

#### NoteBookFolderBasic

| 字段 | 类型 | 说明                              |
|------|------|---------------------------------|
| `folder_id` | string | 文件夹 id                          |
| `name` | string | 笔记本名称                           |
| `status` | DocStatus | 笔记本状态，`0`=正常，`1`=已删除            |
| `create_time` | int64 | 创建时间                            |
| `modify_time` | int64 | 修改时间                            |
| `note_number` | int64 | 笔记数量                            |
| `folder_type` | FolderType | 文件夹类型：`0`=用户自建，`1`=全部笔记，`2`=未分类 |

---

#### NoteBookInfo

| 字段 | 类型 | 说明 |
|------|------|------|
| `basic_info` | DocBasicInfo | 笔记基础信息，见 [DocBasicInfo](#docbasicinfo) |

---

## 接口详情

### 1. 搜索笔记
POST /openapi/note/v1/search_note_book

**触发场景**：用户说「搜索」「找笔记」「查找包含XX的内容」

#### 请求参数

| 字段 | 类型 | 必填 | 说明 |
|------|------|----|----|
| `search_type` | SearchType | 否  | 检索方式，默认为标题，`0`=标题，`1`=正文 |
| `sort_type` | SortType | 否  | 排序方式，默认为更新时间，`0`=更新时间，`1`=创建时间，`2`=标题，`3`=大小 |
| `query_info` | QueryInfo | 否  | 用户 query，见 [QueryInfo](#queryinfo) |
| `start` | int64 | 是  | 翻页字段，起始编号 |
| `end` | int64 | 是  | 翻页字段，终止编号，与start相差不超过20 |
| `query_id` | string | 否  | queryid |

#### 返回字段

| 字段 | 类型 | 说明 |
|------|------|------|
| `docs` | SearchedDoc[] | 检索到的笔记 list，见 [SearchedDoc](#searcheddoc) |
| `is_end` | bool | 是否为最后一批数据 |
| `total_hit_num` | int64 | 检索命中结果总数 |

---

### 2. 列出笔记本
POST /openapi/note/v1/list_note_folder_by_cursor

**触发场景**：用户说「列出笔记本」「有哪些分类」「查看笔记本目录」

#### 请求参数

| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `cursor` | string | **是** | 游标，第一页传 `"0"`，后续传后台返回的值 |
| `limit` | uint64 | **是** | 获取笔记数量限制，不要超过20 |

#### 返回字段

| 字段 | 类型 | 说明 |
|------|------|------|
| `note_book_folders` | NoteBookFolder[] | 见 [NoteBookFolder](#notebookfolder) |
| `next_cursor` | string | 下次请求的起始游标 |
| `is_end` | bool | 是否为最后一批数据 |

---

### 3. 按笔记本拉取笔记列表
POST /openapi/note/v1/list_note_by_folder_id

**触发场景**：用户说「查看XX笔记本的笔记」「列出这个笔记本里的内容」

> 全部笔记根目录的 `folder_id` 为 `user_list_{userid}`，可从「列出笔记本」返回的 `folder_id` 获取。

#### 请求参数       

| 字段 | 类型 | 必填 | 说明              |
|------|------|---|-----------------|
| `folder_id` | string | 否 | 笔记本 ID，根目录为空    |
| `cursor` | string | **是** | 当前游标，首次传空字符串 `""` |
| `limit` | uint64 | **是** | 获取笔记数量限制，不要超过20 |

#### 返回字段

| 字段 | 类型 | 说明 |
|------|------|------|
| `note_book_list` | NoteBookInfo[] | 见 [NoteBookInfo](#notebookinfo) |
| `next_cursor` | string | 下次请求的起始游标 |
| `is_end` | bool | 是否为最后一批数据 |

---

### 4. 从 Markdown 新建笔记
POST /openapi/note/v1/import_doc

**触发场景**：用户说「从 Markdown 新建笔记」「导入笔记」「把这段 Markdown 保存为笔记」

#### 请求参数

| 字段 | 类型 | 必填 | 说明 |
|------|------|---|----|
| `content_format` | int | **是** | 文本类型：`1`=Markdown（默认）目前仅支持 `MARKDOWN`（值为 `1`） |
| `content` | string | **是** | 笔记正文内容, 只支持markdown格式, 不要传空值 |
| `folder_id` | string | 否 | 关联的笔记本id |

#### 返回字段

| 字段 | 类型 | 说明 |
|------|------|----|
| `doc_id` | string | 新doc的唯一ID |

---

### 5. 追加内容到笔记
POST /openapi/note/v1/append_doc

**触发场景**：用户说「在这篇笔记末尾追加内容」「把 XX 添加到笔记里」

#### 请求参数

| 字段 | 类型 | 必填 | 说明                  |
|------|------|-----|---------------------|
| `doc_id` | string | **是** | 目标笔记的唯一ID, 需要是本人的笔记 |
| `content_format` | int | **是** | 文本类型：`1`=Markdown（默认）目前仅支持 `MARKDOWN`（值为 `1`） |
| `content` | string | **是** | 要追加的文本内容, 只支持markdown格式 |

#### 返回字段

| 字段 | 类型 | 说明 |
|------|------|--|
| `doc_id` | string | 目标笔记的唯一ID |

---

### 6. 获取笔记纯文本
POST /openapi/note/v1/get_doc_content

**触发场景**：用户说「读取笔记内容」「获取这篇笔记的纯文本」「把笔记转成 Markdown」

#### 请求参数

| 字段 | 类型 | 必填 | 说明 |
|------|------|-----|------|
| `doc_id` | string | **是** | 目标笔记的唯一 ID, 需要是本人的笔记 |
| `target_content_format` | int | **是** | 目标文本类型：`0`=纯文本（推荐），`1`=Markdown（不支持），`2`=JSON |

#### 返回字段

| 字段 | 类型 | 说明 |
|------|------|------|
| `content` | string | 笔记的文本内容（按 `target_content_format` 格式返回） |

---

## 枚举值

### `sort_type`（排序方式）

| 值 | 说明 |
|----|------|
| `0` | 更新时间（默认） |
| `1` | 创建时间 |
| `2` | 标题 |
| `3` | 大小 |

### `search_type`（检索方式）

| 值 | 说明 |
|----|------|
| `0` | 标题检索（默认） |
| `1` | 正文检索 |

### `content_format`（文本类型）

| 值 | 说明 |
|----|------|
| `0` | PLAINTEXT - 纯文本 |
| `1` | MARKDOWN - Markdown 格式 |
| `2` | JSON - JSON 格式 |

### `FolderType`
| 值 | 说明   |
|----|------|
| `0` | 用户自建 |
| `1` | 全部笔记 |
| `2` | 未分类  |

---

## 游标翻页使用规范

1. **首次请求**：`cursor` 传空字符串 `""`
2. 检查返回的 `is_end`：`false` 表示还有更多数据
3. 将返回的 `next_cursor` 作为下次请求的 `cursor`
4. `is_end = true` 时停止翻页

---

## 错误码

| 错误码 | 说明                        |
|--------|---------------------------|
| 0 | 成功                        |
| 100001 | 参数错误                      |
| 100002 | 携带无效的 ID                  |
| 100003 | 服务器内部错误                   |
| 100004 | 拉取的 size 不合法（超出范围）/ 用户空间不够 |
| 100005 | 不能获取私有笔记的访客信息 / 不是笔记的作者   |
| 100006 | 笔记已被删除                    |
| 100008 | 版本冲突                      |
| 100009 | 单篇笔记超过最大限制                |
| 310001 | 笔记本不存在                    |
| 20002 | apiKey超过最大限频              |
| 20004 | apikey鉴权失败                |
| 110037 | apikey 过期       |

path: _meta.json
content: ownerId: kn7fpa7e88ngzptwrczstadp5h831pc9
slug: ima-skills
version: 1.0.4
publishedAt: 1773919453218

Security scan verdicts — ClawScan: suspicious | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (HIGH)