Read OSS

集成层级体系:一套代码库,支持 25+ AI 智能体

高级

前置知识

  • 第 1 篇:架构与项目导航
  • 第 2 篇:Init 命令深度解析
  • 熟悉面向对象设计模式(模板方法模式、策略模式)
  • 了解 YAML frontmatter

集成层级体系:一套代码库,支持 25+ AI 智能体

执行 specify init --integration windsurf 时,会在 .windsurf/workflows/ 下生成 markdown 文件;使用 --integration gemini 时,则会在 .gemini/commands/ 下生成 TOML 文件;而 --integration claude 会在 .claude/skills/speckit-*/SKILL.md 路径下创建带有自定义 frontmatter 的技能目录。三者都源自同一套 9 个命令模板。这一切背后的关键,正是 Spec Kit 的集成类层级体系——它也是整个代码库中最具架构价值的部分。

四层类层级体系

集成系统以经典的面向对象设计为基础,核心是模板方法模式。四个基类提供了层层递进的行为抽象:

classDiagram
    class IntegrationBase {
        <<abstract>>
        +key: str
        +config: dict
        +registrar_config: dict
        +context_file: str
        +setup()*
        +teardown()
        +process_template()
        +copy_command_to_directory()
        +record_file_in_manifest()
        +write_file_and_record()
        +install_scripts()
    }

    class MarkdownIntegration {
        +setup()
        "~20 agents: Windsurf, Cursor, Roo, Amp..."
    }

    class TomlIntegration {
        +setup()
        +command_filename()
        -_extract_description()
        -_render_toml()
        "2 agents: Gemini, Tabnine"
    }

    class SkillsIntegration {
        +setup()
        +skills_dest()
        "3+ agents: Claude, Codex, Kimi"
    }

    class CopilotIntegration {
        +setup()
        +command_filename()
        "1 agent: fully custom"
    }

    IntegrationBase <|-- MarkdownIntegration
    IntegrationBase <|-- TomlIntegration
    IntegrationBase <|-- SkillsIntegration
    IntegrationBase <|-- CopilotIntegration

层级结构定义于 integrations/base.pyIntegrationBase 提供细粒度的基础原语——文件操作、模板处理、manifest 追踪。三个具体基类(MarkdownIntegrationTomlIntegrationSkillsIntegration)各自以特定格式实现 setup() 方法。CopilotIntegration 则因其特殊需求,直接继承自 IntegrationBase

这一设计的核心理念是:绝大多数集成不需要覆写任何方法。只需设置三个类属性,其余一切都可继承。

IntegrationBase:细粒度基础原语

位于 base.py#L54-L67 的抽象基类定义了四个必须设置的类属性:

  • key — 与 CLI 工具名一致的唯一标识符(如 "windsurf""kiro-cli"
  • config — 包含 namefoldercommands_subdirinstall_urlrequires_cli 的元数据字典
  • registrar_config — 格式规范,包含 dirformatargsextension
  • context_file — 智能体上下文/指令文件的可选路径

base.py#L164-L362 中的基础方法均为静态方法或实例方法,子类在 setup() 中将它们组合使用:

sequenceDiagram
    participant Setup as setup()
    participant List as list_command_templates()
    participant Proc as process_template()
    participant Write as write_file_and_record()
    participant Scripts as install_scripts()

    Setup->>List: Get sorted .md files from shared commands dir
    loop For each template
        Setup->>Proc: Transform raw markdown → agent-ready content
        Setup->>Write: Write to dest dir + record SHA-256 hash
    end
    Setup->>Scripts: Copy integration-specific scripts

write_file_and_record() 在写入前会将换行符统一为 \n,并立即将 SHA-256 哈希值记录到 manifest 中。这确保 manifest 始终与磁盘上的实际文件内容完全一致,这对后文将介绍的安全卸载机制至关重要。

提示: shared_commands_dir() 方法沿用了第 1 篇中介绍的双路径解析模式——优先检查 core_pack/commands/(wheel 安装),其次检查 templates/commands/(源码检出)。所有涉及资源文件的基类方法都遵循这一约定。

process_template() 的七步流水线

process_template() 静态方法是格式转换的核心。它通过七个顺序步骤,将原始命令模板转换为可供智能体使用的内容:

flowchart TD
    S1["1. Extract scripts.{type} from YAML frontmatter"] --> S2["2. Replace {SCRIPT} with extracted command"]
    S2 --> S3["3. Extract agent_scripts.{type}, replace {AGENT_SCRIPT}"]
    S3 --> S4["4. Strip scripts: and agent_scripts: sections from frontmatter"]
    S4 --> S5["5. Replace {ARGS} with agent-specific placeholder"]
    S5 --> S6["6. Replace __AGENT__ with agent name"]
    S6 --> S7["7. Rewrite paths: scripts/ → .specify/scripts/"]

让我们以 plan.md 模板为例,追踪它在使用 sh 脚本处理为 Windsurf 格式时的完整过程:

输入 frontmatter 包含两种脚本变体:

scripts:
  sh: scripts/bash/setup-plan.sh --json
  ps: scripts/powershell/setup-plan.ps1 -Json
agent_scripts:
  sh: scripts/bash/update-agent-context.sh __AGENT__
  ps: scripts/powershell/update-agent-context.ps1 -AgentType __AGENT__

步骤 1-2 执行后:{SCRIPT}scripts/bash/setup-plan.sh --json 步骤 3 执行后:{AGENT_SCRIPT}scripts/bash/update-agent-context.sh __AGENT__ 步骤 4 执行后:scripts:agent_scripts: YAML 块从 frontmatter 中移除 步骤 5 执行后:{ARGS}$ARGUMENTS(Windsurf 的占位符形式) 步骤 6 执行后:__AGENT__windsurf 步骤 7 执行后:scripts/bash/setup-plan.sh.specify/scripts/bash/setup-plan.sh

步骤 7 的路径重写委托给 CommandRegistrar.rewrite_project_relative_paths(),负责将模板中使用的仓库相对路径转换为脚手架输出所需的项目相对路径。

案例分析:Windsurf——四属性集成

Windsurf 很好地展示了这套层级体系的威力。整个集成只有 22 行代码——integrations/windsurf/__init__.py

class WindsurfIntegration(MarkdownIntegration):
    key = "windsurf"
    config = {
        "name": "Windsurf",
        "folder": ".windsurf/",
        "commands_subdir": "workflows",
        "install_url": None,
        "requires_cli": False,
    }
    registrar_config = {
        "dir": ".windsurf/workflows",
        "format": "markdown",
        "args": "$ARGUMENTS",
        "extension": ".md",
    }
    context_file = ".windsurf/rules/specify-rules.md"

无需覆写任何方法。base.py#L455-L508 中的 MarkdownIntegration.setup() 负责处理所有事务:遍历模板、调用 process_template()、写入处理后的文件、安装脚本。27 个集成中,约有 20 个采用这种完全相同的模式——差异仅在于类属性的值。

案例分析:Copilot——完全自定义集成

Copilot 是验证规则的例外。它直接继承 IntegrationBase,原因是它有三项特殊需求,任何现有基类都无法满足——integrations/copilot/__init__.py#L24-L38

  1. .agent.md 扩展名,而非普通的 .md

    def command_filename(self, template_name: str) -> str:
        return f"speckit.{template_name}.agent.md"
  2. 伴生 .prompt.md 文件,存放于 .github/prompts/ 目录下——每个命令对应一个文件,包含引用智能体命令的 YAML 头部:

    prompt_content = f"---\nagent: {cmd_name}\n---\n"
  3. VS Code settings.json 合并——集成附带一个模板 settings 文件,并在合并时保留用户已有的配置,不做覆盖。copilot/__init__.py#L134-L186 中的合并逻辑还处理了边界情况:若文件是含注释的 JSONC 格式(无法通过 json.loads 解析),则跳过合并并输出警告。

flowchart LR
    A["Command templates"] --> B[".github/agents/<br/>speckit.plan.agent.md"]
    A --> C[".github/prompts/<br/>speckit.plan.prompt.md"]
    A --> D[".vscode/settings.json<br/>(merged)"]
    A --> E[".specify/integrations/<br/>copilot/scripts/"]

尽管 Copilot 有自定义的 setup(),它仍然复用了相同的基类原语:process_template()write_file_and_record()record_file_in_manifest() 以及 install_scripts()。层级体系在不强迫你重写一切的前提下,提供了灵活的扩展出口。

案例分析:Claude 与 Gemini——Skills 与 TOML

Claude 使用 SkillsIntegration,按照 agentskills.io 规范,为每个命令创建独立目录。但 Claude 在此基础上增加了后处理步骤——integrations/claude/__init__.py

基类 SkillsIntegration.setup() 创建技能文件后,Claude 的覆写方法会遍历已创建的文件,并注入三个 frontmatter 字段:

Frontmatter 键 作用
user-invocable true 允许用户在 Claude Code 中通过 /command 调用该技能
disable-model-invocation true 阻止模型自动触发该技能
argument-hint "Describe the feature..." 用户调用命令时显示的内联提示文本

argument-hint 的值来自 ARGUMENT_HINTS 字典,将命令名映射为对用户友好的提示语。

Gemini 使用位于 base.py#L515-L684TomlIntegration,同样执行 process_template() 流水线,但最终将结果转换为 TOML 格式。转换过程会用 yaml.safe_load 从 frontmatter 中提取 description(支持块标量),剥离 frontmatter 后,生成包含 descriptionprompt 键的 TOML 文件。在渲染时还处理了正文包含三引号分隔符的边界情况,必要时回退为字面字符串或转义基本字符串。

IntegrationManifest:基于哈希追踪的安全卸载

setup 过程中创建的每个文件都由 IntegrationManifest 追踪管理——这是一个存放于 .specify/integrations/<key>.manifest.json 的 JSON 文件,内容如下:

{
  "integration": "claude",
  "version": "0.6.2.dev0",
  "installed_at": "2026-04-12T10:30:00+00:00",
  "files": {
    ".claude/skills/speckit-plan/SKILL.md": "a1b2c3d4e5f6...",
    ".claude/skills/speckit-specify/SKILL.md": "f6e5d4c3b2a1..."
  }
}

每个值都是安装时文件内容的 SHA-256 十六进制摘要。卸载时,manifest.uninstall() 只删除当前哈希值与记录值一致的文件,已被修改的文件会被跳过并上报。这样可以有效防止误删用户的自定义内容。

flowchart TD
    A["uninstall() called"] --> B["For each tracked file"]
    B --> C{"File exists?"}
    C -->|No| D["Skip (already gone)"]
    C -->|Yes| E{"SHA-256 matches?"}
    E -->|Yes| F["Delete file + clean empty parents"]
    E -->|No| G{"--force flag?"}
    G -->|Yes| F
    G -->|No| H["Skip (user modified)"]
    F --> I["Remove manifest JSON"]

提示: manifest 在删除文件后还会清理空的父目录,避免卸载后留下 .claude/skills/speckit-plan/ 这样的空目录树。

注册机制与新增集成

integrations/__init__.py 中的 _register_builtins() 函数遵循严格的约定:import 语句按字母顺序排列,注册调用同样按字母顺序排列。每个集成子包的目录名必须是合法的 Python 标识符——键名中的连字符在目录名中替换为下划线(kiro-clikiro_cli/),而 key 属性本身保留连字符形式。

新增集成只需三步:

  1. 创建子包 — 在 src/specify_cli/integrations/myagent/__init__.py 中定义继承自 MarkdownIntegration 的类(这是最常见的情况)
  2. _register_builtins() 中注册 — 添加 import 语句和 _register(MyAgentIntegration()) 调用
  3. 编写测试 — 在 tests/integrations/test_integration_myagent.py 中验证注册、配置及占位符替换是否正确

对于大多数智能体来说,完整实现不超过 25 行。类层级体系承担了所有繁重的工作。

下一篇预告

集成层级体系负责生成各智能体专属的命令文件,但这些文件内部究竟包含什么?第 4 篇将深入解析构成 Spec Kit 声明式工作流引擎的 9 个斜杠命令模板——探索 YAML frontmatter 如何构建工作流 DAG、shell 脚本如何提供操作层支撑,以及文档模板如何通过结构化提示约束 AI 输出质量。