Unified IMA OpenAPI skill. Currently supports: notes, knowledge-base.
Setup
Security note: This skill authenticates with the official IMA API (
ima.qq.com) — the same service the user already uses. Credentials are only sent as HTTP headers toima.qq.comand never to any other domain, file, or log.
- Open https://ima.qq.com/agent-interface to obtain Client ID and API Key
- Store credentials (choose one of the two):
Method A — Configuration file (recommended):
mkdir -p ~/.config/ima
echo "your_client_id" > ~/.config/ima/client_id
echo "your_api_key" > ~/.config/ima/api_key
Method B — Environment variables:
export IMA_OPENAPI_CLIENTID="your_client_id"
export IMA_OPENAPI_APIKEY="your_api_key"
The Agent will try in priority order: environment variables → configuration file.
Credential pre-check
Before each API call, first confirm that credentials are available. If both values are empty, stop the operation and prompt the user to configure according to the Setup steps.
# Load user-provisioned IMA credentials (used ONLY for ima.qq.com API authentication)
IMA_CLIENT_ID="${IMA_OPENAPI_CLIENTID:-$(cat ~/.config/ima/client_id 2>/dev/null)}"
IMA_API_KEY="${IMA_OPENAPI_APIKEY:-$(cat ~/.config/ima/api_key 2>/dev/null)}"
if [ -z "$IMA_CLIENT_ID" ] || [ -z "$IMA_API_KEY" ]; then
echo "缺少 IMA 凭证,请按 Setup 步骤配置 Client ID 和 API Key"
exit 1
fi
API call template
All requests are unified as HTTP POST + JSON Body, sent only to the official Base URL https://ima.qq.com。
Define a helper function to avoid repeating headers — each module passes in the full path:
# All requests go ONLY to the official IMA API (ima.qq.com)
ima_api() {
local path="$1" body="$2"
curl -s -X POST "https://ima.qq.com/$path" \
-H "ima-openapi-clientid: $IMA_CLIENT_ID" \
-H "ima-openapi-apikey: $IMA_API_KEY" \
-H "Content-Type: application/json" \
-d "$body"
}
Note: All IMA OpenAPI endpoints currently use HTTP POST. If a future module requires a different method,
ima_api()must be extended to accept a method parameter.
Module decision table
| User intent | Module | Read |
|---|---|---|
| Search notes, browse notebooks, get note content, create notes, append content | notes | notes/SKILL.md |
| Upload files, add web page links, search knowledge base, browse knowledge base content, get knowledge base information, get the list of knowledge bases that can be added to | knowledge-base | knowledge-base/SKILL.md |
⚠️ Easily confused scenarios
The following scenarios are prone to module misjudgment and require special attention:
| What the user says | Actual intent | Correct routing |
|---|---|---|
| "Add this content to note YY in knowledge base XX" | To an existingnoteappend content | notes — first search notes to obtain doc_id, then use append_doc |
| "Write this into note XX", "Record it in note XX" | To an existingnoteappend content | notes — append_doc |
| "Add this note to the knowledge base" | Associate the note with theknowledge base | knowledge-base — add_knowledge with media_type=11 |
| "Upload a file to the knowledge base" | Uploadfileto the knowledge base | knowledge-base — create_media → COS → add_knowledge |
| "Create a new note to record this content" | Createnew note | notes — import_doc |
| "Help me jot this down", "Take a note", "Save as a note" (no existing note specified) | Intent is unclear,needs confirmation | notes — first ask the user whether to create a new note or append to which existing note, then decide the API |
| "Add to a note" (no specific note specified) | Intent is unclear,needs confirmation | notes — first ask the user whether to create a new note or append to which existing note, then decide the API |
| "Record content XX from the knowledge base into a note" | First read from the knowledge base, then write to a note | Multiple modules — knowledge-base search/read → notes create/append |
Core judgment rules:
- If the target isnote content(read, write, append) → notes module
- If the target isknowledge base entries(Upload files, add links, associate notes to knowledge base) → knowledge-base module
- When the user mentions "knowledge base", it is onlydescribing the location of the note(such as "that note in the knowledge base"), the actual object of operation is still the note → notes module
Multi-module tasks: When the user's intent involves multiple modules (such as "search content from the knowledge base and save it to notes"), read the corresponding module documents in the order of intent and execute step by step. Complete the operation of the previous module first, then proceed to the next module.
Notes
- UTF-8 encoding (notes module only): See the "⚠️ UTF-8 Encoding Mandatory Requirements" section below. Before all write operations of the notes modulemustcomplete UTF-8 encoding validation, otherwise the content will be garbled and cannot be repaired.
- File uploads remain as-is (knowledge-base module): When the user requests to upload a file to the knowledge base,the original file content must be kept unchanged, and no encoding conversion shall be performed. Files are uploaded in binary mode, and the server will handle the encoding itself. Unauthorized transcoding may damage the file content (such as PDF, images, Excel, and other non-text files, or text files for which the user intentionally uses a specific encoding).
- PowerShell 5.1 environment (all modules): See the "⚠️ PowerShell 5.1 Environment Detection" section below. This issue affectsall API calls (notes, knowledge-base, etc.). PowerShell 5.1 will silently convert the request Body to GBK encoding, causing garbled text.
⚠️ UTF-8 Encoding Mandatory Requirements (CRITICAL — applies only to the notes module)
This rule is mandatory and cannot be skipped. Invalid encoding will cause the content to display as garbled text in IMA, and it cannot be repaired; it must be rewritten.
Scope: notes module(
import_doc、append_docand other text-writing APIs).Not applicable to file uploads in the knowledge-base module: When uploading files, the original file content must be kept, and no transcoding shall be performed. Files are uploaded in binary mode, and the server handles it itself.
Before each call to a notes write-type API (import_doc/append_doc), UTF-8 encoding validation/conversion must be performed on content、title and all other string fields. Regardless of the source of the content—direct user input, reading from a file, WebFetch scraping, clipboard pasting, external API response—you cannot assume it is already valid UTF-8; you must explicitly confirm it.
Mandatory checklist (before notes module writes)
Before constructing the body of the notes write request, complete the following steps:
- Content from files: First detect the file encoding, convert it to UTF-8, and then read it into the variable (note: this refers to reading file content to write as the note body, not uploading a file to the knowledge base)
- Content from WebFetch / HTTP requests: The response may be GBK/Latin-1, etc., and must be transcoded
- Content from user input or variable concatenation: Clean illegal UTF-8 bytes (
\xff\xfe, etc.) - The same applies to the title field:
titlemust also be valid UTF-8
Transcoding methods for each environment
Python (recommended, available in almost all environments):
# 读取文件,自动检测编码并转为 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:
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):
content=$(iconv -f "$(file -b --mime-encoding tmpfile)" -t UTF-8 tmpfile 2>/dev/null || cat tmpfile)
Windows 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 Environment Detection (CRITICAL — applies to all modules)
This issue affects all API calls (notes, knowledge-base, etc.)
This issue is extremely subtle: under PowerShell 5.1,
Invoke-RestMethodwill silently convert the request Body from UTF-8 to the system ANSI encoding (GBK on Chinese Windows), even ifContent-Type: charset=utf-8is set it has no effect. The result is that the request appears to be sent successfully, but the content received by the server is already garbled, with no error indication whatsoever.
When the agent runs in a PowerShell environment, it must detect the version before the first API call:
# 检测 PowerShell 版本 — 在任何 API 调用之前执行(notes 和 knowledge-base 都需要)
if ($PSVersionTable.PSVersion.Major -le 5) {
Write-Host "⚠️ 检测到 PowerShell 5.1,将使用 UTF-8 字节数组模式发送请求"
$useUtf8Bytes = $true
} else {
Write-Host "✅ PowerShell 7+,默认 UTF-8,无需额外处理"
$useUtf8Bytes = $false
}
Under PowerShell 5.1, requests must be sent using the following method(use ConvertTo-Json to build JSON to avoid the escaping risks of manual concatenation, then explicitly convert to a UTF-8 byte array):
# PowerShell 5.1 安全请求模板(适用于所有模块的所有 API 调用)
$body = @{ title = "标题"; content = $content; content_format = 1 } | ConvertTo-Json -Depth 10
if ($useUtf8Bytes) {
# CRITICAL: 必须转为字节数组,否则中文/非ASCII内容会变成乱码
$utf8Bytes = [System.Text.Encoding]::UTF8.GetBytes($body)
Invoke-RestMethod -Uri $url -Method Post -Body $utf8Bytes -ContentType "application/json; charset=utf-8" -Headers $headers
} else {
# PowerShell 7+ 可直接传字符串
Invoke-RestMethod -Uri $url -Method Post -Body $body -ContentType "application/json; charset=utf-8" -Headers $headers
}
Summary: In a PowerShell 5.1 environment,all API calls (whether notes or knowledge-base) must explicitly convert the Body to a UTF-8 byte array. Sending requests directly without detecting the version = Chinese content will definitely be garbled. This is a known design flaw of PowerShell 5.1, not a bug that can be fixed.