news 2026/9/11 12:30:13

Infisical 文档风格指南:从写作规范到 Vale 自动化检查的完整实践

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Infisical 文档风格指南:从写作规范到 Vale 自动化检查的完整实践

Infisical 文档风格指南:从写作规范到 Vale 自动化检查的完整实践

【免费下载链接】infisicalInfisical is the open-source platform for secrets, certificates, and privileged access management.项目地址: https://gitcode.com/GitHub_Trending/in/infisical

本文以仓库根目录下的 docs/STYLE_GUIDE.md 为绝对主体,结合仓库中实际的 Vale 规则配置(docs/.vale.ini)、CI 工作流(.github/workflows/check-docs-style.yml)与配套贡献规范(docs/CONTRIBUTING.MD)展开,回答"如何为 Infisical 编写面向用户的技术文档"以及"如何用机器自动守住这套规范"两个问题。它面向所有 Infisical 贡献者、技术文档工程师,以及任何想在开源项目中落地"风格指南 + 静态检查"组合的团队。

导读

Infisical 作为开源密钥与证书管理平台,其文档体系(docs/目录下的数百个.mdx页面)有一份自己的"宪法":docs/STYLE_GUIDE.md。这份指南定义了面向用户文档的 14 条核心原则、Mintlify 组件使用规范、句子级写作规则、页面结构与 UI 格式约定,并说明哪些规则由 Vale 静态检查器自动执行、哪些必须靠人工评审。读完本文,你将掌握这套规范的完整内容,理解它与仓库中 Vale 规则文件、make lint-docs-branch命令和Check docs styleCI 检查的对应关系,并能直接在自己的文档贡献中落地执行。


一、快速摘要:14 条总纲

原文档以 14 条快览开篇,是整份指南的索引,逐条对应后文各章节:

  1. 提供上下文(Provide context)— 先解释"是什么、为什么",再讲"怎么做",不假设读者已有前置知识。
  2. 面向用户写作(Write for users)— 不写实现细节,用户关心结果而非内部机制。
  3. 交叉引用(Cross-reference)— 链接对理解页面必不可少的概念。
  4. 使用 Mintlify 组件(Use Mintlify components)— 善用 Steps、Tabs、Cards、Accordions、callouts、diagrams。
  5. 清晰写作(Write clearly)— 主动语态、具体动词、简洁句子、克制使用破折号。
  6. 保持页面聚焦(Keep pages focused)— 每页只有一个目的。
  7. 维持连贯(Maintain flow)— 新增内容要与既有内容自然衔接。
  8. 明确前置条件(State prerequisites)— 开篇告诉读者动手前需要准备什么。
  9. 术语一致(Be consistent)— 全文使用同一套术语。
  10. 按用途组织结构(Structure by purpose)— 指南、概念、概览、参考四类页面结构各异。
  11. 标题用句首大写(Use sentence case)— 页面标题、侧边栏标题与各级标题均用句首大写。
  12. 重写句子(Rewrite the sentences)— 用你自己的语气把话说一遍,逐句朗读。
  13. 粗体只用于 UI(Bold is for UI)— 粗体标记按钮、菜单、字段;交互动词用 select 而非 click 或 tap。
  14. 运行 linter(Run the linter)—make lint-docs-branch检查本指南中的机械性规则。

这 14 条并非平级:第 14 条指向的 lint 只能覆盖"机械性规则",其余条目属于需要人判断的写作决策,这一划分贯穿全文,也对应着仓库中检查工具的实际能力边界。


二、为新用户提供上下文(Provide context)

不假设读者已经知道某个功能是什么、为什么重要。每个页面都应该在深入细节之前,先让新用户"定位"自己。写作顺序遵循"先 what 和 why,再 how":

  • 这是什么功能?
  • 为什么有人要用它?
  • 什么时候用得上?

反例:直接跳进配置步骤,却不解释该功能是做什么的。正例:先用一段简短开场白说明这是什么、为什么重要,再给出步骤。

如果读者不带任何上下文直接落在页面上,他应该能在开头几句话内看懂自己看到的是什么。

受众标注(Audience callouts)

如果页面面向特定受众(管理员 vs. 终端用户、产品管理员 vs. 应用管理员),在页面顶部用<Info>标注,让读者快速判断自己是否来对了地方:

<Info> This page is for product admins setting up PKI infrastructure. Teams issuing certificates should see Applications. </Info>

"何时使用"(When to use)小节

当页面描述的是多种方案中的一种(例如 ACME vs. EST vs. SCEP)时,增加"何时使用"小节,帮助读者判断该方案是否适合自己,用<CardGroup>把适用场景并排列出:

## When to use ACME enrollment <CardGroup cols={2}> <Card title="Web Servers" icon="server"> Nginx, Apache, Tomcat with Certbot. </Card> <Card title="Kubernetes" icon="dharmachakra"> Use cert-manager to issue certificates. </Card> </CardGroup>

这样读者能快速评估"是否继续读下去,还是去别处找答案"。

仓库印证:这类"受众定位 + 平台选择卡片"的模式在现有页面中大量出现,例如 docs/self-hosting/overview.mdx 顶部就用<Accordion title="Why self-host?">说明合规与灵活性两个动机,随后用 6 张平台卡片(Docker、Docker Compose、Kubernetes、Linux package、AWS、GCP)让读者直接选择自己已运行的平台。


三、面向用户写作,而非实现者

文档应当让从未接触过代码库的人也能读懂。判断标准只有一个问题:一个从未看过我们代码的用户能理解这段文字吗?如果不能,就重写。

用户关心"能做什么、会发生什么",不关心"我们是怎么实现的"。因此不要暴露实现细节:API 端点、数据库 schema、内部服务名、以及"底层工作原理"式的解释。

唯一例外:架构类文档(*/architecture.mdx)可以解释系统设计。

从源码结构看,docs/internals/architecture/目录正是这个例外规则的落点,docs/internals/architecture/ 下的页面承担了系统设计解释的职责,而面向业务用户的平台文档(docs/documentation/platform/)则严格遵守"不写实现细节"。


四、交叉引用核心概念(Cross-reference)

当页面提到一个对理解至关重要的概念时,链接到它的文档。判断标准:如果读者不知道这个概念就读不懂本页,那就必须链接。

链接规则:只在概念首次出现时链接,不重复链接。首次链接后读者已知晓,需要时可回翻。

<!-- 好:Gateway 是理解本页的核心概念 --> Users connect through a Gateway without ever seeing credentials. <!-- 好:"了解更多"提供更深上下文 --> Permissions are set at the folder level. Learn more about Folders →

五、使用 Mintlify 组件

充分利用 Mintlify 组件库,而不是依赖纯 Markdown。组件让文档更易扫描、更可交互、更易导航。

步骤(Procedures):<Steps>

当读者需要完成离散的、有序的操作流程时,尤其是 Infisical UI 中的一系列动作,使用<Steps>

<Steps> <Step title="Create a folder"> Go to **Settings → Folders** and click **Create**. </Step> <Step title="Configure permissions">Assign roles to users or groups.</Step> </Steps>

较长的指南应当用## Step 1: Configure in Infisical这样的标题组织主要阶段,在某一阶段内部,当编号动作能提升清晰度时再嵌套<Steps>

备选方案(Alternative approaches):<Tabs>

当一件事有多种做法时,使用<Tabs>

<Tabs> <Tab title="Web">Connect through your browser...</Tab> <Tab title="CLI">Use the command line...</Tab> </Tabs>

提示框(Callouts)

用提示框突出重要信息,四类分别承担不同职责:

  • <Note>— 适用于页面特定部分的上下文。
  • <Warning>— 破坏性操作或不可逆变更。
  • <Tip>— 有帮助的建议或最佳实践。
  • <Info>— 值得了解的额外上下文。

注意:页面级前置条件不要放进 callout,应放在## Prerequisites标题下(见第八节)。

导航:<Card><CardGroup>

用卡片引导读者到相关页面:

<CardGroup cols={2}> <Card title="Quick Start" icon="rocket" href="/docs/quick-start"> Get started in 5 minutes. </Card> <Card title="Concepts" icon="book" href="/docs/concepts"> Understand the fundamentals. </Card> </CardGroup>

图表与可视化(Diagrams and visuals)

当讲解的概念由多个相互连接的部件组成时,使用图表。视觉化呈现关系、数据流和架构,远比纯文字有效。适合画图的场景包括:组件之间如何连接、请求/响应流、认证或授权流程、架构总览、以及任何跨系统多步骤的流程。Mintlify 支持内联 Mermaid 图,也可以直接插入图片。

常见问题(FAQ):<AccordionGroup><Accordion>

FAQ 很有价值——它们覆盖常见坑、误解和"但是……如果……"场景。考虑在以下情况添加 FAQ:功能有常见误区或误解;用户经常问相同问题;存在不适用于主流程的边界情况;"工作原理"有值得解释的细节。

<AccordionGroup> <Accordion title="Can I do X while Y is happening?"> Yes, but only if Z. Here's why... </Accordion> <Accordion title="What happens if something goes wrong?"> The system automatically handles this by... </Accordion> </AccordionGroup>

FAQ 让文档更易扫描——读者可以直接跳到自己的问题,而不是在段落里翻找。

代码示例:何时给、给多少

只在代码确实有助于理解时才包含示例——不要为了让文档显得"技术含量高"而堆代码。一个位置恰当的示例能澄清问题,过多的示例反而淹没读者。

应该包含代码的场景:语法无法仅凭文字说明理解;读者需要可直接复制粘贴的起步材料;展示预期输出有助于验证成功。

应该省略代码的场景:UI 操作步骤已经足够;概念用文字解释更好;加代码只是重复已经说清的内容。

真正写代码时遵守四条:

  • 可复制粘贴——不要带$提示符(会破坏粘贴)。
  • 用直观的占位符<your-api-key><project-id>,不要用abc123foo
  • 尽量用真实值:真实域名、合理的配置。
  • 展示预期输出,帮助读者验证做对了;示例保持最小,只给需要的,不给"所有可能"。
# 好:直观占位符、最小、可复制粘贴 curl -X POST https://app.infisical.com/api/v1/secrets \ -H "Authorization: Bearer <your-access-token>" \ -d '{"key": "DATABASE_URL", "value": "postgres://..."}' # 坏:多余的请求头,过于冗长 curl -X POST https://app.infisical.com/api/v1/secrets \ -H "X-Request-ID: 12345" \ -H "Accept: application/json" \ -H "Content-Type: application/json" \ -H "X-Custom-Header: value" \ ...

自动化佐证:"不要$提示符"和"不要foo占位符"并非只有道德约束力。仓库中 docs/.vale/styles/Infisical/ShellPrompts.yml 以 error 级别扫描代码块内的$提示符,docs/.vale/styles/Infisical/Placeholders.yml 以 error 级别拦截abc123|foobar|foo|baz|qux这类占位符(使用(?<![\w-])前后断言,确保只匹配独立的小写 token,不误伤main-abc123.js这种带连字符的合法标识符;大写FOO/BAR被放行,因为它们读起来像密钥名而非占位符)。两个规则都用scope: raw,因为只有 raw 作用域才能"看穿"代码块。


六、清晰直接的写作(句子级规则)

文档应该读起来像一位经验丰富的同事给你的指示:直接、具体、易于跟随。总原则四条:优先主动语态、用具体动词替代模糊动词、保持句子和段落简洁、首次出现时解释行话。

原文档给出了十组"改写对照",是整份指南中最值得精读的部分,逐一展开:

1. 不要把人类的动词安在非人事物上

路径、策略、属性不会"说""知道""理解"或"想要"。指出行为主体和行为本身。

  • 坏:A grant on/paymentssays nothing about/payments/keys.
  • 好:If you have a role on/payments, that role does not automatically apply to/payments/keys.

2. 用一个从句说清一件事

平实地定义字段或概念。如果第二个从句还需要解释第一个从句,说明第一个从句没有起到作用。

  • 坏:Thescopeproperty defines the boundary within which a grant is considered valid.
  • 好:scopeis the folder path the grant applies to.

3. 只说一遍

删掉用新词复述上一句的句子,保留承载新信息的那句。

  • 坏:Access is granted per folder. Each folder carries its own access list. Because access is defined at the folder level, permissions on one folder do not carry over to another.
  • 好:Access is granted per folder, so permissions on one folder don't carry over to another.

4. 让代词紧贴指代对象

如果读者需要回看才能弄清楚 "it" 或 "they" 指什么,就重复那个名词。重复一个词的成本低于一次重新解析。

  • 坏:Add the service token to the project, then open the environment settings and confirm that it is active.
  • 好:Add the service token to the project, then open the environment settings and confirm the token is active.

5. 每个及物动词都要有宾语

request、create、return、send、apply 这类动词必须说明作用于什么。丢掉宾语,读者就得猜,而这个缺口往往正是作者当时没想清楚的细节。

  • 坏:You create the service in your Infisical dashboard, and the agent requests.
  • 好:You create the service in your Infisical dashboard, and the agent requests credentials for it.

这通常发生在句子被编辑过、丢了尾巴的场景。请单独读一遍每个长句的后半段,检查其中每个动词都有可作用的对象。

6. 先讲行为,再讲标签

把某件事称为"例外""特殊情况"或"注意事项",是让读者先绷紧神经却不知为何。先陈述行为本身。

  • 坏:Folder access is the exception.
  • 好:Folder access doesn't inherit. A role on a parent folder gives no access to the folders inside it.

7. 拆开句中的"中途绕行"

夹在句子中间的从句会让眼睛跳回去找主线。要么拆句,要么把条件移到句首。

  • 坏:The menu adds temporary access and once a grant exists removes folder access.
  • 好:The same menu lets you add temporary access or remove access.

8. 说清实际发生的事情

用"系统、输入、结果"替换抽象表述。抽象往往掩盖了作者是否真的知道机制。

  • 坏:Permissions are evaluated against the resource hierarchy.
  • 好:Infisical checks the exact folder path you asked for, and only that path.

9. 使用缩写

写 "it's"、"don't"、"you'll"、"can't"。完整形式读起来生硬、拖慢句子且毫无收益。

  • 坏:It is not possible to recover a deleted secret. You will need to create it again.
  • 好:You can't recover a deleted secret, so you'll need to create it again.

自动化佐证:仓库 docs/.vale/styles/Infisical/Contractions.yml 用正则逐一替换 "it is"、"you will"、"you are"、"cannot"、"do not" 等完整形式。值得注意:该规则目前以 warning/suggestion 级别运行(见第十二节),因为现有页面存量过多,一旦设为 error 会让所有触碰文档的 PR 失败。

10. 大声朗读

提交之前大声朗读每个句子。如果你不会对站在旁边的同事这样说,就重写。这一条测试能抓住上面大多数规则。

  • 坏:Access removal is reflected within the propagation window.
  • 好:Access is removed within 60 seconds.

标题统一用句首大写(Sentence case)

以下场景始终使用句首大写:

  • frontmatter 的titlesidebarTitle字段
  • 所有层级的 Markdown 标题

冒号后的第一个单词要大写:## Step 1: Configure in Infisical。只有首词、专有名词、产品名和缩写(如 Infisical、Docker、CLI、ACME)大写。

<!-- 好 --> --- title: "Inject secrets into a Docker application" sidebarTitle: "Docker quickstart" --- ## Next steps <!-- 坏 --> --- title: "Inject Secrets Into a Docker Application" sidebarTitle: "Docker Quickstart" --- ## Next Steps

自动化佐证:docs/.vale/styles/Infisical/SentenceCaseHeadings.yml 检查所有 heading 的句首大写,docs/.vale/styles/Infisical/SentenceCaseFrontmatter.yml 检查 frontmatter 的title/sidebarTitle。两条规则都把threshold设为 1.0,即每个单词的大小写都必须正确(默认值 0.8 允许五分之一出错),并把冒号:声明为 indicator,从而支持## Step 1: Set up authentication这种"冒号后另起从句"的合法写法。

不要滥用破折号(em dash)

优先考虑逗号、冒号、括号或句号。偶尔用一次破折号没问题,但一段里出现好几个、或多数句子各有一个,说明标点在代偿句子结构本该承担的工作。

自动化佐证:docs/.vale/styles/Infisical/EmDashes.yml 以段落为作用域(scope: paragraph),统计的出现次数,超过 2 个即告警。


七、保持页面聚焦(Keep pages focused)

每个页面应有清晰、单一的目的。当读者能从"放在一起看"中获益时,把相关工作流放在一起。例如:一个集成指南可以覆盖多种交付方式和相关配置(如 Docker Compose),只要每个小节都服务于同一个集成目标。

  • <Tabs>承载读者只能选一条路的备选方法。
  • 用标题承载主流程完成后读者可能继续做的相关扩展。
  • 当页面的各节服务于真正不同的目的时才拆分页面,而不仅仅因为页面太长。

页面需要拆分的信号:

  • 读者必须滚动跳过与自己无关的内容
  • 目录超过 5–6 个顶级小节
  • 不同受众的目标毫无关联(例如"配置基础设施的管理员" vs. "消费它的终端用户")

更好的结构:

  • 概念总览独立一页
  • 每个工作流或用例各占一页
  • 参考资料(配置选项、API 字段)单独成页
  • 排查指南如果内容可观,独立成页

简短聚焦的页面更易导航、更易链接、更易维护。


八、编辑时维持连贯(Maintain flow)

在既有页面上增改内容时,确保新内容与前后文自然衔接,不要只是插入内容,要把它"连"起来。逐项检查:

  • 页面从上到下仍连贯可读
  • 新章节从逻辑上承接前一章节
  • 过渡自然(读者不应感到突兀)
  • 整体叙事或结构未被破坏

如果新内容与既有流程不匹配,考虑它是否根本不属于这个页面,或者页面结构是否需要重组。


九、明确说明前置条件(State prerequisites)

如果页面假设某些东西已就绪——Gateway 已部署、权限已授予、CLI 已安装——在页面顶部明确说明。读者不应因为漏掉某个未言明的要求而卡在半路。

在主内容之前使用## Prerequisites小节,即使列表很短:

## Prerequisites - An Infisical account - A Gateway that can reach your database

不要把页面级前置条件放进<Info>或其它 callout。<Note>只留给"适用于某一步骤"而非整页的需求细节。


十、术语一致(Use consistent terminology)

全文使用同一套术语,不要为同一概念换同义词——这会迷惑读者,也让搜索更难。

示例:在上下文中选定 "secret" 或 "credential" 之一并坚持;不要混用 "folder" 和 "directory";不要一处叫 "project"、另一处叫 "workspace"。如果 Infisical 对某个概念有特定术语,就一致地使用那个术语。

自动化佐证:术语一致性是 Vale 检查的重头戏。仓库 docs/.vale/styles/Infisical/Terminology.yml 用带前后断言的正则做替换,例如把Azure Active Directory/Azure AD(除 "formerly known as"、"Azure AD CS" 等上下文外)统一替换为 Entra ID。而 docs/.vale/styles/Infisical/SecretsManager.yml 专门处理一个敏感点:Google 的产品叫单数的 "Secret Manager",Infisical 的叫复数的 "Secrets Manager",规则用(?<!GCP )等 lookbehind 排除 GCP/Google 上下文中的合法引用,并且 docs/.vale.ini 在[*gcp*.mdx][*google*.mdx]两类文件上直接关闭该规则——因为那些页面上对 Google 服务的裸引用形态太多,枚举不过来。这是"术语规则与页面主题联动"的精细设计范例。

大小写拼写本身由词汇表兜底:唯一正确写法放 docs/.vale/styles/config/vocabularies/Infisical/canonical/accept.txt(如 Infisical、Infisical Cloud、Secrets Manager、Certificate Manager、Kubernetes、Docker),允许多种大小写的放 docs/.vale/styles/config/vocabularies/Infisical/any-case/accept.txt(如(?i)helm(?i)terraform这类"作为命令是小写、作为项目名是大写"的词汇)。


十一、页面结构(Page structure)

结构取决于页面用途,不要把所有页面塞进同一个模板。

所有页面都需要:

  • titledescription的 frontmatter
  • 让读者定位自己的开场

sidebarTitle可选:当页面标题过长、或脱离上下文读起来很怪时添加,否则直接用title

How-to / 指南类页面:前置条件(如有)→ 分步操作 → 用<CardGroup>给出下一步。

概念类页面:解释它是什么、为何重要 → 各组件如何关联 → 链接相关概念与指南。

概览 / 落地页(Landing pages):简短介绍 → 指向子页面的导航卡片。

一个统领整个板块的落地页还有额外职责:让读者不看侧边栏也能知道该板块包含什么。落地页要镜像该板块的侧边栏结构:

  • 用一两句话开场说明这个板块是干什么的——不是产品的定义,而是读者在这里能找到什么。
  • 覆盖该板块侧边栏中的每个分组。每个分组展开到什么程度取决于分组类型:
    • 分组一卡:当分组内的页面是单一主题的步骤或参考时,一张卡片指向分组的入口页,描述说明该分组用途。Networking 板块就是这样:Gateways 一张卡,Relays 一张卡。
    • 每页一卡:当页面是读者需要二选一的并列选项,且"看到全部选项"本身就是重点时。Self-hosting 对部署平台就是这样——读者正在扫视找自己已经在用的那一个。
  • 当一个板块的分组多到单个卡片组会显得冗长时,为每个分组建独立的##标题,名称与侧边栏一致。简短板块可以全部放在一个<CardGroup>里,不需要标题。
  • 卡片标题与侧边栏标签保持一致,让卡片和它指向的目标读起来一致。
  • 把更深层的解释放在卡片下方,而不是上方——来导航的人不应该为了找链接而翻过一页概念。
  • 只有部分读者需要的细节(如某个选择背后的理由)放进<Accordion>,不要让它们把卡片推到页面下方。

范例页面:仓库中 docs/self-hosting/overview.mdx、docs/documentation/platform/gateways/overview.mdx 和 docs/documentation/platform/identities/overview.mdx 正是这一模式的样板——前文已见 self-hosting 落地页的 6 平台卡片布局,其"为什么自托管"理由被折叠进<Accordion>,正是"把少数读者关心的理由藏到卡片下方"的实践。

参考类页面:结构化信息(表格、字段说明)→ 有帮助的示例。选择最能服务读者的结构。


十二、格式与 UI 约定

粗体只标记 UI,绝不用于强调

粗体标记读者必须在屏幕上找到的东西:按钮、菜单项、标签页、字段名。如果散文需要靠粗体才能"落地",那就重写散文。

作为例外,**Prerequisites:**这种开启列表项或段落的粗体标签是"标签"而非强调,允许。但行内的**Note**:前缀不行——请改用<Note>callout。

  • 坏:This isimportant: rotation only applies toactivesecrets.
  • 好:Rotation only applies to active secrets. SelectSaveto apply the change.

UI 标签用粗体,不用引号或代码

按钮、标签页或字段名用粗体。引号和代码跨度只留给代码、路径、按键和字面值。

  • 坏:Click 'Submit', then navigate toPersonal Settings.
  • 好:SelectSubmit, then go toPersonal settings.

用 select,不用 click 或 tap

与任何控件的交互都用 "select"。它同时覆盖鼠标、触摸和键盘,不对读者的设备做假设。没有 "select" 对应的手势保留自己的动词:right-clickdouble-click

  • 坏:Click the three dot menu, then tapAdd temporary access.
  • 好:Select the three dot menu, then selectAdd temporary access.

自动化佐证:docs/.vale/styles/Infisical/UIActions.yml 以(?<!-)click(?:s|ed|ing)?(?: on)?(?!-)tap系列模式扫描,拦截非连字符形态的 click/tap 动词,统一要求改为 select。原指南同时注明:两条粗体规则("是否该加粗""加粗是否过度")没有任何规则可以检查,判断一个名词是不是应该加粗的按钮,需要一个懂产品的人。


十三、Vale 检查什么:自动化边界与执行机制

命令与 CI

原文档规定:在仓库根目录运行make lint-docs-branch(仅检查本分支改动的.mdx文件),或make lint-docs(检查全部页面);Check docs styleCI 检查对 PR 触碰的文件运行同一套规则。

仓库中的实际实现印证了这套流程:

  • Makefile 中lint-docs目标执行./docs/scripts/lint-docs.sh --alllint-docs-branch执行./docs/scripts/lint-docs.sh --changed,两个目标共用同一脚本,保证本地与 CI 结果不会漂移。
  • docs/scripts/lint-docs.sh 是唯一入口:--all模式下exec vale --glob='*.mdx' .全量检查;--changed模式下用git merge-base计算与--base(默认main)之间的变更文件,只 lint 这些.mdx。一个精巧的设计是LINT_INPUTS正则(docs/.vale.inidocs/.vale/docs/.vale-versiondocs/scripts/lint-docs.sh自身):一旦配置本身被改动,脚本自动退化为全量检查——因为规则变更会波及分支从未触碰的页面。
  • 脚本同时校验 Vale 版本:docs/.vale-version钉住 3.17.1,本机版本不一致时打印警告(结果可能不同),CI 则按该版本下载 tarball 并校验 sha256 校验和。
  • .github/workflows/check-docs-style.yml 在 PR 触碰docs/或工作流自身时触发:先探测 PR 文件列表,再安装钉住版本的 Vale(下载 release 包并用官方 checksums 文件做 sha256sum 校验),最后调用同一脚本。

配置要点:MDX 解析

docs/.vale.ini 中的关键决策:Vale 3.17.1 没有原生 MDX 解析器.mdx被映射为md格式([formats] mdx = md)。这么做有双重收益:一是避免依赖外部mdx2vast二进制(缺失时整轮运行以 E100 中止);二是原生 MDX 解析器会跳过 JSX 元素内的所有内容,包括子节点,那会把大部分散文藏起来,而映射为 Markdown 后,Mintlify 组件内部的散文对 Vale 可见

配套的TokenIgnoresBlockIgnores模式负责在 Markdown 解析前"隐藏"JSX 标签、JSX 表达式、邮箱、URL 和裸主机名(带防护性前后断言避免重复包裹产生不平衡反引号),让组件内部的链接、代码跨度、围栏代码块能被正确 lint。CommentDelimiters = {/*, */}{/* vale off */}{/* vale Infisical.Rule = NO */}这类就地抑制生效。

Vale.Terms = NO是一个反直觉但重要的决定:Vale 由词汇表自动生成的Vale.Terms规则在本语料上产生约 750 个误报、只有 25 个真实发现(因为几乎所有缩写和产品名都有合法的全小写形式——rest是英文单词、helm是二进制、kubernetes.io是 API group、infisical是 CLI 命令),因此大小写一致性改由 docs/.vale/styles/Infisical/Terminology.yml 的显式 swap 承担,词汇表只负责拼写(Vale.Spelling = error)和句首大写例外(Vale.Repetition = error)。

当前不阻塞的规则

两条规则目前不会让运行失败

  • Infisical.UIActions报 warning 级
  • Infisical.Contractions报 suggestion 级

原因:现有页面分别积压数百处(docs/CONTRIBUTING.MD 记录为 561 处和 1,229 处),阻塞性规则会让每个触碰相关页面的 PR 全部失败。两条规则正走在升级为 error 的路上,路线是:非阻塞落地 → 按规则各做一次专门 sweep(不可机械执行:click 作名词、参考表格中刻意的正式措辞都需要人工判断,不能用vale --fix)→ 计数清零后把level:改为error。因此在被触碰的页面上应主动修掉它们,且要读打印输出,而不只是看退出码

判断力部分:Vale 看不到的

原文档明确划界:第 11 节的两条加粗规则没有任何检查器;而提供上下文、面向用户、交叉引用、组件选择、页面结构、以及第五节每一条句子级规则,都是只有评审者才能做的判断。一次干净的 Vale 运行只说明"没有机械性错误",不说明"页面写得好"。原文档建议运行docs-styleskill 来补上判断力那一半。

仓库印证:.agents/skills/docs-style/SKILL.md 正是这个 skill 的实现:make lint-docs-branch只能检查指南的三分之一;Vale 看不见缩进 4 空格及以上、嵌套在 Mintlify 组件里的散文(约占本仓库一半篇幅),一次干净运行对嵌套页面说明不了任何问题。该 skill 规定的人工评审顺序是:先跑 linter(并读取 warning/suggestion)→ 检查结构后不再动它 → 逐句对照指南第五节重写 → 检查 Vale 看不到的格式(加粗滥用、UI 标签的引号/代码误用、无任何标记的按钮字段)→ 以file:line形式逐条报告并先征求同意再修改——不要静默重写工程师的散文。

关于外部风格包的取舍

docs/CONTRIBUTING.MD 还解释了为什么不安装 Google/Microsoft 风格包而选择自写规则:vale sync拉取的包需要 Mintlify 的 CI runner 也执行同步(它不做,配置会指向未下载的样式导致检查失败);CI 按版本 + 校验和钉住 Vale,而同步的包无法匹配;从 46 条规则中只启用 2 条意味着一个随包增长而不断膨胀的禁用列表。结论是:把值得拥有的机制抄下来,自己拥有这个文件。


十四、贡献流程:从写作到合入的完整链路

综合 docs/STYLE_GUIDE.md、docs/CONTRIBUTING.MD 与仓库实现,一次规范的文档贡献流程是:

  1. 动手前先读风格指南(docs/STYLE_GUIDE.md),它覆盖面向用户写作、交叉引用、Mintlify 组件、页面结构与格式、句子级规则。
  2. 先用自己的话脑暴,再让模型帮你搭结构(分组、排序、找出漏掉的章节),散文自己写——结构经得起模型草稿,句子经不起。
  3. 运行 linter:根目录执行make lint-docs-branch,或对子集直接vale <path>。安装方式brew install vale;运行只因 error 失败,warning 和 suggestion 只打印不阻塞,所以要读输出。
  4. 运行docs-styleskill补上判断力评审(见第十三节)。
  5. PR 触发Check docs styleCI,对 PR 触碰的文件运行同一规则集;若 PR 修改了 lint 配置本身,则全量 lint。

词汇表维护要点

当 Vale 误报一个拼写正确的词时,按大小写形态选择文件加入:

  • docs/.vale/styles/config/vocabularies/Infisical/canonical/accept.txt — 只有一个正确大小写的术语。注意:多词条目会强制其所在标题的大小写,所以短语只有永远是 Title Case 时才放这里。
  • docs/.vale/styles/config/vocabularies/Infisical/any-case/accept.txt — 以(?i)前缀,用于合法地以多种大小写出现的词(产品名兼作普通名词、与普通词撞车的缩写)。

注释必须"井号加空格":#Foo会被当作正则而不是注释。偏好把有区分度的词单独列出,而不是依赖多词条目覆盖它——本仓库的 Vale 会掩盖多词短语的各组成部分使其被接受,而 Mintlify 的 CI Vale 不会,Ab Initio单独留下Initio在那边报错就是教训。

强制拼写与抑制规则

  • 强制拼写:向 docs/.vale/styles/Infisical/Terminology.yml 添加 swap,只列"永远错误"的形态,并记住产品名的小写形式通常是它的二进制、包或 API group。
  • 抑制规则:Vale 的句首大写检查在冒号和单字母标签周围有几个已知盲区。在它判错的地方就地抑制,而不是削弱规则:
{/* vale Infisical.SentenceCaseHeadings = NO */} ## Option A: Managed PostgreSQL service {/* vale Infisical.SentenceCaseHeadings = YES */}

{/* vale off */}{/* vale on */}禁用两者之间的所有规则。抑制只用于规则确实对某行判错时,绝不用来安抚页面。

规则必须同时存活于两套 Vale 构建

仓库经验表明,本仓库的 Vale 与 Mintlify CI 运行的 Vale并不总是意见一致。一个 scoped 到rawconditional规则曾因此被移除——它报告 148 个文件缺少description,而这些文件全都有。ShellPromptsPlaceholders之所以也用scope: raw,是因为必须看进代码块;它们在本地行为正确,但在 CI 上的行为被视为未经验证。任何需要整文件视角的检查,与其做成 Vale 规则,不如做成独立检查。


结语:规范是写出来的,也是跑出来的

Infisical 的文档风格指南给出一套可操作的答案:约三分之一的规则由 Vale 在本地与 CI 双重自动化,其余是评审者的判断;机器管住机械错误(大小写、术语、$提示符、click/tap、破折号、缩写),人管住文字质量(上下文、读者视角、句子节奏、页面结构)。这套"风格指南 → Vale 规则文件 → 统一 lint 脚本 → CI 工作流 → AI 评审 skill"的五层链路,既是 Infisical 文档质量的保证,也值得任何维护文档型开源仓库的团队整体借鉴。下一篇文档提交前,记得先读 docs/STYLE_GUIDE.md,再跑一遍make lint-docs-branch

【免费下载链接】infisicalInfisical is the open-source platform for secrets, certificates, and privileged access management.项目地址: https://gitcode.com/GitHub_Trending/in/infisical

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/11 12:29:51

DeepSeek V4.1 Flash协议升级与STP适配指南

1. 项目概述&#xff1a;为什么说“浪费时间&#xff01;DeepSeek 4.1 Flash”不是一句情绪化吐槽&#xff0c;而是一条关键信号 “浪费时间&#xff01;DeepSeek 4.1 Flash”——这个标题乍看像极了某位用户在深夜调试失败后摔键盘的即时发泄&#xff0c;但作为连续跟踪大模型…

作者头像 李华
网站建设 2026/9/11 12:27:21

风储联合一次调频Simulink仿真建模与参数整定实战指南

电网频率这件“小事”&#xff0c;近两年在风电场并网评审里越来越绕不开了。以前调频是火电、水电的活儿&#xff0c;风电只管发有功功率就行。但现在风电渗透率一上来&#xff0c;电网里同步电源被替换掉&#xff0c;系统惯量和调频备用都在缩水&#xff0c;电网公司对风电场…

作者头像 李华
网站建设 2026/9/11 12:25:45

Windows命令拼接实战:从连接符原理到一键自动化执行

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/11 12:25:14

13MB的丑软件,凭什么碾压主流批量改名工具?

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/11 12:24:36

微电网两阶段优化调度系统的MATLAB实现与挑战

1. 多能源微网优化调度系统的核心挑战微电网作为分布式能源系统的重要实现形式&#xff0c;正面临着前所未有的复杂性和不确定性。传统单阶段控制方法在处理风光互补发电、储能系统、柔性负荷等多能源协同问题时&#xff0c;往往表现出三个典型缺陷&#xff1a;时间尺度耦合问题…

作者头像 李华