ob-project-log · git:20260419.396531a · 2026-04-19 · sha256 d26e1c5d389bff34

ob-project-log git:20260419.396531aA

Immutable. This exact content never changes and is served at /api/v1/blob/d26e1c5d389bff34.

---
name: ob-project-log
description: "项目知识沉淀到 Obsidian。三种模式:自动沉淀(Hook)、手动沉淀、浏览追问。触发词:ob-project-log、项目沉淀、追问文章、继续讨论。"
---

<role>Obsidian 项目知识沉淀助手。从 AI 对话中提取项目知识,支持自动沉淀、手动沉淀和浏览追问三种模式。</role>
<purpose>将对话中的项目知识写入 wiki/projects/{project}/,按主题组织为活文档。支持浏览已有文章并追问优化。</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:phase>模式判断:Hook 触发 → 自动沉淀;用户说"追问/优化/继续讨论" → 浏览追问;其他 → 手动沉淀。</gsd:phase>
  <gsd:phase>自动/手动沉淀:识别项目 → 分析对话 → 提取知识 → 匹配/创建文件 → 写入更新。</gsd:phase>
  <gsd:phase>浏览追问:列出文章 → 用户选择 → 读取全文 → 进入追问循环 → 更新文章。</gsd:phase>
</gsd:workflow>

# Obsidian 项目知识沉淀 (ob-project-log / 项目沉淀)

## 做什么

从 AI 对话中提取项目知识,按**主题**写入项目目录。支持三种模式。

## 配置检查

1. 检查全局 CLAUDE.md 中 `OBSIDIAN_REPO` 配置变量
2. 如果未定义,使用 AskUserQuestion 询问用户
3. 将路径保存为 `$OBSIDIAN_REPO` 变量供后续使用

## 模式判断

根据触发方式自动判断模式:

| 触发方式 | 模式 | 行为 |
|----------|------|------|
| 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`
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`(格式见下方"索引机制"章节)

### 4. 创建标记文件

无论是否有内容沉淀,都创建标记文件防止 Hook 死循环:

```bash
echo $(date +%s) > /tmp/ob-project-log-synced-$PPID
```

### 5. 简短告知

```
📝 已自动沉淀到 wiki/projects/{project}/({N} 条更新)
```

**无有价值内容时**:
```
本次对话无需沉淀(未发现项目知识增量)
```

### 6. 偏好自学习

沉淀完成后(无论是否有内容写入),分析本次对话中的偏好信号并更新 `$OBSIDIAN_REPO/wiki/.rating-preferences.md`:

1. 扫描对话,识别以下偏好信号:
   - 用户对文章内容做了修改/调整(说明偏好某种写法)
   - 用户要求补充或删除某些内容(反映质量偏好)
   - 用户对结构、格式、深度表达了满意或不满
   - 用户主动提到"我喜欢/不喜欢"某种风格
2. 如果发现新的偏好信号,追加到 `.rating-preferences.md` 的**偏好规则**部分:
   - 新增规则用 `###` 标题 + 规则内容
   - 标注 `(auto-learned {date})` 标记来源
3. 如果已有规则在本次对话中被验证或强化,更新其 `支撑` 描述
4. 无新偏好信号时跳过,不修改文件

---

## 模式二:手动沉淀

与自动沉淀逻辑相同,但由用户主动触发,增加以下交互:

### 1. 识别项目

```
git remote origin → basename → 当前目录名 → 询问用户
```

目录:`$OBSIDIAN_REPO/wiki/projects/{project}/`

### 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`:
1. 如果索引存在:从索引表格中查找主题匹配的文件,无需全量读取
2. 如果索引不存在:fallback 到原有逻辑(ls 目录 + 逐个读取文件内容),并在写入完成后创建索引

对每个内容块:

- 已有文件主题匹配 → 追加到该文件对应位置
- 无匹配文件 → 新建 `{slug}.md`,slug 从主题生成(短英文+连字符)

**不预设固定文件名**,完全根据对话内容动态决定。

**更新索引**:写入完成后,同步更新 `index.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}/

更新:
  - {filename}.md  → {做了什么}
  - {filename}.md  → {做了什么}(新建)
```

### 6. 偏好自学习

与自动沉淀模式 6 相同:分析本次对话中的偏好信号,更新 `.rating-preferences.md`。

---

## 模式三:浏览追问

找到已有文章,继续提问优化。适用于:
- 之前沉淀的文章不够完整
- 文章内容看不懂,想追问细节
- 想补充新的内容或纠正错误

### 1. 识别项目

```
git remote origin → basename → 当前目录名 → 询问用户
```

目录:`$OBSIDIAN_REPO/wiki/projects/{project}/`

### 2. 列出文章

**索引加速展示**:先读取 `$OBSIDIAN_REPO/wiki/projects/{project}/index.md`:
1. 如果索引存在:直接从索引表格生成文章列表,无需逐个读取文件
2. 如果索引不存在:fallback 到原有逻辑(ls 目录 + 逐个读取文件首部提取主题),并在展示完成后创建索引

注意:`index.md` 是元数据文件,不出现在文章列表中。子目录中的文件以 `decisions/xxx.md` 格式列出。

列出 `$OBSIDIAN_REPO/wiki/projects/{project}/` 下所有文件:

```
📂 wiki/projects/{project}/

  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
  + 新增:{补充了什么}
  ~ 修改:{调整了什么}
```

### 6. 退出

用户说"退出"、"完成"或"好了"时:
- 如有未写入的讨论内容,提示是否更新
- 输出本次追问摘要
- 退出追问模式

---

## 索引机制:index.md

每个项目目录 `$OBSIDIAN_REPO/wiki/projects/{project}/` 下维护 `index.md`,用于加速文件匹配和列表展示,避免全量读取。

### 索引文件格式

```markdown
---
type: project-index
project: {project-name}
updated_at: {date}
---

# {project-name} 知识索引

| ID | 文件 | 主题 | 涵盖维度 | 更新日期 |
|----|------|------|----------|----------|
| OBA-k7jm2p9q | terminal-jump-debug.md | 终端跳转实现指南 | 架构设计、踩坑记录、可复用方案 | 2026-04-15 |
```

### 全局 article_id 机制

文章 ID 格式为 `OBA-{8位随机字母数字}`,全局唯一,随机生成。特性:
- **生成**:8 位随机小写字母+数字,无需扫描现有 ID(极低碰撞概率)
- **不变性**:ID 一旦分配,永不修改(即使文章被更新、移动或删除)
- **唯一性验证**:生成后 grep 确认无碰撞,有碰撞则重新生成
- **删除安全**:文章删除后 ID 不被复用,避免引用歧义

### 索引更新规则

- **触发时机**:每次写入/新建/更新文件后,同步更新 `index.md`
- **更新内容**:ID、文件名(含子目录前缀)、主题(从内容提取)、涵盖维度、更新日期
- **排序**:按更新日期倒序排列(最新在前)
- **子目录文件**:使用 `decisions/xxx.md` 格式,不以 `_` 开头的 `.md` 文件都应纳入索引

### 向后兼容

- 如果 `index.md` 不存在,skill 仍能正常工作(fallback 到 ls + 逐个读取文件)
- fallback 完成后自动创建索引,后续操作即可加速

---

## 异常处理

| 场景 | 处理 |
|------|------|
| OBSIDIAN_REPO 未配置 | 询问用户 |
| 项目识别失败 | 询问用户 |
| 目录不存在 | 自动创建 |
| 对话无有价值内容 | 自动沉淀模式不操作;手动模式告知用户 |
| 追问模式无匹配文章 | 提示用户先沉淀,或创建新文章 |
| 追问模式目录为空 | 提示先使用手动沉淀创建内容 |
| Hook 触发但非 git 项目 | 跳过,不执行任何操作 |
| `index.md` 不存在 | fallback 到原有逻辑(ls + 逐个读取),完成后自动创建索引 |
| `index.md` 损坏或格式异常 | 忽略索引,fallback 到原有逻辑,下次写入时重建索引 |
| 索引与实际文件不一致 | 以实际文件为准,更新索引 |