Skip to content

Configuring Rules

Within CodeCompanion, rules fulfil two main purposes within a chat buffer:

  1. To provide system-level instructions to your LLM
  2. To provide persistent context via files in your project

Similar to Cursor's Rules, they provide a way to guide the behavior of your LLM within a chat. Why? LLMs don't retain memory between sessions so preferences and context need to be re-applied each time a new chat is started.

Enabling Rules

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 = {
        enabled = true,
        default_rules = "default", -- The rule groups to load
      },
    },
  },
})
lua
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,
      },
    },
  },
})

Once enabled, the plugin will look to load a common, or default, set of rules every time a chat buffer is created.

INFO

Refer to the config.lua file for the full set of files included in the default group.

Rule Groups

In the plugin, rule groups are a collection of files and/or directories that can be loaded into the chat buffer. Groups give you flexibility to create different sets of rules for different use-cases. For example, you may want a set of rules specifically for working with Claude Code or another for working with a specific project.

lua
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",
      },
    },
  },
})
lua
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",
      },
    },
  },
})
lua
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",
      },
    },
  },
})
lua
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",
      },
    },
  },
})
lua
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",
          },
        },
      },
    },
  },
})

Nested groups allow you to apply the same conditional to multiple groups alongside keeping your config clean. Infact, the plugin uses this itself. There is a CodeCompanion group with sub-groups for different parts of the plugin, allowing contributors to easily share context with an LLM when they're working on specific parts of the codebase.

When using the Action Palette or the slash command, the plugin will extract these nested groups and display them in the Chat with rules ... menu.

You can also set default groups that are automatically applied to all chat buffers. This is useful for ensuring that your preferred rules are always available.

Autoload

You can set specific rule groups that will be automatically added to chat buffers. This is useful for ensuring that your preferred rules are always available.

lua
require("codecompanion").setup({
  rules = {
    opts = {
      chat = {
        autoload = "my_project_rules",
      },
    },
  },
})
lua
require("codecompanion").setup({
  rules = {
    opts = {
      chat = {
        autoload = { "my_project_rules", "another_project" },
      },
    },
  },
})
lua
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,
      },
    },
  },
})

Parsers

Parsers allow CodeCompanion to transform rules, affecting how they are shared in the chat buffer. This is particularly useful if you reference files in your rules. Currently, the plugin has two in-built parsers:

  • claude - which will import files into the chat buffer in the same way Claude Code does. Note, this requires rules to be markdown files
  • CodeCompanion - parses rules in the same ways as claude but allows for a system prompts to be extracted via a H2 "System Prompt" header
  • none - a blank parser which can be used to overwrite parsers that have been set on the default rules groups

Please see the guide on Creating Rules Parsers to understand how you can create and apply your own.

Applying Parsers

You can apply parsers at a group level, to ensure that all files in the group are parsed in the same way. Alternatively, you can apply them at a file level to have more granular control.

lua
require("codecompanion").setup({
  rules = {
    claude = {
      description = "Rules for Claude Code users",
      parser = "claude",
      files = {
        "CLAUDE.md",
        "CLAUDE.local.md",
        "~/.claude/CLAUDE.md",
      },
    },
  },
})
lua
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" },
      },
    },
  },
})
lua
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",
      },
    },
  },
})

Released under the MIT License.