关于 cawplan-knowledge
cawplan-knowledge 是一项 Agent 技能,指导通过 cawplan CLI 浏览和搜索 CawPlan 知识库。它支持从数据集逐层查看文档与章节,并提供相关片段搜索、全文读取及长文档导航流程。
主要功能
- 01浏览数据集和文档
- 02搜索相关度排序的知识片段
- 03读取完整文档或指定章节
- 04按大纲浏览长文档
- 05按产品或模块筛选数据集
适用场景
- 01跨数据集查找相关信息
- 02阅读长文档中的特定章节
- 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始终是节点自身的--outlinepreview字符串,逐字不变。 直接复制该字段,不要改动。不要自行编写预览文本,也不要用结构摘要(章节的子标题列表、计数、改写)来代替——预览的目的是展示章节实际开头的正文,让用户在选择前判断内容。子标题列表并没有提供选项标签之外的新信息,而自行编写还会额外消耗一轮往返所需的 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,使用相同层级(或父级)。这样就能实现真正的“选择 → 查看 → 再选择”循环——这是纯文本无法提供的体验——而用户无需重新输入任何内容。
-
列出数据集 —— 树的根节点。当用户询问有哪些可用数据集、说出一个需要解析为
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有相同限制:它需要真实的交互式终端,应由人直接运行,而非由你运行。
- 如果没有返回模块,说明该产品没有模块——直接使用上面的仅带
-
列出数据集中的文档——树的第二层,用于浏览特定数据集的内容(用户选择了第 1 步中的数据集,或直接指定了数据集):
cawplan knowledge documents list --dataset <id> # optional: --keyword <text> --page <n> --limit <n><id>必须来自第 1 步的输出。 -
搜索——用户提出“查找有关 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 步)。
-
获取完整文档内容——当用户需要文档全文,或需要特定文档的内容而非匹配片段时:
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。 -
使用索引树浏览大型文档——当用户想要探索不熟悉或篇幅较长的文档时:
-
通过一次调用,以标题树的形式获取文档结构,而不拉取完整内容:
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>— 相同的标题树浏览器,但限定于用户已选择的文档。
-
-
创建数据集 — 当用户要求创建新的知识数据集时:
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查找。 -
向数据集上传文档 — 当用户要求向数据集(现有数据集或刚创建的数据集)添加或上传文件、文本内容时:
# 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上传是同步的(不涉及任务或轮询)——每份文档创建完成后,命令就会返回。 -
更新现有文档 — 当用户要求编辑、替换或重新同步知识库中已有的文档(而不是上传新文档)时:
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标志。 -
将文档移入/移出模块 — 当用户要求将现有文档归入某个模块,或从模块中移出时:
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。