npx skills add ...
npx skills add sdyckjq-lab/llm-wiki-skill --skill llm-wiki
个人知识库构建系统(基于 Karpathy llm-wiki 方法论)。让 AI 持续构建和维护你的知识库, 支持多种素材源(网页、推特、公众号、小红书、知乎、YouTube、PDF、本地文件), 自动整理为结构化的 wiki。 触发条件:用户明确提到"知识库"、"wiki"、"llm-wiki",或要求对已初始化的知识库执行 消化、查询、健康检查等操作。不要在用户只是要求"总结这篇文章"时触发——必须是明确的 知识库相关意图。
npx skills add sdyckjq-lab/llm-wiki-skill --skill llm-wiki
把碎片化的信息变成持续积累、互相链接的知识库。你只需要提供素材,AI 做所有的整理工作。
llm-wiki 帮你构建一个持续增长的个人知识库。它不是传统的笔记软件,而是一个让 AI 帮你维护的 wiki 系统:
传统方式(RAG/聊天记录)的问题:每次问问题,AI 都要从头阅读原始文件,没有积累。知识库的价值在于知识被编译一次,然后持续维护,而不是每次重新推导。
告诉用户这两步就够了:
Scripts located in scripts/ subdirectory.
Path Resolution:
SKILL_DIR = this SKILL.md's directory${SKILL_DIR}/scripts/<script-name>核心主线(本地文件、纯文本、已有知识库操作)默认不需要这些提取依赖。
只有当用户给的是 URL 类来源,并且明确要自动提取网页 / X / 微信公众号 / YouTube / 知乎内容时,才检查以下可选依赖。
如果缺失,提示用户运行:
可选依赖 skill / 工具:
baoyu-url-to-markdown — 普通网页、X/Twitter、部分知乎提取wechat-article-to-markdown — 微信公众号提取youtube-transcript — YouTube 字幕提取即使这些依赖缺失,skill 仍可工作(用户可以直接提供本地文件、粘贴文本,或改走手动入口)。
外挂失败统一分成 not_installed / env_unavailable / runtime_failed / unsupported / empty_result 五类。
所有需要枚举来源、读取 source_label、raw_dir、adapter_name、fallback_hint 的地方,都先读来源总表:
需要拿单个来源的定义时,用:
对 URL 类来源,先运行:
adapter-state.sh check 返回 8 列:
not_installed:提示用户可补安装,同时允许改走手动入口env_unavailable:说明缺少的环境条件,同时允许改走手动入口runtime_failed:说明本次提取执行失败,允许重试一次,再改走手动入口unsupported:直接给出手动入口,不尝试自动提取empty_result:说明自动提取没拿到有效内容,请用户手动补全文本当自动提取实际执行后,再运行:
用返回的 detail、recovery_action、install_hint、fallback_hint 生成提示。核心主线不因外挂失败而中断。
根据用户的意图,路由到对应的工作流:
| 用户意图关键词 | 工作流 |
|---|---|
| "初始化知识库"、"新建 wiki"、"创建知识库" | → init |
| URL / 文件路径 / "添加素材"、"消化"、"整理" / 直接给链接 | → ingest |
| "批量消化"、"把这些都整理" / 给了文件夹路径 | → batch-ingest |
| "关于 XX"、"查询"、"XX 是什么"、"总结一下" | → query |
| "给我讲讲 XX"、"深度分析 XX"、"综述 XX"、"digest XX" | → digest |
| "对比一下 X 和 Y"、"比较 X 和 Y"、"整理一下时间线"、"按时间排列" | → digest(指定格式) |
| "检查知识库"、"健康检查"、"lint" | → lint |
| "知识库状态"、"现在有什么"、"有多少素材" | → status |
| "画个知识图谱"、"看看关联图"、"graph"、"知识库地图" | → graph |
| "删除素材"、"remove"、"delete source"、"移除" | → delete |
| "结晶化"、"crystallize"、"把这个记进知识库"、"总结这段对话" | → crystallize |
重要:如果用户直接给了一个 URL 或文件,但没有明确说要做什么,默认走 ingest 工作流。如果知识库还不存在,先自动走 init 再走 ingest。
除 init 外,其他工作流默认先执行这段检查:
.wiki-schema.md
~/.llm-wiki-pathingest / batch-ingest → 先运行 initquery / lint / status / digest / graph / delete → 提示用户先初始化知识库.wiki-schema.md.wiki-schema.md 的"语言"字段判断 WIKI_LANG
语言:中文 → WIKI_LANG=zh语言:English → WIKI_LANG=enWIKI_LANG=zh所有面向用户的输出和新写入的 wiki 内容,都按 WIKI_LANG 生成:
WIKI_LANG=zh → 使用下文中文示例WIKI_LANG=en → 保持与中文示例相同的结构、信息量和顺序,仅改为自然英文措辞术语对照:
.wiki-schema.md
~/.llm-wiki-path 文件
询问知识库主题(先向用户提问):
询问知识库语言(先向用户提问):
zh(中文)或 en(English)zhWIKI_LANG(zh 或 en)询问保存位置(先向用户提问):
~/Documents/我的知识库/(zh)或 ~/Documents/my-wiki/(en)运行初始化脚本:
补充初始化结果说明:
init-wiki.sh 会同时生成 purpose.md 和 .wiki-cache.jsonpurpose.md 和 .wiki-schema.md 同级存放,用来记录研究目标、关键问题和研究范围purpose.md 里,后续 ingest 会优先参考这里的方向写入语言配置并本地化种子文件:
.wiki-schema.md 中的 语言:{{LANGUAGE}} 替换为:
zh → 语言:中文(种子文件保持中文,无需额外处理)en → 语言:English,同时覆写以下种子文件为英文版:WIKI_LANG=en,读取 ${SKILL_DIR}/templates/index-en-template.md、${SKILL_DIR}/templates/overview-en-template.md、${SKILL_DIR}/templates/log-en-template.md,将 {{DATE}} 和 {{TOPIC}} 替换为实际值后,分别写入 index.md、wiki/overview.md、log.md记录路径到 ~/.llm-wiki-path:
输出引导(根据 WIKI_LANG 切换语言):
中文(zh):
(英文版按「输出语言规则」生成,结构相同。)
这是最核心的工作流。用户给一个素材进来,AI 做所有的整理工作。
执行通用前置检查(见上方定义)。
在开始提取或分析任何内容之前,AI 必须先对用户说下面这句话,然后等待确认:
在开始分析这份素材前,请先快速确认里面不包含这些敏感内容:
- 手机号码(如 138xxxxxxxx)
- 身份证号(18 位数字)
- API 密钥(
sk-...、AIzaSy...、OPENAI_API_KEY=、ANTHROPIC_API_KEY=、Bearer ...)- 明文密码(
password=、passwd=)- 其他你不希望进入知识库的个人信息
如果素材里有上面任何一项,请先用文本编辑器删除或脱敏后再继续。 llm-wiki 不会自动过滤这些内容,处理后的内容会进入你的知识库。
确认无上述内容请回复
y,要中止请回复n。
流程规则:
y(或"可以"、"继续"、"没有"等明确肯定)→ 继续执行后续步骤n(或"停"、"取消"等明确否定)→ 终止本次 ingest,提示用户清理后再来batch-ingest 流程中(已经在顶层确认过一次),AI 可以跳过这一步为什么是自查清单而不是脚本:
根据素材类型自动路由到最佳提取方式:
外挂前置判断:
bash ${SKILL_DIR}/scripts/source-registry.sh match-url "<url>"bash ${SKILL_DIR}/scripts/source-registry.sh match-file "<path>"bash ${SKILL_DIR}/scripts/source-registry.sh get plain_textsource-registry.sh 返回 10 列:source_id、source_label、source_category、input_mode、match_rule、raw_dir、adapter_name、dependency_name、dependency_type、fallback_hintbash ${SKILL_DIR}/scripts/adapter-state.sh check <source_id>adapter-state.sh check 的 8 列结果里读取 state、detail、recovery_action、install_hint、fallback_hintstate=not_installed / env_unavailable / unsupported → 不调用外挂,直接按 detail、recovery_action、install_hint、fallback_hint 告诉用户下一步available 时,才继续自动提取URL 类素材(统一走来源总表,不手写域名表):
Chrome 提示(仅当
adapter_name=baoyu-url-to-markdown时): adapter-state.sh check 会把“提取器可用”与“是否存在 9222 可复用会话”分开表达。 如果 check 返回available,正常调用外挂;即使 detail 提示未检测到 9222,也继续执行。baoyu-url-to-markdown 会自己处理 Chrome 启动,继续执行,不要等待用户确认。 只有在你想复用当前已登录的 Chrome 会话时,才需要手动开启 9222。 如果提取仍然失败(通常是页面需要登录态,如 X/Twitter、知乎等),可提示用户开启调试端口复用已登录会话:open -na "Google Chrome" --args --remote-debugging-port=9222
source_category=manual_only → 不调用外挂,直接使用 fallback_hintadapter_name=wechat-article-to-markdown → 执行 wechat-article-to-markdown "<URL>"adapter_name=youtube-transcript → 调用 youtube-transcriptadapter_name=baoyu-url-to-markdown → 调用 baoyu-url-to-markdown本地文件:
bash ${SKILL_DIR}/scripts/source-registry.sh match-file "<path>"纯文本粘贴:
plain_text统一回退规则:
bash ${SKILL_DIR}/scripts/adapter-state.sh classify-run <source_id> <exit_code> <output_path>classify-run 返回的 8 列结果里读取 state、detail、recovery_action、fallback_hintruntime_failed → 按 detail、recovery_action、fallback_hint 告诉用户“这次自动提取失败,可以先重试一次;如果还不行,就改走手动入口”empty_result → 按 detail、recovery_action、fallback_hint 告诉用户“自动提取没有拿到有效正文,请手动补全文本后继续”根据素材长度和信息密度自动选择处理级别:
判断标准:
提取素材内容:按上面的路由获取素材文本
保存原始素材到 raw/ 对应目录:
{日期}-{短标题}.md图片检测与追踪:保存素材后,扫描内容中是否包含图片引用(![ 或 <img 或 .png/.jpg/.gif/.svg URL)。如果检测到图片:
raw/assets/(Obsidian 用户可在设置中绑定快捷键一键下载附件)"images:记录检测到的图片引用数量image_paths:如果用户已将图片下载到 raw/assets/,用 YAML block list 格式记录路径;如果尚未下载,保持为空数组 []。示例:
image_paths,或在下次 lint 时由 AI 辅助补全读取上下文:
purpose.md > .wiki-schema.md > index.mdpurpose.md 存在,先读取其中的核心目标、关键问题和研究范围purpose.md 指导后续实体、主题、关联的取舍和权重缓存检查:
HIT 或 HIT(repaired) → 跳过本次 LLM 调用,直接读取已有 wiki 页面,并告诉用户这是”无变化,直接复用已有结果”
HIT(repaired) 表示缓存自愈修复成功(上次 update 被跳过但 source 页面存在且 source_path 匹配)MISS:<reason> → 继续执行下面的两步流程
MISS:no_entry — 首次处理此素材(正常情况)MISS:hash_changed — 素材内容有变化,需要重新处理MISS:no_source — 有缓存记录但 source 页面被删除了MISS:repaired_needs_verify — 找到同名 source 页面但 source_path 不匹配,需要重新处理以确认关联正确Step 1:结构化分析:
purpose.md + 现有 wiki 结构(至少读取 index.md 概要)entities、topics、connectionsconfidence 是必需字段,缺失就视为格式异常并触发单步回退置信度赋值规则(Claude 必须遵守):
evidence 字段提供原文摘录(建议 ≤50 字);缺失时脚本会发出 WARN 但不阻塞evidence 字段说明推理依据;缺失时脚本会发出 WARN 但不阻塞evidence 可选evidence 可选Step 1 完成后,必须执行验证:
如果脚本返回非 0,自动回退到单步 ingest(不进行 Step 2)。
Step 2:页面生成:
purpose.md + Step 1 的分析结果 + 现有相关 wiki 页面new_vs_existing.updates 列出的已有页面;如果某页超过 2000 字,只读取 frontmatter + 需要更新的章节容错回退:
entities、topics、confidence 等必需字段,自动回退到原来的单步流程生成素材摘要页(wiki/sources/{日期}-{短标题}.md):
templates/source-template.md 的格式sources: [] 字段;如果这次 ingest 有明确来源,按实际 raw/source 引用填入INFERRED 或 AMBIGUOUS 的关系,用 HTML 注释保留置信度:
create-source-page.sh(自动更新缓存):
SUCCESS → 写入和缓存都已更新ERROR → 写入或缓存失败,检查报错信息后重试更新或创建实体页(wiki/entities/):
wiki/entities/ 下是否已有对应页面templates/entity-template.md[[实体名]] 语法做双向链接更新或创建主题页(wiki/topics/):
templates/topic-template.md## {日期} ingest | {素材标题}create-source-page.sh 自动完成,此处无需再调用 cache.sh updateWIKI_LANG 切换语言):中文(zh):
(英文版按「输出语言规则」生成,结构相同。)
适用于短推文、小红书笔记、简短评论等。
保存原始素材到对应 raw/ 目录
images 和 image_paths frontmatter 字段记录数量和路径读取上下文并检查缓存:
purpose.mdbash ${SKILL_DIR}/scripts/cache.sh check "<raw 文件路径>"HIT 或 HIT(repaired)),直接复用已有结果生成简化摘要页(wiki/sources/):
sources: []create-source-page.sh(自动更新缓存)提取 1-3 个关键概念:
[待创建: [[概念名]]] 标记更新 index.md 和 log.md(缓存已由 create-source-page.sh 自动更新)
跳过:主题页创建/更新、overview 更新
向用户展示简化结果(按 WIKI_LANG 切换语言):
中文(zh):
(英文版按「输出语言规则」生成,结构相同。)
当用户给了一个文件夹路径,或者说"把这些都整理一下"。
确认知识库路径:
WIKI_LANG列出所有可处理文件:
.md, .txt, .pdf, .html.git 目录、node_modules 等展示文件列表,确认处理范围(按 WIKI_LANG 切换语言):
zh:
(英文版按「输出语言规则」生成,结构相同。)
逐个处理:对每个文件执行 ingest 工作流
cache checkMISS 的文件才继续执行完整或简化处理每 5 个文件后暂停,展示进度并询问是否继续(按 WIKI_LANG 切换语言):
zh:
(英文版按「输出语言规则」生成,结构相同。)
全部完成后:
WIKI_LANG 切换语言):zh:
(英文版按「输出语言规则」生成,结构相同。)
确认知识库路径:
WIKI_LANG读取 index.md 了解知识库全貌
搜索相关页面:
.wiki-schema.md 中的"别名词表",如果用户的查询关键词命中了某一组别名,则将该组所有同义词都纳入搜索(如搜"LLM"时同时搜"大语言模型"和"大模型")
wiki/ 目录下搜索所有关键词(原始 + 别名展开)综合回答:
WIKI_LANG 用对应语言回答用户的问题[[页面名]] 格式)判断是否值得持久化:
重复检测:
wiki/queries/ 下搜索同主题页面superseded-by 标记保存 query 页面:
templates/query-template.md 生成页面wiki/queries/{date}-{short-hash}.md,避免同主题命名冲突type: query 和 derived: truederived: true 表示这是衍生内容,不是一手素材自引用防护:
INFERRED 处理wiki/queries/;只有当前问题确实需要时,才把 query 页面作为补充材料读取更新索引和日志:
执行通用前置检查(见上方定义)。如果没有可用知识库,提示用户先初始化。
确定检查范围:
Step 0:调用脚本做机械检查(必须先做,不要跳过):
脚本一次读取后统一检查孤立页、index、图片、来源信息和全部 wikilink。明确路径和唯一裸名会按实际页面路径解析;同名页面不会被合并。歧义链接不猜目标、不计入关系,并列出全部候选;“待创建”和真正断链分开报告,代码示例不会被当成链接。
普通检查只读并完整报告数据问题,退出码为 0;路径、参数、解析或读取失败返回 1。需要让 CI 因歧义、真正断链或路径冲突而阻断时,显式运行:
严格模式完成报告后,有 error 返回 2,只有“待创建”等提示仍返回 0。可在末尾加 --json 获取同一份结构化完整报告。所有这些检查都不会修改知识库 Markdown。
逐项检查(AI 判断类,脚本做不了):
矛盾信息(阅读相关页面,检查是否有互相矛盾的说法):
交叉引用缺失(检查相关主题的页面之间是否应该互相链接但没链):
置信度报告(统计 EXTRACTED / INFERRED / AMBIGUOUS / UNVERIFIED):
AMBIGUOUS 条目,提醒用户优先验证补充建议:基于 Step 0 脚本的孤立页/断链输出,给出修复建议(脚本只列问题,不给方案)
[[链接]]输出报告(按 WIKI_LANG 切换语言,整合 Step 0 脚本输出 + Step 3 AI 判断结果):
zh:
(英文版按「输出语言规则」生成,结构相同。)
询问用户:要自动修复哪些问题?(按 WIKI_LANG 用对应语言提问)
执行通用前置检查(见上方定义)。如果没有可用知识库,提示用户先初始化。
先运行 bash ${SKILL_DIR}/scripts/source-registry.sh list 读取来源总表
获取知识库路径(按上面的 CWD 检查逻辑)
统计:
source_label 和 raw_dir 逐项统计 raw/ 文件数wiki/entities/ 下的页面数wiki/topics/ 下的页面数wiki/sources/ 下的页面数wiki/comparisons/ 和 wiki/synthesis/ 下的页面数purpose.md 是否存在读取 log.md 最后 5 条记录
读取 index.md 获取主题概览
运行 bash ${SKILL_DIR}/scripts/adapter-state.sh summary-human 获取外挂状态
运行 node ${SKILL_DIR}/scripts/source-signal-coverage.js <wiki_root> 获取来源信号覆盖数据,从返回 JSON 的 summary 中读取:
ok(已参与)、missing_sources(缺少 sources)、empty_sources(sources 为空)、invalid_sources(格式无效)、not_applicable(当前不参与)输出报告(按 WIKI_LANG 切换语言):
zh:
(英文版按「输出语言规则」生成,结构相同。)
外挂状态直接使用 bash ${SKILL_DIR}/scripts/adapter-state.sh summary-human 的输出,不要自己再重写一套来源清单。
区别于 query:query 是快速问答,不生成新页面;digest 是跨素材深度综合,生成持久化报告。
"给我讲讲 XX"、"深度分析 XX"、"综述 XX"、"digest XX"、"全面总结一下 XX""对比一下 X 和 Y"、"比较 X 和 Y"、"X 和 Y 有什么区别""整理一下时间线"、"按时间排列"、"时间顺序"执行通用前置检查(见上方定义)。如果没有可用知识库,提示用户先初始化。
搜索相关页面:
.wiki-schema.md 中的"别名词表"展开同义词(不跨组传递,自动去重)wiki/ 下搜索所有关键词(原始 + 别名展开),同一别名组命中同一页面只计一次深度阅读所有相关页面 + 选择输出格式:
生成结构化深度报告,保存到 wiki/synthesis/{主题}-{格式}.md(按 WIKI_LANG 切换语言):
文件名规则:默认格式用
{主题}-深度报告.md,对比表用{主题}-对比.md,时间线用{主题}-时间线.md
模板 A:深度报告格式(默认)
zh:
(英文版按「输出语言规则」生成,结构相同。)
模板 B:对比表格式(触发词:对比 / 比较)
模板 C:时间线格式(触发词:时间线 / 按时间)
更新 index.md 和 log.md:
## {日期} digest | {主题}向用户展示结果(按 WIKI_LANG 切换语言):
zh:
(英文版按「输出语言规则」生成,结构相同。)
"画个知识图谱"、"看看关联图"、"graph"、"知识库地图"、"展示知识关联"
执行通用前置检查(见上方定义)。如果没有可用知识库,提示用户先初始化。
扫描双向链接:
wiki/ 下所有 .md 文件[[链接]] 语法,建立关系列表:页面A → 页面B生成 Mermaid 图表文件 wiki/knowledge-graph.md:
生成规则:
[名称],名称太长则截断到 10 字A --> B 无标注箭头,不自动判断关系类型可选:手动美化图谱(生成后由用户自己做,AI 不自动处理):
生成的 wiki/knowledge-graph.md 默认只有 --> 箭头。如果用户希望图谱更清楚地
表达关系类型,可以:
wiki/knowledge-graph.md.wiki-schema.md 里的"关系类型词汇表"(实现 / 依赖 / 对比 / 矛盾 / 衍生)A -->|实现| B 之类的带标注写法AI 在 graph 工作流里不自动打标——因为自动判断关系类型需要额外阅读整段上下文,
成本高且准确率难保证。人类对"哪些关系最值得打标"的判断更可靠。
用户如果明确要求 AI 给某几条边打标,可以单独说"把 A 和 B 之间的关系标成'实现'",
AI 再手动修改 wiki/knowledge-graph.md 对应的那一行。
2b. 生成交互式图谱数据(wiki/graph-data.json):
脚本会递归扫描 wiki/{entities,topics,sources,comparisons,synthesis,queries}/**/*.md,
解析 wikilink 与 <!-- confidence: EXTRACTED|INFERRED|AMBIGUOUS --> 注释,
调用本地 Node helper 计算 3 信号边权重(共引强度 / 来源重叠 / 类型亲和度)、Louvain 社区和规则 insights,
并把 wiki/graph-data.json 与同目录唯一的 wiki/graph-warnings.json 成对写入(内容 >2MB 自动降级,单节点只留 500 行;图规模超预算时 insights 自动降级)。节点身份使用实际知识库相对路径,因此六类正式目录中的同名页面都会保留。明确路径和唯一裸名正常建边;歧义链接不建边并报告候选;“待创建”和真正断链分别报告。
正常构建即使发现数据问题也返回 0,只有工具、输入或写入失败返回 1,并且绝不修改 Markdown。CI 要阻断数据错误时,另运行 node scripts/wiki-link-cli.js check "$WIKI_ROOT" --strict;严格检查有 error 返回 2。自定义输出必须仍在知识库内、文件名保持 graph-data.json,并使用自己的目录;该目录中的 graph-warnings.json 是它唯一的配对详情文件,两个自定义输出要放在两个不同目录。
依赖 jq + node(如缺失可运行 brew install jq node)。
2c. 图谱运行时说明:
jq + nodenpm installnode 只用于运行随仓库分发的本地预构建 helper2d. 生成交互式图谱 HTML(东方编辑部 × 数字山水风):
生成 wiki/knowledge-graph.html。脚本会先验证成对告警,再安全内嵌图谱和最多 2 MiB(gzip level 9)的告警详情,离线双击即可打开。详情超过上限时会稳定精简并保留全部总数;详情缺失或与图谱不是同一代时仍显示图谱,并提示重新构建。
页面保持三栏国风布局:左侧文献索引,中间数字山水图谱,右侧常驻节点详情。
包含搜索、社区筛选、节点视觉分层、首屏推荐预览、摘要、正文、相邻节点、洞察、小地图和关系置信度图例。
离线页只负责解释告警,不提供改名、解决或其他写入操作。
读取 insights 并向用户展示结果(按 WIKI_LANG 切换语言):
先读取 insights:
zh:
(英文版按「输出语言规则」生成,结构相同。各洞察类别为空时省略该行。)
"删除素材"、"remove"、"delete source"、"移除"
执行通用前置检查(见上方定义)。如果没有可用知识库,提示用户先初始化。
识别目标素材:
raw/ 下搜索用户提到的素材名扫描影响范围:
安全确认:
执行级联清理:
raw/ 下对应原始文件wiki/sources/ 下对应素材摘要页wiki/entities/、wiki/topics/、wiki/comparisons/、wiki/synthesis/ 中仍需保留的页面,只移除该素材相关的引用段落index.mdlog.md 追加删除记录wiki/overview.md 需要重新生成清理缓存:
断链检查:
delete-helper.sh 再扫一遍指向已删除页面的链接向用户报告结果:
zh:
(英文版按「输出语言规则」生成,结构相同。)
触发条件: 用户说"结晶化"、"crystallize"、"把这个记进知识库"、"这段对话很有价值"
输入: 用户主动提供的内容(文字粘贴进对话,或明确引用某段上下文)。 用户必须主动提供内容,Claude 不自动提取当前会话。
处理步骤(MVP):
wiki/synthesis/sessions/{主题}-{日期}.md,格式参考 templates/synthesis-template.md
sources,默认不参与 graph source overlaplog.md(记录本次结晶化操作)MVP 版本不自动创建 entity 页面,不自动更新 index.md。
confidence 规则:
结晶化来源的内容默认标记为 INFERRED(来自推断/对话,非原始文档)。
输出示例: 已创建 wiki/synthesis/sessions/AI-agent-设计决策-20260413.md 已更新 log.md
bash ${SKILL_DIR}/scripts/source-registry.sh get <source_id>bash ${SKILL_DIR}/scripts/adapter-state.sh check <source_id>source_id source_label state state_label detail recovery_action install_hint fallback_hintbash ${SKILL_DIR}/scripts/adapter-state.sh classify-run <source_id> <exit_code> <output_path>