mcpField
F
frontmatter-guard

frontmatter-guard

github.com/garrytan文档处理31.3k235 次安装今天更新
代码仓库

关于 frontmatter-guard

frontmatter-guard 是用于 gbrain 脑页面的结构校验技能,面向维护内容的 Agent。它扫描 frontmatter 错误、提供备份保护的修复流程,并与 gbrain doctor 共用校验逻辑。

主要功能

  1. 01扫描八类 frontmatter 问题
  2. 02按来源生成审计报告
  3. 03校验单个文件或目录
  4. 04预览并备份后修复错误
  5. 05安装提交前校验钩子

适用场景

  1. 01检查多个来源中的脑页面格式
  2. 02在 CI 或提交前验证 Markdown
  3. 03修复同步暂挂文件的 frontmatter
  4. 04避免直接写入无效 YAML

MCP 相关

技能说明可通过 MCP 使用 gbrain 操作;它指导 Agent 审计、校验并经用户批准修复文件。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/garrytan/gbrain --skill frontmatter-guard

安装后在 Claude Code 中输入/frontmatter-guard确认已加载。

附带文件routing-eval.jsonl

详细介绍

Frontmatter Guard Skill

约定: 引用规则请参阅 skills/conventions/quality.md;本 Skill 负责结构校验,不负责引用审计。

契约

本 Skill 保证:

  • 每个 brain 页面都会按八个标准 frontmatter 校验类别进行扫描
  • 机械性错误(嵌套引号、缺少结束的 ---、空字节、slug 不匹配)可以按需自动修复,并生成 .bak 备份
  • 校验逻辑与 gbrain doctor 的 frontmatter_integrity 子检查共享,保证单一事实来源
  • 按来源生成报告(gbrain 自 v0.18.0 起支持多来源);绝不会静默审计错误的根目录
  • 对于 sync 暂停的文件,会根据其暂停记录(代码、原因、键、行号、修复方式)进行说明,并且只能通过用户批准、经过预览且绑定哈希的修复操作来修复

为什么需要它

Brain 页面会随着时间的推移不断累积。Agent 在写入时可能产生格式错误的 frontmatter:

  • 缺少结束的 ---(实体检测缺陷)
  • 会议页面中的非结构化 YAML(采集缺陷)
  • slug 不匹配(路径重命名未同步)
  • 空字节(复制粘贴事故导致的二进制损坏)
  • 标题中的嵌套双引号(title: "Alice "Ace" Example")

如果没有这一守卫,这些问题会悄无声息地累积,直到 gbrain sync 报错或搜索返回垃圾结果。守卫机制让问题在审计时就能被发现,并且易于修复。

安全写入 brain 文件(请先阅读)

  • 通过 put_page / capture(MCP 或 gbrain put)写入页面。gbrain 会自行序列化 frontmatter,因此磁盘上的文件始终是有效的 YAML。

  • 直接写入 Markdown 文件的脚本或 Agent 必须使用 YAML 序列化器(yaml.dump、js-yaml 的 dump)构建 frontmatter,绝不能通过字符串拼接。一旦标题包含 : 、#、引号或换行符,title: ${title} 就会出错。

  • 在写入生成的内容之前检查,但不触碰磁盘:

    printf '%s' "$content" | gbrain frontmatter validate --stdin --path notes/2026-10-04-digest.md
    

    退出码 1 表示需要先修复。默认采用严格的生产者规则:即使通过给值加引号使 gbrain 能够导入,只要其他工具会拒绝该 YAML,同样视为失败。--importable 则回答较窄的问题:"sync 能否接受它?"

  • 绝不能从不可信文本中写入 gbrain 用于访问或身份识别的键(visibility、derived_from、slug、type、id、source_id)。

暂存文件:读取后修复

无法在不猜测的情况下导入的文件会被暂存:其余源文件仍会同步,新文件尚无页面,现有页面则会保留最近一次正常修订,并拒绝 put_page,直到文件修复(不要重试写入)。暂存信息会显示在以下位置:同步输出(Held <path>: <code> … Next: <command>)、gbrain sources status <id>(--json:git_holds.items[])、doctor 的 git_held_files、get_page 的 file_held,以及标记为 stale 的搜索结果。

每条暂存记录都包含 code、reason、key、line、message(仅显示位置,不显示值)、fix(准确的 argv)和 docs。根据 reason 采取相应措施:

暂存原因操作
invalid_frontmatter / yaml_parse预览 gbrain repair frontmatter --source <id>;通常会显示 needs_review,并指出需要手动修复的确切行。
invalid_frontmatter / needs_interpretation使用 --include-ambiguous 预览,向用户展示每个文件的差异,只应用用户批准的更改。
invalid_frontmatter / ambiguous_identity_key 或 ambiguous_protected_key切勿猜测。向用户显示该行;由用户决定唯一值(visibility 决定谁可以读取页面)。
frontmatter_slug_conflict删除 slug: 行或移动文件;使用 --include-ambiguous 时,修复方案会提议删除该行。
file_too_large文件超过固定页面大小限制(Markdown 为 24 MiB,代码为 5 MB);其下的所有页面都可搜索,因此符合大小限制的页面绝不要拆分。请用户将其加入 sync.exclude,或拆分成不超过限制的多个文件。MCP 传输拒绝的较小页面应按文件处理(docs/guides/memory-boundaries.md#large-page-limits)。
content_rejected用户选择了 content_sanity.junk_disposition=reject;更改前请先征求用户同意。

修复流程(含实际输出的操作指南:docs/guides/repair.md#held-files):

gbrain sources status <id>                                  # what is held and why
gbrain repair frontmatter --source <id>                     # pass 1: safe quoting only; writes nothing
gbrain repair frontmatter --source <id> --include-ambiguous --diff   # pass 2: every interpretation
gbrain repair frontmatter --source <id> --include-ambiguous --only <path> --apply --expect <hash> --yes

每次使用 --apply 前,以及使用 --include-ambiguous 应用更改前,都要先征求用户同意:每种解释(将多行合并为标题、保留后出现的重复项)都只是猜测,只有用户才能确认。先展示差异,然后严格按照预览的哈希值应用。安全类别的更改只会将值按 gbrain 当前读取方式准确加引号,但仍会重写文件,因此同样需要征得用户同意。

如果某个损坏文件在升级前阻止了源的同步,它会在下次同步时恢复;如需立即恢复,请运行 gbrain sync --source <id> --no-pull。

验证类别

代码含义可自动修复?
MISSING_OPEN文件开头不是 ---否(需要人工处理)
MISSING_CLOSE首个标题之前没有结束的 ---是
YAML_PARSEYAML 解析失败有时(取决于原因)
SLUG_MISMATCHFrontmatter 中的 slug: 与根据路径生成的 slug 不一致是(移除该字段)
NULL_BYTES二进制损坏(\x00)是
NESTED_QUOTEStitle: "outer "inner" outer" 这种形式是
NON_STRING_FIELDtitle/type/slug 是未加引号的非字符串标量(例如 title: 123、slug: 2024-06-01)否(为值加引号)
EMPTY_FRONTMATTER有开头和结尾标记,但中间没有内容否(需要人工处理)

阶段

阶段 1:审计

对所有已注册的源运行只读扫描(或通过 --source <id> 指定一个源)。

gbrain frontmatter audit --json

报告内容:

  • 按错误代码分组的各源计数
  • 每个源最多 20 个受影响页面的示例
  • 总计数
  • 扫描时间戳

输出为 JSON;Agent 会解析 errors_by_code 和 per_source,以决定后续步骤。

阶段 2:验证单个路径

验证单个文件或目录(无需注册源):

gbrain frontmatter validate <path> --json

退出代码为 0 表示正常;为 1 表示发现错误。可在 CI 流水线或 pre-commit 钩子中使用。

阶段 3:修复

发现问题时:

gbrain frontmatter validate <path> --fix

--fix 会在修改前,把每个被修改的文件备份到 ~/.gbrain/backups/frontmatter/ 下;会为 gbrain 读取的 YAML 加上引号(只改动相应的行);随后重新校验,若仍有错误则以退出码 1 结束。修复后的文件需要在 git 中重新暂存(git add)。--include-ambiguous 会增加解释性的修复方案;批量应用前,请先用 --dry-run 预览这些方案。

--dry-run 只预览,不写入。批量应用修复前请先使用它。

在受管理的 brain 上,不允许原地执行 --fix:请改用 gbrain repair frontmatter --source <id>(见上文),该命令会通过协调写入器发布每个修复后的文件。

阶段 4:提交前钩子(可选)

对于本身就是 git 仓库的 brain 仓库,安装提交前钩子,从源头阻止格式错误的页面被提交:

gbrain frontmatter install-hook [--source <id>]

该钩子会对 .md/.mdx 文件的暂存内容(即将提交的内容,而非工作区副本)运行一次 gbrain frontmatter validate --staged 进程。使用 git commit --no-verify 可以绕过。安装钩子会写入用户的仓库,因此需先征得同意。当 doctor 的 frontmatter_hook 报告钩子版本过旧时,使用 gbrain frontmatter install-hook --force 进行更新。

触发词

当用户说出以下任一说法时,转到本技能:

  • "validate frontmatter"
  • "check frontmatter"
  • "fix frontmatter"
  • "frontmatter audit"
  • "brain lint"

输出规则

  • 始终先运行 gbrain frontmatter audit --json;不要假定 brain 是干净的。
  • 用通俗的语言向用户汇报数量;不要直接倾倒原始 JSON。
  • 对于 --fix 操作:运行前先说明将修改多少个文件,然后再请用户确认。
  • SLUG_MISMATCH 修复会删除 frontmatter 中的 slug: 字段——gbrain 从路径推导 slug。若用户是有意重命名标题,需要提醒这一点。
  • 未经用户明确输入,切勿自动修复 MISSING_OPEN 或 EMPTY_FRONTMATTER——这些通常意味着人工作者开始编写页面却没有写完。

关联

  • gbrain doctor —— frontmatter_integrity 子检查项报告的数量与 audit 相同;frontmatter_repairable 统计 gbrain repair frontmatter 可以修复的文件,git_held_files 列出被 git 占用的文件。
  • skills/maintain/SKILL.md —— 更广泛的 brain 健康审计;若怀疑存在其他类别的问题,可在本技能之后接续使用。
  • gbrain lint —— 与技能文件 lint 的规则有重叠(这是一个命令行命令,而非技能);lint 输出中的 frontmatter-* 规则名称来自本技能的校验功能。

输出格式

审计摘要(简洁,便于 Agent 读取):

Frontmatter audit — 17 issue(s) across 1 source(s)

[default] /Users/me/brain
  17 issue(s)
    MISSING_CLOSE: 8
    NESTED_QUOTES: 5
    NULL_BYTES: 4
  sample:
    people/jane.md — MISSING_CLOSE
    companies/acme.md — NESTED_QUOTES
    (+ 12 more)

Fix with: gbrain frontmatter validate /Users/me/brain --fix

JSON 封装(传入 --json 时):

{
  "ok": false,
  "total": 17,
  "errors_by_code": { "MISSING_CLOSE": 8, "NESTED_QUOTES": 5, "NULL_BYTES": 4 },
  "per_source": [
    {
      "source_id": "default",
      "source_path": "/Users/me/brain",
      "total": 17,
      "errors_by_code": { "MISSING_CLOSE": 8, "NESTED_QUOTES": 5, "NULL_BYTES": 4 },
      "sample": [{ "path": "people/jane.md", "codes": ["MISSING_CLOSE"] }]
    }
  ],
  "scanned_at": "2026-04-25T22:30:00.000Z"
}

gbrain frontmatter validate <path> --json 返回类似的封装结构,但键是按单个文件的结果,而非按源。

预防——编写有效的 Frontmatter

这是最重要的一节。 修复损坏的 frontmatter 固然好,但从一开始就不写出损坏的 frontmatter 更好。

YAML 数组(历史上头号错误来源)
# Correct: single-quoted YAML flow (canonical form gbrain emits)
tags: ['yc', 'w2025', 'ai']

# Correct: unquoted scalars (fine when values have no special chars)
tags: [yc, w2025, ai]

# Correct: block style
tags:
  - yc
  - w2025

# Tolerated post-v0.37.5.0 but non-canonical: JSON-style double quotes
tags: ["yc", "w2025"]

# Broken: mixed JSON objects and strings (invalid YAML)
tags: [{"name": "sports"}, "posterous"]

此前为何会出错: 在 v0.37.5.0 之前,校验器会统计未转义的 " 字符,并标记任何包含 3 个及以上此类字符的行。像 tags: ["yc", "w2025"] 这样的流式序列按设计包含 4 个未转义的 "。它本是合法的 YAML,但这个简单计数器仍会将其标记出来。某次 doctor 运行中,一个 Brain 就标记了 6,981 处此类问题。v0.37.5.0 起,在标记前会先用 js-yaml.safeLoad 解析可疑的值,因此 JSON 风格的数组不再触发 NESTED_QUOTES。

为何仍应编写规范形式: 自动修复引擎(gbrain frontmatter validate --fix)以及推断 frontmatter 的序列化器,都会为 tags: / aliases: 输出单引号 YAML。在新内容中编写规范形式,可以让源文件的风格保持一致,也能使 --fix 运行产生的差异为空。

LLM 的经典陷阱: 像 tags: [${items.map(t => JSON.stringify(t)).join(', ')}] 这样的代码会生成 tags: ["yc", "w2025"]。应使用单引号,并对含撇号的值做回退处理:tags: [${items.map(t => t.includes("'") ? JSON.stringify(t) : "'" + t + "'").join(', ')}]。或者使用知道如何输出规范 YAML 的 YAML 库。

带引号的标量
# Correct: single quotes for values with special chars
title: 'My "Quoted" Title'

# Correct: double quotes when value has apostrophes
title: "Men's Fashion Guide"

# Broken: double quotes wrapping inner double quotes
title: "My "Quoted" Title"
何时需要加引号
  • 无需引号即可用于简单值:type: person、batch: w2025
  • 当值包含 : " ' # [ ] { } | > & * ! ? , 或以 @ 开头时,需要加引号
  • 单引号是默认的安全选择
  • 只有当值本身包含撇号时,才使用双引号

出现失败时

对于任何 gbrain 错误 code、退出码、[AGENT] 块或通知块,请遵循 Agent 操作协议。针对本技能的补充说明:

  • gbrain frontmatter validate 退出码为 1:表示发现了错误(这是结果,而非崩溃)。解析 errors_by_code,并按来源报告各类错误的数量。
  • 在执行修复前,需说明将有多少文件被修改,并取得用户同意;修复操作会写入 .bak 备份,而且 YAML_PARSE 错误并非总能自动修复。
  • gbrain sync 会暂存某个文件(invalid_frontmatter、frontmatter_slug_conflict、file_too_large、content_rejected):同步本身仍然成功。请读取暂存信息(gbrain sources status <id>),并遵循上文的“已暂存文件”说明。
  • 若某页面对应的较新文件已被暂存,put_page 会拒绝写入:请先修复该文件;重试写入仍会被拒绝。

反模式

未经用户确认,不要自动修复 MISSING_OPEN 或 EMPTY_FRONTMATTER。 这些问题通常意味着人工作者开始编写页面但未完成。在未完成的草稿周围悄悄插入 --- 标记是错误的做法。

在未仔细阅读审计结果前,不要为了让 doctor 显示通过而使用 --fix。 SLUG_MISMATCH 的情况会被专门提交人工审核,因为 gbrain 是从路径推导 slug 的。不一致通常意味着用户有意重命名了文件;只有在确认重命名是有意为之时,自动删除 slug 字段才是正确的结果。

不要跳过 .bak 备份。 对于非 git Brain 仓库,.bak 是安全保障。修复运行后若积累了 .bak 文件,这属于设计特性而非缺陷:用户可以审查差异,并在确认无误后删除备份。

不要在未注册源的 Brain 上运行 audit。 命令行会优雅地返回“no registered sources to audit”,但迁移会输出 skipped: no_sources 阶段结果。不要用手动遍历路径的方式掩盖这一问题;正确的修复方法是通过 gbrain sources add 注册源。

不要在任何 git 仓库之外的 Brain 目录上安装 pre-commit 钩子。 安装钩子命令会自动跳过这些目录,并输出一行提示(若 Brain 是宿主仓库的子目录则没有问题,钩子会安装在宿主仓库根目录,并限定于该子目录)。如果看到“skipped, not a git repo”,且仍希望在写入时进行校验,请改为在定时任务中使用 audit 命令。

评论

支持 Markdown