ima-copilot
Installs, troubleshoots, and personalizes the official Tencent IMA skill (a wrapper layer that orchestrates upstream ima-skill, not a replacement). Use when the user mentions IMA, 腾讯 IMA, ima.qq.com, ima-skill, installing or configuring ima-skill, IMA API key / credentials, searching across IMA knowledge bases, 知识库搜索, 笔记搜索, fan-out search with preferred KBs / priority boosting, or wants to diagnose, repair, or personalize an ima-skill install. Also trigger on the missing-YAML-frontmatter bug in ima-skill submodule SKILL.md files and errors like "Skipped loading skill(s) due to invalid SKILL.md".
1How It Works & Mechanism
Operates as a "wrapper layer" rather than a fork: The directory contains no upstream ima-skill source code and only provides installation, diagnosis, repair, and search orchestration. Consequently, upstream updates are received cleanly without conflicts.
- **Never vendor upstream files.** This skill directory does not contain any copy, fork, or excerpt of ima-skill's own content. When ima-skill ships a new release, users get the new release without any interference from this wrapper.
Installation mechanics: Downloads the zip archive from the official IMA distribution domain → extracts to a /tmp staging directory → hands off to vercel-labs/skills npx CLI for distribution, with all steps being idempotent.
ZIP_URL="${BASE_URL}/ima-skills-${IMA_VERSION}.zip" ZIP_PATH="${STAGING_DIR}/ima-skills.zip" echo " Downloading ${ZIP_URL}" http_code=$(curl -sS -L --fail -o "$ZIP_PATH" -w "%{http_code}" "$ZIP_URL" || echo "000")
Distribution decisions do not rely on programmatic probing of upstream zip structure: Prefers the conventional layout <staging>/ima-skill/SKILL.md, and only falls back to finding the shallowest SKILL.md recursively if the layout changes, avoiding misidentifying submodule files under notes/ and knowledge-base/.
SKILL_SRC="" if [ -f "$STAGING_DIR/ima-skill/SKILL.md" ]; then SKILL_SRC="$STAGING_DIR/ima-skill" else
Target agents are detected via directory existence (~/.claude, ~/.agents, openclaw commands) and installed only to detected agents; falls back to claude-code if none are detected.
AGENTS=() [ -d "$HOME/.claude" ] && AGENTS+=("claude-code") [ -d "$HOME/.agents" ] && AGENTS+=("codex") if [ -d "$HOME/.openclaw" ] || command -v openclaw >/dev/null 2>&1; then AGENTS+=("openclaw") fi
Cross-agent sharing leverages the default symlink mode of vercel skills: A single npx call targets multiple -a options; the first successful installation becomes canonical, while the rest symlink to it, synchronizing repairs across all three runtimes.
if ! npx -y skills add "$SKILL_SRC" -g -y "${AGENT_FLAGS[@]}"; then
Credential management follows an XDG plaintext file approach with environment variable priority: Scripts first read env variables, then fall back to ~/.config/ima/{client_id,api_key}, failing with an error if both are missing.
client_id = os.environ.get("IMA_OPENAPI_CLIENTID", "").strip() api_key = os.environ.get("IMA_OPENAPI_APIKEY", "").strip() config_dir = Path.home() / ".config" / "ima"
Diagnostic scripts are strictly read-only: Prints item-by-item status with ✅/⚠️/❌ along with a summary, returning exit codes: 0 = all passed, 1 = requires manual intervention, 2 = diagnostic self-failure (missing network or required tools).
# This script is strictly read-only. It will never modify, create, or delete # any file outside its own stdout. Safe to run as many times as you want.
Deduplicates symlink-shared paths: Normalizes paths across three agents using python3 os.path.realpath and scans each underlying physical directory only once to prevent duplicate issue reporting.
canonical() { python3 -c "import os,sys; print(os.path.realpath(sys.argv[1]))" "$1" 2>/dev/null || echo "$1" }
ISSUE-001 detection uses a "tri-state state machine" rather than a boolean check: Distinguishes between unfixed (first line does not start with ---), Strategy A applied (renamed to MODULE.md), Strategy B applied (frontmatter added), along with a conflict state where both SKILL.md and MODULE.md coexist.
if [ -f "$skill_md" ]; then local first_line first_line=$(head -n 1 "$skill_md" 2>/dev/null || echo "") if [ "$first_line" = "---" ]; then return 0 fi return 1 fi
Fixes are delivered as documented shell commands to be executed by the agent only after explicit user consent rather than embedded in executable scripts: 'we ship instructions, not patches'.
4. **Do not** add the fix commands into any shipped script — keep them in this file so the agent reads and executes them at runtime under user consent. This preserves the contract: we ship instructions, not patches.
Fan-out search bypasses upstream API limitations: Because IMA OpenAPI lacks a cross-KB endpoint, the script enumerates all KBs via pagination, calls search_knowledge concurrently across each KB (default 12 workers), and sorts/groups results on the client side.
with concurrent.futures.ThreadPoolExecutor(max_workers=args.workers) as pool:
Detects silent 100-hit truncations via response heuristics: Considers a KB truncated and prints a distinct ⚠️ notice only if the hit count equals HARD_HIT_CAP (100) and the response contains neither is_end nor next_cursor.
truncated = len(hits) >= HARD_HIT_CAP and not data.get("is_end") and not data.get("next_cursor")
Personalization is driven entirely by user-side configuration: Managed via priority_kbs, skip_kbs, and fanout_strategy in ~/.config/ima/copilot.json; absence of this file falls back to neutral defaults (fan-out all KBs, sort by hit count, no boosting).
The personalization file is **per-user** and private. This skill ships only a template — see `config-template/copilot.json.example`. A user with no config file gets a neutral default: fan out all accessible KBs, sort groups by hit count, no boosting.
2Core Capabilities
3External Dependencies
| Kind | Dependency / Endpoint |
|---|---|
| cli | curl(下载官方 zip + 凭证 liveness 调用) |
| cli | unzip(解包官方发行 zip) |
| cli | npx(要求 Node.js 18+) |
| cli | python3(search_fanout.py 运行环境;diagnose.sh 用它做 realpath 规范化) |
| cli | sed / cp / mv / mktemp / head(修复命令链使用的系统工具,统一用 command 前缀绕过用户别名) |
| package | skills(vercel-labs/skills,npm 包名 skills;npx 按需现场拉取并执行) |
| network | 上游 ima-skill 官方发行包(zip) |
| api | IMA OpenAPI · search_knowledge_base(枚举 KB / 凭证 liveness) |
| api | IMA OpenAPI · search_knowledge(单库检索,扇出的基本调用) |
| network | 凭证发行页(用户手工创建 Client ID / API Key,非脚本请求) |
| network | 可达性探测/文档引用域(api_key_setup.md 建议用 curl 探 http 码) |
4Recommended Governance & Evidence
- scripts/: Executes local script or command: bash scripts/install_ima_skill.sh: curl downloads official zip → unpacks via unzip into /tmp/ima-copilo
- 网络端点: Declares external network access: https://app-dl.ima.qq.com/skills/ima-skills-<version>.zip (curl downloads official distribution package; only validates
- 本地工作目录: File read/write and artifact output: /tmp/ima-copilot-staging/<ts>-<pid>/ (downloaded zip and extracted content; installer's cleanup() handled by
5Second-Pass Verification
- [ok] 外部依赖调用点存在性(curl / unzip / npx / node 版本 / python3 / sed) — install_ima_skill.sh 对 curl/unzip/npx 做 `command -v` 前置检查、对 node 校验 `-lt 18`、用 `unzip -q -o` 解包、用 `npx -y skills add "$SKILL_SRC" -g -y ...` 分发;diagnose.sh 用 python3 打 realpath;known_issues.md 用 `command sed -i.bak`。逐条在源码内命中,无凭空依赖。
- [ok] npx 运行时依赖的真实身份与版本策略 — 实测 GET https://registry.npmjs.org/skills/latest 返回 name=skills、version=1.5.26、repository=git+https://github.com/vercel-labs/skills.git、description='The open agent skills ecosystem',与脚本 `npx -y skills add` 及文档 [vercel-labs/skills] 指向一致;未 pin 版本,每次按需现拉。
- [discrepancy] SKILL.md 示例诊断输出 vs diagnose.sh 实际输出 — SKILL.md 示例写 `✅ upstream ima-skill installed (claude-code)`、`❌ upstream ima-skill NOT installed (openclaw)`;脚本实际打印 `✅ ima-skill installed (claude-code) at $CLAUDE_PATH`(带路径、无 upstream 前缀)与 `⚠️ ima-skill NOT installed (openclaw) — run install_ima_skill.sh`(warn 而非 fail,退出码经汇总后仍为 1)。示例仅示意,功能无差异,但照字面比对会对不上。
- [discrepancy] 备份路径描述 vs known_issues.md 实际命令 — SKILL.md 说修复会把原文件拷到 `/tmp/ima-copilot-backups/<timestamp>/<relative-path>`;实际命令是 `BACKUP="/tmp/ima-copilot-backups/$(date +%Y%m%d-%H%M%S)"` 后以扁平重命名保存(`$BACKUP/notes-SKILL.md`、`$BACKUP/knowledge-base-SKILL.md`),并不保留相对目录结构;回滚命令与之一致,功能成立但文档描述不准。
- [discrepancy] 『未探测到 agent 就跳过、不写用户未选择的路径』的表述 — SKILL.md 与 installation_flow.md 都强调未探测到的 agent 静默跳过;但脚本在『零 agent 探测到』时的实际兜底是 `echo " Defaulting to claude-code as the most common case."` 并继续安装到 claude-code。SKILL.md 的概述未点明这条例外(references 里写了),属概括与实现的轻微出入。
- [ok] diagnose.sh『严格只读』声明复核 — 全文复读:输出只用 echo/printf,读取只用 head -n 1、[ -f ] 探测、tr -d、curl 一次 POST 读响应、python3 打印 realpath;无 > 重定向、无 sed -i、无 chmod、无 rm、无 mkdir。修正结论:『never modify, create, or delete any file』成立。
- [ok] 凭证读取点与去向(是否外发第三方) — 只有 diagnose.sh 与 search_fanout.py 读 env/文件;请求头统一 ima-openapi-clientid / ima-openapi-apikey,目标域名仅 ima.qq.com。全目录 URL 扫描命中集合 = ima.qq.com(含 /openapi 与 /agent-interface)、app-dl.ima.qq.com、github.com/vercel-labs/skills(文档引用)+ npm registry(npx 隐式);无第三方回调、无埋点、无硬编码密钥常量。
- [unlocatable] 站外 API 行为断言的可验证性(100 截断 / 220030 无权限 / 无跨库端点) — 『恰好 100 条即静默截断且无 is_end/next_cursor』『订阅型 KB 返回 code 220030』『无跨库端点』均为 IMA OpenAPI 的站外行为断言,仓库内无测试/fixture 可证;只能确认实现与断言自洽(HARD_HIT_CAP = 100、PERMISSION_DENIED_MARKER = "220030"、truncated 判定式)。要坐实需真实凭证实测,本侦查不硬写。
6Verdict & Scenarios
9677c96e7b3f34a4…