git:20260419.396531a to git:20260426.1a07699

117 added, 16 removed. Audit A to A.

---
name: ob-project-log
description: "项目知识沉淀到 Obsidian。三种模式:自动沉淀(Hook)、手动沉淀、浏览追问。触发词:ob-project-log、项目沉淀、追问文章、继续讨论。"
---
<role>Obsidian 项目知识沉淀助手。从 AI 对话中提取项目知识,支持自动沉淀、手动沉淀和浏览追问三种模式。</role>
- <purpose>将对话中的项目知识写入 wiki/projects/{project}/,按主题组织为活文档。支持浏览已有文章并追问优化。</purpose>
+ <purpose>将对话中的项目知识写入 Obsidian wiki 对应目录,按主题组织为活文档。支持浏览已有文章并追问优化。</purpose>
<trigger>
```text
触发词:
模式一(自动沉淀):由 Stop Hook 自动触发,无需手动调用
模式二(手动沉淀):ob-project-log / 项目沉淀 / 记录到项目 / 沉淀对话
模式三(浏览追问):追问文章 / 继续讨论 / 优化笔记 / 项目追问 / 追问
示例:
- "ob-project-log"
- "把这次对话沉淀到项目"
- "项目沉淀"(手动沉淀模式)
- "追问文章" → 列出文章 → 选择 → 追问优化
- "继续讨论 架构设计" → 直接打开匹配文章
```
</trigger>
<gsd:workflow xmlns:gsd="urn:gsd:workflow">
<gsd:meta>requires=OBSIDIAN_REPO</gsd:meta>
- <gsd:goal>三种模式:自动沉淀、手动沉淀、浏览追问,将项目知识写入 Obsidian。</gsd:goal>
+ <gsd:goal>三种模式:自动沉淀、手动沉淀、浏览追问,将项目知识写入 Obsidian。写入后自动更新项目 CLAUDE.md 的 Obsidian 索引段。</gsd:goal>
<gsd:phase>模式判断:Hook 触发 → 自动沉淀;用户说"追问/优化/继续讨论" → 浏览追问;其他 → 手动沉淀。</gsd:phase>
- <gsd:phase>自动/手动沉淀:识别项目 → 分析对话 → 提取知识 → 匹配/创建文件 → 写入更新。</gsd:phase>
- <gsd:phase>浏览追问:列出文章 → 用户选择 → 读取全文 → 进入追问循环 → 更新文章。</gsd:phase>
+ <gsd:phase>自动/手动沉淀:识别项目 → 分析对话 → 提取知识 → 匹配/创建文件 → 写入更新 → 更新项目 CLAUDE.md 索引段。</gsd:phase>
+ <gsd:phase>浏览追问:列出文章 → 用户选择 → 读取全文 → 进入追问循环 → 更新文章 → 更新项目 CLAUDE.md 索引段。</gsd:phase>
</gsd:workflow>
# Obsidian 项目知识沉淀 (ob-project-log / 项目沉淀)
## 做什么
从 AI 对话中提取项目知识,按**主题**写入项目目录。支持三种模式。
## 配置检查
1. 检查全局 CLAUDE.md 中 `OBSIDIAN_REPO` 配置变量
2. 如果未定义,使用 AskUserQuestion 询问用户
3. 将路径保存为 `$OBSIDIAN_REPO` 变量供后续使用
+ ## 项目路径解析
+
+ **核心问题**:不同类型的项目,Obsidian wiki 目录不同。必须先检测项目类型,再确定写入路径。
+
+ ### 检测流程(按优先级)
+
+ 1. **检查 CLAUDE.md 已有索引路径**:如果 `<!-- ob-index:start -->` 区域内已有 `> 索引路径:` 行,直接使用该路径
+ 2. **检查 `.study-meta.json`**:如果项目根目录存在此文件且包含 `"managedBy": "repo-study"`,判定为 repo-study 项目
+ 3. **检查目录名后缀**:如果项目目录名以 `-study` 结尾,且 `$OBSIDIAN_REPO/wiki/open-source/{project-name}/` 存在,判定为 repo-study 项目
+ 4. **模糊搜索已有目录**:在 `$OBSIDIAN_REPO/wiki/` 下搜索与项目名匹配的目录
+ 5. **以上都不匹配**:默认为开发项目
+
+ ### 路径规则
+
+ | 项目类型 | 检测条件 | Wiki 路径 | 示例 |
+ |----------|---------|-----------|------|
+ | **repo-study 项目** | `.study-meta.json` 存在,或目录名以 `-study` 结尾且在 `open-source/` 下有对应目录 | `$OBSIDIAN_REPO/wiki/open-source/{project-name}/` | `wiki/open-source/codex-plugin-cc-study/` |
+ | **开发项目** | 其他 | `$OBSIDIAN_REPO/wiki/projects/{project-name}/` | `wiki/projects/CodeIsland/` |
+
+ ### 使用约定
+
+ 文档中所有 `$WIKI_PATH` 指代根据上述规则解析后的项目 wiki 目录路径。路径末尾无 `/`。
+
+ ```
+ $WIKI_PATH = $OBSIDIAN_REPO/wiki/open-source/{project} # repo-study
+ $WIKI_PATH = $OBSIDIAN_REPO/wiki/projects/{project} # 开发项目
+ ```
+
## 模式判断
根据触发方式自动判断模式:
| 触发方式 | 模式 | 行为 |
|----------|------|------|
| Stop Hook 自动触发 | **自动沉淀** | 分析对话,提取知识,静默写入 |
| "项目沉淀" / "记录到项目" / "ob-project-log" | **手动沉淀** | 同上,但输出详细摘要 |
| "追问文章" / "继续讨论" / "优化笔记" / "项目追问" | **浏览追问** | 列出文章,选择后进入追问循环 |
---
## 模式一:自动沉淀(Hook 触发)
Stop Hook 在每次对话结束时自动触发,Claude 执行以下流程:
### 1. 检测环境
- 当前目录是否在 git 项目中
- `$OBSIDIAN_REPO` 是否已配置
- 两者都满足才继续
### 2. 分析对话
判断本次对话是否包含值得沉淀的项目知识:
**值得沉淀的信号**:
- 讨论了项目架构、模块划分、数据流
- 做了技术选型或方案决策
- 踩了坑并找到了解决方案
- 发现了设计规范或最佳实践
- 提出了改进计划或未来展望
**不需要沉淀的信号**:
- 纯闲聊或无结论讨论
- 临时调试命令(无长期价值)
- 已经沉淀过的重复内容
- 仅涉及文件编辑/创建(无知识增量)
### 2.5 读取质量偏好
如果 `$OBSIDIAN_REPO/wiki/.rating-preferences.md` 存在:
1. 读取偏好文件,提取核心偏好规则
2. 在后续提取和写入时参考这些规则:
- 内容需要有深度和干货(非表面介绍)
- 标题需准确反映内容
- 文章间应互相串联(使用 [[wikilinks]])
- 包含 reference/相关链接
- 其他偏好规则作为写作质量指引
3. 不存在则跳过,使用默认标准
### 3. 提取与写入
- 按维度提取内容(参考 [references/study-dimensions.md](references/study-dimensions.md))
- **涉及具体代码时**:生成 code-ref callout 引用,不嵌入代码片段(参考 [references/code-ref-format.md](references/code-ref-format.md))
- **质量规范**:判断文章类型,按 [references/writing-quality.md](references/writing-quality.md) 对应类型标准写入
- 提取 git remote URL 生成 GitHub 链接(`git remote get-url origin` → 提取 `owner/repo`)
**索引加速匹配**:在匹配已有文件前,先检查 `index.md`:
- 1. 读取 `$OBSIDIAN_REPO/wiki/projects/{project}/index.md`
+ 1. 读取 `$WIKI_PATH/index.md`
2. 如果存在:从索引表格中查找主题匹配的文件,无需全量读取所有文件
3. 如果不存在:fallback 到原有逻辑(ls 目录 + 逐个读取文件),并在写入完成后创建索引
- 匹配已有文件或新建文件
- 追加/合并内容,不覆盖
**新建文件的 frontmatter 模板**(必填):
```yaml
---
article_id: OBA-{随机8位}
tags: [{项目名}, {主题标签}]
type: {预定义类型} # concept/tutorial/troubleshooting/reference/note
updated_at: {YYYY-MM-DD}
created_at: {YYYY-MM-DD}
source: conversation
---
```
**article_id 分配规则**(随机生成,无状态):
1. 生成方式:`OBA-` + 8位随机小写字母数字
2. 生成命令:`python3 -c "import random,string; print(''.join(random.choices(string.ascii_lowercase+string.digits,k=8)))"`
3. 生成后验证唯一性:`grep -rh "OBA-{生成的ID}" "$OBSIDIAN_REPO/wiki/" --include="*.md"`,如果已存在则重新生成
4. 已有文章更新时**不修改** article_id
5. ID 一旦分配即永久绑定,即使文章被删除,该 ID 也不会被复用
**写入后验证**(遵循 [frontmatter-schema](references/frontmatter-schema.md)):
1. **Frontmatter**:确认 article_id、tags(非空)、type(预定义值)、updated_at 存在
2. **Wikilink**:扫描 `[[xxx]]` 引用,确认目标文件存在
3. **索引一致性**:确认新文件已出现在 `index.md` 表格中
4. **交叉引用**:在同目录已有文章中查找相关主题,添加 `[[新文章名]]` 反向链接
**更新索引**:写入完成后,同步更新 `index.md`(格式见下方"索引机制"章节)
+ ### 3.5 更新项目 CLAUDE.md 索引段
+
+ 写入文章后,自动更新项目 CLAUDE.md 中的 Obsidian 索引段(格式参考 [references/claude-index-format.md](references/claude-index-format.md))。
+
+ **流程**:
+
+ 1. **获取项目 git 根目录**:`git rev-parse --show-toplevel`
+ 2. **查找 CLAUDE.md**:`{git_root}/CLAUDE.md`
+ 3. **发现 Obsidian 索引路径**(按优先级):
+ - 读取 CLAUDE.md 中已有的 `<!-- ob-index:start -->` 标记内的路径
+ - 精确匹配:`$WIKI_PATH/index.md`
+ - 模糊搜索:在 `$OBSIDIAN_REPO/wiki/` 下搜索 frontmatter 含 `project: {project_name}` 的 index.md
+ - 目录名匹配:`find "$OBSIDIAN_REPO/wiki/" -type d -name "*{project}*"`
+ 4. **读取 Obsidian 索引**:解析 index.md 表格中的文件名和主题
+ 5. **生成 CLAUDE.md 索引段**:
+ - 表格列:文件 | 主题 | 何时读取
+ - "何时读取" 基于主题和涵盖维度自动推导
+ 6. **写入 CLAUDE.md**:
+ - 已有 `<!-- ob-index:start -->` 标记 → 替换标记区域内容
+ - 已有旧的手动 "Obsidian 知识库" 部分(无标记)→ 替换为标记区域
+ - 都没有 → 在 CLAUDE.md 末尾追加标记区域
+
+ **跳过条件**:
+ - 项目不在 git 仓库中
+ - CLAUDE.md 不可写
+ - 未找到对应的 Obsidian 索引文件
+
### 4. 创建标记文件
无论是否有内容沉淀,都创建标记文件防止 Hook 死循环:
```bash
echo $(date +%s) > /tmp/ob-project-log-synced-$PPID
```
### 5. 简短告知
```
- 📝 已自动沉淀到 wiki/projects/{project}/({N} 条更新)
+ 📝 已自动沉淀到 {wiki_relative_path}({N} 条更新)
```
**无有价值内容时**:
```
本次对话无需沉淀(未发现项目知识增量)
```
### 6. 偏好自学习
沉淀完成后(无论是否有内容写入),分析本次对话中的偏好信号并更新 `$OBSIDIAN_REPO/wiki/.rating-preferences.md`:
1. 扫描对话,识别以下偏好信号:
- 用户对文章内容做了修改/调整(说明偏好某种写法)
- 用户要求补充或删除某些内容(反映质量偏好)
- 用户对结构、格式、深度表达了满意或不满
- 用户主动提到"我喜欢/不喜欢"某种风格
2. 如果发现新的偏好信号,追加到 `.rating-preferences.md` 的**偏好规则**部分:
- 新增规则用 `###` 标题 + 规则内容
- 标注 `(auto-learned {date})` 标记来源
3. 如果已有规则在本次对话中被验证或强化,更新其 `支撑` 描述
4. 无新偏好信号时跳过,不修改文件
---
## 模式二:手动沉淀
与自动沉淀逻辑相同,但由用户主动触发,增加以下交互:
### 1. 识别项目
```
- git remote origin → basename → 当前目录名 → 询问用户
+ CLAUDE.md 已有索引路径 → .study-meta.json → 目录名 -study 后缀 → 模糊搜索 → 询问用户
```
- 目录:`$OBSIDIAN_REPO/wiki/projects/{project}/`
+ 按"项目路径解析"章节确定 `$WIKI_PATH`。
### 2. 提取内容
如果 `$OBSIDIAN_REPO/wiki/.rating-preferences.md` 存在,先读取偏好规则作为内容质量指引。
分析当前对话,按 [references/study-dimensions.md](references/study-dimensions.md) 中的维度提取有价值内容。
每个内容块包含:
- **维度**:属于哪个知识维度(架构设计、核心机制、设计规范等)
- **主题**:具体讲什么(如"插件架构"、"错误处理规范")
- **内容**:核心知识,简洁精准
- **代码引用**(如适用):当对话涉及具体代码文件时,生成 code-ref callout
**提取标准**:只取有长期参考价值的内容。闲聊、临时调试、重复内容不取。
**代码处理规则**(详见 [references/code-ref-format.md](references/code-ref-format.md)):
- 对话中讨论了具体代码文件/函数/类 → 生成 `> [!code-ref]` callout
- code-ref 包含:简要描述、仓库路径 + 行号、GitHub 链接、设计意图
- **不嵌入代码片段**,只保留文字描述 + code-ref 引用
- 短配置片段(JSON/YAML,< 5 行且不太变化)可内联,不需要 code-ref
### 3. 匹配或创建文件
- **索引加速匹配**:先读取 `$OBSIDIAN_REPO/wiki/projects/{project}/index.md`:
+ **索引加速匹配**:先读取 `$WIKI_PATH/index.md`:
1. 如果索引存在:从索引表格中查找主题匹配的文件,无需全量读取
2. 如果索引不存在:fallback 到原有逻辑(ls 目录 + 逐个读取文件内容),并在写入完成后创建索引
对每个内容块:
- 已有文件主题匹配 → 追加到该文件对应位置
- 无匹配文件 → 新建 `{slug}.md`,slug 从主题生成(短英文+连字符)
**不预设固定文件名**,完全根据对话内容动态决定。
**更新索引**:写入完成后,同步更新 `index.md`(格式见下方"索引机制"章节)
+ **更新项目 CLAUDE.md 索引段**:与自动沉淀模式 3.5 相同,写入后自动更新项目 CLAUDE.md 中的 Obsidian 索引段(参考 [references/claude-index-format.md](references/claude-index-format.md))。
+
### 4. 写入规则
#### 基本规则
- **不覆盖**:已有内容保留,新内容追加或合并
- **去重**:相同主题合并,不重复
- **敏感信息**:API key、密码、token → `{REDACTED}`
- **简洁**:每条点到为止
#### 代码引用
涉及具体代码时使用 code-ref callout,格式见 [references/code-ref-format.md](references/code-ref-format.md):
```
> [!code-ref] {描述}
> **仓库**: {repo} | **路径**: `{path}:{line_start}-{line_end}`
> 🔗 [GitHub]({github_url}#L{start}-L{end})
>
> {设计意图}
```
#### 质量规范(必须遵循)
写入前判断文章类型,按 [references/writing-quality.md](references/writing-quality.md) 中对应类型的标准执行:
| 类型 | 触发信号 | 必填要素 |
|------|----------|----------|
| **概念/分析** | 架构、原理、对比 | 独到视角 + 关键论点有 code-ref 支撑 + 底部参考 |
| **操作指南** | 安装、配置、教程 | 前置条件 + 编号步骤 + 代码示例 + 常见问题 |
| **踩坑记录** | Bug、兼容性、意外行为 | 症状 + 根因 + 方案 + 预防 |
| **决策记录** | 选型、方案取舍 | 背景 + 备选方案 + 对比 + 选择理由 |
**质量底线**:文章必须通过 [质量自检清单](references/writing-quality.md),不达标的先补充再写入。
### 5. 输出摘要
```
- 📝 已沉淀到 wiki/projects/{project}/
+ 📝 已沉淀到 {wiki_relative_path}
更新:
- {filename}.md → {做了什么}
- {filename}.md → {做了什么}(新建)
```
### 6. 偏好自学习
与自动沉淀模式 6 相同:分析本次对话中的偏好信号,更新 `.rating-preferences.md`。
---
## 模式三:浏览追问
找到已有文章,继续提问优化。适用于:
- 之前沉淀的文章不够完整
- 文章内容看不懂,想追问细节
- 想补充新的内容或纠正错误
### 1. 识别项目
```
- git remote origin → basename → 当前目录名 → 询问用户
+ CLAUDE.md 已有索引路径 → .study-meta.json → 目录名 -study 后缀 → 模糊搜索 → 询问用户
```
- 目录:`$OBSIDIAN_REPO/wiki/projects/{project}/`
+ 按"项目路径解析"章节确定 `$WIKI_PATH`。
### 2. 列出文章
- **索引加速展示**:先读取 `$OBSIDIAN_REPO/wiki/projects/{project}/index.md`:
+ **索引加速展示**:先读取 `$WIKI_PATH/index.md`:
1. 如果索引存在:直接从索引表格生成文章列表,无需逐个读取文件
2. 如果索引不存在:fallback 到原有逻辑(ls 目录 + 逐个读取文件首部提取主题),并在展示完成后创建索引
注意:`index.md` 是元数据文件,不出现在文章列表中。子目录中的文件以 `decisions/xxx.md` 格式列出。
- 列出 `$OBSIDIAN_REPO/wiki/projects/{project}/` 下所有文件:
+ 列出 `$WIKI_PATH/` 下所有文件:
```
- 📂 wiki/projects/{project}/
+ 📂 {wiki_relative_path}
1. [OBA-k7jm2p9q] architecture.md — 架构设计
更新于 2024-01-15 | 涵盖:目录结构、模块职责、数据流
2. [OBA-xn8btf3w] decisions.md — 方案决策
更新于 2024-01-14 | 涵盖:技术选型、设计权衡
3. [OBA-5qr2d7nk] troubleshooting.md — 踩坑记录
更新于 2024-01-10 | 涵盖:bug 排查、兼容性问题
请输入编号或文章 ID 选择文章,或输入关键词搜索:
```
**如果用户指定了关键词**(如 "继续讨论 架构"):直接模糊匹配文章,跳过选择步骤。
**如果目录为空**:提示用户先沉淀内容(切换到手动沉淀模式)。
### 3. 读取并展示
读取选中文章全文,向用户展示核心摘要:
```
📄 {filename}.md
{文章核心内容摘要,3-5 个要点}
---
你可以:
- 提问关于文章内容的问题
- 要求补充某个方面的内容
- 指出错误或不够清楚的地方
- 说"更新"将讨论内容写入文章
- 说"退出"结束追问模式
```
### 4. 追问循环
进入交互式追问模式:
- 用户提问 → AI 基于文章内容回答,结合对话上下文
- 用户要求补充 → AI 分析需要补充的内容
- 用户指出问题 → AI 确认并给出修正建议
### 5. 更新文章
当用户说"更新"或在追问中产生新知识时:
- 读取文章当前内容
- 将讨论中的新见解合并到文章对应位置
- 不删除已有内容,只追加/补充
- 去重,避免与已有内容重复
更新后展示 diff 摘要:
```
✅ 已更新 {filename}.md
+ 新增:{补充了什么}
~ 修改:{调整了什么}
```
+ 更新后同步更新项目 CLAUDE.md 索引段(与自动沉淀模式 3.5 相同)。
+
### 6. 退出
用户说"退出"、"完成"或"好了"时:
- 如有未写入的讨论内容,提示是否更新
- 输出本次追问摘要
- 退出追问模式
---
## 索引机制:index.md
- 每个项目目录 `$OBSIDIAN_REPO/wiki/projects/{project}/` 下维护 `index.md`,用于加速文件匹配和列表展示,避免全量读取。
+ 每个项目目录 `$WIKI_PATH/` 下维护 `index.md`,用于加速文件匹配和列表展示,避免全量读取。
### 索引文件格式
```markdown
---
type: project-index
project: {project-name}
+ article_id: OBA-{随机8位}
updated_at: {date}
---
# {project-name} 知识索引
| ID | 文件 | 主题 | 涵盖维度 | 更新日期 |
|----|------|------|----------|----------|
| OBA-k7jm2p9q | terminal-jump-debug.md | 终端跳转实现指南 | 架构设计、踩坑记录、可复用方案 | 2026-04-15 |
```
+ **index.md 的 article_id**:
+ - index.md 本身也需要 article_id(与其他文章同等对待)
+ - 新建 index.md 时分配,后续更新不修改
+ - 使用与文章相同的生成和验证规则
+
### 全局 article_id 机制
文章 ID 格式为 `OBA-{8位随机字母数字}`,全局唯一,随机生成。特性:
- **生成**:8 位随机小写字母+数字,无需扫描现有 ID(极低碰撞概率)
- **不变性**:ID 一旦分配,永不修改(即使文章被更新、移动或删除)
- **唯一性验证**:生成后 grep 确认无碰撞,有碰撞则重新生成
- **删除安全**:文章删除后 ID 不被复用,避免引用歧义
### 索引更新规则
- **触发时机**:每次写入/新建/更新文件后,同步更新 `index.md`
- **更新内容**:ID、文件名(含子目录前缀)、主题(从内容提取)、涵盖维度、更新日期
- **排序**:按更新日期倒序排列(最新在前)
- **子目录文件**:使用 `decisions/xxx.md` 格式,不以 `_` 开头的 `.md` 文件都应纳入索引
### 向后兼容
- 如果 `index.md` 不存在,skill 仍能正常工作(fallback 到 ls + 逐个读取文件)
- fallback 完成后自动创建索引,后续操作即可加速
+
+ ---
+
+ ## CLAUDE.md 索引联动
+
+ 项目 CLAUDE.md 中的 Obsidian 索引段实现了渐进式知识加载(详见 [references/claude-index-format.md](references/claude-index-format.md)):
+
+ ```
+ Level 1: CLAUDE.md `<!-- ob-index -->` 区域(自动加载,紧凑概览)
+ → Level 2: Obsidian index.md(按需加载,完整表格含 ID 和维度)
+ → Level 3: 具体文章(按需加载,完整内容)
+ ```
+
+ ### 自动维护触发时机
+
+ | 触发来源 | 时机 |
+ |----------|------|
+ | 自动沉淀(模式一) | 写入文章 + 更新 index.md 后 |
+ | 手动沉淀(模式二) | 写入文章 + 更新 index.md 后 |
+ | 浏览追问(模式三) | 更新文章后 |
+ | ob-index | 重建索引后(由 ob-index skill 负责) |
+
+ ### 索引段格式
+
+ ```markdown
+ <!-- ob-index:start -->
+ ## Obsidian 知识库
+
+ > 索引路径:`{OBSIDIAN_REPO}/wiki/{section}/{project}/index.md`
+ > 渐进式加载:先读本概览,需要详情时读取索引文件,再读取具体文章。
+
+ | 文件 | 主题 | 何时读取 |
+ |------|------|----------|
+ | file.md | 一句话主题描述 | 需要了解{主题}时 |
+ <!-- ob-index:end -->
+ ```
---
## 异常处理
| 场景 | 处理 |
|------|------|
| OBSIDIAN_REPO 未配置 | 询问用户 |
| 项目识别失败 | 询问用户 |
| 目录不存在 | 自动创建 |
| 对话无有价值内容 | 自动沉淀模式不操作;手动模式告知用户 |
| 追问模式无匹配文章 | 提示用户先沉淀,或创建新文章 |
| 追问模式目录为空 | 提示先使用手动沉淀创建内容 |
| Hook 触发但非 git 项目 | 跳过,不执行任何操作 |
| `index.md` 不存在 | fallback 到原有逻辑(ls + 逐个读取),完成后自动创建索引 |
| `index.md` 损坏或格式异常 | 忽略索引,fallback 到原有逻辑,下次写入时重建索引 |
| 索引与实际文件不一致 | 以实际文件为准,更新索引 |