mcpField
S
swain-search

swain-search

github.com/cristoslc生产力2116 次安装25 周前更新
代码仓库

关于 swain-search

swain-search 是一项研究 Skill,用于收集、规范化并缓存来源,形成可复用的资料集。它支持创建、扩展、刷新和发现资料集,并对远程来源执行证据核验。

主要功能

  1. 01创建、扩展、刷新和发现资料集
  2. 02规范化网页、文档及媒体来源
  3. 03检查现有资料集中的相关研究
  4. 04记录并核验远程来源快照

适用场景

  1. 01为研究主题收集来源
  2. 02向现有资料集添加新材料
  3. 03按主题查找已收集的来源

安装

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

$npx skills add https://github.com/cristoslc/swain --skill swain-search

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

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

CHANGELOG.md
README.md
references/
manifest-schema.md
normalization-formats.md
paywall-proxies.yaml
trovewatch-guide.md
wordlist.txt
scripts/
bootstrap.sh
convert-cookies.py
export-snapshot.sh
extract_frames.py
fetch_x_thread.py
log-snapshot-metadata.sh
migrate-to-troves.sh
ocr_frames.py
parse_vtt.py
resolve-proxy.sh
trovewatch.sh
verify-snapshot-evidence.sh
yt-dlp.sh
tests/
test-convert-cookies.py
test-export-snapshot.sh
test-resolve-proxy.sh

详细介绍

swain-search

收集、规范化并缓存源资料,形成可供 swain-design 产物引用的可复用资料库。

脚本调用约定

脚本位于此技能的 scripts/ 目录下。使用占位符 <SKILL_DIR> 表示包含此 SKILL.md 的文件夹,并在运行时解析。在已安装的技能中,该目录为 .claude/skills/swain-search/。在 swain 仓库中,该目录为 skills/swain-search/。

在每个会话中,运行媒体或 X 线程流程之前,先运行一次引导脚本:

bash "<SKILL_DIR>/scripts/bootstrap.sh"

该脚本会检查 uv 是否位于 PATH 中。首次运行后,~/.local/share/swain-search/.bootstrapped 中的标记文件会使后续运行直接跳过初始化。如果脚本以非零状态退出,请停止并告知操作者缺少什么。

模式检测

信号模式
该主题没有资料库,或用户说“研究 X”/“收集资料”Create — 新建资料库
资料库已存在,且用户提供了新来源或说“添加到”/“扩充”Extend — 向现有资料库添加来源
资料库已存在,且用户说“刷新”或来源已超过 TTLRefresh — 重新获取过期来源
用户询问“我们有哪些资料库”或“查找关于 X 的来源”Discover — 按标签搜索现有资料库

既有资料检查

在创建新资料库或执行网页搜索之前,先扫描现有资料库中的相关内容。这样可以避免重复研究,并发现与既有工作的关联。

阶段 1 — 字面关键词匹配

搜索来源名称、URL 片段和作者姓名:

# Search trove manifests by tag
grep -rl "<keyword>" docs/troves/*/manifest.yaml 2>/dev/null

# Search trove source content
grep -rl "<keyword>" docs/troves/*/sources/**/*.md 2>/dev/null

# Search trove syntheses
grep -rl "<keyword>" docs/troves/*/synthesis.md 2>/dev/null
阶段 2 — 语义主题匹配

获取来源并了解其内容后,从来源的内容(而不仅是名称或 URL)中提取 3-5 个主题关键词。然后按主题搜索现有资料库:

# Search trove tags for topic keywords
grep -l "<topic-keyword-1>\|<topic-keyword-2>\|<topic-keyword-3>" docs/troves/*/manifest.yaml 2>/dev/null

# Search synthesis summaries for topic keywords
grep -l "<topic-keyword-1>\|<topic-keyword-2>\|<topic-keyword-3>" docs/troves/*/synthesis.md 2>/dev/null

主题关键词应描述来源的主题,而不是它的名称。例如,一个名为 “Cog” 的仓库实现了 Claude Code 的记忆系统,其主题关键词应为 agent-memory、memory-architecture、claude-code、persistent-memory 等,而不是 cog 或 marciopuga。

如果尚未获取来源(仅提供 URL),请使用 URL 或标题中可用的主题信息,并在获取来源后再进行完整的主题匹配。

决策关卡

在继续进入 Create 或 Extend 模式之前,输出一条可见的路由决策:

既有资料检查: 阶段 1 找到 [N 个匹配项/未找到匹配项]。阶段 2 找到 [N 个匹配项/未找到匹配项]:[trove-id(标签:x、y),…]。 决策: 扩充 [trove-id]/新建资料库 [slug],因为 [原因]。

这样可以审计资料库路由决策。如果任一资料库匹配 2 个或更多主题关键词,默认进入 Extend 模式,除非该主题确实不同(主题相近但内容不同)。

匹配项的处理方式

如果现有资料库包含相关来源:

  1. 报告发现内容 — 显示资料库 ID、匹配的来源标题及相关摘录
  2. 建议扩充而非新建 — 如果现有资料库涵盖相同主题,应扩充该资料库,而不是另建平行资料库
  3. 交叉链接 — 如果主题相近但内容不同,则创建新资料库,并在 synthesis.md 中注明相关资料库

所有模式(Create、Extend、Discover)都会执行此步骤,并且在任何网页搜索之前执行。始终优先检查现有资料库内容。

快照证据门禁(SPEC-220)

在远程来源被视为已收集的证据之前,本次运行必须生成原始快照,并在 .agents/search-snapshots/metadata.jsonl 中记录一条元数据。

远程来源的必要流程:

  1. 首先导出/下载原始快照:
    • bash "<SKILL_DIR>/scripts/export-snapshot.sh" --url "<source-url>" --out-dir ".agents/search-snapshots/raw"
  2. 使用 writing-skills 或 skill-creator 规范化下载的文件(绝不能只保留浏览器摘要笔记)。
  3. 记录元数据:
    • bash "<SKILL_DIR>/scripts/log-snapshot-metadata.sh" --source-url "<source-url>" --export-mode "<mode>" --raw-path "<raw-path>" --normalized-path "<normalized-path>" --normalization-skill "<writing-skills|skill-creator>"
  4. 发布前进行验证:
    • bash "<SKILL_DIR>/scripts/verify-snapshot-evidence.sh" --source-url "<source-url>"

如果验证失败,请将该来源标记为未经验证,不要将其发布到下游,并向操作人员报告警告。

创建模式

从零开始构建一个资料库。

步骤 1 — 收集输入

向用户询问(或根据上下文推断)以下信息:

  1. 资料库 ID — 主题的短标识(例如 websocket-vs-sse)。如果上下文明确,请给出建议。
  2. 标签 — 用于发现的关键词(例如 real-time、websocket、sse)
  3. 来源 — 可任意组合以下类型:
    • 网络搜索查询(“搜索 WebSocket 与 SSE 的对比”)
    • URL(网页、论坛帖子、文档)
    • 视频/音频 URL
    • 本地文件路径
  4. 新鲜度 TTL 覆盖项 — 可选;大多数资料库使用默认值即可

如果此流程由 swain-design 调用(例如,某个 spike 进入 Active 阶段),工件上下文会提供主题、标签,有时也会提供初始来源。

步骤 2 — 收集并规范化

针对每个来源,使用相应的功能。阅读 references/normalization-formats.md,了解每种来源类型对应的确切 Markdown 结构。

网络搜索查询:

  1. 使用网络搜索功能查找相关结果
  2. 选择最相关的前 3–5 个结果
  3. 对每个结果:抓取页面,并按照网页格式规范化为 Markdown
  4. 如果没有可用的网络搜索功能,请告知用户并跳过

网页 URL:

  1. 使用浏览器或页面抓取功能获取页面
  2. 删除样板内容(导航栏、广告、侧边栏、Cookie 横幅)
  3. 按照网页格式规范化为 Markdown
  4. 如果抓取失败,请在清单中记录该 URL,并设置 failed: true 标记,然后继续

需要身份验证的网站(支持 Cookie):

当目标网站需要身份验证或订阅权限时,请提供从浏览器导出的 Cookie:

  1. 从已登录目标网站的浏览器中导出 Cookie:

    • Firefox:使用 “cookies.txt” 扩展,或通过 DevTools → Storage → Cookies → 右键单击 → “Export All” 导出。
    • Chrome:使用 “EditThisCookie” 扩展,或通过 DevTools → Application → Cookies → 右键单击 → “Export” 导出。
    • 也可以使用任何能够生成 JSON 数组的工具,其中 Cookie 对象包含 Host raw、Name raw、Content raw、Path raw、Expires raw、Send for raw 和 This domain only raw 字段。
  2. 将导出的 JSON 文件传递给 export-snapshot.sh:

    bash "<SKILL_DIR>/scripts/export-snapshot.sh" \
      --url "<source-url>" \
      --out-dir ".agents/search-snapshots/raw" \
      --cookies "path/to/cookies.json"
    

    --cookies 标志会通过 convert-cookies.py 将 Cookie 转换为 Netscape 格式,并将 Cookie jar 附加到 curl 请求中。导出模式会记录为 <mode>-with-cookies。

  3. 如果未提供 Cookie,则在不进行身份验证的情况下继续抓取(与之前的行为相同)。

  4. 对于基于浏览器的页面抓取路径(MCP 浏览器工具),可自动使用浏览器自身会话中的 Cookie,无需提供单独的 Cookie 文件。此标志适用于基于 curl 的快照导出。 类似 Google Docs / Drive 的文档:

  5. 先导出原始内容(必需):

    • bash "<SKILL_DIR>/scripts/export-snapshot.sh" --url "<source-url>" --out-dir ".agents/search-snapshots/raw"
  6. 优先使用 API 导出模式(google-doc-export、google-slides-export、google-drive-download)。

  7. 如果 API 导出失败,仅在浏览器辅助工具可用时使用回退方案。

  8. 使用 writing-skills 或 skill-creator 规范化导出的文件。

  9. 在 .agents/search-snapshots/metadata.jsonl 中记录元数据。

  10. 在将来源纳入 trove 输出之前,使用 verify-snapshot-evidence.sh 进行验证。

付费墙代理回退方案:

获取网页后,检查该 URL 的域名是否有可用的付费墙代理:

  1. 运行 bash "<SKILL_DIR>/scripts/resolve-proxy.sh" <url>
    • 退出代码 1:未配置代理——直接使用获取到的内容
    • 退出代码 0:输出 PROXY:<name>:<proxy-url> 和 SIGNAL:<text> 行
  2. 如果退出代码为 0,检查获取到的内容中是否包含每个 SIGNAL 文本(区分大小写的字面匹配)
  3. 如果任一信号匹配(或文章正文不足约 200 个词):
    • 记录:"检测到 <url> 有付费墙——尝试代理回退方案"
    • 按顺序尝试每个 PROXY URL,使用与网页相同的页面获取功能抓取内容
    • 首个返回实质性内容(长于被截断的原始内容)的代理胜出
    • 在清单条目中设置 proxy-used: <name> 和 notes: "Full article retrieved via <name> proxy"
  4. 如果没有信号匹配:直接使用获取到的内容(无需代理)
  5. 如果所有代理均失败:保留原始截断内容,并设置 notes: "Paywalled; proxies exhausted — content from direct fetch only"

代理注册表位于 references/paywall-proxies.yaml。在此处添加新域名或代理——无需修改技能文件。

视频/音频 URL(YouTube、Instagram、播客):

遵循以下分层流程。每一层都会写入 /tmp/swain_search_media_transcript.txt。随后根据 references/normalization-formats.md 中的媒体格式规范化该文件。输出写入 sources/<source-id>/<source-id>.md。

  1. 获取字幕和元数据,通过一次 yt-dlp 调用完成:

    bash "<SKILL_DIR>/scripts/yt-dlp.sh" --write-auto-sub --sub-lang en --write-info-json --skip-download --sub-format vtt -o "/tmp/swain_search_media" "<URL>"
    

    对于 Instagram URL,添加 --cookies-from-browser <browser>(chrome/safari/firefox/brave)。对于尚未发布在 YouTube 上的播客或会议 URL,先通过网页搜索功能将标题解析为 YouTube 链接。

  2. VTT 路径(优先)。如果 /tmp/swain_search_media.en.vtt 存在且非空:

    test -s /tmp/swain_search_media.en.vtt && uv run "<SKILL_DIR>/scripts/parse_vtt.py"
    

    脚本会写入 [HH:MM:SS] line 片段。在来源 frontmatter 中设置 transcript-source: vtt。

  3. 字幕说明回退方案。如果没有 VTT,则读取 /tmp/swain_search_media.info.json 并获取 description 字段。移除 #\w+ 标签。去除首尾空白。如果剩余文本超过 100 个字符,则将其写入 /tmp/swain_search_media_transcript.txt(每行一个段落)。设置 transcript-source: caption。省略时间戳。

  4. 帧提取回退方案(需要操作员批准)。如果说明文字过短(不超过 100 个字符),则停止并询问:

    未找到字幕或可用的说明文字。我可以提取帧并读取屏幕上的文字来生成文字稿。这需要 opencv-python-headless(约 30MB,通过 uv 安装)。是否继续?

    获得批准后:

    • 下载视频:bash "<SKILL_DIR>/scripts/yt-dlp.sh" -o "/tmp/swain_search_video.mp4" "<URL>"。对于 Instagram,添加 --cookies-from-browser <browser>。
    • 提取帧:uv run --with opencv-python-headless python3 "<SKILL_DIR>/scripts/extract_frames.py" /tmp/swain_search_video.mp4。通过场景变化检测保存 /tmp/swain_search_frame_000.png 及后续帧。
    • 探测视觉读取能力。使用 Read 工具读取 /tmp/swain_search_frame_000.png。尝试读取可见文字。如果成功,继续执行第 5 步;如果失败,继续执行第 6 步。
  5. 视觉 OCR(首选)。对每个剩余帧使用 Read 工具。提取所有可见文本。去重相邻帧中的重复内容。将文本写入 /tmp/swain_search_media_transcript.txt。设置 transcript-source: vision-ocr。不添加时间戳。

  6. 本地 OCR 回退方案。如果视觉方案失败,请询问:

    视觉方案不可用。将通过 EasyOCR 回退到本地 OCR(首次运行需下载约 400 MB)。是否继续?

    获得批准后:

    uv run --with "easyocr,opencv-python-headless" python3 "<SKILL_DIR>/scripts/ocr_frames.py"
    

    设置 transcript-source: local-ocr。不添加时间戳。

  7. 规范化并写入来源。根据视频标题生成来源 ID slug。仅使用小写字母、数字和连字符。按照媒体格式将内容写入 sources/<source-id>/<source-id>.md。在 frontmatter 中添加 transcript-source。仅当第 2 步已运行时,才添加 duration、speakers 和 YouTube 深层链接。

如果所有层级均未成功,则在清单中记录该来源,并设置 failed: true 和 reason: <tier>。

X/Twitter 讨论串:

URL 模式:(x|twitter|fxtwitter|fixupx).com/.+/status/\d+。通过公开的 fxtwitter API 展开。无需身份验证。

  1. 获取讨论串:

    uv run "<SKILL_DIR>/scripts/fetch_x_thread.py" "<URL>"
    

    脚本会写入两个文件:/tmp/swain_search_thread.json 保存原始响应,/tmp/swain_search_thread_transcript.txt 保存拼接后的文本,其中包含带引文的帖子块引用。脚本还会向 stdout 输出一个元数据 JSON 对象。提取以下字段:author_name、author_handle、author_url、published_date、tweet_count、title_guess、source_url、post_urls、cited_posts。

  2. 无法展开的讨论串。如果脚本在讨论串开篇帖子上退出,并显示 "only 1 post returned",说明上游部署缺少账户代理。将该条目记录为 failed: true 和 reason: x-thread-unrollable。继续处理。

  3. 将来源 ID 生成为 <author_handle>-<first-few-title-words>。规范化为仅包含小写字母、数字和连字符。去除所有 @。

  4. 按照 references/normalization-formats.md 中的 x-thread 格式进行规范化:

    • Frontmatter:在通用字段中添加 author-handle、author-name、published-date 和 tweet-count。
    • 正文:将每条帖子原文呈现为编号列表。将每个编号链接回对应的推文 URL。去除开头自动添加的提及链。这些是 X 在回复中添加的 @handle 前缀。将行内 @mentions 链接为 [@handle](https://x.com/handle)。将话题标签链接为 [#tag](https://x.com/hashtag/tag)。
    • 引用帖子:将每个 cited_posts 条目作为缩进块引用,置于引用它的帖子下方。最多追加 3 条有实质内容的自回复,作为续文。跳过只有裸 URL 的自回复;这些内容已出现在 external_links 中。若自回复超过 3 条,则添加链接。
  5. 保存到 sources/<source-id>/<source-id>.md。

本地文件:

  1. 使用文档转换功能(PDF、DOCX 等),或在文件已是 Markdown 格式时直接读取
  2. 使用 writing-skills 或 skill-creator,按照文档格式进行规范化
  3. 对于 Markdown 文件:仅添加 frontmatter,保留内容

论坛讨论串 / 讨论:

  1. 获取内容,并按照论坛格式进行规范化(按时间顺序排列,标注作者)
  2. 将嵌套讨论串展平为按时间顺序排列的内容,并保留回复对象上下文

代码仓库:

  1. 克隆代码仓库或读取其内容
  2. 在 sources/<source-id>/ 下镜像原始目录树
  3. 默认镜像整个目录树。对于大型代码仓库(数千个文件),选择性摄取内容,并在清单条目中设置 selective: true
  4. 将最重要文件的路径填入 highlights 数组(相对于 source-id 目录)

文档站点:

  1. 抓取或获取文档站点
  2. 在 sources/<source-id>/ 下镜像章节层级
  3. 默认镜像整个站点。对于大型站点,选择性摄取内容,并设置 selective: true
  4. 将最重要页面的路径填入 highlights 数组
  5. 尽可能保留内部链接结构

CLI 工具: 首先,检测目标是否为 CLI 工具。检查以下条件:

  • 目标存在于 PATH 中(运行 command -v <tool-name>)
  • 名称符合 CLI 模式(小写字母、连字符、不含空格)
  • 上下文表明这是一个命令行工具

如果目标是 CLI 工具,请运行以下采集流程:

  1. 手册页采集:

    • 运行 man <tool-name>
    • 如果成功,保存为 cli-manpage 类型
    • 如果没有手册页,则跳到帮助信息采集
  2. 主要帮助信息采集:

    • 运行 <tool-name> --help
    • 如果失败,尝试 <tool-name> -h
    • 保存为 cli-help 类型
  3. 子命令发现:

    • 在帮助输出中查找以下模式:
      • "Commands:" 或 "Subcommands:" 标题
      • "Usage:" 部分下缩进排列的命令列表
      • <tool> <command> [options] 之类的命令模式
    • 过滤掉非命令项:
      • 保留单个单词或带连字符的字符串
      • 保留用法行中的位置参数
      • 跳过以 - 开头的内容(这些是标志)
  4. 递归采集子命令:

    • 对每个子命令,运行 <tool-name> <subcommand> --help
    • 保存为 cli-subcommand-help 类型,并设置 depth: 1
    • 如果子命令还有自己的子命令,则再深入一层
    • 最大深度:2 层
  5. 失败处理:

    • 没有手册页?仅采集帮助信息
    • --help 和 -h 都失败?在清单中注明
    • 所有采集均失败?标记为 failed: true 并继续

每次采集都将成为一个独立的来源:

  • sources/<tool>-manpage/<tool>-manpage.md(类型:cli-manpage)
  • sources/<tool>-help/<tool>-help.md(类型:cli-help)
  • sources/<tool>-<subcommand>-help/<tool>-<subcommand>-help.md(类型:cli-subcommand-help)

每个规范化来源都会获得一个基于 slug 的来源 ID,并采用每个来源单独存放在目录中的布局:

  • 扁平来源(web、forum、media、document、local):sources/<source-id>/<source-id>.md
  • 分层来源(repository、documentation-site):sources/<source-id>/,其中镜像保留原始目录树

来源 ID 生成:

  • 根据来源标题或 URL 派生 slug 作为来源 ID(例如:mdn-websocket-api、strangeloop-2025-realtime)
  • 如果 slug 与现有来源 ID 冲突,则使用 references/wordlist.txt 中的两个随机单词追加 __word1-word2
  • 如果词表缺失,则追加 __ 和 4 位十六进制字符作为备用方案(例如:__a3f8)
步骤 3 — 生成清单

按照 references/manifest-schema.md 中的架构创建 manifest.yaml。包括:

  • 知识库元数据(id、创建日期、标签)
  • 每种来源类型的默认新鲜度 TTL
  • 每个来源各有一个条目,包含来源信息(URL/路径、获取日期、内容哈希、类型)

将内容哈希计算为规范化 Markdown 内容的纯十六进制 SHA-256 摘要(不带前缀):

shasum -a 256 sources/mdn-websocket-api/mdn-websocket-api.md | cut -d' ' -f1
步骤 4 — 生成综合总结

创建 synthesis.md,对所有来源的关键发现进行结构化提炼。

按主题而非来源组织综合总结。将相关发现分组,按 ID 引用来源,并呈现:

  • 关键发现 — 所有来源对该主题的综合结论
  • 一致之处 — 各来源结论趋同的地方
  • 分歧之处 — 来源相互矛盾或提出不同方案的地方
  • 空白 — 来源未涉及但可能重要的内容

保持简洁。综合总结是一个起点,而非全面报告;用户或产物作者会对其进行完善。

第 5 步 — 提交并标记

使用双提交模式(与 swain-design 生命周期标记相同),为资料集生成一个可访问的提交哈希。

提交 A 之前 — 在 manifest.yaml 中添加一条 history 记录,并用 -- 占位表示提交哈希:

history:
  - event: created
    date: 2026-03-09
    commit: "--"
    sources: 3

提交 A — 提交资料集内容:

git add docs/troves/<trove-id>/
git commit -m "research(<trove-id>): create trove with N sources

Co-Authored-By: <model-name-from-system-prompt> <noreply@unknown>"
TROVE_HASH=$(git rev-parse HEAD)

提交 B — 将提交哈希回填到历史记录中,然后更新引用此资料集的工件的 frontmatter(如果存在):

# Replace "--" with the real hash in the history entry
# Update artifact frontmatter: trove: <trove-id>@<TROVE_HASH>
git add docs/troves/<trove-id>/manifest.yaml
git add docs/<artifact-type>/<phase>/<artifact-dir>/   # if artifact exists
git commit -m "docs(<trove-id>): stamp history hash ${TROVE_HASH:0:7}

Co-Authored-By: <model-name-from-system-prompt> <noreply@unknown>"

如果还没有引用此资料集的工件(独立研究),提交 B 仍需标记历史记录 — 报告该哈希,以便之后引用。

推送 — 提交 B 后,始终推送到 origin/trunk,以便其他 Agent 和会话立即使用此资料集。这是强制要求,不可选:

git push origin trunk

生成综合文件 URL — 为最终报告构建指向综合文件的稳定永久链接:

REMOTE_URL=$(git remote get-url origin | sed 's/\.git$//' | sed 's/[email protected]:/https:\/\/github.com\//')
SYNTHESIS_URL="${REMOTE_URL}/blob/${TROVE_HASH}/docs/troves/<trove-id>/synthesis.md"
第 6 步 — 报告

告知用户创建了哪些内容:

已创建资料集 <trove-id>,包含 N 个来源 — 提交为 <TROVE_HASH:0:7>。

  • docs/troves/<trove-id>/manifest.yaml — 来源信息和元数据
  • docs/troves/<trove-id>/sources/ — N 个规范化来源文件
  • docs/troves/<trove-id>/synthesis.md — 主题提炼:<SYNTHESIS_URL>

在工件中通过以下内容引用:trove: <trove-id>@<TROVE_HASH:0:7>

报告中始终包含综合文件 URL。一次运行创建多个资料集时,列出每个资料集的综合文件 URL。

扩展模式

向现有资料集添加新来源。

  1. 读取现有的 manifest.yaml
  2. 收集并规范化新来源(与创建步骤 2 相同)
  3. 为新来源分配基于 slug 的来源 ID(遵循相同的 ID 生成规则)
  4. 将新条目追加到 manifest.yaml
  5. 更新 refreshed 日期
  6. 重新生成 synthesis.md,纳入所有来源(旧来源和新来源)
  7. 追加一条 history 记录,设置 event: extended,并将 commit: "--" 作为占位符
  8. 提交并标记(与创建步骤 5 使用相同的双提交模式):
    • 提交 A:`git commit -m "research(): extend with N new sources

Co-Authored-By: noreply@unknown"`

  • 捕获 TROVE_HASH=$(git rev-parse HEAD)
  • 提交 B:将哈希回填到历史记录中,并更新引用此资料集的工件 frontmatter(如果工件存在)
  • 推送(强制):git push origin trunk
  • 生成 SYNTHESIS_URL(与创建步骤 5 使用相同的方法)
  1. 报告添加的内容,包括新的提交哈希和综合文件 URL

刷新模式

重新获取过期来源,并更新发生变化的内容。

  1. 读取 manifest.yaml
  2. 对每个来源,检查 fetched 日期加上 freshness-ttl 是否已过期
  3. 对过期来源:
    • 重新获取原始内容
    • 重新规范化为 Markdown
    • 计算新的内容哈希
    • 如果哈希发生变化:替换来源文件,并更新 manifest 条目
    • 如果哈希未变化:仅更新 fetched 日期
  4. 更新 manifest 中的 refreshed 日期
  5. 如果任何内容发生变化,重新生成 synthesis.md
  6. 追加一条 history 记录,设置 event: refreshed、sources-changed: M,并将 commit: "--" 作为占位符
  7. 提交并标记(与创建步骤 5 使用相同的双提交模式):
    • 提交 A:`git commit -m "research(): refresh N sources (M changed)

Co-Authored-By: noreply@unknown"`

  • 捕获 TROVE_HASH=$(git rev-parse HEAD)
  • 提交 B:将哈希回填到历史记录中,并更新引用此资料集的工件 frontmatter — 检查 manifest 中的 referenced-by,查找所有依赖项
  • 推送(强制):git push origin trunk
  • 生成 SYNTHESIS_URL(与创建步骤 5 使用相同的方法)
  1. 报告:“已刷新 N 个来源。M 个来源的内容发生变化,K 个来源未变化。新哈希:<TROVE_HASH:0:7>。综合文件:<SYNTHESIS_URL>”

对于 freshness-ttl: never 的来源,刷新时跳过。

发现模式

帮助用户查找与其主题相关的现有资料集。

  1. 扫描 docs/troves/*/manifest.yaml,查找所有资料集
  2. 根据以下条件匹配用户的查询:
    • 标签匹配 — 资料集标签包含查询关键词
    • 标题匹配 — 资料集 ID 的 slug 包含查询关键词
  3. 对于每个匹配项,显示:资料集 ID、标签、来源数量、上次刷新日期、引用它的项目列表
  4. 如果没有匹配项,建议创建新的资料集

优雅降级

此技能会以通用方式引用各项能力。若某项能力不可用:

能力回退方案
网络搜索跳过基于搜索的来源。告知用户:“没有可用的网络搜索能力——请直接提供 URL,或添加搜索 MCP。”
浏览器/页面抓取工具尝试基本 URL 抓取。如果失败:“无法抓取此 URL——请粘贴内容或提供本地文件。”
远程文档快照导出如果导出失败且没有辅助工具:将来源标记为未经验证,不要发布到下游,并报告确切的 URL 和失败原因。
媒体转录“没有可用的转录能力——请提供预先制作的转录文件,或添加媒体转换工具。”
文档转换“无法转换此文件类型——请提供 Markdown 版本,或添加文档转换工具。”
付费墙代理保留截断的内容。在清单中注明:“有付费墙;代理已用尽。”建议用户手动提供内容。

切勿因缺少某项能力而导致整个运行失败。尽可能收集信息,跳过无法完成的部分,并清楚地报告情况。

能力检测

收集来源前,检查可用的工具。查找符合以下模式的工具——具体工具名称因安装环境而异:

  • 网络搜索:名称中包含 "search" 的工具(例如,brave_web_search、bing-search-to-markdown)
  • 页面抓取:名称中包含 "fetch"、"webpage"、"browser" 的工具(例如,fetch_content、webpage-to-markdown、browser_navigate)
  • 媒体转录:名称中包含 "audio"、"video"、"youtube" 的工具(例如,audio-to-markdown、youtube-to-markdown)
  • 文档转换:名称中包含 "pdf"、"docx"、"pptx"、"xlsx" 的工具(例如,pdf-to-markdown、docx-to-markdown)
  • CLI 工具捕获:内置 bash 能力(man、命令执行)——在 POSIX 系统上始终可用

在开始收集时报告可用的能力,让用户了解哪些操作可行、哪些不可行。

从制品链接

制品通过 frontmatter 引用资料集:

trove: websocket-vs-sse@abc1234

格式为 <trove-id>@<commit-hash>。commit hash 会将资料集固定到特定版本——随着来源的添加或刷新,资料集会不断演进,而该 hash 可确保结果可复现。

Create 第 5 步、Extend 第 8 步和 Refresh 第 7 步中的双提交工作流会自动处理此事——提交 A 记录资料集内容,提交 B 则将 hash 写入历史记录条目和引用该资料集的制品 frontmatter。不要将此事推迟给操作人员处理。

评论

支持 Markdown