Install
$ agentstack add skill-levi-qiao-obsidian-llm-wiki-ingest ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
Ingest 技能
核心目标
你正在维护一个 LLM Wiki(Obsidian 知识库)。raw/ 目录是"待处理收件箱",wiki/ 是"编译输出层"。本技能负责将原始资料编译到知识库中,并自动归档。
目录结构
raw/— 用户自定义的分类结构(可动态调整)raw/09-archive/— 已处理文件的归档目录,禁止读取(固定,写死)wiki/concepts/— 概念(框架、方法论、理论)wiki/entities/— 实体(人物、公司、工具、产品)wiki/sources/— 资料摘要wiki/syntheses/— 综合研究报告
触发条件
- 用户执行
/ingest— 扫描raw/所有子目录(排除09-archive/),找出待处理文件 - 用户执行
/ingest— 仅处理指定文件 - 隐式触发 — 用户说"把这个资料摄入知识库"、"导入这篇文章"时,自动执行
工作流程
前置检查:扫描待处理文件
关键准则:
- 使用 Glob 扫描
raw/**/*.{md,pdf,txt}(自动排除raw/09-archive/) - 读取
raw/.processed.json,识别已处理的文件 - 为每个待处理文件创建处理清单,确保不遗漏任何文件
- 按文件名字母顺序处理,便于追踪进度
处理清单示例:
📋 待处理文件清单:
- [ ] raw/01-articles/文件A.md (ID: file-a)
- [ ] raw/01-articles/文件B.md (ID: file-b)
- [ ] raw/02-papers/文件C.pdf (ID: file-c)
重要:在开始处理前,向用户展示这个清单,让用户确认要处理的文件列表。
对每个待处理源文件,严格按以下步骤执行:
步骤 1:读取源文件
- 如果是
.md文件:使用 Read 工具完整读取内容 - 如果是
.pdf文件:使用 Read 工具尝试提取文本。如果无法提取或内容为空,改为记录文件元信息(文件名、页数) - 检查点 ✓:确认文件内容已完整读取,记录文件路径和字数
步骤 2:内容分析与 ID 生成
生成稳定 ID:
- 从文件名提取(去除扩展名和路径)
- 转换为 kebab-case
- 示例:
raw/01-articles/Attention Is All You Need.md→ ID:attention-is-all-you-need - 检查点 ✓:确认 ID 已生成,且在
.processed.json中不存在(避免重复处理)
从源文件中提取:
- 核心主旨 — 这段资料讲什么(1-2句话)
- 实体 — 人物、公司、工具、产品等具体名词(列出所有实体)
- 概念 — 框架、方法论、理论等抽象名词(列出所有概念)
- 关键标签 — 3-5个细粒度标签(优先复用 index.md 标签云中的现有标签)
如果是非中文内容,则翻译成中文。
检查点 ✓:确认已提取实体列表、概念列表、标签列表
步骤 3:知识网络化(动态 Top-K)
读取总索引:
Read wiki/index.md
智能定位候选页面:
- 用步骤 2 提取的实体、概念、标签作为关键词
- 在 index.md 中匹配相关页面(不限数量)
- 按相关性排序,动态决定更新数量:
- 简单博客/短文( 5000 字):15-30 个页面
- 如果需要更新超过 20 个页面 → 询问用户是否批量处理
只读取 Top-K 页面的内容(避免全量扫描)
对于步骤 2 提取的每个实体和概念:
目标目录:
- 实体 →
wiki/entities/ - 概念 →
wiki/concepts/
处理逻辑:
- 页面不存在 → 按照 CLAUDE.md 的 Frontmatter 规范创建新页面
- 页面已存在 → 读取现有内容,增量合并新信息
- 发现冲突 → 根据冲突类型处理:
- 时间性冲突(旧版本 vs 新版本)→ 直接更新,在页面中标注
## 历史版本 - 观点性冲突(A 说法 vs B 说法)→ 在页面中新建
## 知识冲突区块 - 复杂冲突(无法判断)→ 在
wiki/_conflicts/创建冲突文件,暂停并询问用户
页面模板:
---
type: entity | concept
tags: [标签1, 标签2, 标签3]
source_id: 稳定ID
created: 2026-04-29
updated: 2026-04-29
---
## 定义
[对该实体/概念的定义]
## 关键信息
[从源文件中提取的详细信息]
## 关联连接
- [[摘要-source-slug]] — 来源
- [[RelatedEntity]] — 相关实体
标签使用原则:
- 优先复用已存在的标签
- 每个页面 3-5 个标签
- 标签使用中文或英文,保持一致性
检查点 ✓:确认所有实体和概念页面已创建或更新,记录创建/更新的页面列表
步骤 4:创建来源摘要
在 wiki/sources/ 创建 Markdown 文件:
---
type: source
tags: [标签1, 标签2, 标签3]
source_id: 稳定ID
created: 2026-04-29
updated: 2026-04-29
---
## 核心摘要
[3-5句话的核心总结]
## 关联连接
- [[EntityName]] — 关联实体
- [[ConceptName]] — 关联概念
文件名使用 kebab-case:摘要-{稳定ID}.md
检查点 ✓:确认来源摘要页面已创建
步骤 5:更新索引与日志
更新总索引 wiki/index.md
按照 type(类型)分组,将新增页面添加到对应分类下:
- 格式:
- [[页面名称]] — 一句话描述 - 更新标签云:重新统计所有标签使用频率
检查点 ✓:确认 index.md 已更新,新增页面已添加到索引
更新操作日志 wiki/log.md(Append-only):
## [YYYY-MM-DD] ingest | 操作简述
- 变更: 新增 [[PageName]] (N个); 更新 [[ExistingPage]] (M个)
- 标签: #标签1 #标签2 #标签3
- 冲突: 无 (或: 时间性冲突已更新; 或: 复杂冲突已生成报告到 _conflicts/)
- 源文件: raw/xx/文件名.md
检查点 ✓:确认 log.md 已追加新记录
步骤 6:更新处理状态并归档源文件
更新 raw/.processed.json:
使用稳定 ID(从文件名提取),记录处理状态:
{
"文件ID": {
"original_path": "raw/01-articles/xxx.md",
"archived_path": "raw/09-archive/xxx.md",
"processed_at": "2026-04-29T14:30:00Z",
"pages_created": ["页面1", "页面2"],
"pages_updated": ["页面3"]
}
}
时间戳格式:使用 ISO 8601 格式(YYYY-MM-DDTHH:MM:SSZ)
检查点 ✓:确认 .processed.json 已更新
归档源文件:
关键准则:只有在以下所有条件都满足时,才能归档源文件:
- ✓ sources 页面已创建
- ✓ 实体/概念页面已创建或更新
- ✓ index.md 已更新
- ✓ log.md 已更新
- ✓
.processed.json已更新
使用 Bash 工具执行移动操作:
# 确保归档目录存在
mkdir -p raw/09-archive
# 移动文件(使用相对路径)
mv "raw/01-articles/文件名.md" raw/09-archive/
验证归档:
# 验证文件已移动
test -f "raw/09-archive/文件名.md" && echo "归档成功" || echo "归档失败"
检查点 ✓:确认源文件已成功移动到 raw/09-archive/,原位置不再存在该文件
绝对禁止修改源文件内部的文字。
步骤 7:完成提示
对于每个处理完成的文件,输出:
✅ 已完成文件处理:raw/xx/文件名.md
- 稳定ID: xxx
- 新增页面:N 个
- 更新页面:M 个
- 已归档到:raw/09-archive/
所有文件处理完成后,输出总结:
🎉 所有文件摄入完成!
📊 总计:
- 处理文件:X 个
- 新增页面:N 个
- 更新页面:M 个
- 源文件已归档到:raw/09-archive/
📝 下一步:使用 `/sync` 提交到 Git
冲突处理
当发现新旧知识冲突时,根据冲突类型自动处理:
1. 时间性冲突(旧版本 vs 新版本)
特征:同一事实的不同时间点描述,新信息明显更新 处理:直接更新为新版本,在页面中添加 ## 历史版本 区块记录旧信息
2. 观点性冲突(A 说法 vs B 说法)
特征:不同来源对同一问题的不同观点,无法判断对错 处理:在页面中新建 ## 知识冲突 区块,保留两种说法并对比
3. 复杂冲突(无法判断类型)
特征:涉及多个页面、多个维度的矛盾,LLM 无法自动决策 处理:
- 在
wiki/_conflicts/创建冲突文件:conflict_YYYY-MM-DD_主题.md - 文件内容包含:
- 冲突描述
- 涉及的页面和来源
- 建议的解决方案
- 决策选项(供用户勾选)
- 暂停 ingest 流程,向用户报告冲突位置
- 等待用户决策后继续
细节准则
文件处理准则
- 批量处理:处理多个文件时,按字母顺序逐个处理,每个文件完成后立即归档
- 错误恢复:如果某个文件处理失败,记录错误信息,继续处理下一个文件
- 进度追踪:处理多个文件时,实时更新处理清单,标记已完成的文件
- 文件名编码:处理中文文件名时,使用相对路径和
cd命令避免编码问题
页面创建准则
- 命名规范:
- 实体:使用原名(中文或英文),保持 TitleCase
- 概念:使用中文名称,保持 TitleCase
- 来源:使用
摘要-{kebab-case-id}格式
- 去重检查:创建页面前,检查是否已存在同名或相似页面
- 链接完整性:每个页面必须包含
## 关联连接区域,至少链接到来源页面 - 标签一致性:优先复用现有标签,避免创建语义相同的新标签
索引更新准则
- 分类准确:确保页面添加到正确的分类(Concepts/Entities/Sources/Syntheses)
- 描述简洁:每个条目的描述控制在 10-15 字以内
- 标签统计:标签云按使用频率降序排列,格式为
#标签 (数量) - 计数准确:每个分类的计数必须与实际页面数量一致
日志记录准则
- 时间格式:使用
[YYYY-MM-DD]格式 - 操作类型:明确标注操作类型(ingest/query/lint/sync)
- 变更详情:列出所有新增和更新的页面,使用 wikilink 格式
- 源文件追溯:记录源文件的原始路径,便于追溯
归档验证准则
- 移动前检查:确认所有相关页面和索引都已更新
- 移动后验证:使用
ls或find命令验证文件已成功移动 - 原位置清理:确认原位置不再存在该文件
- 归档记录:在
.processed.json中记录归档路径和时间
注意事项
- 绝对不读取
raw/09-archive/下的任何文件 - 所有 wiki 页面必须包含
## 关联连接区域,不能产生孤岛页面 - 使用简体中文编写所有内容
- 实体命名使用 TitleCase,概念和来源使用 kebab-case
- 使用 Glob 工具扫描文件,使用 Read 工具读取内容,使用 Write/Edit 工具创建/更新页面
- 使用 Bash 工具移动文件到归档目录
- 只读取总索引和相关页面,不要全量扫描
- 处理多个文件时,必须逐个完成,不能跳过任何文件
- 每个文件处理完成后,立即归档,不要等到所有文件都处理完才归档
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: levi-qiao
- Source: levi-qiao/obsidian-llm-wiki
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.