Defer(...) / NoDefer(...) 修饰符临时改变工具的延迟加载状态,而无需改动全局配置。本文是该能力的完整参考。defer_loading 字段决定(详见 MCP 文档-延迟加载)。这些是全局生效的默认设置。本特性允许您在不改默认配置的前提下,针对单次会话或单个自定义代理临时调整行为。写法 | 含义 |
Read | 普通工具,按全局默认决定是否 defer |
Defer(Glob) | 该会话/代理强制让 Glob 走延迟加载(不直接进入模型的工具列表,可通过 ToolSearch 发现) |
NoDefer(Bash) | 该会话/代理强制让 Bash 不走延迟加载(直接进入模型的工具列表) |
Defer(mcp__github__*) | 通配匹配,把整组 MCP 工具置为延迟加载 |
Defer(*) | 把当前列表内的所有工具都置为延迟加载(极端裁剪) |
* 是唯一支持的通配字符,匹配任意字符序列。其他字符(?、[] 等)按字面量处理。--tools 参数codebuddy --tools "Read,Defer(Glob),NoDefer(Bash)"
tools 字段与 CLI 等价。.codebuddy/agents/*.md 的 YAML frontmatter 里:---name: code-readerdescription: 只读型代码探索代理tools:- Read- Grep- Defer(Glob) # 让 Glob 走延迟加载,需要时通过 ToolSearch 发现- NoDefer(Bash) # 即便默认让 Bash 延迟加载,本代理也强制不延迟---
--allowed-tools / settings.permissions.allow--disallowed-tools / settings.permissions.denymatcher# ✖ 错误:会立即报错codebuddy --allowed-tools "Defer(Glob)"# Error: Defer(...) / NoDefer(...) modifiers belong in --tools, not in permission rule fields.# ✔ 正确:分开写codebuddy --tools "...,Defer(Glob)" --allowed-tools "Glob(src/**)"
优先级 | 来源 | 说明 |
0a | 任一层 NoDefer(X) 命中 | 强制非 defer(无论其他来源说什么) |
0b | 任一层 Defer(X) 命中 | 强制 defer |
1 | MCP 工具级 tools[name].defer_loading | MCP 静态配置 |
2 | MCP 服务器级 defer_loading | MCP 静态配置 |
3 | 环境变量 CODEBUDDY_DEFER_TOOL_LOADING | 全局开关 |
4 | 用户设置 settings.deferToolLoading | 全局开关 |
5 | 内置默认(CodeBuddy Code 出厂配置) | 兜底 |
NoDefer 永远胜过 Defer:即使自定义代理写了 Defer(X),CLI --tools 写 NoDefer(X) 后,本次会话内 X 仍然不延迟加载——用户运行时表态优先。NoDefer 优先”这一条规则裁决。--allowedTools 重复时的语义一致)。ToolSearch 与 DeferExecuteToolDefer(...),CodeBuddy Code 会自动把以下两个工具加进去(如果还没在列表里):工具 | 作用 |
ToolSearch | 让模型能搜索发现被延迟加载的工具 |
DeferExecuteTool | 让模型实际调用被延迟加载的工具 |
# 等价于 codebuddy --tools "Bash,Read,Defer(Edit),ToolSearch,DeferExecuteTool"codebuddy --tools "Bash,Read,Defer(Edit)"
ToolSearch 发现并通过 DeferExecuteTool 调用。少了任意一个,Defer(...) 就成了"模型再也用不到这个工具"。自动附加让最常见的写法符合直觉。Defer(*) 不会卷走自身Defer(*) 时,理论上"所有工具"都会被延迟加载——包括 ToolSearch 和 DeferExecuteTool 自身,从而让 defer 工作流失效。为避免这种"自我封死",自动附加会同时给这两个工具加上 NoDefer 护栏:codebuddy --tools "Defer(*)"# 行为等价于:# codebuddy --tools "*,ToolSearch,DeferExecuteTool" + NoDefer(ToolSearch),NoDefer(DeferExecuteTool)
ToolSearch / DeferExecuteTool,从而能搜索并调用其他被延迟加载的工具。NoDefer(...)、没有 Defer(...):用户意图是把工具拉回直接调用,与 defer 工作流无关ToolSearch 或 DeferExecuteTool:幂等,不重复添加# 知道这次只用 Read/Edit,把其他大型工具暂时收起来codebuddy --tools "Read,Edit,Defer(Bash),Defer(Glob),Defer(Grep)"
Read、Edit、ToolSearch,需要时再通过 ToolSearch 调出其他工具。# 假设 Bash 默认被配为延迟加载,但本次需要它直接可调用codebuddy --tools "default,NoDefer(Bash)"
default 表示“全部内置工具”,与修饰符可同时使用。---name: explorerdescription: 大型仓库探索专用代理,把搜索类工具收起来减少干扰tools:- Read- Edit- ToolSearch- Defer(Glob)- Defer(Grep)- Defer(LSP)---
codebuddy --tools "default,Defer(mcp__github__*)"
ToolSearch 搜索 github pr、github issue 等关键词找到。Error: Invalid --tools value: Invalid tool spec "Defer(Read(*.md))": Defer(...) only accepts a tool name or glob; permission filters like Read(*.md) belong in --allowed-tools, not --tools.
--allowed-tools:codebuddy --tools "Defer(Read)" --allowed-tools "Read(*.md)"
Error: Invalid permission rule "Defer(Glob)" in --allowed-tools / settings.permissions.allow: Defer(...) / NoDefer(...) modifiers belong in --tools, not in permission rule fields.
Defer(NoDefer(X)):嵌套修饰被拒,无意义语义Defer():空内容被拒defer(Read):小写不识别,按字面量“含括号的工具名”拒绝tools 字段使用宽松校验:单条非法写法只会发出警告日志后被忽略,不会让 CodeBuddy Code 启动失败。从日志中查找形如下面的提示来定位:[AgentToolSpec] my-agent: invalid-pattern — Invalid tool spec "Defer(Read(*.md))": ...
--tools 使用严格校验,遇到非法写法会立刻报错。--allowed-tools 完全正交,可以同时使用:codebuddy \\--tools "Read,Write,Defer(Glob)" \\--allowed-tools "Glob(src/**)"
Glob 走延迟加载(不直接进入模型的工具列表)ToolSearch > DeferExecuteTool 调用 Glob 时,仍受 Glob(src/**) 权限约束Glob(/etc/*) 会按权限规则被拒绝修饰 | 对 ToolSearch 的影响 | 对 DeferExecuteTool 的影响 |
Defer(X)(X 原本不延迟加载) | 首次访问时自动加入可被搜索的延迟工具集合 | 首次调用时自动注册并放行 |
NoDefer(X)(X 原本延迟加载) | 不会出现在搜索结果中(X 已直接进入模型的工具列表,无需搜索) | 调用 X 时返回错误,引导直接调用 |
Error: Tool "Bash" is not deferred in this session (NoDefer modifier). Call it directly instead of via DeferExecuteTool.
--tools 里直接以服务器名作为修饰目标,只能写工具名或通配(如 Defer(mcp__github__*))Defer(mcp__*) 等通配条目无法反向枚举具体工具名,MCP 工具的懒索引仍依赖 mcp-server-manager 自身的异步驱动流程文档反馈