Linear 作为「为什么」证据源:OpenBot pstack why 技能中的 Linear 检索实战指南
Linear 作为「为什么」证据源:OpenBot pstack why 技能中的 Linear 检索实战指南
在 OpenBot 的 pstack 技能包里,why 技能专门回答“这段代码为什么长成这样”,而 Linear 是它七个证据类别中最擅长提供产品与业务驱动力的一类。本文以 Linear Tickets 检索手册 为主线,完整拆解 Linear 里存了什么、该怎么用 MCP 检索、什么算好证据、有哪些坑,以及检索结果如何被上游的合成器(synthesizer)按置信分层引用。
一、Linear 在 why 技能的证据版图中的位置
why 技能的设计前提是:代码只展示“是什么”,不展示“为什么”。为什么存在于提交、PR、工单、长文档和聊天记录里,而这些记录都不完整、有偏差,甚至完全缺失。因此该技能在 SKILL.md 中定义了七个证据类别,每个类别“最擅长”给出一种形状的“为什么”:
| 序号 | 证据类别 | 最擅长 | 典型 MCP |
|---|---|---|---|
| 1 | 源码历史 | 评审阶段留下的实现期理由 | git、gh(始终可用) |
| 2 | 工单 / Issue 追踪 | 产品与业务的强制驱动因素 | Linear、Jira、GitHub Issues、Plane、Shortcut |
| 3 | 长篇文档 | 代码落地前写好的设计理由 | Notion、Confluence、Google Docs、Coda |
| 4 | 实时团队聊天 | 从未沉淀成文档的即时讨论 | Slack、Discord、Teams、Mattermost |
| 5 | 基础设施可观测性 | 促使代码防御化的运行时现实 | Datadog、New Relic、Honeycomb、Grafana |
| 6 | 错误 / 异常追踪 | 具体异常轨迹催生的补救代码 | Sentry、Rollbar、Bugsnag |
| 7 | 产品分析仓库 | 影响代码形态的数据现实 | Databricks、Snowflake、BigQuery、dbt |
Linear 属于第 2 类。源码历史是唯一“保底”的证据源(git 和 gh 总在),而 Linear 的价值在于:当某个技术决策的动因在工程之外时(客户诉求、合规期限、事故跟进),它往往是最强的证据源。若该类别没有对应的 MCP,技能要求把它记录为覆盖缺口(gap)而不是主动放弃,例如“实时团队聊天未检索:环境中没有匹配的 MCP,对话记录不可搜索”。这条规则同样适用于 Linear:如果环境里没有 Linear MCP,“问题/工单追踪”一栏必须显式写出未检索,而不是默默跳过。
七类证据的分工由 source-playbook.md 统一索引,其中 Linear 手册同时也是 Jira、GitHub Issues、Plane、Shortcut 的适配母本:换一个同类 MCP 时,替换的是工具名,检索逻辑基本不变。
二、Linear 里到底有什么:六类可检索内容
linear.md 开宗明义地列出 Linear 承载的内容:
- 描述功能、缺陷及其动机的 Issue:正文里常直接写明“为什么要做”。
- 挂在 Issue 上的项目文档:往往是 PRD 或 spec。
- 父子 Issue 关系:从更大的计划(initiative)到具体工单的层级。
- Issue 评论:澄清、范围变更、“我们为什么要做这个”的理由说明。
- 标签:如
compliance、customer-request、perf,直接标示动机类型。 - 解释范围变更的状态更新:工单状态流转时的说明。
- 附件与关联的 GitHub PR:把业务记录和代码提交串起来。
文档给出的定位非常精确:Linear 是产品/业务上下文所在之处,是“因为客户 X 提出”或“这是 Q3 合规计划的一部分”那一层。
这一点决定了检索姿势。源码历史告诉你改了什么、评审时争论了什么;Linear 告诉你谁在推动、为什么现在做、做完要满足什么外部约束。二者在同一次调查中并行检索,才可能还原完整动因。
三、五步检索流程:用 Linear MCP 逐层下钻
linear.md 给出的检索路径是“先窄后宽,再回到层级结构”,共五步。
1. 从被链接的工单开始
如果种子提交或 PR 引用了工单 ID(例如 ENG-1234、[BUG-567]),先用 get_issue 取回它们,并读完整个 Issue,包括评论。这一步之所以排第一,是因为它把代码锚点直接接到业务记录上,信噪比最高。
代码锚点在 why 技能的第 2 步构建,包含文件路径与行范围、关键符号、最近几次提交、从合并提交主题里的 (#1234) 模式抽出的 PR 号,以及提交或 PR 正文中提到的工单 ID。这些信息随后会填入 investigator 提示模板的 TICKET_IDS 占位符,见 investigator-prompt.md。换句话说,Linear 检索不是漫无目的的搜索,而是从代码锚点出发的定向追踪。
2. 用关键词列相关 Issue
使用 list_issues 做文本搜索,关键词覆盖功能名、关键符号、业务术语,并尝试多种表述。同一件事在不同团队口中可能叫 retry policy、backoff、rate limit 或 throttle,只搜一种写法极容易漏掉关键工单。
3. 走通 Issue 树
如果你落在子 Issue 上,去取它的父 Issue。文档的判断很干脆:子 Issue 是战术性的,父 Issue 常常承载“为什么”。典型形态是父 Issue 标题像计划名(“Q3 Enterprise Readiness”“Reduce Payment Failures”),子 Issue 才是具体改动。
4. 读项目文档
若 Issue 属于某个项目,用 get_project 查看挂载的文档。项目级文档是规格与理由最常被记录的地方。这一步与“长篇文档”类别有交叉,但 Linear 项目文档是随工单体系一起组织的,往往比独立文档库更贴近具体改动。
5. 检查标签与里程碑
标签提示动机类别(customer-request、incident-followup、compliance);里程碑把工作绑定到期限上,而期限本身常常暴露动机(合规截止、发布会、续约谈判)。
与 investigator 提示模板的衔接
这五步是 investigator 在自己那一类证据里的固定动作。模板对该角色的约束是明确的:只在自己的证据源里深挖,遇到跨源引用不要追,记到 Additional Leads 交给别的 investigator,因为“一个类别一个 investigator”的设计依赖这条边界。模板同时要求逐字引用并标注精确位置(工单 ID、PR 号、commit hash、file:line),记录搜过什么而不只是找到什么——空搜索结果也是一个发现,见 investigator-prompt.md。
模板里还有一条对 Linear 检索尤其关键的原则:机制不等于动机。把 limit = 50 改成 limit = 100 只证明改动发生,不证明原因;原因要在提交信息、PR 描述、关联工单或评审评论里找。同理,不允许从代码风格推断作者意图——只能引用作者写明的内容。
四、什么才算这里的“好证据”
linear.md 给了五类可直接引用的样例:
- Issue 描述写明了业务问题:“Customer Acme needs X because of their SOC2 audit”。
- 评论记录了一次决策:“We decided to go with approach B because approach A would require touching the billing service”。
- 父 Issue 的标题像一个计划:“Q3 Enterprise Readiness”或“Reduce Payment Failures”。
- 附带的 PRD 或 spec。
- 形如
customer:acme、incident-followup、compliance、perf-regression的标签。
共同点是包含具体的“因为”:谁需要、为满足什么约束、为什么排除了替代方案。这类文本可以直接支撑合成器输出中的 [Direct] 层——单一来源、作者亲笔写明,可以平实地陈述“这存在是因为 X”。
反面例子则是“improve user experience”这类通用话术。文档在陷阱一节专门指出:有些团队强制要求填 “Why” 段落,但填的是套话,这种文本大概率不是真正的答案。
五、五个必须警惕的陷阱
linear.md 列出的坑,本质上都是“历史证据的失真”:
- 范围漂移(Scope drift)。PR 引用的工单可能被关闭后以不同范围重开。必须读完整历史,而不是当前标题。
- 机械模板。强制 “Why” 段落产生的套话,读起来像理由,实际上不含信息。
- 过期工单。老工单反映的是后来被改掉的计划。要核对日期,并与代码实际交付时间交叉验证。
- “重复”关闭链。遇到 closed-as-duplicate,沿 duplicate-of 关系回溯到权威工单,否则你引用的是别人的转录。
- 私有工作区内容。访问不到就记为缺口,不要猜。
第 5 条与 why 技能的全局姿态一致:保持审慎、精确,清楚区分“知道”与“推断”。这也是为什么 Linear 手册要求返回作者、创建日期、关闭日期——日期是判断“这条记录是否还适用于当前代码”的唯一客观依据。
六、返回给合成器的字段:为什么格式这么硬
linear.md 规定每个相关工单返回:
- 工单 ID 与标题;
- 从描述或评论中逐字引用的问题/动机(不要转述——合成器需要原文来引用);
- 标签、父 Issue、所属项目;
- 作者、创建日期、关闭日期;
- 若可用,工单链接。
“不要转述”这条是硬约束。合成器在 synthesizer-prompt.md 中要求每条 [Direct]/[Supported] 论断都带精确引用,并且要抽查引用是否真的存在、是否真的说了那句话。转述会在这一环节丢失可核验性。
合成器最终产出的结构固定为:The Question、The Code in Question、What We Found、What We Can Reasonably Infer、Competing Hypotheses、What We Don't Know、Sources Consulted、Confidence Summary。其中 Sources Consulted 中“问题/工单追踪”一行,要么写出检索过的工单 ID 与关键词,要么老实写 “Not searched. No matching MCP available in this environment.”。如果 why 的结论将用于后续改代码,还要在 Sources Consulted 之后补一组 Preserve / Change / Avoid / Risk 约束集,把血缘结论转成改动计划的前置约束。
七、置信分层:Linear 证据能撑起多强的结论
epistemics.md 把每条论断压到五个层级之一,层级决定它出现在哪一节、用什么措辞:
- Direct:作者亲笔写明了原因。Linear 里最常见的形态是工单描述“we're adding this because customer Acme requested it in their security review”,或评论里“we decided to go with approach B because…”。措辞可以自信、现在时、带引用。
- Supported:多条间接证据收敛到同一结论。比如 PR 标题写 “improve performance”、工单标签是
perf、同期提交都改同一条热路径——三者叠加,但没有任何一处明说。措辞自信但明确标注是推导出来的,并逐条引用。 - Inferred:上下文合理读法,无人明确支持。必须显式写出推理链(“Given A and B, C seems likely because D”)并使用 “appears to”“likely”“suggests” 等模糊限定语。
- Speculative:证据薄弱且存在同样合理的其他解释,放在 Competing Hypotheses 里。
- Unknown:搜过但没找到。这是有效结果,必须写清搜了哪些关键词、扫了哪些工单、时间范围。
epistemics.md 还列出了一批只能用于 Direct/Supported 的措辞:because、the reason is、was designed to、fixes/addresses/solves、the team decided。同时明确禁止 obviously、clearly、of course、just 和 “I think”——这些词会掩盖不确定性,或者把合成伪装成个人观点。
对 Linear 检索者最有指导意义的两条是:
- 警惕谄媚陷阱。用户常在提问里夹带假设(“我猜是为了性能?”)。该假设只是待查的候选之一,不能直接确认;支持就带引用支持,不支持就说不支持,并给出证据真正支持的内容。
- 证据冲突时两边都呈现。工单说“为了客户 X 的合规要求”,PR 说“清理这一块的技术债”,两者可能都对(工单驱动了工作,PR 是作者的表述框架),不要挑更顺故事的那条。
八、在 OpenBot 中把 Linear 接到这套流程上
pstack 的 why 技能以 SKILL.md 作为入口,frontmatter 中声明了 name: why 与一段 description(用于 “why does X work this way”“why we picked Y”、设计理由、回归、事后复盘、数据驱动阈值等场景),并用 disable-model-invocation: true 阻止模型自行触发,需要显式调用。技能在执行时的一个硬性要求是:所有子角色都必须以可访问 MCP 的模式运行,不能使用 readonly / Ask 模式,因为只读模式会剥离 MCP 访问权限,直接让 Linear 这类基于 MCP 的 investigator 和合成器的引用抽查失效。
Linear 在 OpenBot 里的接入记录在插件清单 plugin.json 中:
slug为linear,分类coding,描述为“在登录账号所属工作区里列出指派给自己的 Issue、梳理 backlog、更新状态、起草新 Issue”;- 应用
app-linear-mcp的 server 配置为transport: "http",url指向 Linear 的 MCP 服务端点,auth使用{ "kind": "link", "label": "Sign in" },即通过浏览器完成登录授权; - 内置了三条可直接使用的提示词:查询本周指派给自己的事项、梳理 backlog 中过期/阻塞/无归属的项、为同步队列崩溃按复现步骤提 Issue。
这意味着“谁来检索 Linear”不是靠共享一个服务账号:每个用户用浏览器登录自己的 Linear 账号,检索范围自然落在其有权访问的工作区内。这也解释了手册里“私有工作区内容访问不到就记为缺口”的现实来源——权限是账号级的,而不是提示词能绕过的。
而 Linear 插件在插件目录中的排序位置,可在 plugin-catalog/catalog.json 的 order 数组中看到(linear 与 notion、sentry 等并列)。至于 pstack 包本身,则记录在 production-catalog/catalog.json 的 packs 中:来源 cursor,分类 coding,安装全部 52 个 pstack 技能,调用方式是 $pstack-<name>,例如 $pstack-why。
技能落地位置由 home-skills.ts 定义:HOME_SKILL_FOLDER 为 .agents/skills,OpenBot 只读取该目录,且只接受带 SKILL.md 并符合 Agent Skills 规范的技能;技能文件夹可以是符号链接(npx skills 就是这么做的)。因此 pstack 的 why 及其 references/sources/*.md 手册,最终是从用户主目录下的技能目录被读取的,而不是从仓库运行时加载。
九、能力边界与缺口记录方式
这套流程刻意保留“不知道”。Linear 手册与 epistemics.md 都要求:What We Don't Know 一节必须具体到“搜了什么、在哪搜、时间范围、结果如何”,而不是一句“我们不知道”。例如:“在问题追踪器中检索了 rate-limit、throttle、backoff 三个关键词,扫过自 2023 年以来触及该文件的 6 个 PR,并用 grep 查找过仓库中与该阈值匹配的字符串字面量,均未出现理由说明。”
对 Linear 检索本身而言,典型的合理缺口包括:
- 环境中没有 Linear MCP,整个类别不可搜索;
- 工单存在但正文与评论都只有模板化描述;
- 工单可读但项目文档无权限,PRD 无法确认;
- 存在多个候选工单且互相矛盾,且没有 canonical 记录可以裁决。
诚实的“未找到”比编一个通顺理由更有价值:读者据此可以去找当初的作者、产品负责人或团队 lead 求证,或者判断这个问题不值得继续追。
十、结语
Linear 手册虽然篇幅不长,但它把“从工单里挖动机”这件事拆成了可执行、可核验、可交接的流程:从被引用的工单出发,用多种表述做关键词检索,沿父子关系上溯到计划层,读项目文档,最后用标签和里程碑锁定动机类型。它同时给出了证据的质量标准(有没有具体的“因为”)、失真的五种典型来源(范围漂移、模板、过期、重复链、权限),以及一套强制逐字引用的返回格式,好让上游的置信分层不被转述污染。
在 OpenBot 的 pstack why 技能里,这份手册只是七分之一;但凡是“为什么现在做、为谁做、被什么外部约束推着做”这类问题,它往往是最先给出答案的那一份。