mcpField
C
cawplan-knowledge

cawplan-knowledge

github.com/cawcut生产力195 次安装1 天前更新
代码仓库

关于 cawplan-knowledge

cawplan-knowledge 是一项 Agent 技能,指导通过 cawplan CLI 浏览和搜索 CawPlan 知识库。它支持从数据集逐层查看文档与章节,并提供相关片段搜索、全文读取及长文档导航流程。

主要功能

  1. 01浏览数据集和文档
  2. 02搜索相关度排序的知识片段
  3. 03读取完整文档或指定章节
  4. 04按大纲浏览长文档
  5. 05按产品或模块筛选数据集

适用场景

  1. 01跨数据集查找相关信息
  2. 02阅读长文档中的特定章节
  3. 03探索关联到 CawPlan 产品的知识

安装

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

$npx skills add https://github.com/cawcut/skill-cawplan --skill cawplan-knowledge

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

详细介绍

CawPlan 知识

引导

cawplan skill check

导航模型

整个知识库是一棵连贯且可逐层深入的树:数据集 → 文档 → 标题 → 章节内容,此外还有搜索结果,它们是按相关性预先筛选出的同一棵树。用户无需知道或输入 CLI 标志名称(--outline、--section、--dataset、--grep, ……)——这些只是实现细节,你应根据用户询问的是树的哪一层来选择。如果用户粘贴了字面形式的 cawplan ... 命令,而不是用自然语言提出请求,应将其视为对所需内容(数据集、文档或章节)的指示,而不是要逐字执行的脚本;底层标志仍由你自行选择。

在每一层,都要根据候选项数量以及选择过程需要迭代多少次来决定呈现方式:

  • 范围有限、一次即可选定(当前层的实际候选项数量不超过 AskUserQuestion 的上限——每次调用最多 4 个选项 × 4 个问题,即总计 ≤16 项——而且用户只需选择一次,不会马上进行多轮快速重选或回退):此处可以使用带 preview 的 AskUserQuestion。例如,从少数几个非空数据集中选择,或从一小组主题相同的端点中选择。如果某一层的原始条目数量超过上限(例如总共有 96 个数据集,但只有 3 个非空),应先筛选出实际候选项——不要为了避免使用纯文本,而通过多次连续调用 AskUserQuestion 强行呈现大量条目。
  • 大量条目或迭代式浏览(文档的完整标题树、有几十个标题,或用户需要在多轮对话中快速跳转和重新选择,且不想每次都等待):对于深入或迭代浏览的部分,使用纯文本、编号列表或嵌套列表,并允许用户自由回复——例外情况见步骤 5(树的顶层在候选项有限时可使用 AskUserQuestion),以及为何已确认在此之外继续深入使用 AskUserQuestion 是错误做法:每次选择都需要经过一次模态往返,无法快速重选或回退。

无论采用哪种方式,展示叶节点结果(章节内容、文档全文)后,都要再次显示用户刚才浏览的那一层列表,让用户可以继续浏览,而不是以一次性回答结束本轮对话。

让可点击路径更省事

使用 AskUserQuestion 时,以下做法可以避免流程显得缓慢或浅尝辄止:

  • preview 始终是节点自身的 --outline preview 字符串,逐字不变。 直接复制该字段,不要改动。不要自行编写预览文本,也不要用结构摘要(章节的子标题列表、计数、改写)来代替——预览的目的是展示章节实际开头的正文,让用户在选择前判断内容。子标题列表并没有提供选项标签之外的新信息,而自行编写还会额外消耗一轮往返所需的 token。结构应放在 label / description 中;正文应放在 preview 中。
    • 它已经是纯文本,直接粘贴即可:--outline(以及 CLI 自带的选择器)会通过 markdownToPlainText(src/lib/knowledge/plaintext.ts)处理每个预览——标题、**bold**、`code` 和表格竖线都会转换,表格会变为空格对齐的列。预览面板会原样显示文本,因此原始 Markdown 会让 ###/**/| 作为可见噪声漏出来(已并排验证;转换后的效果更好)。不要手动清理,也不要重新添加 Markdown 语法。
    • preview 为空的节点确实没有自己的正文(例如仅包含子章节的标题,或图片)。如实说明即可——不要用自创的摘要来补充。
  • 合并 1:1 层级。 大多数数据集只包含一份文档,因此数据集→文档会浪费一次点击。将 dataset / document 合并为一个选项,省去一整轮往返。
  • 填满调用。 一次 AskUserQuestion 可包含 4 个问题 × 4 个选项——最多能在一轮往返中回答 16 个选项。将相关选择分组到一次调用中,胜过连续多次调用。
  • 先获取,再提问,而不是反过来。 内容按文档缓存 12h,且 --outline 已包含预览,因此应预先获取菜单所需内容;这样选择后即可直接渲染现有内容,无需等点击后再付费获取。
  • 在同一轮中重新提供菜单。 渲染所选内容后,立即再次调用 AskUserQuestion,使用相同层级(或父级)。这样就能实现真正的“选择 → 查看 → 再选择”循环——这是纯文本无法提供的体验——而用户无需重新输入任何内容。
  1. 列出数据集 —— 树的根节点。当用户询问有哪些可用数据集、说出一个需要解析为 id 的数据集名称,或尚未选择数据集且你需要提供起点时:

    cawplan knowledge datasets list
    

    返回调用者可访问的所有数据集:{id, name, document_count}。工作区中可能有许多数据集,但实际存在的(非空)数据集很少——在决定如何呈现选项前,先筛选出 document_count > 0 的数据集:如果筛选后的集合较小(≤16),在此处使用带 preview 的 AskUserQuestion(例如,将每个选项的描述设为其文档样例)作为一次性选择器是可行的;如果是完整的原始列表(数十个以上,且大多为空),则改用纯文本树,而不是强行通过多次连续的 AskUserQuestion 调用来呈现。 当用户提到的是 CawPlan 产品而不是数据集时(例如“Access Card 的知识库里有什么?”——产品查询本身属于 /cawplan-product-insights 的职责,而非此技能;假设在你执行到这里时,product_id 已经解析完毕),将同一根列表缩小到该产品,而不是列出所有内容:

    cawplan knowledge datasets list --product <product_id>
    

    这会返回该产品拥有(在该产品下创建)以及与该产品关联的数据集——这是两种不同的关系,不要混为一谈。模块按文档划分,而非按数据集划分:产品可以选择使用模块树来组织其知识(product_modules——与 QA 测试套件使用的树相同),每份文档最多属于一个模块。只有该产品拥有的数据集中的文档才能归入其模块;关联的数据集不会归入任何模块。先检查模块树,再决定是否进一步缩小范围(每个节点的 knowledge 列出至少有一份文档位于该节点下的数据集):

    cawplan knowledge datasets modules --product <product_id>
    
    • 如果没有返回模块,说明该产品没有模块——直接使用上面的仅带 --product 的列表(拥有 + 关联),无需执行模块步骤。
    • 如果返回了模块,且用户尚未指定模块,则将其作为选项提供给用户(使用有数量限制的 AskUserQuestion,限制与此处其他层级相同——如果选项很多,则使用纯文本),然后同时使用两个标志缩小范围:
      cawplan knowledge datasets list --product <product_id> --module <module_id>
      
      --module 只保留该产品拥有且至少有一份文档位于该模块下的数据集——关联的数据集会被排除,因此结果为空表示“该模块中没有任何文档属于该产品拥有的数据集”,而非“该产品中什么都没有”。documents list 项包含 module_id/module_name(以及类似 KBD-00001 的 display_id),因此选择数据集后,你可以确认其中哪些文档实际位于该模块中。 不要在 Agent 执行上述任一命令时使用 -i/--interactive——与下文第 5 步的 browse 有相同限制:它需要真实的交互式终端,应由人直接运行,而非由你运行。
  2. 列出数据集中的文档——树的第二层,用于浏览特定数据集的内容(用户选择了第 1 步中的数据集,或直接指定了数据集):

    cawplan knowledge documents list --dataset <id>
    # optional: --keyword <text> --page <n> --limit <n>
    

    <id> 必须来自第 1 步的输出。

  3. 搜索——用户提出“查找有关 X 的信息”时的默认路径;概念上等同于按相关性排序的结果筛选后的同一棵树,而非列出全部内容:

    cawplan knowledge search --query "<text>"
    

    未选择数据集时,将搜索调用者有权访问的所有数据集。只有当用户明确指定或选择一个或多个数据集以缩小范围时,才添加 --dataset <id>——选择多个数据集时重复此标志:

    cawplan knowledge search --query "<text>" --dataset <id>
    cawplan knowledge search --query "<text>" --dataset <id-1> --dataset <id-2>
    

    搜索返回的是按相关性排序的片段,而非完整文档——与查询词不匹配的章节可能会被遗漏。如果用户需要整份文档,或者搜索一直漏掉你知道存在的章节,请改用第 4 步,而不是继续尝试更多搜索查询。

    多个搜索结果应按数据集 → 文档分组呈现(与此技能其余部分的树结构相同),而非作为扁平的排序列表——这样用户可以使用相同的自由文本回复方式,直接从任一结果深入查看该文档的大纲(第 5 步)或完整章节(第 4 步)。

  4. 获取完整文档内容——当用户需要文档全文,或需要特定文档的内容而非匹配片段时:

    cawplan knowledge documents get --dataset <id> --document <id>
    

    <dataset id> 和 <document id> 必须来自第 1 步和第 2 步的输出。返回原始源文件内容,不做改动,也不会从搜索索引片段重新拼接。 对于大型文档,或只需要其中一个章节时,不要将完整内容读入自己的上下文——内容可能在不知不觉中超出文件读取工具的上下文窗口;即使获取了“完整”内容,目标章节也可能在过长的响应中丢失。如果你已知道(或可通过步骤 5 中的 --outline 查到)所需标题的确切名称,请改用 --section "<heading text>"——它会返回该标题下完整且边界清晰的内容(详情见步骤 5),不会有内容被截断或延伸到下一章节的风险:

    cawplan knowledge documents get --dataset <id> --document <id> --section "6.7 Fetch NFC Card"
    

    只有在要搜索正文中的模式而非已知标题,或源内容没有按 Markdown 标题清晰划分时,才使用 --grep <pattern> --context <n>:

    cawplan knowledge documents get --dataset <id> --document <id> --grep "6.7 Fetch NFC Card" --context 20
    

    根据章节的预期长度,扩大或缩小 --context(默认为 3 行)。如果还想保存完整文档以供后续使用,可在同一次调用中添加 --output <path>——它会将原始文件保存到磁盘,同时输出 --section/--grep 的结果。只有在需要浏览标题尚不明确、且 --outline(步骤 5)未涵盖的章节(例如非 Markdown 源文件)时,才单独使用 --output 作为后备方案(然后自行对文件使用 grep/sed)。

    获取的内容会按文档缓存在本地(默认 TTL 为 12h,与其他 cawplan 命令使用相同缓存)——对相同的 --dataset/--document 重新运行 documents get 并指定不同的 --outline/--section/--grep 时,会重新筛选缓存副本,而不是重新获取,因此连续尝试几次来定位章节的成本很低。只有在源文档自上次获取后可能发生变化时,才添加 --refresh。

  5. 使用索引树浏览大型文档——当用户想要探索不熟悉或篇幅较长的文档时:

    • 通过一次调用,以标题树的形式获取文档结构,而不拉取完整内容:cawplan knowledge documents get --dataset <id> --document <id> --outline 该命令会返回 data.outline,这是一个由服务器根据缓存内容构建的嵌套 {level, title, line, preview, children} 树 — 不要自行用正则表达式解析 data.content;CLI 已经完成了这项工作(src/lib/knowledge/outline.ts)。每个节点的 preview 都是该标题下正文最前面的几行非空内容,因此这一次调用已经包含了足够的信息,可以描述每个标题 — 无需为了给菜单生成预览文本而针对每个标题单独获取内容。不要为了重建标题树而重新获取内容。

    • 仅展示树的顶层:如果文档的顶层标题(第 1 级)数量符合 AskUserQuestion 的限制(总数 ≤16,每个问题 ≤4 个),则提供可点击的 AskUserQuestion 选项,每个顶层标题对应一个选项,preview = 该标题自身的 --outline 预览原文(参见上文“让可点击路径更轻量” — 适用相同规则:使用真实预览文本,而不是自行编写的子标题摘要)。这样,用户可以点击进入长文档,而不是总要手动输入。

    • 顶层以下不要使用 AskUserQuestion — 文档标题树的更深层级正是上文导航模型中所说的“规模较大或需要反复浏览”的情况:有几十个甚至更多标题,用户需要在多轮交互中快速跳转和重新选择。Claude Code 没有原生的文档树 UI;而且,一旦某个标题下有不止几个子标题(例如,一个章节下有 20-30 个小节),每次选择都要通过 AskUserQuestion 弹出模态框往返操作,已确认会显得笨拙。因此,应将其余标题树渲染为真正缩进的纯文本树 — 每个节点单独占一行,每层嵌套缩进 2 个空格,直接对应 data.outline 的 children 结构 — 并让用户自由回复任意章节、标题、章节组合或其他请求。这是真正的嵌套树,不是将顶层标题用逗号或项目符号连接后压平成一行摘要;压成一行就失去了展示结构的意义。

      默认仅展示前两个标题层级(# 和 ##)— 更深的层级(### Request Header、### Response Body 等)是几乎每个端点下都会重复出现的标准子字段,只会增加干扰;除非用户要求深入查看某个特定节点,否则应跳过。只要有助于区分名称相似的标题,就将每个节点的 preview 一并展示(例如,作为标题下方的一行缩进文本,或放在标题后的破折号后)— data.outline 中已经包含这些内容,无需额外获取。

      示例(按以下形式原样渲染,不要压缩成一行摘要):

      Document outline:
      
      1. Introduction
        1.1 Create API Token & Download API Documentation
        1.2 Obtain Your Hostname
      2. Overview
        2.1 API Token
      3. User
        3.1 Schemas
        3.2 User Registration
        3.3 Update User
      4. Access Policy
        4.1 Create
        4.2 Update
      

      用户可以回复 3.2、User、3.2 + 4.1,或描述他们想要查看的内容。

    • 当用户选择某个章节时,只获取该章节边界清晰的完整文本: cawplan knowledge documents get --dataset <id> --document <id> --section "<heading text>" 此命令会按不区分大小写的子字符串匹配标题(返回所有匹配项,因此匹配多个标题的查询会产生多个 matches),并提取每个标题下从该标题行开始、到下一个同级或更高级标题之前为止的内容——不会像固定行数的 --grep --context <n> 那样延伸到相邻章节。若要定位大纲中的特定标题,优先使用 --section;如果不知道确切标题,或者想搜索正文而非标题,则使用 --grep 进行自由格式的模式搜索。

    • 显示章节后,再次显示大纲,以便用户继续浏览。 不要再次获取或打印整个文档。

    • 这是一种 Agent 侧的浏览模式。不要在 Agent 中使用 --interactive,也不要运行 cawplan knowledge browse。两者都需要真正的交互式终端——由用户在终端中直接运行 cawplan——如果作为子进程运行(这是 Agent 唯一的运行方式),会立即报错。

    • 如果用户明确想通过终端进行交互式浏览,请告知他们在真正的终端中自行运行以下命令之一(不要代替他们运行):

      • cawplan knowledge browse — 完整的选择器:数据集 → 文档(带实时预览)→ 标题树;按 Esc 返回上一级。如果用户还没有选择文档,这是最佳起点。
      • cawplan knowledge documents get --dataset <id> --document <id> — 相同的标题树浏览器,但限定于用户已选择的文档。
  6. 创建数据集 — 当用户要求创建新的知识数据集时:

    cawplan knowledge datasets create --name "<name>" [--description "<text>"] [--permission only_me|all_team_members|partial_members] [--owner-product <product_id>] [--product <product_id> ...]
    

    创建前先向用户确认数据集名称——这是创建操作,不具备幂等性。 --owner-product 会将该产品设为数据集的所有者——如果文档应归入该产品的模块,则必须指定此参数(无所有者的数据集无法使用模块,向其中上传模块内容会失败并返回 BAD_REQUEST)。--product(可重复指定)只会将数据集关联到产品,以便进行产品范围内的搜索;它不会授予使用模块的权限。如果用户希望按模块组织某个产品的数据集,则使用相同的 id 同时传入这两个参数。 响应中包含新数据集的 id;后续调用 documents upload 时直接使用该值,无需再次运行 datasets list 查找。

  7. 向数据集上传文档 — 当用户要求向数据集(现有数据集或刚创建的数据集)添加或上传文件、文本内容时:

    # real files (pdf/docx/markdown/...), batch: repeat --file for multiple in one dataset
    cawplan knowledge documents upload --dataset <id> --file <path> [--file <path> ...]
    
    # plain-text content from local files, batch: repeat --text-file for multiple
    cawplan knowledge documents upload --dataset <id> --text-file <path> [--text-file <path> ...]
    

    <id> 必须来自 datasets list 或 datasets create。一次调用中不要混用 --file 和 --text-file——CLI 会拒绝;如果一批内容中两者都有,请分两次运行命令。上传前先向用户确认目标数据集和文件列表,因为这会修改数据集。

    要上传到模块,请添加 --module <module_id>(来自 datasets modules --product <owner_product_id>);该参数会应用于该次调用中的每个 --file/--text-file。模块必须属于数据集的所有者产品(datasets create --owner-product),否则 API 会返回 BAD_REQUEST。

    如果模块尚不存在,请先创建(这是创建操作,请先与用户确认名称以及父级模块〔如有〕):

    cawplan knowledge modules create --product <owner_product_id> --name "<module name>"
    cawplan knowledge modules create --product <owner_product_id> --name "<sub-module name>" --parent <parent_module_id>
    

    --parent 会将新模块嵌套到现有模块下(id 来自 modules list --product <id>,输出与 datasets modules 相同);若要创建顶层模块,则省略此参数。树的深度最多为 5 层。使用返回的 data.id 作为上传时的 --module。 --file 上传在服务端以异步方式处理(每个文件都会执行 convert-to-markdown → index 流程)。默认情况下,CLI 会为每个文件提交一个请求,并轮询直到全部完成后才返回,因此处理较大的文件时命令可能需要一段时间——这是预期行为,并非卡住。如果命令看起来很慢,请勿重新运行。若用户希望提交后立即返回,而不是等待,请添加 --no-wait;它会立即返回每个文件对应的 job_id,之后可通过以下方式检查:

    cawplan knowledge documents job-status --dataset <id> --job <job_id>
    

    --text-file 上传是同步的(不涉及任务或轮询)——每份文档创建完成后,命令就会返回。

  8. 更新现有文档 — 当用户要求编辑、替换或重新同步知识库中已有的文档(而不是上传新文档)时:

    cawplan knowledge documents update --dataset <id> --document <id> --text-file <path>
    # or, for a real file:
    cawplan knowledge documents update --dataset <id> --document <id> --file <path>
    

    <dataset id> 和 <document id> 必须来自 datasets list/documents list——运行前请确认要替换的是哪份现有文档,因为此操作会覆盖内容。若要将文档归入其他模块,请使用 documents set-module(第 9 步),而不是 update。与上传的 --file 情况一样,此操作分为异步/同步两种模式,并支持 --no-wait/--poll-interval/--poll-timeout 标志。

  9. 将文档移入/移出模块 — 当用户要求将现有文档归入某个模块,或从模块中移出时:

    cawplan knowledge documents set-module --dataset <id> --document <id> --module <module_id>
    cawplan knowledge documents set-module --dataset <id> --document <id> --clear
    

    必须且只能传入 --module/--clear 其中一个。与上传时 --module 的归属产品规则相同。由于此操作会修改文档,请先与用户确认文档和目标模块。

输出

每一层都遵循上述导航模型:对于范围明确、只需选择一次的选项,使用 AskUserQuestion;对于较大的列表或需要反复浏览的内容,使用纯文本编号/嵌套列表。对于文档标题树,具体划分位于顶层:如果符合数量限制,使用 AskUserQuestion 选择一级标题;顶层以下的所有内容都使用纯文本自由选择。无论采用哪种方式,在展示叶节点结果后,都要再次展示用户此前浏览的层级,方便继续浏览。

  • 数据集列表:列出 name、id、document_count 的表格/列表——树的根节点;提供选项前先筛除空数据集。
  • 文档列表:列出指定数据集中文档名称/ID 的表格/列表;如果结果经过分页,注明总数——第二层。
  • 搜索结果:按数据集 → 文档分组(而非扁平的排名列表),并为每个片段提供来源元数据;注明搜索范围是单个数据集,还是所有可访问数据集。每条结果都应可继续查看该文档的大纲或完整章节。
  • 文档大纲:如果符合数量限制(总计 ≤16 项、每个问题 ≤4 项),将一级标题作为可点击的 AskUserQuestion 选项;顶层以下的所有内容都以纯文本菜单呈现,供用户自由选择——不要直接展示原始内容。如果某个节点的 preview 值值得内联展示(用于区分名称相似的标题),请逐字内联该字段——不要自行编写摘要。
  • 文档内容:直接引用/概述从 --section/--grep 匹配结果中提取的内容,而不是重新拼接之前搜索结果中的内容——这是树的叶节点。
  • 创建/上传:确认实际创建/上传的内容(数据集 ID/名称,或响应中每份文档的 ID/名称)——检查响应中的 code,确认成功后再报告。

决策指南

  • 用户完全没有提供起点(“知识库里有什么?”):使用 datasets list——从树的根节点开始;筛选非空数据集,然后如果符合 ≤16 个,则使用 AskUserQuestion,否则以纯文本呈现。
  • 用户指定了一个或多个数据集(“在 X 数据集中搜索……”):先用 datasets list 解析每个数据集,然后使用 search --dataset <id>(多个数据集时重复执行)。
  • 用户指定的是 CawPlan 产品,而非数据集(“X 的知识库里有什么?”):使用 datasets list --product <product_id>(自有及关联的数据集);先检查 datasets modules --product <product_id>——如果有模块且用户没有指定模块,就将模块作为选项提供;然后在列表调用中添加 --module <module_id>(该产品自有、且在此模块下至少包含一篇文档的数据集;不包括关联的数据集);如果没有模块,则直接使用仅指定产品的列表调用。
  • 用户提出一般性问题,且没有数据集上下文:直接调用 search,不带 --dataset。
  • 用户询问“X 中有哪些文档”:使用 documents list --dataset <id>,而非 search。
  • 用户要求获取文档的完整内容或摘要,或搜索结果只有标题/片段而没有正文:使用 documents get --dataset <id> --document <id>。
  • 用户想浏览/探索一篇较长或不熟悉的文档,而非查看已知章节:使用 documents get --outline;如果一级标题数量符合上限,则通过 AskUserQuestion 将这些标题作为选项提供(否则以纯文本呈现);对于更深层级,将剩余树状结构作为纯文本菜单提供,并允许用户自由选择;之后按需循环执行 --section "<heading>" → 大纲 → 章节。
  • 用户粘贴了字面上的 cawplan knowledge ... 命令,而非描述想要做什么:将其理解为在指定数据集/文档/章节,而不是要逐字运行的脚本——自行解析缺失的 ID(步骤 1–2),并选择实际符合用户需求的标志(--outline、--section、--grep 等)。
  • 用户要求创建新数据集:确认名称后使用 datasets create --name <name>;如果该数据集属于某个产品且应使用该产品的模块,则添加 --owner-product <product_id>(若还要将其关联起来以供按产品搜索,则同时添加 --product <product_id>)。
  • 用户要求将文件或文本上传/添加到数据集:确认目标数据集和文件后,使用 documents upload --dataset <id> --file <path>... 或 --text-file <path>...;若要将它们放在数据集所属产品的某个模块下,则添加 --module <module_id>。
  • 用户要求创建模块(或子模块)以整理产品文档:确认名称和父模块后,使用 modules create --product <owner_product_id> --name <name> [--parent <module_id>];然后使用 documents upload --module <id> 上传到该模块。
  • 用户要求将文档移至另一个模块,或移出其所属模块:确认后使用 documents set-module --dataset <id> --document <id> --module <module_id>(或 --clear)。
  • 用户要求编辑/替换/重新同步已有文档:确认要操作的现有文档后,使用 documents update --dataset <id> --document <id> --file|--text-file <path>。使用模块整理文档(--module/documents set-module),不要使用文件夹。

参考资料

  • references/CAWPLAN_OPEN_API.md — 第 12 节:知识 API。

评论

支持 Markdown