claude-obsidian 的 Agent 运维手册:基于 AGENTS.md 解析产品/仓库边界、Bootstrap 流程与可恢复事务协议
【免费下载链接】claude-obsidianSelf-organizing AI second brain for Obsidian + Claude Code. Drop any source and Claude reads, links, and files it into one connected knowledge graph of plain Markdown you own. AI note-taking, personal knowledge management (PKM), and an open-source Notion alternative. Based on Karpathy's LLM Wiki pattern.项目地址: https://gitcode.com/GitHub_Trending/cl/claude-obsidian
本文以 AGENTS.md 为主体,完整继承其中的产品与 vault 边界规则、五步 Bootstrap 流程、15 个标准技能清单、五步变更事务协议、vault 目录约定与验证约束,并结合 claude_obsidian/paths.py、claude_obsidian/cli.py、claude_obsidian/transaction.py 与 Makefile 等源码,逐一印证这些规则在实现层面如何落地。读完后你将掌握:如何在 Agent 会话中正确解析用户 vault、如何用“先 dry-run 后审批哈希”的两段式流程执行变更、以及如何理解 vault 内各目录的语义边界。
1. AGENTS.md 是什么:写给 Agent 的操作宪法
AGENTS.md 是 claude-obsidian 仓库的 Agent 指令文件,其开篇即给出产品定位:
claude-obsidian is a local-first Agent Skills package for building source-cited, compounding Obsidian knowledge bases. It also ships a Claude Code plugin adapter. The portable workflow is implemented in
skills/and the standard-libraryclaude_obsidian/core; host hooks never define knowledge behavior.
这段话确立了三条架构原则,全文其余规则都围绕它们展开:
- 本地优先(local-first):可变知识状态只属于用户 vault,不落在产品源码树里;
- 行为由技能定义:可移植的工作流实现集中在
skills/(15 个 SKILL.md)和纯标准库的claude_obsidian/核心包,从 claude_obsidian/init.py 的包注释可以确认“no third-party runtime dependencies”这一设计约束; - hooks 不定义知识行为:宿主钩子只做生命周期适配,这一点在 hooks/hooks.json 中可见——
SessionStart(matcher 为startup|resume|clear|compact)与Stop两个钩子仅调用python3 ${CLAUDE_PLUGIN_ROOT}/scripts/claude-obsidian.py hook session-start / stop,超时均为 5 秒。
需要说明的是,AGENTS.md 的 Reference 一节还列出了公开规范仓库、LLM Wiki 模式出处等外部引用,本文按只引用仓库内部证据的原则不再展开外部链接。
2. 产品与 vault 的边界:源码树永远不是你的知识库
AGENTS.md 的 “Product and vault boundaries” 一节给出了四条硬规则,每一条都能在源码中找到对应实现。
2.1 仓库是产品源码,不是默认用户 vault
文档规定:“This repository is the product source. It is not the default user vault.”并进一步定义:用户 vault 是包含.claude-obsidian.json、wiki/、.raw/的目录,所有可变状态必须归属于它。templates/vault/只是可分发的种子模板(仓库中 templates/vault/ 确实只含.gitignore、.obsidian/配置、.raw/.manifest.json、inbox/.gitkeep和wiki/下四个骨架页 hot/index/log/overview,没有任何用户内容)。
这条规则在实现层由 claude_obsidian/paths.py 的assert_not_plugin_tree()强制:
- 目标与插件根同路径时抛出
PLUGIN_ROOT_IS_NOT_VAULT(“refusing to write mutable vault state into the plugin installation”); - 目标位于插件树内部(如
templates/、examples/下)时抛出PLUGIN_TREE_IS_NOT_VAULT; - 即使是隐式 cwd 发现命中插件安装目录,也会以可操作的错误提示要求显式
--vault。
claude_obsidian/cli.py 中_selection()对每个命令都传入plugin_root=PLUGIN_ROOT, allow_plugin_root=False,init/adopt则在入口处先调用assert_not_plugin_tree(destination, PLUGIN_ROOT)(见 cli.py L780-L801)。这意味着“把 vault 建到产品 checkout 里”在两条路径上都会被拒绝。
2.2 禁止从插件缓存或${CLAUDE_PLUGIN_ROOT}推导用户 vault
文档明文禁止:“Never derive a user vault from the plugin cache or${CLAUDE_PLUGIN_ROOT}”。对应实现是 claude_obsidian/paths.py 的resolve_vault_root():其 docstring 明确写着 “The plugin installation root is never accepted by implicit discovery”,并且在搜索祖先目录之前先对 cwd 做一次assert_not_plugin_tree检查——源码注释解释了动机:“Product distributions intentionally exclude contributor vault sentinels”,从而保证源码树与发行版两种 checkout 的行为一致、错误可操作。
2.3 发行版中的 marketplace 目录注入规则
AGENTS.md 还规定了一条发布纪律:含有贡献者 vault 状态的 checkout没有marketplace 目录;config/public-marketplace.json只在经过审计的发布产物内被注入为.claude-plugin/marketplace.json,解包后的 distribution-clean 产物可保留该清单并幂等重建;公共默认分支必须从干净产物填充,绝不允许直接推送贡献者 vault 状态。仓库中 config/public-marketplace.json 的存在与 README.md “Operator reference” 中release build/release audit子命令的说明相互印证:发布产物由 claude_obsidian/release.py 的build_public_artifact本地构建并自审,且“reject contributor hot/log state, root raw sources, runtime metadata...”。
3. vault 解析顺序与 fail-closed 语义
AGENTS.md 给出四级解析顺序:
| 优先级 | 来源 | 说明 |
|---|---|---|
| 1 | 显式--vault | 命令行参数 |
| 2 | CLAUDE_OBSIDIAN_VAULT环境变量 | 进程级显式指定 |
| 3 | 最近的.claude-obsidian.json | 从当前目录向上查找 |
| 4 | 当前目录或其祖先中无歧义的已初始化 vault | 隐式发现 |
文档要求:“Fail closed when no vault is selected.”(选不出 vault 时直接失败,绝不回退到产品树。)
这段规则在 claude_obsidian/paths.py 中逐条落实,返回的VaultSelection数据类携带source字段(explicit/environment/workspace-config/cwd-discovery),可用于审计选择来源。几个值得注意的实现细节:
- 工作区配置的安全读取:
.claude-obsidian.json必须声明schema为claude-obsidian.workspace.v1,且大小不超过 64 KiB;读取路径使用 no-follow 打开标志并在读前读后比对st_dev/st_ino/st_size/st_mtime_ns/st_mode(paths.py L205-L257),防止配置在读取窗口内被替换; - “已初始化 vault”的判定:
is_initialized_vault()要求同时存在wiki/目录和(.obsidian/或.raw/)之一,这解释了为什么种子模板必须包含这几类路径; - 失败即报错:隐式发现失败时抛出
VaultSelectionError("VAULT_NOT_FOUND", "no vault selected; pass --vault or set CLAUDE_OBSIDIAN_VAULT"),而不是静默选一个目录。
doctor子命令(cli.py L134-L159)则把这一选择过程变成可观测输出:报告 schemaclaude-obsidian.doctor.v1,包含selection_source、legacy_layout以及对vault_exists、obsidian_config、wiki、raw、meta_writable、mutation_lock_held六项检查,供 Agent 在动手前先确认自己操作的是哪个 vault。
4. Bootstrap:Agent 会话启动的五步流程
AGENTS.md 的 “Bootstrap” 一节规定了 Agent 接手任务时的标准启动顺序:
- 读 AGENTS.md。开发 checkout 中还应在存在时读取宿主专属的根
CLAUDE.md——发布产物有意不含它(当前 checkout 中确实没有该文件,与文档描述一致); - 完整读取被选定的技能(对应
skills/<name>/SKILL.md,如 skills/wiki/SKILL.md); - 只读取该技能路由到的 reference,不贪多;
- 解析用户 vault。若
wiki/hot.md存在,静默读取(hot 页是“bounded recent context, never a transcript”,见第 6 节); - 新 vault 先 dry-run 再 apply:
python3 scripts/claude-obsidian.py init PATH,审阅输出后确认;已有 vault 则用adopt而非init。
其中第 5 步的两段式流程是整个系统的一致模式,cli.py 把它抽象成了通用函数:
def _approval_fields(vault_root, operation, generated_at): approval_hash = str(inspect_bundle(vault_root, operation)["approval_sha256"]) return { "approved_plan_sha256": approval_hash, ... } def _require_approved_plan(args, vault_root, operation): plan = inspect_bundle(vault_root, operation) actual = str(plan["approval_sha256"]) supplied = getattr(args, "approved_plan_sha256", None) if not supplied: raise TransactionValidationError( "PLAN_APPROVAL_REQUIRED", "--apply requires --approved-plan-sha256 from the reviewed dry-run") if not hmac.compare_digest(supplied, actual): raise TransactionValidationError( "PLAN_CHANGED", "the regenerated transaction differs from the reviewed plan; ...")即:dry-run 输出一个对整个事务 bundle 规范化内容计算的 SHA-256 审批哈希;--apply时必须原样回传,且比较使用hmac.compare_digest防时序侧信道。任何文件系统或生成内容漂移都会使重算哈希与评审哈希不符,从而在写 vault 之前以PLAN_CHANGED失败。command_init还额外保证:评审时记录的 vault 根身份(存在/不存在)在 apply 时仍然成立,新建根目录失败时不做路径级删除,只回滚内容(cli.py L815-L853 的注释解释了原因:并发命名空间替换可能让清理逻辑误删他人的空目录)。
对init与adopt的区分也值得注意:adopt面向已有 Obsidian vault,是“非破坏性采纳”;examples/sample-vault/.claude-obsidian.json 提供了一个带工作区配置文件的示例 vault 结构可作参照。
5. 15 个标准技能:核心、扩展与参考三层
AGENTS.md 声明所有 15 个技能位于skills/<name>/SKILL.md,frontmatter 使用可移植 Agent Skills 子集——恰好只有name和description两个字段——并且不要在commands/下创建镜像文件,Claude Code 通过命名空间名称(如/claude-obsidian:wiki)调用插件技能。仓库顶层目录确认了这 15 个技能目录的完整集合:
| 分层 | 技能 | 职责(依据 AGENTS.md 与 README 技能表) |
|---|---|---|
| 核心工作流 | wiki | 初始化/采纳 vault、诊断就绪度、路由任务 |
| 核心工作流 | save | 保存一条有边界的回答或洞见,而非自动转录 |
| 核心工作流 | wiki-ingest | 把已捕获来源转为链接页面与来源记录 |
| 核心工作流 | wiki-query | 只读地从 vault 证据作答 |
| 核心工作流 | wiki-lint | 报告死链、孤儿、元数据缺失、过期索引与空章节 |
| 扩展 | autoresearch | 有边界的网络研究,显式出网与独立规范合并 |
| 扩展 | canvas | wiki 范围内的 Obsidian Canvas 创建与维护 |
| 扩展 | defuddle | 摄取前清洗网页内容为可读文本 |
| 扩展 | wiki-fold | 对操作日志做可溯源的抽取式折叠 |
| 扩展 | wiki-mode | Generic / LYT / PARA / Zettelkasten 归档规范 |
| 扩展 | wiki-retrieve | 上下文前缀、BM25 与可选余弦重排 |
| 扩展 | wiki-cli | 基于 Obsidian CLI 的读取与事务安全写入 |
| 参考技能 | obsidian-markdown | Obsidian Flavored Markdown 的正确写法 |
| 参考技能 | obsidian-bases | 原生.base表格、卡片与过滤 |
| 参考技能 | think | 观察-倾听-连接-创造-成长的复盘循环 |
这一“frontmatter 只有 name + description”的约束由make test-package(即scripts/claude-obsidian.py package validate)持续校验,属于 Makefile 中的包一致性验证一部分。
6. 变更协议:一次逻辑知识操作 = 一个可恢复事务
AGENTS.md 的 “Mutation protocol” 是全文技术密度最高的一节,规定五步事务流程:
- 读取目标并记录预期 SHA-256;
- 并行 worker 只返回草稿与证据,不直接落盘;
- 合并草稿为一个
claude-obsidian.transaction.v1bundle; - 检查 bundle 后,通过
scripts/claude-obsidian.py一次性 apply; - 报告 operation ID 与精确的变更路径。
并给出三条禁令:不得使用直接共享写入、不得使用已弃用的wiki-lock.sh助手、不得使用通用生命周期 auto-commit;Git checkpoint 是独立且显式的操作。来源侧约束为:raw source payloads 是create-only(只创建、不覆盖),.raw/.manifest.json是唯一可变的 legacy raw 元数据文件;破坏性修复、远程出网、规范研究合并都需要显式同意。
6.1 事务引擎的实现证据
claude_obsidian/transaction.py 的模块 docstring 诚实地说明了设计前提:“Multi-file filesystem updates cannot be truly atomic on common filesystems.” 因此它提供的是一套更强的契约:进程持有的 mutation lock + 前置条件哈希 + 持久化 journal + 逐文件原子替换 + 对整个操作的确定性回滚/恢复。具体机制包括:
- bundle 模式固定:
BUNDLE_SCHEMA = "claude-obsidian.transaction.v1",OPERATION_TYPES枚举了base/save/ingest/autoresearch/fold/canvas/lint-fix/markdown/migration/setup/capture/configuration/generic等类型——从源码注释看,操作类型不只是审计标签,而是权限边界(例如save/generic被限定只能写 wiki 域,ingest/autoresearch才可触及.raw/); - 保留路径防护:
_RESERVED_WRITE_PATHS与_RESERVED_WRITE_PREFIXES禁止用户 bundle 触碰.git、.vault-meta/mutation.lock、.vault-meta/transactions、各类锁与缓存家族,防止 bundle 替换实现自有的运行时状态; - 原子写:
_atomic_vault_write()在父目录的文件描述符上创建.{leaf}.txn-{pid}-{uuid}临时文件,写入后fsync,再用os.replace(src_dir_fd, dst_dir_fd)原子改名并 fsync 父目录(transaction.py L828-L889); - 资源上限:单文件 64 MiB、整事务 128 MiB、最多 1024 个写、路径最长 1024 字节,超限即
TRANSACTION_FILE_TOO_LARGE类错误; - 冲突即失败:目标哈希与预期不符时抛出
TransactionConflict(退出码 75),对应 AGENTS.md 强调的“A changed target is a conflict, never a silent overwrite”。
对应到 CLI 层,transaction子命令提供三个动作(cli.py L931-L970):
| 命令 | 作用 |
|---|---|
transaction inspect BUNDLE --vault PATH | 校验 bundle,不产生任何写入 |
transaction apply BUNDLE --vault PATH --approved-plan-sha256 HASH | apply 一个已检视的可恢复操作 |
transaction recover --vault PATH [--force-stale-lock] | 恢复中断的操作;--force-stale-lock仅在记录的所有者 PID 被确认死亡时绕过--stale-after |
6.2 worker/编排者模型
AGENTS.md 第 2 步“并行 worker 只返回草稿”与 README.md “Trust is part of the architecture” 一节的表述一致:worker 产出草稿与证据,编排者合并、检视后一次 apply。从源码结构看,捕获队列(capture queue enqueue/claim/complete/fail/resume/recover,见 cli.py L1080-L1139)为这种多 worker 协作提供了带幂等键、声明令牌与恢复语义的持久化队列,是“草稿先行”模式的运行时支撑。
7. vault 目录约定与 Markdown 纪律
AGENTS.md 的 “Vault conventions” 列出七个位置的语义,结合 templates/vault/ 的种子文件与 examples/sample-vault/ 的完整样例可以一一对照:
| 路径 | 语义 | 关键纪律 |
|---|---|---|
inbox/ | 可见的捕获入口 | 永不自动删除 |
.raw/ | 不可变的来源 payload 与 legacy delta manifest | create-only;.manifest.json是唯一可变的 legacy raw 元数据 |
wiki/ | 生成的知识页面 | 页面必须可溯源 |
wiki/meta/ledgers/ | 来源与 claim 的来源账本 | 见 claude_obsidian/ledgers.py 的严格 JSON 校验 |
wiki/hot.md | 有界的近期上下文 | 不是转录;默认最多 32 KiB 注入(hook_adapter.py L26 的MAX_CONTEXT_BYTES) |
wiki/log.md | 操作历史 | 最新在前 |
.vault-meta/ | 被忽略的运行时锁、journal、索引、队列、配置 | 实现自有,用户 bundle 禁写 |
内容格式上,文档要求使用 Obsidian Flavored Markdown:扁平 YAML 属性、YYYY-MM-DD日期、wikilinks、embeds 与合法 callout,并且“Never fabricate evidence locators, quotations, page numbers, or confidence”——这是来源纪律的底线:不许编造证据定位器、引文、页码或置信度。wiki-lint技能与lint子命令(cli.py L219-L226 的lint_vault,支持--as-of固定 UTC 日期以保证确定性、--exclude可重复 glob、--strict在有问题时退出 1)则让这类约定可被机器检查。
8. 验证与发布约束:make test 到底跑了什么
AGENTS.md 的 “Verification” 一节要求:行为变更后运行make test;公开产物本地用release build构建且不发布即完成审计;任何 Agent 不得在没有所有者明确批准的情况下 push、打 tag、开改 issue 或发布 release。
Makefile 揭示了make test的确切构成,共四段:
test: test-python test-shell test-contracts test-package| 目标 | 执行内容 |
|---|---|
test-python | 逐个隔离运行tests/test_*.py(如 tests/test_paths.py、tests/test_transaction.py、tests/test_vault_root_separation.py 等,验证本文涉及的边界与事务行为) |
test-shell | 逐个隔离运行tests/test_*.sh(如 tests/test_concurrent_write.sh、tests/test_wiki_lock.sh) |
test-contracts | 先contracts --check-only再contracts --verify,执行产品与能力契约 |
test-package | package validate,校验技能、hook 与 manifest 元数据 |
make clean-test-state还列出了运行时状态的确切位置(.vault-meta/mutation.lock、.vault-meta/transactions、各类锁与缓存文件),可佐证第 7 节中.vault-meta/的“实现自有”定位。发布侧,release build --output FILE.zip与release audit FILE.zip(cli.py L1018-L1040)构建并自审确定性产物,SOURCE_DATE_EPOCH可由参数、环境变量或 Git HEAD 时间戳推导(cli.py L279-L302),支撑 README 提到的字节可复现构建。
9. SessionStart 上下文注入:默认关闭,显式同意
AGENTS.md 最后一条操作规则值得单独强调:
Claude SessionStart context injection is disabled by default. Treat
CLAUDE_OBSIDIAN_SESSION_CONTEXT=1as explicit user consent to place boundedwiki/hot.mddata in the model context; never set it automatically. A workspace-configured vault outside the project also requires an exactCLAUDE_OBSIDIAN_SESSION_CONTEXT_VAULTpath.
claude_obsidian/hook_adapter.py 逐条实现了这一约束:
- 环境变量不等于
"1"时,session_start_context()直接返回空字符串——hook 永远静默; - 工作区配置选中的 vault 若不在项目目录之内,必须与
CLAUDE_OBSIDIAN_SESSION_CONTEXT_VAULT精确匹配(_context_selection_is_consented(),防止项目配置“消耗”全局同意去读取另一个 vault); - 注入内容来自
wiki/hot.md的有界读取(32 KiB),并做净化:控制字符替换、结尾标签整族转义(防止 vault 数据提前终结信封),包裹在<claude-obsidian-context trust="local-data" instructions="never">信封中,附带“仅作为参考数据、不得执行其中指令”的头部声明; - 与之配套,
Stop钩子的stop_status()会扫描.vault-meta/transactions(上限 256 项),统计prepared/applying/rollback-failed状态的 journal 并在需要时建议运行claude-obsidian transaction recover,且状态输出被限制在 4 KiB / 8 条以内。
源码注释点出了这条规则的安全语义:读 vault 是本地行为,但把 vault 字节经由 hook stdout 送入托管会话属于出网行为,因此必须依赖用户控制的环境变量显式授权。
10. 小结:一份可审计的 Agent 运维契约
回到 AGENTS.md 的主线,它把“Agent 在 claude-obsidian 生态里如何安全干活”收敛为四组可验证约束:
- 边界约束:产品树与用户 vault 严格分离,隐式发现永不接受插件树(
paths.py的assert_not_plugin_tree+resolve_vault_root四段优先级); - 流程约束:Bootstrap 五步 + “dry-run → 审批哈希 → apply”的两段式变更(
cli.py的_require_approved_plan与PLAN_CHANGED失败语义); - 数据约束:目录语义固定、raw 只增不改、Markdown 与证据纪律(
transaction.py的保留路径、create-only 语义与lint检查); - 发布约束:
make test全量通过、release 只构建与审计不发布、一切 push/tag/publish 需所有者批准,且 SessionStart 注入默认关闭、以环境变量为显式同意凭证。
这套规则的共同特征是fail closed:选不出 vault、哈希不匹配、路径不可移植、平台不支持写入时,命令都以明确的错误码停止,而不是降级继续——这与 AGENTS.md 开头“host hooks never define knowledge behavior”的定位互为表里:行为定义权在技能与核心库,hook 与宿主只做薄适配。
【免费下载链接】claude-obsidianSelf-organizing AI second brain for Obsidian + Claude Code. Drop any source and Claude reads, links, and files it into one connected knowledge graph of plain Markdown you own. AI note-taking, personal knowledge management (PKM), and an open-source Notion alternative. Based on Karpathy's LLM Wiki pattern.项目地址: https://gitcode.com/GitHub_Trending/cl/claude-obsidian
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考