一只阿木木

拆解 claude-obsidian——一个 Claude Code Skill 是如何工作的?

拆解 claude-obsidian

——一个 Claude Code Skill 是如何工作的?

作者:一只阿木木 我相信:在 AI 时代,每个普通人都该拥有一个自动生长的知识系统。

先说你为什么要读这篇文章

如果你:

  • 用了 claude-obsidian 觉得很神奇,但不知道"它到底在哪里"
  • 想给它写一个自定义 skill,但不知道从哪里下手
  • 对"Claude Code Skill 是什么东西"有点模糊
  • 想造自己的 AI Agent 工具,正在找参考架构

那这篇文章就是为你写的。

我们要做的事情只有一件:把 claude-obsidian 的源码目录彻底拆开,逐层搞清楚每个文件是干什么的,它们又是如何协同工作的。

不会有废话,全是结构。


第一层:它到底是什么?重新理解"Claude Code Skill"

在拆代码之前,先把这个概念说清楚——因为很多人对"Skill"的定义是模糊的。

10 大多数 Obsidian AI 插件是聊天界面,它们回答你关于现有笔记的问题。claude-obsidian 是一个知识引擎,它自主地创建、组织、维护和演化你的笔记。

这个区别背后,是架构上的根本不同:

传统 Obsidian 插件是这样工作的:

text

用户操作 → Obsidian JS API → 修改 vault 文件

Claude Code Skill是这样工作的:

text

用户自然语言 → Claude Code Agent → 读取 SKILL.md 指令 → 调用工具(读写文件)→ 修改 vault 文件

关键差异:执行者从 JavaScript 代码变成了 LLM。SKILL.md 不是代码,是给 LLM 看的"操作手册"。LLM 读了这份手册,知道该怎么做,然后自己去做。

12 Skills 可以在 SKILL.md 旁边包含支持文件。Plugins 可以提供专门的子 agent,用于特定任务,Claude 可以在适当时自动调用它们。

这是整个系统的第一层认知——Skill 是 LLM 的说明书,不是传统意义上的程序代码。


第二层:完整目录结构,逐行注释

1 项目的完整目录结构如下:

text

claude-obsidian/
├── .claude-plugin/
│   ├── plugin.json          # 插件清单(元数据 + 配置)
│   └── marketplace.json     # 分发配置(用于 plugin marketplace)
│
├── skills/                  # 15 个 Claude Code skills(v1.9.2)
│   ├── wiki/                # 主编排器 + 7 个参考文件
│   ├── wiki-ingest/         # INGEST 操作(核心写入)
│   ├── wiki-query/          # QUERY 操作(知识检索)
│   ├── wiki-lint/           # LINT 操作(健康检查)
│   ├── wiki-cli/            # Obsidian CLI 传输层(v1.7+)
│   ├── wiki-retrieve/       # 混合检索(v1.7+,可选)
│   ├── wiki-mode/           # 方法论模式路由(v1.8+)
│   ├── wiki-fold/           # 日志折叠(DragonScale 可选)
│   ├── save/                # /save:会话归档
│   ├── autoresearch/        # 自主研究循环
│   │   └── references/
│   │       └── program.md   # 可配置的研究目标
│   ├── canvas/              # 可视化层(图片/PDF/笔记)
│   │   └── references/
│   │       └── canvas-spec.md  # Obsidian canvas JSON 规范
│   ├── defuddle/            # Web 内容提取封装
│   ├── obsidian-bases/      # Bases schema 参考
│   ├── obsidian-markdown/   # OFM 语法参考
│   └── think/               # 10 原则思维框架(v1.9+)
│
├── agents/
│   ├── verifier.md          # 提交前审计 agent(v1.7.1+)
│   ├── wiki-ingest.md       # 并行批量摄入 agent
│   └── wiki-lint.md         # 健康检查 agent
│
├── commands/
│   ├── wiki.md              # /wiki 引导命令
│   ├── save.md              # /save 命令
│   ├── autoresearch.md      # /autoresearch 命令
│   └── canvas.md            # /canvas 可视化命令
│
├── hooks/
│   └── hooks.json           # SessionStart + Stop 热缓存钩子
│
├── _templates/              # Obsidian Templater 模板
├── wiki/                    # 预填充的示例 vault
├── bin/
│   └── setup-vault.sh       # 一键配置脚本
└── scripts/
    ├── allocate-address.sh  # 原子性页面地址分配器
    └── wiki-lock.sh         # 文件级并发锁

目录很大,但有清晰的层次。下面我们分层拆解最关键的几个部分。


第三层:.claude-plugin/ ——插件的身份证

12 .claude-plugin/plugin.json 文件定义了插件的元数据和配置。清单文件是可选的——如果省略,Claude Code 会自动发现默认位置的组件,并从目录名推导插件名称。当你需要提供元数据或自定义组件路径时才需要使用清单。

plugin.json 的基本结构是这样的:

JSON

{
  "name": "claude-obsidian",
  "version": "1.9.2",
  "description": "Self-organizing AI second brain for Obsidian",
  "skills": ["skills/wiki", "skills/wiki-ingest", ...],
  "agents": ["agents/wiki-ingest.md", "agents/wiki-lint.md"],
  "hooks": "hooks/hooks.json"
}

marketplace.json 是用于 claude plugin marketplace 系统的分发清单。3.claude-plugin/marketplace.json 清单使这个仓库与 Claude Code 的 marketplace 系统兼容。


第四层:skills/ ——系统的大脑

这是整个项目最重要的目录。每个 skill 的结构是:

text

skills/
└── skill-name/
    ├── SKILL.md          # 核心:给 LLM 的操作说明书
    └── references/       # 补充参考文档(可选)
        └── *.md

12 对 skill 的 SKILL.md 所做的更改会在当前会话中立即生效。这意味着你修改 SKILL.md 之后不需要重启,Claude 下一次调用时就会读到新内容——这是非常重要的开发特性。

skills/wiki/——主编排器

这是整个系统的入口。当你输入 /wiki 时,Claude Code 读取的就是这个 skill 的 SKILL.md。

它的职责是:

  • 初始化 vault(第一次运行时)
  • 检查 vault 健康状态(后续运行时)
  • 1 后续运行时,/wiki 从上次停止的地方继续——检查 vault 健康状态,显示过期声明,以及显示来自 hot.md 的最近活动。

skills/wiki-ingest/——最核心的 skill

这是负责把原始资料"编译"成 wiki 的 skill,也是整个系统逻辑最复杂的地方。

触发词:ingest、process this source、add this to the wiki、read and file this、batch ingest、ingest this url

它在 SKILL.md 里定义了完整的 ingest 流程:

第一步:去重检查

在摄入任何文件之前,检查 .raw/.manifest.json 以避免重新处理未更改的来源。manifest 的结构包含每个来源文件的哈希值、摄入时间、创建的页面和更新的页面。

这个机制避免了重复 ingest 同一个文件,同时也作为 ingest 历史的审计日志。

第二步:地址分配

./scripts/allocate-address.sh 原子性地保留并返回下一个地址。--peek 参数在不保留的情况下打印下一个值(安全,只读)。--rebuild 从现有 frontmatter 中观察到的最高 c-NNNNNN 重新计算计数器。 


在写入任何新的非元数据页面之前,调用 ./scripts/allocate-address.sh 并捕获输出。在页面的 frontmatter 中包含 address: c-XXXXXX。

第三步:单写锁

Phase 2 是单写模式。不要从多个 Claude 会话或分配地址的子 agent 并行运行 ingest。flock 在 helper 中防止计数器损坏,但不会序列化页面写入本身。

第四步:写入 wiki 页面

SKILL.md 规定了页面写入的完整 Markdown 规范:

语法标准:使用正确的 Obsidian Flavored Markdown 编写所有 Obsidian Markdown。Wikilinks 格式为 [[Note Name]],callouts 格式为 > [!type] Title,embeds 格式为 ![[file]],属性使用 YAML frontmatter。

一个典型的 wiki 页面的 YAML frontmatter 长这样:

YAML

---
address: c-000042
type: entity          # entity | concept | source | synthesis
title: "Redis aeEventLoop"
created: 2026-05-01
updated: 2026-05-15
confidence: high      # high | medium | low
sources:
  - .raw/redis/ae-analysis.md
tags: [redis, event-loop, io-multiplexing]
---

skills/wiki-query/——检索 skill

你提问。Claude 读取热缓存(最近上下文),扫描索引,深入相关页面,综合出答案。它引用的是具体的 wiki 页面,不是训练数据。

检索的三层优先级(在 SKILL.md 里明确定义):

text

第一层:wiki/hot.md(约 500 tokens)——最近上下文
第二层:wiki/index.md(约 1000 tokens)——总目录
第三层:相关的具体 wiki 页面(约 3000 tokens)——详细内容

skills/wiki-retrieve/——可选的混合检索层(v1.7+)

这是 v1.7 新增的高级检索 skill,基于 Anthropic 2024 年 9 月的 contextual retrieval 研究。

wiki-retrieve skill 提供了一个基于 Anthropic 2024 年 9 月上下文检索研究的三层检索管道。BM25 是始终开启的稀疏层。上下文前缀层需要同意(--allow-egress),用于希望将页面内容发送到 Anthropic API 以生成前缀的用户。余弦重排序默认使用本地 ollama 模型。v1.7 的 50 个查询基准测试测量到 top-1 准确率提升了 32 个百分点,错误减少了 41%。

注意:这个 skill 是可选的,默认不启用。开启命令:

Bash

bash bin/setup-retrieve.sh

第五层:agents/ ——并发执行的子 Agent

Plugins 可以提供专门的子 agent,用于 Claude 可以在适当时自动调用的特定任务。Agent 的结构包含 frontmatter:name、description、model、effort、maxTurns、disallowedTools,以及详细的系统提示。

claude-obsidian 有三个 agent:

agents/wiki-ingest.md——并行 ingest agent

当你批量 ingest 多个来源时,这个 agent 会被主 Claude 调用,并行处理多个文件。

 并行 ingest 子 agent 可能同时操作同一个 wiki 页面。scripts/wiki-lock.sh 提供文件级的建议锁:一个写入者获取锁,另一个等待并在下一轮重试。PostToolUse 自动提交钩子在暂存前检查锁列表,在写入进行时推迟提交。

它的 frontmatter 大概是这样的:

Markdown

---
name: wiki-ingest
description: 并行处理多个来源的 ingest,当用户批量摄入时调用
model: sonnet
effort: high
maxTurns: 50
disallowedTools: []
---
(详细的 ingest 操作系统提示)

agents/verifier.md——提交前审计 agent(v1.7.1+)

在写入 wiki 文件触发 PostToolUse 钩子之前,verifier agent 负责审计本次写入的质量:

  • 检查 frontmatter 是否完整
  • 检查 wikilinks 是否有效
  • 检查是否引用了 .raw/ 里的来源

Plugin agents 支持 name、description、model、effort、maxTurns、tools、disallowedTools、skills、memory、background 和 isolation frontmatter 字段。唯一有效的 isolation 值是 "worktree"。

第六层:hooks/hooks.json——Hot Cache 的运行机制

这是整个系统"跨会话记忆"的技术实现,也是最精妙的设计之一。

wiki/hot.md 存储最近会话的滚动摘要。它通过钩子在 SessionStart 时自动注入,并在 Stop 时通过 scripts/update-hot-cache.sh 调用 claude -p 单次模式在后台重新生成。新会话从最近的上下文开始,无需任何回顾。

hooks.json 的结构:

JSON

{
  "hooks": {
    "SessionStart": [
      {
        "matcher": "*",
        "hooks": [
          {
            "type": "command",
            "command": "bash ${CLAUDE_PLUGIN_ROOT}/scripts/load-hot-cache.sh"
          }
        ]
      }
    ],
    "Stop": [
      {
        "matcher": "*",
        "hooks": [
          {
            "type": "command",
            "command": "bash ${CLAUDE_PLUGIN_ROOT}/scripts/update-hot-cache.sh"
          }
        ]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "bash ${CLAUDE_PLUGIN_ROOT}/scripts/auto-commit.sh"
          }
        ]
      }
    ]
  }
}

三个钩子的职责:

钩子事件
触发时机
做什么
SessionStart
会话开始时
读取 wiki/hot.md,注入上下文
Stop
会话结束时
把本次会话摘要写入 wiki/hot.md
PostToolUse
每次写文件后
自动 git add + git commit

这些钩子在 .claude/settings.json 里定义,并使用 $CLAUDE_PROJECT_DIR,所以在任何 clone 里无需编辑就能工作。

第七层:安全边界设计

claude-obsidian 的安全设计有几个值得学习的地方:

.raw/ 的只读约定

这不是代码层面的限制,而是 SKILL.md 里明确写给 LLM 的规则:不得修改 .raw/ 目录下的任何文件。 LLM 会遵守这个规则,因为它被写进了 skill 的操作说明里。

Web 出口隔离

上下文前缀层是同意门控的(--allow-egress),用于希望将页面内容发送到 Anthropic API 进行前缀生成的用户。

没有这个标志,所有处理都在本地进行。

URL 内容安全

在 skills/autoresearch/SKILL.md 中的 Web egress 卫生策略(v1.8.2+)规定:拒绝 file:// / javascript: / RFC1918 主机,剥离 <script> 标签和 wikilink 注入尝试,将 fetch 内容体限制在 50KB 以内。

第八层:数据流全貌

把所有层次合在一起,看一次完整的 ingest 的数据流:

text

用户输入:"ingest redis/ae-analysis.md"
        ↓
Claude Code 接收输入
        ↓
读取 skills/wiki-ingest/SKILL.md(操作说明)
        ↓
检查 .raw/.manifest.json(去重)
        ↓
调用 scripts/allocate-address.sh(获取页面地址)
        ↓
读取 .raw/redis/ae-analysis.md(原始来源)
        ↓
提取实体、概念、关系、矛盾
        ↓
写入 wiki/entities/*.md(新实体页)
写入 wiki/concepts/*.md(新概念页)
更新 wiki/sources/*.md(来源摘要页)
更新 wiki/index.md(总目录)
        ↓
PostToolUse 钩子触发 → git commit
        ↓
Stop 钩子触发 → 更新 wiki/hot.md
        ↓
Obsidian 自动刷新(检测到文件变更)

第九层:commands/ vs skills/ 的区别

很多人看到 commands/ 目录会疑惑:skill 和 command 有什么区别?

skills/commands/
触发方式
自然语言触发(关键词识别)
斜杠命令精确触发(/wiki)
内容形式
操作说明 + 参考文档
引导流程说明
典型作用
定义"怎么做某件事"
定义"用户明确执行某命令时怎么引导"

举例:

  • skills/wiki-ingest/ 定义了 ingest 的完整操作逻辑
  • commands/wiki.md 定义了用户输入 /wiki 时的引导流程(检查 Obsidian、初始化 vault、问用户问题等)

用一张图理解整个架构

text

┌─────────────────────────────────────────┐
│              用户自然语言输入              │
└─────────────────┬───────────────────────┘
                  ↓
┌─────────────────────────────────────────┐
│           Claude Code Agent             │
│  读取 SKILL.md → 理解操作规则 → 执行     │
└──────┬────────────────────┬────────────┘
       ↓                    ↓
┌─────────────┐    ┌──────────────────┐
│   skills/   │    │    agents/       │
│ wiki-ingest │    │  wiki-ingest.md  │
│ wiki-query  │    │  wiki-lint.md    │
│ wiki-lint   │    │  verifier.md     │
│ autoresearch│    └──────────────────┘
│ ...         │
└──────┬──────┘
       ↓
┌─────────────────────────────────────────┐
│              hooks/ 钩子层               │
│  SessionStart → 读 hot.md               │
│  Stop → 写 hot.md                       │
│  PostToolUse → git commit               │
└──────┬──────────────────────────────────┘
       ↓
┌─────────────────────────────────────────┐
│            vault 文件系统               │
│  .raw/        ← 只读输入区              │
│  wiki/        ← LLM 写入区             │
│  wiki/hot.md  ← 会话记忆               │
└─────────────────────────────────────────┘

从拆解到实践:你现在可以做什么

理解了这个架构,你有三件事可以立刻做:

Level 1:自定义 program.md 编辑 skills/autoresearch/references/program.md,配置你的研究偏好(优先学术来源、技术文档、或特定领域)。这是最低成本的定制。

Level 2:修改 SKILL.md 比如在 skills/wiki-ingest/SKILL.md 里添加规则:"当摄入技术文档时,额外生成一个 api-reference/ 分类的页面"。修改后立刻生效。

Level 3:写一个全新的 skill 这就是下一篇文章要做的事情——从零写一个"从 GitHub Trending 自动 ingest"的 skill,完整代码。

👇 如果你想继续跟着做:

关注「一只阿木木」,我们在 AI 时代一起构建自己的知识系统。

我是【一只阿木木】,AI 知识系统架构师,坐标杭州。

扫码加入行动营👇获取更多Obsidian + AI数字大脑实践

Image

关注【一只阿木木】。

我相信:在 AI 时代,每个普通人都该拥有一个自动生长的知识系统

去做,才是真的学。🌊