CodeCompanion Rules 配置指南:为 Neovim 聊天注入持久化 LLM 指令与项目上下文
2026/9/17 18:41:17 网站建设 项目流程

CodeCompanion Rules 配置指南:为 Neovim 聊天注入持久化 LLM 指令与项目上下文

【免费下载链接】codecompanion.nvim✨ AI Coding, Vim Style项目地址: https://gitcode.com/GitHub_Trending/co/codecompanion.nvim

导读

CodeCompanion 的 Rules(规则)机制借鉴了 Cursor Rules 与 Claude Code 的思路,为每次新建的聊天会话自动注入"系统级指令"与"项目级上下文"两类信息——前者约束 LLM 的行为与输出风格,后者把仓库内既有的事实与偏好(如CLAUDE.mdAGENTS.md.cursorrules等文件)持续带入对话。本文以 doc/configuration/rules.md 为骨架,结合仓库源码与测试,完整讲解规则组(Rule Groups)的配置方式、autoload 自动加载策略、Prompt Library 联动,以及 claude / CodeCompanion / none 三类内置解析器的底层原理,读完即可在自己的 Neovim 配置中落地一套可复用、可按项目切换的规则体系。

为什么需要 Rules

LLM 在两次会话之间不保留任何记忆,因此每次开启新聊天时,用户的编码偏好、项目技术栈约定、常用工具链信息都必须重新注入。Rules 正是为解决这一痛点而设计,它在聊天缓冲区中承担两个核心职责:

  1. 提供系统级指令:以system角色的消息注入聊天,持续约束 LLM 的行为;
  2. 提供持久化项目上下文:把项目目录(乃至用户主目录)下约定的规则文件作为上下文附加到会话中。

从源码实现看,lua/codecompanion/interactions/shared/rules/helpers.lua 中的add_context函数会把每个规则文件包装成Sharing:\n\n---\n<content>\n---的上下文块,并附带context.id = "<rules>" .. path .. "</rules>"去重标识,确保同一文件不会在会话中被重复注入;若解析器提取出了system_prompt,则会先以role = "system"的消息加入对话(见 helpers.lua)。这正是"两条目的"在代码层面的落点。

启用 Rules

Rules 功能默认并未关闭,插件开箱即用。最简配置如下(完整默认值见 lua/codecompanion/config.lua):

require("codecompanion").setup({ rules = { default = { description = "Collection of common files for all projects", files = { ".clinerules", ".cursorrules", ".goosehints", ".rules", ".windsurfrules", ".github/copilot-instructions.md", "AGENT.md", "AGENTS.md", { path = "CLAUDE.md", parser = "claude" }, { path = "CLAUDE.local.md", parser = "claude" }, { path = "~/.claude/CLAUDE.md", parser = "claude" }, }, is_preset = true, }, opts = { chat = { autoload = "default", -- The rule groups to load enabled = true, }, }, }, })

启用后,每次创建聊天缓冲区,插件都会尝试加载这个通用(default)规则集合。is_preset = true标记该组为内置预设,默认组中涵盖了当前生态最主流的规则文件命名——Claude Code 的CLAUDE.md、GitHub Copilot 的.github/copilot-instructions.md、Cursor 的.cursorrules、Windsurf 的.windsurfrules、Cline 的.clinerules、Goose 的.goosehints,以及AGENT.md/AGENTS.md

注意:default组中的CLAUDE.md系列文件显式指定了parser = "claude",用于处理其中的@文件引用语法(详见下文"Parsers"章节)。

按条件启用(enabled)

若只想在特定场景下启用 Rules,可以给opts.chat.enabled传入一个回调函数。以下示例仅当聊天使用 HTTP 适配器(即走真实 API 的适配器,而非 ACP 等协议)时才启用规则:

require("codecompanion").setup({ rules = { default = { description = "Collection of common files for all projects", files = { -- Omitted for brevity }, }, opts = { chat = { ---@param chat CodeCompanion.Chat ---@return boolean condition = function(chat) -- In this example, only enable rules for chats -- that are using http adapters return chat.adapter.type == "http" end, }, }, }, })

从 config.lua 的类型标注可见,enabled支持boolean | fun(chat: CodeCompanion.Chat): boolean两种形态。在加载回调中(helpers.lua),只有当rules.enabled为真且配置了autoload时,回调才会被挂载到聊天的on_created事件上。

Rule Groups:把规则组织成可复用集合

规则组(Rule Groups)是一组文件或目录的集合,可以整体加载进聊天缓冲区。它带来了极大的灵活性:可以为"使用 Claude Code 的场景"单独建一组,也可以为某个特定项目建一组专用规则。

基础组(Literal Paths)

最基本的组就是一系列字面路径,可以是绝对路径或相对 cwd 的路径:

require("codecompanion").setup({ rules = { my_project_rules = { description = "Rule files for My Project", files = { -- Literal file paths (absolute or relative to cwd) "~/.claude/CLAUDE.md", "CLAUDE.md", "CLAUDE.local.md", }, }, }, })

条件组(enabled 回调)

通过enabled函数可以控制某组规则是否出现在选择器(picker)中。下面的示例让my_project_rules只有在 cwd 包含my_project字样时才可见:

require("codecompanion").setup({ rules = { my_project_rules = { description = "Rule files for My Project", ---@return boolean enabled = function() -- Don't show this group unless in a specific dir return vim.fn.getcwd():find("my_project", 1, true) ~= nil end, files = { "~/.claude/CLAUDE.md", "CLAUDE.md", "CLAUDE.local.md", }, }, }, })

该回调的消费逻辑位于 helpers.lua:enabledfalse时直接跳过;为函数时则调用cfg.enabled(chat)决定是否展示。

目录扫描(Directories)

files里也可以放目录配置,用path + files的组合指定"在某个目录下按文件名模式扫描":

require("codecompanion").setup({ rules = { my_project_rules = { description = "Rule files for My Project", files = { -- Specify dirs to search in (supports glob patterns and literals) { path = vim.fn.getcwd(), files = { ".clinerules", ".cursorrules", "*.md" } }, { path = "~/.config/rules", files = "*.md" }, -- Mix with literal file paths "~/.claude/CLAUDE.md", "CLAUDE.md", "CLAUDE.local.md", }, }, }, })

文件模式(File Patterns)

files数组支持五种书写形态,覆盖了从单文件到通配符的全部需求:

require("codecompanion").setup({ rules = { my_project_rules = { description = "Rule files for My Project", files = { -- 1. Literal file paths "CLAUDE.md", "~/.claude/CLAUDE.md", -- 2. File path with parser { path = "CLAUDE.local.md", parser = "claude" }, -- 3. Directory with file patterns { path = ".", files = { ".clinerules", "*.md" } }, -- 4. Directory with parser { path = "~/.config/rules", files = "*.md", parser = "claude" }, -- 5. Glob patterns (searches filesystem) "docs/**/*.md", ".github/*.md", }, }, }, })

这五种形态与Rules:resolve_paths()(lua/codecompanion/interactions/shared/rules/init.lua)的解析逻辑一一对应:

  • 字面路径:直接vim.fs.normalize后检查存在性,若是目录则递归扫描其下全部文件;
  • 带 parser 的文件:解析路径时记录文件级 parser,供后续read_files阶段匹配(见 init.lua);
  • 目录 + patterns:调用file.scan_directory(normalized_dir, { patterns = file_spec.files })按模式扫描目录;
  • glob 模式:通过vim.fn.glob展开通配符(源码用tostring(path):match("[%*%?%[]")判断是否含*?[),命中目录则继续递归扫描;
  • 解析过程中通过seen表对所有路径做vim.fs.normalize后的去重,避免同一文件被重复收集。

嵌套组(Nested Groups)

规则组还可以嵌套,父组的parser会被子组继承,从而对多个子组统一施加同一解析器:

require("codecompanion").setup({ rules = { my_project_rules = { description = "Rule files for My Project", parser = "claude", files = { ["mcp"] = { description = "The MCP implementation in My project", files = { ".rules/mcp/mcp.md", }, }, }, }, }, })

嵌套组的意义在于"一个条件管多组"、保持配置整洁。插件自己就是最佳范例——config 中内置了名为CodeCompanion的组,其下按模块细分了adapterschatacpcode-reviewrulesteststools等子组(见 config.lua),便于贡献者在开发特定模块时把对应.codecompanion/*.md上下文快速分享给 LLM;且该组通过enabled函数限定仅在 cwd 包含 "codecompanion" 时才展示。

展开逻辑在 helpers.lua 的expand_rules_group:遇到数组形式的files就把整组作为可选条目加入 picker;否则递归进入子组,并以parent/child形式拼接展示名。因此在使用 Action Palette 或 slash 命令时,嵌套组会被扁平化提取并显示在Chat with rules ...菜单中。

Autoload:自动加载规则组

默认情况下,你还可以指定哪些组在每次新建聊天时自动加载:

-- 单个组 require("codecompanion").setup({ rules = { opts = { chat = { autoload = "my_project_rules", }, }, }, })
-- 多个组 require("codecompanion").setup({ rules = { opts = { chat = { autoload = { "my_project_rules", "another_project" }, }, }, }, })
-- 按条件动态决定 require("codecompanion").setup({ rules = { opts = { chat = { ---@return string|string[] autoload = function() if vim.fn.getcwd():find("another_project", 1, true) ~= nil then return { "my_project", "another_project" } end return "my_project" end, }, }, }, })

autoload的类型为string | table | function(见 config.lua)。其消费逻辑在 helpers.lua:函数形态必须返回字符串或字符串数组(否则会assert报错),随后遍历每个组名,通过callbacks_extendon_created回调挂到聊天创建事件上,最终调用add_to_chat_from_config完成注入;若组名不存在则记录Could not find ... rules警告日志。

Prompt Library 中的规则

默认情况下,Prompt Library 的 prompt永远不会自动加载规则组——除非 prompt 通过自身的rules字段显式指名。要改变这一行为,让未指定规则的 prompt 也享受 autoload 组:

require("codecompanion").setup({ rules = { opts = { chat = { autoload = "default", autoload_groups_in_prompt_library = true, }, }, }, })

开启后:prompt 若未声明任何rules,则会把rules.opts.chat.autoload指定的组加载进聊天;若 prompt 自己指名了规则,则使用它自己的规则。autoload_groups_in_prompt_library的默认值为false(见 config.lua)。prompt 中的rules字段会随 prompt 定义被保留(见 lua/codecompanion/prompt_library/init.lua 及 Markdown frontmatter 解析 lua/codecompanion/prompt_library/markdown.lua)。

Parsers:解析器如何改写规则

解析器允许 CodeCompanion 对规则内容做变换,从而影响规则在聊天缓冲区中的分享方式。内置解析器注册在 config.lua:

解析器说明
claude按 Claude Code 的方式把规则中@引用的文件导入聊天(要求规则为 markdown 文件)
CodeCompanionclaude行为一致,但额外支持通过 H2 标题## System Prompt提取系统提示词
cli供 CLI 交互使用,只解析文件路径、不解析内容
none空解析器,可用于覆盖默认规则组上已设置的解析器

claude 解析器:解析@文件引用

lua/codecompanion/interactions/shared/rules/parsers/claude.lua 实现了该解析器:它先用 treesitter 解析 markdown,遍历所有段落节点,找出以@开头的行(line:match("^%s*@(%S+)")),将这些路径收集进included_files;非绝对路径(不以/~开头)会基于源文件所在目录做相对解析(vim.fs.joinpath(source_dir, path)),并校验文件确实存在。解析结果通过meta.included_files返回。

随后在 init.lua 的add_to_chat中,这些被引用的文件会经 helpers.lua 的add_files_or_buffers注入聊天——如果该文件正作为 buffer 打开,就直接读取 buffer 内容(并遵循rules.opts.chat.default_paramsall/diff同步策略);否则按普通文件读取。注入仍使用<rules>...的 ID 去重,因此一个文件即使同时被显式列出又被@引用,也只会注入一次。

CodeCompanion 解析器:提取 System Prompt

lua/codecompanion/interactions/shared/rules/parsers/codecompanion.lua 在 claude 解析器基础上增加了一个能力:识别 H2 标题## System Prompt,将其下的内容(跳过@引用行)提取为system_prompt;其余部分照常作为用户内容,@引用同样被解析为included_files。提取出的system_prompt最终以role = "system"的消息注入对话(见 helpers.lua),这是"提供系统级指令"的直接实现。

应用解析器:组级与文件级

解析器可以施加在组级(组内所有文件统一生效),也可以施加在文件级(更细粒度控制),文件级优先:

-- 组级:整组使用 claude 解析器 require("codecompanion").setup({ rules = { claude = { description = "Rules for Claude Code users", parser = "claude", files = { "CLAUDE.md", "CLAUDE.local.md", "~/.claude/CLAUDE.md", }, }, }, })
-- 文件级:每个文件单独指定 require("codecompanion").setup({ rules = { claude = { description = "Rules for Claude Code users", files = { { path = "CLAUDE.md", parser = "claude" }, { path = "CLAUDE.local.md", parser = "claude" }, { path = "~/.claude/CLAUDE.md", parser = "claude" }, }, }, }, })
-- 禁用:用 none 覆盖默认规则组上的解析器 require("codecompanion").setup({ rules = { claude = { description = "Rules for Claude Code users", parser = "none", -- Disable parsing for the entire group files = { "CLAUDE.md", "CLAUDE.local.md", "~/.claude/CLAUDE.md", }, }, }, })

解析优先级在 lua/codecompanion/interactions/shared/rules/parsers/init.lua 的parse函数中清晰可见:文件级 parser 优先于组级 parser,两者都缺失时返回原样内容。resolve函数(同文件第 14-68 行)则支持三种解析器来源:配置内置名、可调用返回 parser 表的工厂函数、以及用户磁盘上的自定义 parser 文件(先尝试require,失败则loadfile加载)。

若想编写自己的解析器,可参考仓库指南 doc/extending/parsers.md,其中介绍了自定义解析器的接口与注册方式;内置解析器各有对应测试,如 tests/interactions/shared/rules/parsers/test_claude_parser.lua 与 tests/interactions/shared/rules/parsers/test_parsers.lua,可作为行为基准。

规则的实际加载链路

把以上模块串起来,一次规则加载的完整调用链为:

  1. 聊天创建时,add_callbacks(helpers.lua)读取autoload(字符串/表/函数),为每个组名注册on_created回调;
  2. 回调调用Rules.add_to_chat_from_config(chat, args)(init.lua),创建Rules实例并执行make
  3. make(init.lua)依次执行resolve_paths()(路径解析与去重)→read_files()(读取内容并匹配文件级 parser)→parse_files()(组级/文件级 parser 变换)→add_to_chat()(注入 system 消息、上下文块与被@引用的文件)。

结语

通过 Rules 机制,CodeCompanion 把"LLM 无记忆"这一天然缺陷转化为可配置、可复用的工程实践:default预设开箱即覆盖主流规则文件,Rule Groups提供从字面路径、目录扫描、glob 到嵌套组的丰富组织形态,autoloadautoload_groups_in_prompt_library精确控制加载时机,而claude/CodeCompanion/none三类解析器则决定了规则内容最终以何种形态进入对话。掌握这些配置项,你就能让每个聊天会话自动携带准确的编码约定与项目事实,减少反复粘贴上下文的时间成本。

【免费下载链接】codecompanion.nvim✨ AI Coding, Vim Style项目地址: https://gitcode.com/GitHub_Trending/co/codecompanion.nvim

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询