返回 CodeWhale
CONFIGURATION.md
根目录 / docs / zh_hans / CONFIGURATION.md
1 # 配置(Configuration)
2
3 > 本文翻译自英文版 [CONFIGURATION.md](../CONFIGURATION.md),与英文修订 `6c283be28`(2026-08-26)同步。
4
5 Codewhale 从 TOML 文件加环境变量读取配置。进程启动时,它还可能从工作区本地的 `.env` 文件加载字面(literal)的内置 provider 凭据。请以受跟踪的 `.env.example` 为模板;把它复制为 `.env`,然后只添加凭据值。
6
7 工作区不具备配置权威性。因此 Codewhale 会忽略 config/profile/home 路径、provider/模型/base-URL 路由、MCP/插件状态、审批/沙箱/shell 姿态、可执行文件路径、运行时设置,以及 `.env` 里每一个其他非凭据条目。变量展开被拒绝,所以仓库不能把环境中的秘密替换进凭据值。请用 `config.toml`、CLI 标志或启动 shell 导出的值来设置这些显式的控制面设置。`.env` 通过稳定的常规文件句柄读取,上限 1 MiB,符号链接、重解析点和多链接文件都会被拒绝。
8
9 ## 宪章、项目指令与仓库权威
10
11 Codewhale 有多个指令层级(instruction surfaces)。它们刻意保持分离,这样个人宪章、仓库策略、项目指令和运行时安全控制就不会被混淆。
12
13 - **内置全局宪章(Bundled global Constitution)**——编译进二进制的基础法律。它是每个会话的默认底线。
14 - **用户全局宪章(User-global constitution)**——常规引导式设置的产物。用 `/constitution` 或 `/setup` 管理;Codewhale 把结构化数据存放在 `$CODEWHALE_HOME/constitution.json`(默认 `~/.codewhale/constitution.json`),并渲染成独立的 `<codewhale_user_constitution>` 散文块(prose block)。它可以表达偏好和停止条件,但不会改变运行时审批策略、沙箱、shell、网络、信任或 MCP 权限。
15 - **仓库本地宪章(Repo-local constitution)**——可选的 `.codewhale/constitution.json` 项目策略,见下文。
16 - **`AGENTS.md`**——跨智能体**项目指令**(散文)。这是"智能体应如何在这个仓库工作"的规范文件。运行 `/init` 生成一份。`CLAUDE.md` 和 `.claude/instructions.md` 作为兼容回退被读取。
17 - **记忆与交接(Memory and handoffs)**——被召回的状态。有用,但权威低于宪章和项目指令。
18
19 ### 管理用户全局宪章(`/setup` 和 `/constitution`)
20
21 内置的**协作约定(working agreement)**是安全默认,不再需要强制的首次启动屏幕。之后通过 `/constitution` 或渐进式 `/setup` 指南自定义它。Provider/模型就绪状态、工作区信任和运行时姿态与此指引保持分离。
22
23 在**宪章(Constitution)**步骤:
24
25 - **`1`–`6`** 调整引导式草稿。**`G`** 预览它,再次按 **`G`** 批准并保存一份新的结构化 `constitution.json`。
26 - **`A`**(仅在已配置 provider 时显示)让你配置的第一个模型起草宪章。起草**不是**保存:草稿会通过同样的预览渲染,你仍然要按 **`G`** 批准后才会持久化任何内容。
27 - **`K`** 保持你现有的已加载宪章不变(仅在已有有效文件时显示)。
28 - **`U`**(或 `/constitution bundled`)记录内置/默认法律。
29
30 `/constitution`(别名 `/law`)是设置完成后主要的管理面。子命令:`status`(默认)、`preview`、`review`、`repo`(仓库本地法律块)、`explain`、`edit`/`guided`、`repair`、`posture` 和 `bundled`。管理宪章永远不会改变运行时审批、沙箱、shell、网络、信任、默认模式或 MCP 权威——这些都留在运行时姿态/配置里。
31
32 每个仓库可以携带两个不同且互补的文件:
33
34 - **`AGENTS.md`**——普通的项目工作指令。
35 - **`.codewhale/constitution.json`**——Codewhale 特有的**仓库权威/优先级策略**:当本地来源冲突时,Codewhale 应该先信任谁,以及在声称任务完成之前要验证什么。`.codewhale/` 位于仓库内部(像 `.github/` 一样)。例如:
36
37 ```json
38 {
39 "schema_version": 1,
40 "authority": [
41 "current user request",
42 "live code and tests",
43 "GitHub issue/PR details",
44 "AGENTS.md",
45 "memory",
46 "old handoffs"
47 ],
48 "protected_invariants": [
49 "do not break old-session transcript replay"
50 ],
51 "branch_policy": "PRs target the integration branch, not main",
52 "verification_policy": {
53 "before_claiming_done": ["run focused tests", "read changed files back"]
54 },
55 "escalate_when": [
56 "a destructive action was not explicitly authorized"
57 ]
58 }
59 ```
60
61 所有字段都是可选的。存在时,该文件会被渲染进系统提示,作为更高权威块中的简洁散文。旧的 `WHALE.md` 文件会被忽略,并报告为仅迁移诊断。
62
63 每个 `protected_invariants` 条目可以是普通字符串(建议性散文,历史形态),也可以是携带路径 glob 的对象,后者会在工具门禁中额外被**机械强制执行**。见下文[强制执行的仓库法不变项](#强制执行的仓库法不变项)。
64
65 这是 Codewhale 层级中的**仓库本地法律**层:*内置全局宪章* → *用户全局宪章*(`$CODEWHALE_HOME/constitution.json`,渲染为散文)→ *仓库宪章*(`.codewhale/constitution.json`,即本文件)→ *AGENTS/项目指令* → *记忆与交接* → *当前回合的当前请求与实时证据*。运行时策略(在代码中强制执行的权限/沙箱/成本上限)与所有这些提示层是分离的。仓库宪章给出项目决策规则;它不取代内置宪章、用户全局宪章或当前用户请求。
66
67 > **`WHALE.md` 已弃用。** 它与 `AGENTS.md` 混淆重叠。Codewhale 不再把 `WHALE.md` 作为项目或全局上下文读取。如果存在,setup/上下文诊断会报告它被忽略,以便你迁移它。把普通指令移到 `AGENTS.md`,把 Codewhale 特有的权威策略移到 `.codewhale/constitution.json`。个人常驻指引属于 `/constitution` / `$CODEWHALE_HOME/constitution.json`。(随模型提示一起提供的全局 Codewhale 宪章是另一回事,不受影响。)
68
69 ### 强制执行的仓库法不变项
70
71 默认情况下,`protected_invariants` 条目是建议性散文:它被渲染进提示,作为智能体应遵守的指引,但没有任何东西会阻止写入。写成**带 `paths` 的对象**的条目则不同——它会编译成机械写入拦阻(hold),由引擎的工具门禁在写入运行之前评估。法律变成机制,而不只是请求。
72
73 强制条目具有这样的形态:
74
75 ```json
76 {
77 "schema_version": 1,
78 "protected_invariants": [
79 "Keep DeepSeek support first-class.",
80 {
81 "text": "The wire format is frozen; protocol changes need a human.",
82 "paths": ["crates/protocol/**"],
83 "action": "block"
84 },
85 {
86 "text": "Release notes need human review.",
87 "paths": ["CHANGELOG.md"],
88 "action": "ask"
89 }
90 ]
91 }
92 ```
93
94 - `text`——必填。拦阻时展示的理由。空的 `text` 会被跳过。
95 - `paths`——工作区相对 glob(globset 语法,例如 `crates/protocol/**`、`**/secrets.toml`、`CHANGELOG.md`)。没有可用 `paths` 的对象即使形态是对象也仍只是建议性的。
96 - `action`——可选,默认 `ask`。`ask` 在 Ask 和 Auto-Review 中强制弹窗;在 Full Access 中则拒绝受保护的写入而不打开模态框。`block` 在每个姿态中都**直接拒绝写入**。
97
98 语义:
99
100 - **只收紧(Tighten-only)。** schema 没有 allow/widen 形态,所以法律只能*增加*拦阻——精心构造的宪章永远不能授予权威或削弱其上的门禁。
101 - **模式不能绕过。** 与内置安全底线一样,`ask` 拦阻在 Ask 和 Auto-Review 中强制弹窗。Full Access 从不打开审批模态框,所以同样的拦阻按失败即阻断(fail closed)处理为硬阻断;`block` 总是拒绝。模式无法关掉拦阻。
102 - **仅仓库本地。** 只有仓库的 `.codewhale/constitution.json` 参与。用户全局宪章保持建议性散文,永远不进入这个机制。
103 - **失败安全。** 文件缺失、解析错误或无效 glob 会退化为更少或零规则——绝不会在未受保护的路径上产生拦阻,也绝不会让门禁中毒。跨匹配时最强的动作胜出,所以 `block` 高于 `ask`。
104 - **留下回执(receipt)。** 每次拦阻都会发出 `tool.repo_law_decision` 工具审计事件,指名不变项、匹配的路径和源文件;批准/拒绝理由也会指名不变项。
105
106 **覆盖范围刻意有限。** 拦阻只对写入工具 `write_file`、`edit_file`、`apply_patch` 和 `fim_edit` 评估,并且只针对它们输入中指定的文件系统目标(`path`/`target`/`destination`/`file_path`、`changes[].path`,以及 unified-diff / `apply_patch`-envelope 头)。一条写入受保护路径的 shell 命令**不会**被仓库法拦阻——这类写入仍由普通审批、沙箱和 shell 写入门禁管辖,不由这个机制管辖。
107
108 ### 专家级完整基础提示覆盖(#3638)
109
110 全局宪章(基础系统提示,通常从 `crates/tui/src/prompts/text.rs` 编译为 `BASE_PROMPT`)可以不重新构建就按用户替换。这是专家逃生舱,不是常规 `/constitution` 引导式设置的产物。因为这是一个提示信任边界,它需要**两个刻意的步骤**——单靠文件不够:
111
112 1. 把替换文件放到 `~/.codewhale/prompts/constitution.md`(设置了 `$CODEWHALE_HOME` 时在其下)。
113 2. 设置显式的选择加入标志 `CODEWHALE_ALLOW_BASE_PROMPT_OVERRIDE=1`(也接受 `true`/`on`/`yes`)。
114
115 如果文件存在但标志未设置,覆盖会被**忽略**(有一条指向该标志的日志行),内置宪章保持不变。这用于把 TUI 重新用于软件工程之外的场景——例如长文写作或文档审查——此时面向工程的基座提示不合适。它在启动时加载一次;**缺失或空文件是空操作**,所以现有安装会保留内置提示。
116
117 范围刻意很窄:只有字节稳定的**基础提示段**可被覆盖。模式增量、审批策略、工具分类、上下文管理和压缩中继仍由 Codewhale 的运行时组装拥有,所以覆盖**无法移除安全相关指引**(沙箱、审批)——它只替换任务/语气框架。要定制普通的个人行为,优先用 `/constitution`;要定制按仓库行为,优先用上面的 `AGENTS.md` + `.codewhale/constitution.json`。
118
119 ## 配置在哪里读取(Where It Looks)
120
121 默认配置路径:
122
123 - `~/.codewhale/config.toml`
124 - 旧版回退:`~/.deepseek/config.toml`
125
126 覆盖:
127
128 - CLI:`codewhale --config /path/to/config.toml`
129 - 环境:`CODEWHALE_CONFIG_PATH=/path/to/config.toml`
130 - 旧环境别名:`DEEPSEEK_CONFIG_PATH=/path/to/config.toml`
131
132 如果两者都设置,`--config` 胜出。环境变量覆盖在文件加载后应用。
133
134 ### TUI 可编辑性审计
135
136 在 TUI 内运行 `/config audit`,查看哪些已记录的键可以从当前会话更改、哪些还可以持久化、哪些只能文件级或重启级。审计包含高影响运行时控制的当前值,例如 `approval_policy`、`allow_shell`、`stream_chunk_timeout_secs`、`base_url`、`mcp_config_path` 以及 `[subagents]` 的并发/深度/超时键。
137
138 手工编辑前,以该命令的"Command / reason"列为事实来源。例如,`/config approval_mode on-request --save` 写入顶层 `approval_policy = "on-request"`,而 provider base URL 可以保存但仍需要重启模型客户端。
139
140 ### 用户工作区条目
141
142 交互式 Agent 会话默认在审批门禁下暴露 shell 工具,除非你显式禁用它们。对于应放在用户全局配置里、供非交互或持久任务 profile 使用的 shell 选择加入,而不是放在仓库里,请添加工作区作用域条目:
143
144 ```toml
145 [workspace.'/absolute/path/to/project']
146 allow_shell = true
147 ```
148
149 该条目仅在启动的工作区路径匹配表键时生效。旧版 `[projects."/absolute/path/to/project"]` 表也接受用于这种用户自有的覆盖。
150
151 在交互模式下,按项目覆盖 `<workspace>/.codewhale/config.toml` 会在这个用户条目之后应用。项目级的 `allow_shell = false` 仍可收紧会话;项目级的 `allow_shell = true` 会被忽略。
152
153 ### 按项目覆盖(#485)
154
155 当 TUI 在一个包含常规文件 `<workspace>/.codewhale/config.toml` 的工作区启动时,该文件中声明的安全值会合并到全局配置之上。旧的 `<workspace>/.deepseek/config.toml` 文件在 Codewhale 路径不存在时仍会被读取。符号链接的项目配置文件会被拒绝。这让仓库可以建议模型或收紧本地安全姿态,而不触碰用户的 `~/.codewhale/config.toml`。传 `--no-project-config` 可跳过单次启动的覆盖。
156
157 项目覆盖中支持的键(仅顶层字段):
158
159 | 键 | 效果 |
160 |---|---|
161 | `model` | 覆盖 `default_text_model` |
162 | `reasoning_effort` | 为复杂仓库强制 `"high"` / `"max"` |
163 | `approval_policy` | 只接受收紧用户当前权限姿态的值 |
164 | `sandbox_mode` | 只接受收紧用户当前沙箱姿态的值 |
165 | `notes_path` | 把笔记留在仓库内 |
166 | `max_subagents` | 为受限仓库限制子智能体并发(钳制到 `1..=128`) |
167 | `allow_shell` | `false` 可禁用 shell 访问;`true` 被忽略 |
168
169 覆盖刻意很窄——它覆盖仓库维护者最可能想要跨贡献者标准化的字段。凭据、端点、provider 选择、MCP 配置、hooks、skills、重试、热栏绑定和 `instructions = [...]` 设置保持用户全局。如果仓库本地配置声明了 `api_key`、`base_url`、`provider`、`mcp_config_path`、`hotbar`、`allow_shell = true` 或 `instructions`,Codewhale 会忽略该键并保留用户的全局设置。
170
171 合并的 `codewhale` 运行时为 DeepSeek 认证和模型默认值使用同一个配置文件。`codewhale auth set --provider deepseek` 把 key 保存到 `~/.codewhale/config.toml`(需要时在首次启动迁移旧 `~/.deepseek/config.toml`),`codewhale --model deepseek-v4-flash` 作为 `DEEPSEEK_MODEL` 转发给 TUI。
172
173 `codewhale login` 登录 Codewhale 账号——它与 `codewhale account login` 是同一个浏览器设备流(device flow),不是 provider-key 命令。Provider 凭据完全通过 `codewhale auth set --provider <provider>` 配置。
174
175 该 provider 凭据与可选的管理产品账号是分开的。`codewhale account login` 启动 Codewhale 浏览器设备流;`codewhale account status` 和 `codewhale account logout` 检查或移除所选 `--profile` 的会话。账号会话优先使用 OS 凭据管理器,在无凭据管理器可用时自动回退到私有 `0600` Codewhale secrets 文件(无头主机、SSH、容器)。`codewhale account keys list|set|remove` 管理已登录账号的 BYOK 保险库(vault),不显示秘密值。更旧的 `codewhale cloud ...` 拼写仍是命令别名。
176
177 ### 可移植配置包(Portable config bundles)
178
179 `codewhale config export --portable [--project] [--out FILE]` 写出一份可移植、无秘密的配置包:排序的 TOML,丢弃凭据和机器特有键(API key、base URL、socket 路径),绝不以脱敏占位符取代它们。不带 `--out` 时,包输出到 stdout。类型化表、数组、数字、布尔和日期时间保持类型化。机器绑定权威刻意不可移植:项目信任覆盖、凭据读取器、自动运行的 hooks、可执行 LSP 定义和本地路径绑定被省略,而不是复制到新主机。
180
181 `codewhale config import <FILE|HTTPS_URL|-> [--dry-run] [--yes] [--project]` 应用一份包。信封是严格的(`schema_version = 1`,kind `codewhale.portable-config`;未知字段失败)。导入打印确定性计划——新增/更改/跳过/冲突/拒绝——然后征求同意,除非给了 `--yes`;无头使用需要它。凭据形态的条目按键名和值形态被拒绝;拒绝指名字段,从不指名值。远程包只来自 HTTPS(loopback http 除外),上限 5 MiB。应用把目标文档备份到 `<config>.bundle-backup-<timestamp>-<random>`,任何失败都回滚,重新导入已应用的包不改变任何东西。
182
183 导入也拒绝导出省略的非可移植权威类,包括嵌套/驼峰/点号凭据键和 cookie 头。这让手工编写或远程的包不会重新引入机器信任、本地凭据访问或本地导出拒绝携带的自动可执行命令。结构化表被深度合并:可移植的模型或偏好更新不会擦除目标本地的 provider 凭据、端点、hooks 或刻意从包中省略的可执行定义。数组和标量值仍替换对应的可移植值。
184
185 节映射到作用域:`[project]` 条目只落到工作区文档(`--project`,必须指向实际的工作区配置),`[global]` 只落到用户全局文档;`preferences`、`profiles` 和 `plugins` 在任一作用域应用。全局包操作拒绝工作区文档,正如项目操作拒绝用户全局文档。
186
187 ### 凭据读取优先级(#5197)
188
189 凭据读取**默认与文件夹无关**:下面的每一层都是用户全局或进程作用域,所以在一个仓库保存的 key 会在每个其他仓库以相同方式解析。仓库本地配置从不携带凭据材料——上面的项目覆盖只读取其 allowlist 键并忽略 `api_key`,而针对工作区作用域配置的凭据写入会被重新定位到用户全局 `~/.codewhale/config.toml`(#5045、#5193)。
190
191 对于活动 provider,运行时按以下精确顺序解析 API key(首个匹配胜出):
192
193 1. **路由特有认证契约。** 其 `auth_mode` 禁用 API key 的路由在此停止,不带凭据。OAuth 路由使用它们显式同意的 token:`openai-codex` 读取 `OPENAI_CODEX_ACCESS_TOKEN` 或 consent 授予的 Codex CLI 登录(只读,从不刷新或重写);`[providers.xai] auth_mode = "oauth"` 读取 Codewhale 自己的 xAI 设备登录存储(或 consent 授予的 Grok CLI 文件)。
194 2. **显式 CLI key。** `--api-key` 连同其来源标记转发,胜过每一个已保存的槽位;对于 `deepseek`/`deepseek-CN`,它也胜过根级 `api_key`。
195 3. **配置文件 `api_key`。** 活动 provider 的 `[providers.<name>] api_key` 表槽位,外加 `deepseek`/`deepseek-CN` 的旧根级 `api_key` 和字面 `provider = "custom"` 路由。文件拥有的 key 保持绑定到它们文件拥有的端点:当环境用自定义主机替换路由的 base URL 时,已保存的 key 不会被发送到那里。
196 4. **`api_key_env` 绑定。** `[providers.<name>] api_key_env = "VAR"` 命名环境变量。对于自定义 provider,未设置或空绑定是响亮错误,而不是静默回退(#5104)。
197 5. **Secret store。** 由 `codewhale auth set` 写入的持久按 provider 槽位(默认文件型位于 `~/.codewhale/secrets/` 下;只有显式选择时才用 OS 钥匙串)。对命名的自定义路由、自托管 provider、除显式认证的 loopback 之外的自定义端点,以及其 `auth_mode` 不需要 key 的路由,跳过。
198 6. **周围环境(Ambient environment)。** provider 自己的变量(`DEEPSEEK_API_KEY`、`OPENROUTER_API_KEY`、`MOONSHOT_API_KEY`……)。环境 key 只会被发送到 provider 的官方端点,并且在与 secret store 相同的条件下被跳过。
199 7. **无 key 回退。** 自托管 provider 和 loopback 端点可以在没有凭据的情况下运行;其他每条路由都会以 provider 特有的设置指引失败。
200
201 旧版兼容:`~/.deepseek/config.toml` 在首次启动时迁移进 `~/.codewhale/config.toml`,`DEEPSEEK_*` 环境变量仍作为 `CODEWHALE_*` 形式的别名被接受,`DEEPSEEK_SECRET_BACKEND` 是 `CODEWHALE_SECRET_BACKEND` 的旧别名。
202
203 运行 `codewhale auth status` 检查活动 provider 的配置文件、OS 钥匙串后端、环境变量、胜出来源和末四位标签,而不打印 key 本身。该命令只探测活动 provider 的钥匙串条目。
204
205 对于托管、通用 OpenAI 兼容、自托管、OpenAI Responses 或原生 Anthropic provider,设置 `provider = "<id>"` 或传 `codewhale --provider <id>`。规范的 provider ID 是 `deepseek`、`nvidia-nim`、`openai`、`atlascloud`、`wanjie-ark`、`volcengine`、`openrouter`、`orcarouter`、`xiaomi-mimo`、`novita`、`fireworks`、`siliconflow`、`arcee`、`siliconflow-CN`、`moonshot`、`sglang`、`vllm`、`ollama`、`ollama-cloud`、`huggingface`、`modelscope`、`together`、`qianfan`、`openai-codex`、`anthropic`、`openmodel`、`zai`、`stepfun`、`minimax`、`deepinfra`、`sakana`、`longcat`、`opencode-go`、`opencode-zen`、`meta`、`xai`、`mistral`、`telecomjs`、`modelstudio-token-plan`、`google`、`antigravity`、`edenai` 和 `custom`(通过 `[providers.<name>]` 定义的用户自定义 OpenAI 兼容端点)。逐 provider 的 registry,包括线协议、认证变量、默认 base URL、模型 ID 和能力元数据,见 [PROVIDERS.md](PROVIDERS.md)。facade 把 provider 凭据保存到共享用户配置,并把解析后的 key、base URL、provider 和模型转发给 TUI 进程。使用 `codewhale auth set --provider nvidia-nim --api-key "YOUR_NVIDIA_API_KEY"` 或 `codewhale auth set --provider openai --api-key "YOUR_OPENAI_COMPATIBLE_API_KEY"` 或 `codewhale auth set --provider atlascloud --api-key "YOUR_ATLASCLOUD_API_KEY"` 或 `codewhale auth set --provider wanjie-ark --api-key "YOUR_WANJIE_API_KEY"` 或 `codewhale auth set --provider xiaomi-mimo --api-key "YOUR_XIAOMI_KEY"` 或 `codewhale auth set --provider fireworks --api-key "YOUR_FIREWORKS_API_KEY"` 或 `codewhale auth set --provider siliconflow --api-key "YOUR_SILICONFLOW_API_KEY"` 或 `codewhale auth set --provider arcee --api-key "YOUR_ARCEE_API_KEY"` 或 [PROVIDERS.md](PROVIDERS.md) 中匹配的 provider ID,通过 facade 保存 provider key。通用 `openai` provider 默认 `https://api.openai.com/v1`,接受 `OPENAI_BASE_URL`,默认 `gpt-5.6`。自定义 OpenAI 兼容网关仍可显式选择自己的模型。`atlascloud` 默认 `https://api.atlascloud.ai/v1`,接受 `ATLASCLOUD_BASE_URL`,默认模型是 `deepseek-ai/deepseek-v4-flash`。`wanjie-ark` 指向 Wanjie Ark 的 OpenAI 兼容端点 `https://maas-openapi.wanjiedata.com/api/v1`,默认 `deepseek-reasoner`,并原样透传模型 ID,因为 Wanjie 模型访问按账号作用域。SGLang、vLLM 和 Ollama 是自托管的,默认可以不用 API key 运行。Ollama 默认 `http://localhost:11434/v1`,并原样发送 `codewhale-coder:1.3b` 或 `qwen2.5-coder:7b` 这样的模型标签。自托管 provider 和 loopback 自定义 URL(`localhost`、`127.0.0.1`、`[::1]`、`0.0.0.0`)不读取 secret store,除非显式请求 API key 认证;当本地服务器确实需要 bearer 认证时,用环境变量或配置文件 key。Ollama Cloud 是独立的托管 `ollama-cloud` provider。它默认 `https://ollama.com/v1` 和 `gpt-oss:120b`;用 `codewhale auth set --provider ollama-cloud` 保存它的 key。环境认证先读 `OLLAMA_CLOUD_API_KEY`,然后是 Ollama 官方的 `OLLAMA_API_KEY`。SiliconFlow 默认 `https://api.siliconflow.com/v1`,接受 `SILICONFLOW_BASE_URL`,默认用 `deepseek-ai/DeepSeek-V4-Pro`。`provider = "siliconflow-CN"` 选择中国区域默认 `https://api.siliconflow.cn/v1`,配 `[providers.siliconflow_cn]` 表和 `SILICONFLOW_API_KEY` 凭据槽位。Arcee AI 默认 `https://api.arcee.ai/api/v1`,接受 `ARCEE_BASE_URL`,对 Codewhale 智能体工作默认用 `trinity-large-thinking`。`trinity-large-preview` 也作为直接的 Arcee API 模型列出;OpenRouter 的 `arcee-ai/trinity-large-thinking` 仍是 OpenRouter 命名空间形式,而直接 Arcee provider 用裸的 `trinity-large-thinking` ID。直接的 Arcee 大模型 API 调用按 256K 上下文 BF16 服务跟踪;Thinking 具备推理能力,而 Preview 未标记为推理模型。
206
207 ### 自定义 OpenAI 兼容网关
208
209 对于实现 OpenAI Chat Completions API 的单个第三方服务,最简单的设置是把内置的 `openai` provider 名指向该网关:
210
211 ```toml
212 provider = "openai"
213 default_text_model = "your-model-id"
214
215 [providers.openai]
216 api_key = "YOUR_OPENAI_COMPATIBLE_API_KEY"
217 base_url = "https://your-gateway.example/v1"
218 ```
219
220 把端点放在 `[providers.openai]` 下,而不是旧的顶层 `base_url`,这样 OpenAI 兼容 provider 才能收到它。`default_text_model` 是发送给网关的模型 ID;`[providers.openai].model` 可用作 OpenAI provider 特有的覆盖。
221
222 如果你有多个 OpenAI 兼容网关,或者需要为 AgentProfile provider 固定一个稳定名称,定义一个用户命名的自定义 provider 表:
223
224 ```toml
225 provider = "lm-studio"
226
227 [providers.lm-studio]
228 kind = "openai-compatible"
229 base_url = "http://127.0.0.1:1234/v1"
230 api_key = "lm-studio"
231 model = "qwen-2.5-7b"
232 ```
233
234 自定义 provider 名可以用 `provider = "<name>"`、`--provider <name>` 或 AgentProfile 的 `provider = "<name>"` 选择——只要匹配的 `[providers.<name>]` 表存在。
235
236 StepFun 有一等公民的 provider 条目,所以把 Coding Plan 凭据和 base URL 保持在 `[providers.stepfun]` 作用域内:
237
238 ```toml
239 provider = "stepfun"
240
241 [providers.stepfun]
242 api_key = "YOUR_STEPFUN_API_KEY"
243 base_url = "https://api.stepfun.ai/step_plan/v1"
244 model = "step-3.7-flash"
245 ```
246
247 `/provider` 设置会问 key 属于哪个 StepFun 计费路由——按量付费(`https://api.stepfun.ai/v1`)或 Step Plan 订阅(`https://api.stepfun.ai/step_plan/v1`)——并在保存前对照你选的端点验证 key。答案被写入 `[providers.stepfun].base_url`,不会写到别处。如果该 key 已经持有 Codewhale 不识别为这两条路由之一的 base URL,问题会被跳过,你的值保持原样。
248
249 阿里云百炼 / Model Studio DashScope Qwen 路由使用同样的 OpenAI provider 形态:
250
251 ```toml
252 provider = "openai"
253
254 [providers.openai]
255 api_key = "YOUR_DASHSCOPE_API_KEY"
256 base_url = "https://dashscope-intl.aliyuncs.com/compatible-mode/v1"
257 model = "qwen-plus"
258 context_window = 1000000
259 ```
260
261 使用与你的 API key 区域匹配的区域 DashScope `compatible-mode/v1` base URL。Codewhale 把 `qwen-plus` 保持在 `openai` provider 路由作用域内,不会从模型前缀推断出不同的 provider。同样的规则适用于所有 provider 前缀模型字符串:`deepseek-ai/...` 或 `deepseek/...` 这样的前缀是所选 provider 下的 provider 拥有线 ID,不是自动切换到 DeepSeek provider。当网关/模型的真实总上下文窗口与 Codewhale 的静态模型元数据不同时,设置 `context_window`。完整的解析顺序以及如何检查当前生效的值,见[上下文长度(context window)](#上下文长度context-window)。
262
263 如果网关接受 `POST /chat/completions` 但拒绝 `/v1/chat/completions`,设置 provider 本地的 `path_suffix`:
264
265 ```toml
266 [providers.openai]
267 base_url = "https://your-gateway.example/v1"
268 path_suffix = "/chat/completions"
269 ```
270
271 该后缀只应用于聊天补全请求。模型列表和 DeepSeek beta 路径保持内置路由,所以通用网关覆盖不会意外重写 `/models` 或 `/beta/completions`。
272
273 对于证书损坏或被拦截的私有网关,用 `SSL_CERT_FILE` 指向受信任的 CA 包。旧 provider 表键 `insecure_skip_tls_verify = true` 仍被解析,这样 `codewhale doctor` 能报告过期配置,但 provider 客户端会拒绝它,而不是禁用 TLS 证书验证。
274
275 Ollama、SGLang 和 vLLM 这样的本地 HTTP 端点在它们使用 localhost 或 loopback 地址时默认被允许。对于非本地的 `http://` 网关,只在受信任的网络上用 `DEEPSEEK_ALLOW_INSECURE_HTTP=1` 启动:
276
277 ```bash
278 DEEPSEEK_ALLOW_INSECURE_HTTP=1 codewhale
279 ```
280
281 需要额外请求头的第三方 OpenAI 兼容网关可以在顶层或 `[providers.deepseek]` 这样的 provider 表下设置 `http_headers = { "X-Model-Provider-Id" = "your-model-provider" }`。配置后,codewhale 会在模型 API 请求上发送这些自定义头。等效的环境覆盖是 `DEEPSEEK_HTTP_HEADERS`,使用逗号分隔的 `name=value` 对,例如 `X-Model-Provider-Id=your-model-provider,X-Gateway-Route=dev`。`Authorization` 和 `Content-Type` 由客户端管理,不会被此设置覆盖。
282
283 ### 视觉模型(Vision Model)
284
285 Codewhale 的聊天 provider 和 `image_analyze` 工具是分开配置的。主聊天路径保持所选文本/工具 provider;图像分析在启用 `vision_model` 功能时通过 `[vision_model]` 运行。
286
287 小米当前的图像理解文档包括用于图像输入的 `mimo-v2.5`。要让 MiMo 用于 `image_analyze`,显式配置视觉模型:
288
289 ```toml
290 [features]
291 vision_model = true
292
293 [vision_model]
294 model = "mimo-v2.5"
295 api_key = "YOUR_XIAOMI_KEY"
296 base_url = "https://api.xiaomimimo.com/v1"
297 ```
298
299 上面的例子使用小米 MiMo 的按量付费 OpenAI 兼容端点。如果你为 `[vision_model]` 使用 Token Plan key(`tp-...`),必须显式设置 `base_url`,因为这个通用 OpenAI 兼容块不会自动选择 MiMo 端点。新加坡账号用 `https://token-plan-sgp.xiaomimimo.com/v1`,中国区域账号用 `https://token-plan-cn.xiaomimimo.com/v1`,欧洲/阿姆斯特丹账号用 `https://token-plan-ams.xiaomimimo.com/v1`。
300
301 ### 自动模型路由(`[auto.router]`)
302
303 使用 `model = "auto"` 时,Codewhale 在强模型和便宜模型之间路由每个回合。路由决策来自一次小型的分类器调用,或在没有分类器路由可用时来自本地启发式。
304
305 **没有默认分类器。** 不设置 `[auto.router]` 时,Auto 是本地且免费的:它使用启发式方法,不做分类器调用,无论你持有哪些 key。持有 DeepSeek key 曾经会自动推选 `deepseek-v4-flash`;那已被移除,因为它把 token 花在用户从未选择的路由上,并且让某个 provider 凌驾于其他所有 provider 之上(`crates/tui/src/config.rs:2392-2402`)。选择网络分类器现在是需要你写下来的事。
306
307 用 `[auto.router]` 把分类器指向任何已配置的 provider:
308
309 ```toml
310 [auto.router]
311 provider = "zai"
312 model = "glm-5-turbo"
313 thinking = "off" # 可选;默认 off
314 ```
315
316 分类器调用只在 `[auto.router]` 已设置**且**该 provider 有 key 时发生——`router_available = router_configured && has_api_key_for(...)`(`crates/tui/src/model_inventory.rs:206-218`)。任一条件不满足意味着由启发式决定,而不是失败。回合的路由回执(`/status` → Auto)记录是哪一种。
317
318 要在解析后的路径引导(bootstrap) MCP 和 skills 目录,运行 `codewhale setup`。要只搭建 MCP,运行 `codewhale mcp init`。
319
320 注意:`setup`、`doctor`、`mcp`、`features`、`sessions`、`resume`/`fork`、`exec`、`review` 和 `eval` 都可以从安装的 `codewhale` 命令获得。合并的调度器还提供 `auth`、`config`、`model`、`thread`、`sandbox`、`app-server`、`mcp-server`、`completions`、`login`/`logout`、`account`、`metrics`、`update`、`lane`、`workflow` 和 `web`。普通提示进入进程内 TUI 运行时。发布安装程序把同样的字节暴露为 `codew`。
321
322 ### 启动更新检查
323
324 默认情况下,TUI 启动一个后台检查,查找最新的稳定 Codewhale release,并且只在有更新版本可用且官方发布资源完整时显示一条短 toast。该检查从不阻塞启动,从不阻塞回合,离线时静默失败。
325
326 为气隙、企业代理或受管桌面环境完全禁用启动检查:
327
328 ```toml
329 [update]
330 check_for_updates = false
331 ```
332
333 #### 节流
334
335 答案缓存在 `~/.codewhale/update-check.json`,并在 `check_interval_hours`(默认 `1`)内复用。只有*网络请求*被节流——有更新待定时,提示仍在每次启动出现。设为 `0` 表示每次启动都检查。
336
337 ```toml
338 [update]
339 check_interval_hours = 1
340 ```
341
342 失败的检查不会被缓存,所以一次故障不会在间隔过去之前抑制提示。
343
344 #### 自动抑制
345
346 以下任一值被设置为非假值(非 falsey)时,检查会被跳过,不联系网络:
347
348 | 变量 | 原因 |
349 | --- | --- |
350 | `CODEWHALE_NO_UPDATE_CHECK` | 显式选择退出。 |
351 | `NO_UPDATE_NOTIFIER` | 跨 CLI 惯例,为兼容性而遵循。 |
352 | `CI`、`CONTINUOUS_INTEGRATION`、`GITHUB_ACTIONS`、`GITLAB_CI`、`BUILDKITE`、`CIRCLECI`、`JENKINS_URL`、`TEAMCITY_VERSION`、`TF_BUILD` | 自动化构建;终端前没有人。 |
353
354 `""`、`0`、`false`、`no` 和 `off` 的值不算已设置,所以 `CI=false` 导出不会为普通用户禁用检查。
355
356 #### 提供哪条更新命令
357
358 Codewhale 从不会自己安装任何东西——它只告诉你存在更新。它命名的命令取决于运行中的二进制是如何安装的,从其路径检测:
359
360 | 安装方式 | 提供的命令 |
361 | --- | --- |
362 | GitHub release 二进制(包括 Termux) | `codewhale update` |
363 | npm(`node_modules` 在路径上) | `npm install -g codewhale@latest` |
364 | Homebrew(`Cellar` / `linuxbrew` 前缀) | `brew upgrade codewhale` |
365 | `cargo install`(`~/.cargo/bin`) | `cargo install codewhale-cli --locked --force` |
366
367 对于包管理器安装,提示还会警告不要用 `codewhale update`:替换 Homebrew 或 npm 拥有的二进制会让管理器描述一个磁盘上已不存在的版本,而下次升级会静默把你退回。
368
369 如果你把二进制移到了路径启发式无法读取的位置,用 `CODEWHALE_INSTALL_METHOD=npm|homebrew|cargo|binary` 覆盖检测。
370
371 要重定向启动检查,把 `update_uri` 设置为返回 GitHub 兼容 latest-release JSON 的内部端点。接受带 `tag_name` 字段的最小镜像元数据;如果存在 `assets`,Codewhale 会要求与官方 release 相同的上传资源集,然后才显示 toast。
372
373 ```toml
374 [update]
375 check_for_updates = true
376 update_uri = "https://internal.mirror.example/codewhale/releases/latest"
377 ```
378
379 未设置 `update_uri` 时,启动检查在回退到官方 GitHub API 端点之前,会遵循 `CODEWHALE_RELEASE_BASE_URL` 这样的 release 镜像环境变量。如果配置的 `update_uri` 无法获取或解析,且设置了 release 镜像环境变量,TUI 会回退到该镜像,而不是让启动失败。
380
381 ## Workshop 输出预算
382
383 `[workshop]` 在工具结果超过 `large_output_threshold_tokens` 时,仍会把过大的工具结果路由到合成路径。两个可选的字节上限(#5367)在该路由之后提高模型可见的下限,并且永不降低:
384
385 - `read_result_max_bytes`——单个 `read` / `read_file` 结果的上限。缺省时保持编译期默认(`read` 为 50KiB / 2000 行,`read_file` 为 16KiB / 500 行)。
386 - `tool_result_max_bytes`——溢出后通用工具结果的上限。缺省时保持 12K 字符的紧凑下限(窗口 ≥500K token 时为 48K)。硬上限 2MiB。
387
388 ## 上下文长度(context window)
389
390 也叫上下文大小、上下文上限、最大上下文或窗口。这是 Codewhale 做预算的总 token 窗口,它驱动头部/底部上下文百分比、自动压缩触发、上下文压力检查和请求输出上限。如果 Codewhale 在你知道能服务 1M 窗口的模型上于 128K 压缩,这就是要改的设置(#5134)。
391
392 **查看当前生效的值及其来源。** 下面每一项都会打印解析后的窗口*和*它的来源:
393
394 - `/status`——`Context window:` 行显示百分比和 token 数,`Window source:` 行指出出处和确切覆盖它的键。
395 - `/config` → Provider——`Context window`(你的覆盖,或 `(not set)`)和 `Effective context window`(`1048576 tokens · configured`)。在 `/config` 过滤里输入 `context length` 直接跳到它们。
396 - `/context report`——`Window: 1048576 tokens (12.4% used, ...; source: configured)`。
397 - `/context json`——机器可读的 `context_window_tokens` 和 `context_window_source`。
398
399 **修改它**用 provider 表键 `context_window`:
400
401 ```toml
402 [providers.moonshot]
403 context_window = 1048576
404 ```
405
406 或从 CLI:
407
408 ```bash
409 codewhale config set providers.moonshot.context_window 1048576
410 codewhale config unset providers.moonshot.context_window # 回到自动
411 ```
412
413 为你实际所在的 provider 使用对应表(`providers.openai`、`providers.deepseek`、`providers.moonshot`……);`/status` 会告诉你。该值是路由*总*窗口的正 token 数。
414
415 ### 有效窗口如何解析
416
417 首个匹配胜出,每个界面打印的来源标签就是这一级:
418
419 1. `configured`——`config.toml` 中的 `[providers.<name>] context_window`。硬覆盖:它下面的任何东西都不能升高或降低结果。读取时别名:`contextWindow`、`context_window_tokens`、`contextWindowTokens`、`context_length`、`contextLength`。
420 2. `provider-reported`——provider 实际为 Kimi Code `k3` 路由报告的路由作用域 1M 元数据,当它在最近 24 小时内被观察到时。
421 3. `static Kimi Code safe floor`——Kimi Code 会员 262,144 token,因为 1M 访问是计划门控的(Allegretto 及以上)。
422 4. `catalog`——内置路由目录(手工策展的报价优先,然后是内置 Models.dev 行)。对于 `openai-codex`,一份新鲜的(24 小时内)`$CODEX_HOME` 模型名册(roster)会纠正这一级。
423 5. `model-name hint`——从模型名本身解析出的 `_Nk` 后缀(`qwen3-32b-256k` → 256,000),与厂商无关。服务引擎可能不遵循的命名约定不是关于路由的事实,所以这一级位于*catalog 之下*:同一 id 的任何 catalog 行都胜过它(#5441)。
424 6. `fallback`——静态按 provider 能力表:Anthropic 线路由 200,000,`openai-codex` 128,000,Ollama 8,192,否则用 Codewhale 的静态按模型元数据,模型未知时最终 128,000。
425
426 ### "(unverified)" 是什么意思
427
428 `model-name hint` 和 `fallback` 级仍驱动真实预算——压缩触发、上下文计量和输出预留都使用该数字——但它们是猜测,不是任何人检查过的能力。每个渲染这些窗口之一的界面都会在来源标签上追加 `(unverified)`(状态行、上下文压力消息、`/status`、`/config` 和模型选择器芯片),这样你没有配置、provider 也没有报告的窗口永远不会被读成经过验证的上限(#5239、#5441)。上面的 `context_window` provider 表键就是修法:配置的窗口是硬覆盖,渲染为 `configured` 且无标记。
429
430 输出上限遵循同样规则(#5440):catalog 未描述的 Anthropic 家族模型保持 64K Messages 下限作为钳制,ChatGPT/Codex OAuth 路由保持其长期 4K 策略,但回执和选择器把这些数字标为 `unverified`(或"假定下限"),而不是 `documented`。钳制到可辩护的下限是产品选择;把它呈现为已记录事实则不是。
431
432 上下文窗口没有环境变量,也没有按模型覆盖键。按 provider 的 `context_window` 是唯一的用户旋钮,这也是为什么当网关或自托管运行时服务 Codewhale catalog 未建模的窗口时,它是该设置的正确选择。Codewhale 不会发明它无法辩护的窗口——它回退到保守值,标为 `fallback`,并在每个显示它的界面标记 `(unverified)`。
433
434 ### 相邻旋钮
435
436 - `auto_compact_threshold_percent`(settings.toml;也接受 `auto_compact_threshold`;`10`–`100`,默认 `80`):自动压缩触发时占完整路由上下文窗口的份额,会被钳制,确保它永远不会在输出预留和裕量(headroom)之后越过可花费的输入上限。可在 `/config` 编辑。不触碰它而提高窗口,会随之提高绝对压缩点。
437 - `auto_compact`(settings.toml,on/off):完全关闭自动压缩;`/compact` 和 Ctrl+L 保持可用。
438 - `CODEWHALE_MAX_OUTPUT_TOKENS`(环境变量;旧别名 `DEEPSEEK_MAX_OUTPUT_TOKENS`):覆盖请求的输出上限。没有覆盖时,Codewhale 从安全的 `65536` 请求上限开始,并与任何更小的已记录模型或路由上限求交;catalog 的 `max_output`(如 DeepSeek V4 的 384K)仍是能力上限,不是每个响应请求的量。显式覆盖在解析后的路由上下文窗口和任何路由输出上限内被保留,预检/紧急预算预留的正是能到达线路的同一有效值。单独记录的路线输入上限也会钳制预检和压缩,即使总上下文窗口更大。空白规范变量会回退到非空旧值;非空但无效或为零的规范值是权威的,会回退到安全的自动默认值,而不是激活过期的旧设置。`config.toml` 中没有 `max_output_tokens` 键。
439
440 压缩设置见[设置文件(持久化 UI 偏好)](#设置文件持久化-ui-偏好),每个显示 token 数实际度量什么见[Token 数量与驱动项](#token-数量与驱动项)。
441
442 ## Profiles
443
444 你可以在同一文件里定义多个 profile:
445
446 ```toml
447 api_key = "PERSONAL_KEY"
448 default_text_model = "deepseek-v4-pro"
449
450 [profiles.work]
451 api_key = "WORK_KEY"
452 base_url = "https://api.deepseek.com/beta"
453
454 [profiles.nvidia-nim]
455 provider = "nvidia-nim"
456 api_key = "NVIDIA_KEY"
457 base_url = "https://integrate.api.nvidia.com/v1"
458 default_text_model = "deepseek-ai/deepseek-v4-pro"
459
460 [profiles.fireworks]
461 provider = "fireworks"
462 default_text_model = "accounts/fireworks/models/deepseek-v4-pro"
463
464 [profiles.siliconflow]
465 provider = "siliconflow"
466 default_text_model = "deepseek-ai/DeepSeek-V4-Pro"
467
468 [profiles.siliconflow.providers.siliconflow]
469 base_url = "https://api.siliconflow.com/v1"
470
471 [profiles.openai-compatible]
472 provider = "openai"
473
474 [profiles.openai-compatible.providers.openai]
475 base_url = "https://openai-compatible.example/v4"
476 model = "glm-5"
477
478 [profiles.atlascloud]
479 provider = "atlascloud"
480
481 [profiles.atlascloud.providers.atlascloud]
482 base_url = "https://api.atlascloud.ai/v1"
483 model = "deepseek-ai/deepseek-v4-flash"
484
485 [profiles.sglang]
486 provider = "sglang"
487 base_url = "http://localhost:30000/v1"
488 default_text_model = "deepseek-ai/DeepSeek-V4-Pro"
489
490 [profiles.vllm]
491 provider = "vllm"
492 base_url = "http://localhost:8000/v1"
493 default_text_model = "deepseek-ai/DeepSeek-V4-Pro"
494
495 [profiles.ollama]
496 provider = "ollama"
497 base_url = "http://localhost:11434/v1"
498 default_text_model = "codewhale-coder:1.3b"
499
500 [profiles.ollama-cloud]
501 provider = "ollama-cloud"
502
503 [profiles.ollama-cloud.providers.ollama_cloud]
504 base_url = "https://ollama.com/v1"
505 model = "gpt-oss:120b"
506 ```
507
508 用以下方式选择 profile:
509
510 - CLI:`codewhale --profile work`
511 - 环境:`DEEPSEEK_PROFILE=work`
512
513 如果选中的 profile 缺失,codewhale 会以列出可用 profiles 的错误退出。
514
515 ## Harness Profiles
516
517 v0.9 为模型特有的 harness 姿态添加了配置数据模型。这是预览 schema:它可以被解析和测试,但运行时 provider/模型选择和提示/工具行为在后续 v0.9 切片中接入。没有配置的 profile 匹配时,解析器会回退到 cutline 文档中列出的模型家族的内置种子 profiles。配置的 profiles 总是优先于这些种子。
518
519 ```toml
520 [[harness_profiles]]
521 provider_route = "deepseek"
522 model_pattern = "deepseek-v4.*"
523
524 [harness_profiles.posture]
525 kind = "cache-heavy" # standard | cache-heavy | lean | custom
526 max_subagents = 10 # 0 表示运行时默认
527 prefer_codebase_search = false
528 compaction_strategy = "prefix-cache" # default | prefix-cache | aggressive
529 tool_surface = "full" # full | read-only | auto
530 safety_posture = "standard" # standard | strict | permissive
531 ```
532
533 harness profile 里未知的姿态名或未知键会让配置反序列化失败,而不是静默变成 `custom`。这是有意为之:一旦运行时接线(wiring)消费这些 profiles,拼写错误应该可见。v0.9 的实现顺序和自动创建者边界记录在 [`HARNESS_PROFILE_CUTLINE.md`](../rfcs/HARNESS_PROFILE_CUTLINE.md)。
534
535 ## 环境变量
536
537 大多数运行时环境变量覆盖配置值。API key 变量在已保存配置和钥匙串凭据之后作为回退。
538
539 三个面向用户的槽位——provider、模型、base URL——暴露 `CODEWHALE_*` 别名。两种形式都设置时 `CODEWHALE_*` 值胜出;`DEEPSEEK_*` 形式为更老的 shell 保留:
540
541 - `CODEWHALE_PROVIDER`(首选)/ `DEEPSEEK_PROVIDER`(旧别名)——`deepseek|deepseek-anthropic|nvidia-nim|openai|atlascloud|wanjie-ark|volcengine|openrouter|xiaomi-mimo|novita|fireworks|siliconflow|arcee|siliconflow-CN|moonshot|sglang|vllm|ollama|ollama-cloud|huggingface|modelscope|together|qianfan|openai-codex|anthropic|openmodel|zai|stepfun|minimax|deepinfra|mistral`
542 - `CODEWHALE_MODEL`(首选)/ `DEEPSEEK_MODEL`(旧别名)——活动 provider 的默认模型
543 - `CODEWHALE_BASE_URL`(首选)/ `DEEPSEEK_BASE_URL`(旧别名)——活动 provider 的 base URL
544
545 `CODEWHALE_BASE_URL` 只应用于**活动**路由。固定到另一个 provider 的请求——子智能体或 fleet 子进程、路由工具、每回合自动路由器、选择器预览——从该 provider 自己的 `[providers.<table>]` 解析其端点,然后是它的 provider 作用域变量(`MOONSHOT_BASE_URL`、`OPENAI_BASE_URL`……),然后是该 provider 的默认值。它从不继承活动会话的主机,而没有配置 `base_url` 的自定义路由会在 loopback 占位符上失败关闭(fail closed),而不是借用另一个 provider 的端点。旧的根级 `base_url` 行为相同:写在你的配置文件里,它像以往一样由 DeepSeek 和 DeepSeek-CN 身份共享,但环境写入的值属于它被指向的那个身份。提供或重新选择有效路由端点的受管配置覆盖,会把通用覆盖从每条路由上拿走。
546
547 其余变量:
548
549 - `DEEPSEEK_API_KEY`
550 - `DEEPSEEK_ANTHROPIC_BASE_URL`
551 - `DEEPSEEK_HTTP_HEADERS`(自定义模型请求头,逗号分隔 `name=value` 对)
552 - `DEEPSEEK_DEFAULT_TEXT_MODEL`(`DEEPSEEK_MODEL` 的额外旧别名)
553 - `DEEPSEEK_STREAM_IDLE_TIMEOUT_SECS`(流空闲超时秒数;默认 `900`,钳制到 `1..=3600`)
554 - `DEEPSEEK_STREAM_OPEN_TIMEOUT_SECS`(连接建立 + 响应头等待秒数;默认 `45`,钳制到 `5..=300`;区别于每块空闲超时)
555 - `CODEWHALE_CACHE_MAXIMAL`(`1`/`true`/`on`/`yes`)——缓存最大化上下文模式(#528)。开启时,Repo Working Set 块把顶层活动文件的**完整当前内容**物化(materialize)到每回合的系统提示中(确定性顺序,字节有界),而不是只列出路径。这些文件未变化时该块保持字节稳定,这样 DeepSeek 的 KV 前缀缓存能持续命中;编辑文件会从该块开始缓存未命中。默认关闭(仅路径列表)。字节上限默认每文件 24 KB / 总计 96 KB。
556 - `NVIDIA_API_KEY` 或 `NVIDIA_NIM_API_KEY`(provider 为 `nvidia-nim` 时首选;回退到 `DEEPSEEK_API_KEY`)
557 - `NVIDIA_NIM_BASE_URL`、`NIM_BASE_URL` 或 `NVIDIA_BASE_URL`
558 - `NVIDIA_NIM_MODEL`
559 - `OPENAI_API_KEY`
560 - `OPENAI_BASE_URL`
561 - `OPENAI_MODEL`
562 - `ATLASCLOUD_API_KEY`
563 - `ATLASCLOUD_BASE_URL`
564 - `ATLASCLOUD_MODEL`
565 - `WANJIE_ARK_API_KEY`、`WANJIE_API_KEY` 或 `WANJIE_MAAS_API_KEY`
566 - `WANJIE_ARK_BASE_URL`、`WANJIE_BASE_URL` 或 `WANJIE_MAAS_BASE_URL`
567 - `WANJIE_ARK_MODEL`、`WANJIE_MODEL` 或 `WANJIE_MAAS_MODEL`
568 - `VOLCENGINE_API_KEY`、`VOLCENGINE_ARK_API_KEY` 或 `ARK_API_KEY`
569 - `VOLCENGINE_BASE_URL`、`VOLCENGINE_ARK_BASE_URL` 或 `ARK_BASE_URL`
570 - `VOLCENGINE_MODEL` 或 `VOLCENGINE_ARK_MODEL`
571 - `OPENROUTER_API_KEY`
572 - `OPENROUTER_BASE_URL`
573 - `OPENROUTER_MODEL`
574 - `XIAOMI_MIMO_TOKEN_PLAN_API_KEY`、`MIMO_TOKEN_PLAN_API_KEY`、`XIAOMI_MIMO_API_KEY`、`XIAOMI_API_KEY` 或 `MIMO_API_KEY`
575 - `XIAOMI_MIMO_BASE_URL` 或 `MIMO_BASE_URL`
576 - `XIAOMI_MIMO_MODEL` 或 `MIMO_MODEL`
577 - `XIAOMI_MIMO_MODE` 或 `MIMO_MODE`(`token-plan-sgp`、`token-plan-cn`、`token-plan-ams` 或 `pay-as-you-go`)
578 - `NOVITA_API_KEY`
579 - `NOVITA_BASE_URL`
580 - `NOVITA_MODEL`
581 - `FIREWORKS_API_KEY`
582 - `FIREWORKS_BASE_URL`
583 - `FIREWORKS_MODEL`
584 - `HUGGINGFACE_API_KEY` 或 `HF_TOKEN`(`HF_TOKEN` 是 provider 为 `huggingface` 时接受的回退别名)
585 - `MODELSCOPE_API_KEY`
586 - `HUGGINGFACE_BASE_URL` 或 `HF_BASE_URL`
587 - `HUGGINGFACE_MODEL` 或 `HF_MODEL`
588 - `SILICONFLOW_API_KEY`
589 - `SILICONFLOW_BASE_URL`
590 - `SILICONFLOW_MODEL`
591 - `ARCEE_API_KEY`
592 - `ARCEE_BASE_URL`
593 - `ARCEE_MODEL`
594 - `TOGETHER_API_KEY`
595 - `TOGETHER_BASE_URL`
596 - `TOGETHER_MODEL`
597 - `QIANFAN_API_KEY` 或 `BAIDU_QIANFAN_API_KEY`
598 - `QIANFAN_BASE_URL` 或 `BAIDU_QIANFAN_BASE_URL`
599 - `QIANFAN_MODEL` 或 `BAIDU_QIANFAN_MODEL`
600 - `OPENAI_CODEX_ACCESS_TOKEN` 或 `CODEX_ACCESS_TOKEN`
601 - `OPENAI_CODEX_BASE_URL` 或 `CODEX_BASE_URL`
602 - `OPENAI_CODEX_MODEL` 或 `CODEX_MODEL`
603 - `OPENAI_CODEX_ACCOUNT_ID` 或 `CODEX_ACCOUNT_ID`
604 - `ANTHROPIC_API_KEY`
605 - `ANTHROPIC_BASE_URL`
606 - `ANTHROPIC_MODEL`
607 - `ZAI_API_KEY` 或 `Z_AI_API_KEY`
608 - `ZAI_BASE_URL` 或 `Z_AI_BASE_URL`
609 - `ZAI_MODEL` 或 `Z_AI_MODEL`
610 - `STEPFUN_API_KEY` 或 `STEP_API_KEY`
611 - `STEPFUN_BASE_URL` 或 `STEP_BASE_URL`
612 - `STEPFUN_MODEL` 或 `STEP_MODEL`
613 - `MINIMAX_API_KEY`
614 - `MINIMAX_BASE_URL`
615 - `MINIMAX_MODEL`
616 - `DEEPINFRA_API_KEY` 或 `DEEPINFRA_TOKEN`
617 - `DEEPINFRA_BASE_URL`
618 - `DEEPINFRA_MODEL`
619 - `MISTRAL_API_KEY`
620 - `MISTRAL_BASE_URL`
621 - `MISTRAL_MODEL`
622 - `MOONSHOT_API_KEY` 或 `KIMI_API_KEY`
623 - `MOONSHOT_BASE_URL` 或 `KIMI_BASE_URL`
624 - `MOONSHOT_MODEL`、`KIMI_MODEL_NAME` 或 `KIMI_MODEL`
625 - `SGLANG_BASE_URL`
626 - `SGLANG_MODEL`
627 - `SGLANG_API_KEY`(可选;许多 localhost SGLang 服务器不需要认证)
628 - `VLLM_BASE_URL`
629 - `VLLM_MODEL`
630 - `VLLM_API_KEY`(可选;许多 localhost vLLM 服务器不需要认证)
631 - `OLLAMA_BASE_URL`
632 - `OLLAMA_MODEL`
633 - `OLLAMA_API_KEY`(可选;许多 localhost Ollama 服务器不需要认证)
634 - `OLLAMA_CLOUD_BASE_URL`
635 - `OLLAMA_CLOUD_MODEL`
636 - `OLLAMA_CLOUD_API_KEY`(首选的 Cloud key;`OLLAMA_API_KEY` 是官方回退)
637
638 对于下面每一个产品级 `CODEWHALE_*` 变量,匹配的旧 `DEEPSEEK_*` 名称仍作为兼容回退被读取;两者都设置时,`CODEWHALE_*` 值胜出。
639
640 - `CODEWHALE_LOG_LEVEL` 或 `RUST_LOG`(`info`/`debug`/`trace` 启用轻量详细日志)
641 - `CODEWHALE_SKILLS_DIR`
642 - `CODEWHALE_MCP_CONFIG`
643 - `CODEWHALE_NOTES_PATH`
644 - `CODEWHALE_MEMORY`(`1|on|true|yes|y|enabled` 开启用户记忆)
645 - `CODEWHALE_MEMORY_PATH`
646 - `CODEWHALE_TELEMETRY` / `DEEPSEEK_TELEMETRY`(旧别名)——匿名使用计数在 0.9.12 源码中默认关闭,采集还要求明确接受当前版本的告知。首次运行的披露或单独设置 `true` 均不代表同意。接受 `0|1|true|false|yes|no|on|off|enabled|disabled`。显式 "off" 是**底线**:它胜过 `--telemetry true` 和配置里的 `telemetry = true`,而此列表无法读取的值也解析为 off,因为杀开关(kill switch)里的拼写错误绝不能解析为 "on"。见 [`TELEMETRY.md`](TELEMETRY.md)。
647 - `CODEWHALE_TELEMETRY_ENDPOINT` / `DEEPSEEK_TELEMETRY_ENDPOINT`(旧别名)——`https://`,或仅对 loopback 的普通 `http://`。覆盖配置文件。未设置时选择随附默认 `https://telemetry.codewhale.net/v1/telemetry`;设置为**空字符串**会把批次路由到本地 dry-run 文件,不联系任何人。无论哪种方式,它只决定会话发送到哪里——不能覆盖选择退出。
648 - `CODEWHALE_ALLOW_SHELL`(`1`/`true` 启用)
649 - `CODEWHALE_APPROVAL_POLICY`(`on-request|untrusted|never`)
650 - `CODEWHALE_SANDBOX_MODE`(`read-only|workspace-write|danger-full-access|external-sandbox`)
651 - `CODEWHALE_NO_NEW_PRIVS`(`0`/`false`/`no`/`off`/`disabled` 选择退出)——仅 Linux。TUI 进程在启动时设置内核不可逆的 no-new-privileges 标志作为纵深防御,这为 Codewhale 的整个进程树阻断 `sudo`/`su`/setuid 辅助程序。如果你是 wheel 组用户,通过 Codewhale 管理并需要提权工作,启动前把这个变量设为假值(#5413);其他启动加固(无 ptrace、无核心转储)保持开启。任何其他值都保持默认的加固姿态。
652 - `CODEWHALE_MANAGED_CONFIG_PATH`
653 - `CODEWHALE_REQUIREMENTS_PATH`
654 - `CODEWHALE_MAX_SUBAGENTS`(钳制到 `1..=128`)
655 - `CODEWHALE_TASKS_DIR`(运行时任务队列/工件存储,默认 `~/.codewhale/tasks`,旧 `~/.deepseek/tasks` 仅在旧目录存在时回退)
656 - `CODEWHALE_RUNTIME_DIR`(覆盖运行时线程存储根目录)。交互式会话默认 `$CODEWHALE_HOME/sessions/<session-id>/runtime`,这样每个 Codewhale 进程拥有自己的存储(#5630)。存储是单所有者的:第二个进程在**同一**根目录上会在启动时失败。设置此变量以跨进程共享一个存储,或当运行时 API 服务器应使用稳定的非会话路径时。未设置时,API/服务器路径保持 `$CODEWHALE_HOME/tasks/runtime`。旧别名:`DEEPSEEK_RUNTIME_DIR`。
657 - `CODEWHALE_ALLOW_INSECURE_HTTP`(`1`/`true` 允许非本地 `http://` base URL;默认拒绝)
658 - `CODEWHALE_FORCE_HTTP1`(`1|true|yes|on` 把 HTTP 客户端钉到 HTTP/1.1,禁用 HTTP/2;在 Windows 或错误处理长连接 H2 流的代理后面有用)
659 - `CODEWHALE_HOME`(覆盖基础数据目录;默认 `~/.codewhale`)。如果你之前导出过 `DEEPSEEK_HOME`,把它改名为 `CODEWHALE_HOME`;新 Codewhale 状态路径不使用旧环境变量。
660 - `CODEWHALE_RELEASE_BASE_URL`(`codewhale update` 和 TUI 启动更新检查在 `[update].update_uri` 未设置时使用的 release 资源镜像,或该配置 URI 无法获取时的回退)
661 - `CODEWHALE_AUTOMATIONS_DIR`(覆盖自动化存储目录;默认 `~/.codewhale/automations`,旧 `~/.deepseek/automations` 仅在旧目录存在时回退)
662 - `NO_ANIMATIONS`(`1|true|yes|on` 在启动时强制 `low_motion = true` 和 `fancy_animations = false`,无论已保存设置如何;见 [`docs/ACCESSIBILITY.md`](../ACCESSIBILITY.md))。
663 - `SSL_CERT_FILE`——企业代理 / TLS 检查 MITM 用户把它指向 PEM 包(或单个 DER 证书),证书会与平台的系统信任库一起添加。失败记录警告并继续——现有系统根仍然适用。
664
665 ### 指令来源(`instructions = [...]`,#454)
666
667 添加一组额外的系统提示来源,它们按声明顺序,与自动加载的 `AGENTS.md` 拼接:
668
669 ```toml
670 instructions = [
671 "./AGENTS.md",
672 "~/.codewhale/global.md",
673 "~/team/agents-shared.md",
674 ]
675 ```
676
677 规则:
678
679 - 路径经过 `expand_path`,所以 `~` 和环境变量都可用。
680 - 每个文件上限 100 KiB;过大的文件会被截断并带 `[…elided]` 标记,而不是跳过。
681 - 缺失文件会带一条 tracing 警告被跳过,这样过期条目不会让启动失败。
682 - 只有用户自有的配置、profiles 和受管配置可以设置这个数组。项目配置(`<workspace>/.codewhale/config.toml`,或旧版 `<workspace>/.deepseek/config.toml`)会忽略 `instructions`,这样克隆的仓库不能挑选任意本地文件放进提示。
683
684 ### Hooks
685
686 Hooks 是 **TUI 运行时功能**。它们从交互式 TUI 以及它驱动的引擎回合循环触发;`codewhale exec`、CLI 子命令、app-server / ACP 面和 `workflow` 工具不会触发它们。
687
688 [`docs/HOOKS.md`](HOOKS.md) 是全部十一个 hook 事件的权威参考——它们的触发点、环境变量、stdin 负载、超时与后台语义,以及其中哪三个可以操纵 Codewhale。下面的章节更深入覆盖配置面和操纵契约。
689
690 写 hook 之前值得在那里读两个契约点:
691
692 - `background = true` 意味着**提交后从不等待**。hook 仍会收到文档化的 stdin 负载和同样的超时,但它没有退出码,也无法操纵。
693 - 引用其事件永不携带的条件的条件(`tool_call_after` / `on_error` 之外的 `exit_code` 条件,`shell_env` 上的 `mode` 条件,非工具事件上的工具条件)会在**加载时被拒绝**,记入日志,并在 `/hooks list` 中显示。它不会静默永不匹配。拒绝是逐条进行的,所以一个坏 hook 永远不会连累另一个只是共享其 `name` 或同样未命名的 hook。
694
695 ### `/hooks` 列表
696
697 在 TUI 内运行 `/hooks`(或 `/hooks list`)查看每个配置的生命周期 hook,按事件分组,包括每个 hook 的名称、命令预览、有效超时和条件。设置了 `[hooks].default_timeout_secs` 时,它会替换每个逐 hook 的 `timeout_secs`,列表显示该有效值并指出覆盖来源,而不是回显逐 hook 数字。`default_timeout_secs = 0` 在加载时被拒绝——它会让配置中的每个 hook 立即过期——所以覆盖被忽略,逐 hook 的 `timeout_secs` 生效,列表显示该逐 hook 值且无覆盖出处,拒绝出现在 `configuration problems` 下。`[hooks].enabled` 标志的状态显示在顶部,这样 hooks 被全局抑制时一目了然,任何在加载时被拒绝的条目都带原因列在 `configuration problems` 下。Hooks 在 `[[hooks.hooks]]` 条目下配置——完整 schema 见 [`docs/HOOKS.md`](HOOKS.md)。
698
699 ### 可变的 `message_submit` hooks
700
701 `message_submit` hooks 在提交的消息加入历史或发送给模型之前运行。与仅观察的生命周期 hooks 不同,非后台 `message_submit` hooks 可以替换或阻止提交的文本。
702
703 ```toml
704 [[hooks.hooks]]
705 event = "message_submit"
706 command = "~/.codewhale/hooks/inject-context.sh"
707 timeout_secs = 2
708 continue_on_error = true
709 ```
710
711 hook 在 stdin 上收到 JSON:
712
713 ```json
714 {
715 "event": "message_submit",
716 "text": "original user text",
717 "text_bytes": 18,
718 "text_original_bytes": 18,
719 "text_truncated": false,
720 "session_id": "sess_12345678",
721 "workspace": "/path/to/workspace",
722 "mode": "agent",
723 "model": "deepseek-chat",
724 "total_tokens": 1234
725 }
726 ```
727
728 整个序列化文档上限 32 KiB。Codewhale 保留在 JSON 转义和有界元数据之后能容纳的最大 UTF-8 安全 `text` 前缀,三个 `text_*` 字段让截断显式化。即时消息、恢复的队列条目、合并的操纵和先前 hook 的替换都穿过同样的序列化边界。
729
730 如果 hook 以 `0` 退出并打印带非空字符串 `text` 字段的 JSON,该值会替换提交的文本:
731
732 ```json
733 { "text": "replacement user text" }
734 ```
735
736 以 `0` 退出但 stdout 为空,或 stdout JSON 没有 `text`,则当前文本保持不变。JSON `text` 字段不能为空;`{"text":""}` 被视为无效 stdout 并忽略。以 `2` 退出会在回合开始前阻止提交;结构化 `reason` 字段可以提供 TUI 中显示的、有界且脱敏的状态消息。原始 stdout、stderr 和进程错误文本不会复制进拒绝回执。其他非零退出遵循 hook 的 `continue_on_error` 设置。超时和派生失败也会在 `continue_on_error = true` 允许提交继续时,以瞬态 TUI 状态消息的形式浮现。
737
738 多个 `message_submit` hooks 按配置顺序运行,每个 hook 收到前一个 hook 产生的文本。标记为 `background = true` 的 hooks 是仅观察的,不能转换或阻止消息——它们仍收到同样的 stdin 负载和同样的环境,只是从不被等待。现有环境变量保持可用。`shell_env` hooks 保持它们现有的 `KEY=VALUE` stdout 契约;JSON stdout 契约存在于 `message_submit`(上面)和 `tool_call_before`(下面)。
739
740 ### `tool_call_before` 决策 hooks
741
742 `tool_call_before` hooks 在每次工具调用执行之前运行。除了旧的硬拒绝(退出码 `2`,无论 stdout 如何总是胜出),前台 hook 可以以退出码 `0` 在 stdout 上打印 JSON 决策:
743
744 ```json
745 {
746 "decision": "allow" | "deny" | "ask",
747 "reason": "human-readable explanation (used for deny)",
748 "updatedInput": { "command": "ls -la" },
749 "additionalContext": "text appended to the tool result for the model"
750 }
751 ```
752
753 所有字段都是可选的。空 stdout、非 JSON stdout 和没有 `decision` 字段的 JSON 行为与以前完全一样(allow)。无法识别的 `decision` 字符串会记录一条固定警告,不回显不可信值,并按 allow 处理。
754
755 - `deny` 阻止工具;模型收到包含 `reason` 的权限拒绝工具结果。
756 - `ask` 在 Ask 和 Auto-Review 中强制交互式审批提示,即使是对本会自动运行的工具。Full Access 不打开工具审批提示,所以 hook 的 `ask` 不会降级该姿态。
757 - `updatedInput` 必须是 JSON 对象;它在执行前替换工具输入。多个 hook 提供时,最后一个 hook 胜出。
758 - `additionalContext` 作为 `[hook context] ...` 追加到发回模型的工具结果。多个 hook 的上下文会拼接。
759
760 多个 hook 匹配时,优先级是 deny > ask > allow。标记为 `background = true` 的 hooks 不能操纵工具调用——它们被提交且从不等待,所以没有裁决可贡献。
761
762 一个完全没有产生裁决的前台 hook——它撞上超时、进程无法启动,或严格进程以非零退出且没有显式 JSON 决策——不会被当作许可。如果*那个* hook 配置了 `continue_on_error = false`,结果会拒绝工具调用,拒绝会指名 hook 和有界原因。严格性是从实际匹配这次调用的 hooks 上读取的,所以作用域在另一个工具上的严格门禁不能拒绝它,而宽松 hook 的超时也不会仅仅因为配置里别处存在严格 hook 就拒绝。在默认的 `continue_on_error = true` 下,结果被记录,调用继续。
763
764 `reason` 和 `additionalContext` 有上限(每个字段 2,000 字符,一次调用的拼接上下文 8,000),并且在到达 TUI 或模型之前剥离控制字符。
765
766 拒绝 hook 示例:
767
768 ```toml
769 [[hooks.hooks]]
770 event = "tool_call_before"
771 command = '''echo '{"decision":"deny","reason":"blocked by project policy"}' '''
772 condition = { type = "tool_name", name = "exec_shell" }
773 ```
774
775 ask hook 示例(为每个 MCP 工具强制审批):
776
777 ```toml
778 [[hooks.hooks]]
779 event = "tool_call_before"
780 command = '''echo '{"decision":"ask"}' '''
781 condition = { type = "tool_name", name = "mcp__*" }
782 ```
783
784 输入重写示例:
785
786 ```toml
787 [[hooks.hooks]]
788 event = "tool_call_before"
789 command = "~/.codewhale/hooks/clamp-shell-timeout.sh"
790 condition = { type = "tool_name", name = "exec_shell" }
791 ```
792
793 其中脚本读取 hook 上下文,然后用调整后的参数打印 `{"updatedInput": {...}}`。
794
795 `tool_name` 条件支持 `*` glob:`mcp__*` 匹配每个 MCP 工具(例如 `mcp__github__create_issue`)但不匹配 `read_file` 这样的内置工具;精确名称保持精确匹配。模式中的其他正则元字符按字面匹配。
796
797 ### 项目本地 hooks
798
799 仓库可以在 `<workspace>/.codewhale/hooks.toml` 中携带策略,使用与 `[hooks]` 表相同的形态(顶层字段加 `[[hooks]]` 条目)。项目 hooks 是可执行的 shell 配置,所以 Codewhale 只会在工作区通过信任提示或 `[projects."<workspace>"] trust_level = "trusted"` 条目在用户自有配置中被信任之后才加载它们。会话 `/trust on` 模式本身不启用仓库提供的 hooks,仓库本地旧标记(如 `.deepseek/trusted`)也不启用项目 hooks。一旦受信任,项目 hooks 会追加到 `config.toml` 的全局 hooks 之后,所以它们最后运行,并且对于 `updatedInput`,在平局时胜出。格式错误的受信任项目文件记录警告,启动回退到仅全局 hooks。
800
801 ```toml
802 # .codewhale/hooks.toml
803 [[hooks]]
804 event = "tool_call_before"
805 command = '''echo '{"decision":"deny","reason":"no shell in this repo"}' '''
806 condition = { type = "tool_name", name = "exec_shell" }
807 ```
808
809 ### 回合结束观察者 hooks
810
811 `turn_end` hooks 在每轮模型回合结束后观察结束状态,此时回合后状态、用量总计、成本核算、通知、回执和队列恢复都已更新。它们在 stdin 上收到 JSON,并且是仅观察的:stdout 被忽略,失败记录为警告,hook 不能阻止用户输入、修改转录或改变下一个排队的后续动作。
812
813 仅观察的 UI 事件共享一个 32 条目队列和两个持久 worker;终端循环使用非阻塞提交,不为每个事件创建线程。队列满或调度器不可用会丢弃那个观察者事件,并保留为事件特有的错误 toast,独立于普通的 agent/回合状态文本。
814
815 ```toml
816 [[hooks.hooks]]
817 event = "turn_end"
818 command = "~/.codewhale/hooks/turn-audit.sh"
819 timeout_secs = 2
820 continue_on_error = true
821 ```
822
823 负载包含通用 hook 元数据加回合后核算:
824
825 ```json
826 {
827 "event": "turn_end",
828 "session_id": "sess_12345678",
829 "workspace": "/path/to/workspace",
830 "mode": "agent",
831 "created_at": "2026-07-12T10:30:00+00:00",
832 "model_backed": true,
833 "provider": "deepseek",
834 "model": "deepseek-chat",
835 "billing_surface": null,
836 "turn_id": "turn_12345678",
837 "status": "completed",
838 "error": null,
839 "duration_ms": 1834,
840 "usage": {
841 "input_tokens": 1200,
842 "output_tokens": 180,
843 "prompt_cache_hit_tokens": 900,
844 "prompt_cache_miss_tokens": 300,
845 "prompt_cache_write_tokens": 0,
846 "reasoning_tokens": null,
847 "reasoning_replay_tokens": null
848 },
849 "totals": {
850 "session_tokens": 1380,
851 "conversation_tokens": 1380,
852 "input_tokens": 1200,
853 "output_tokens": 180
854 },
855 "tool_count": 2,
856 "queued_message_count": 1,
857 "stop_hook_active": false
858 }
859 ```
860
861 `created_at` 锚定时间窗口定价;`provider` 和 `model` 标识模型支撑回合使用的有效路由。`billing_surface` 是从实际服务该回合的端点派生的可选、非秘密分类。可识别的 StepFun 路由发出 `stepfun-payg` 或 `stepfun-plan`;原始 base URL 从不写入 hook 或运行时记录。运行时 `TurnRecord` 导出把同一字段称为 `effective_billing_surface`,`scorecard` 接受它作为别名。这让订阅配额与 token 定价用量分开。无法识别和自定义端点保持 `null` 且不计价。
862
863 仅 shell 的生命周期完成把 `model_backed` 设为 `false`,并可能报告 `null` provider;离线 scorecard 从模型 token 和成本总计中排除这些记录。没有匹配 `TurnStarted` 的仅完成 shell、手动压缩和 purge 事件,会保留带合成 `lifecycle_<uuid>` 回合 id 和完成被观察时间的观察者通知。
864
865 对于 `interrupted` 或 `failed` 回合,`status` 反映该终态,`error` 在可用时携带引擎错误字符串。`stop_hook_active` 保留用于未来的重入保护,目前总是 `false`。
866
867 ### 子智能体生命周期 hooks
868
869 `subagent_spawn` 和 `subagent_complete` hooks 观察子智能体生命周期事件。它们在 stdin 上收到有界 JSON 元数据,并且是仅观察的:hook 失败记录为警告,不阻止子智能体调度、不改变提示,也不改变结果。对于这些观察者事件,`continue_on_error` 没有效果:即使前面的 hook 非零退出,后面的匹配 hooks 仍会运行。
870
871 ```toml
872 [[hooks.hooks]]
873 event = "subagent_complete"
874 command = "~/.codewhale/hooks/subagent-audit.sh"
875 timeout_secs = 2
876 continue_on_error = true
877 ```
878
879 `subagent_spawn` 收到:
880
881 ```json
882 {
883 "event": "subagent_spawn",
884 "agent_id": "agent_12345678",
885 "session_id": "sess_12345678",
886 "workspace": "/path/to/workspace",
887 "mode": "agent",
888 "model": "deepseek-chat",
889 "total_tokens": 1234,
890 "prompt_preview": "bounded prompt preview",
891 "prompt_truncated": false
892 }
893 ```
894
895 `subagent_complete` 收到同样的通用字段加终端元数据:
896
897 ```json
898 {
899 "event": "subagent_complete",
900 "agent_id": "agent_12345678",
901 "session_id": "sess_12345678",
902 "workspace": "/path/to/workspace",
903 "mode": "agent",
904 "model": "deepseek-chat",
905 "total_tokens": 1234,
906 "status": "completed",
907 "result_preview": "bounded result preview",
908 "result_truncated": false
909 }
910 ```
911
912 预览在交付前被限制,所以生命周期 hooks 不会收到完整的子智能体提示、转录或无界结果。需要完整子智能体细节时,用 `agent` 返回的转录句柄。
913
914 ### 运行中回合的输入
915
916 输入区快捷键在整个会话中保持同样的角色:
917
918 - **Enter** 空闲时发送,繁忙时排队一个下一回合后续动作。该行为在 provider 首个 token 之前与之后不变。
919 - 输入区为空且可见排队后续动作时,**Enter** 现在把最旧的排队后续动作送入活动回合。
920 - **Ctrl+Enter**(或终端转发它时的 **Cmd+Enter**)显式操纵活动回合。空闲时它正常发送。
921 - 默认情况下,**Shift+Enter**、**Alt+Enter** 和 **Ctrl+J** 插入换行。
922 - 设置 `composer_multiline_mode = true` 让 **Enter** 插入换行、**Shift+Enter** 发送。**Alt+Enter**、**Ctrl+J** 以及受支持的 **Ctrl+Enter** / **Cmd+Enter** 行为不变。
923 - **Ctrl+G** 和 **Ctrl+S** 只暂存草稿;它们从不发送或操纵。
924
925 ### 输入区暂存(`/stash`,Ctrl+G / Ctrl+S)
926
927 在输入区按 **Ctrl+G** 把当前草稿停放到 `~/.codewhale/composer_stash.jsonl`。`/stash list` 显示停放的草稿,带单行预览和时间戳;`/stash pop` 恢复最近停放的草稿(LIFO);`/stash clear` 清空文件。上限 200 条目;多行草稿完整往返。**Ctrl+S** 在转发它的终端中仍是别名;Cursor 和 VS Code 把 Ctrl+S 保留给 Save,所以 Ctrl+G 是可移植默认。
928
929 ## 设置文件(持久化 UI 偏好)
930
931 codewhale 还把用户偏好存储在:
932
933 - 新安装:`~/.codewhale/settings.toml`
934 - 存在旧设置文件时:`~/.deepseek/settings.toml` 或旧平台配置目录 `deepseek/settings.toml`
935
936 值得注意的设置包括 `auto_compact`,它对已知上下文窗口(直到 1M-token V4 类)使用模型感知的默认开启策略。自动压缩在活动模型上限之前运行,并把压缩后的摘要带入下一个请求。触发默认是 `auto_compact_threshold_percent = 80`。喜欢手动连续的可以持久化 `auto_compact = false`;手动 `/compact` / Ctrl+L 保持可用。你可以用 TUI 里的 `/settings` 和 `/config`(交互式编辑器)检查或更新这些设置。
937
938 常用设置键:
939
940 - `theme`(`system`、`terminal`、`underwater`、`underwater-retro`、`dark`、`light`、`grayscale`、`catppuccin-mocha`、`tokyo-night`、`dracula`、`gruvbox-dark`、`claude`、`matrix`、`solarized-light`、`uwu`;默认 `system`):`system` 跟随终端背景检测,`dark`/`light` 使用 Codewhale Whale 配对,`terminal` 继承宿主终端,`grayscale` 是低意见的黑/白主题,命名的社区预设应用于整个 TUI。`whale`、`mono`、`black-white`、`tokyonight` 和 `gruvbox` 这样的别名被接受。在 Whale 中,钴蓝色拥有动作/焦点,海沫绿拥有实时工作,Signal Gold 拥有人类决策和鲸鱼,珊瑚色拥有警告,玫瑰色拥有危险,紫色拥有 Operate,绿色保持已完成/已验证。文本标签、标记和动效策略在颜色不可用时携带同样的状态;颜色从来不是唯一的线索。用户创作的覆盖只存在于 `~/.codewhale/themes/<name>.json`(或 `$CODEWHALE_HOME/themes/<name>.json`),用 `/theme custom:<name>` 选择。文件名是有界的 slug,符号链接和超过 64 KiB 的文件被拒绝,颜色必须是 `#RRGGBB`,未知字段会验证失败。`/theme schema` 打印嵌入的 JSON Schema,`/theme path` 显示确切目录。覆盖命名一个编译好的 `base` 主题,只改变列出的语义颜色;它不能包含或读取另一个文件。
941 - `auto_compact`(on/off,模型感知默认对已知上下文窗口开启,除非显式配置)
942 - `auto_compact_threshold_percent`(10-100,默认 `80`):仅当 `auto_compact` 启用时使用的发送前自动压缩阈值。
943 - `paste_burst_detection`(on/off,默认 on):为不发出括号粘贴事件的终端提供的快速按键粘贴回退检测。这独立于终端的括号粘贴模式。
944 - `work_surface_placement`(`top`、`left`、`right` 或 `off`;默认 `top`):把工作栏——任务 / 待办 / Workers——放在转录上方(默认顶栏)、侧栏,或完全隐藏(`off`)。侧边选择在窄终端上回退到顶栏布局,不改变已保存的偏好。用 `/config work_surface_placement right --save`(或 `left` / `top` / `off`)实时设置。
945 - `rail_panel`(`tasks`、`agents`、`context`、`pinned`;默认 `tasks`,别名键 `rail`):工作栏显示哪个面板。面板选择与放置正交。`tasks` 是完整的实时工作列表(待办,然后子智能体);`agents` 收窄到子智能体行;`pinned` 显示目标加待办清单;`context` 是只读会话事实列表。除 `context` 外的每个面板中,行都可选择、可点击,并打开它们的详情面。`Alt+!`/`Alt+@`/`Alt+#`/`Alt+$` 实时切换面板。
946 - `work_surface_top_height`(2–16)和 `work_surface_side_width`(26–80):顶栏高度和侧栏宽度的上限。两者通常通过拖动分隔线持久化,而不是手工编辑;条带在上限之下仍自动适配其内容。
947 - `focus_texture`(`off`、`scrim` 或 `grain`;默认 `off`):模态视图的焦点上下文纹理。`scrim` 把聚焦模态之外的已渲染背景朝主题表面调暗;`grain` 在空白单元格上撒稀疏点。纹理是静态的(没有时间分量,所以不受 `low_motion` 影响),从不覆盖带文本的单元格,并在两种颜色都可解析的地方保持 4.5:1 的正文对比度底线。在低于环境活跃最小尺寸的帧上,以及聚焦模态已覆盖 90% 及以上帧时,它被完全跳过。用 `/config focus_texture scrim --save` 实时设置。
948 - `mention_menu_limit`(整数,默认 `128`):输入区渲染可见窗口之前保留的 `@`-提及弹出候选最大数。可见行仍取决于终端高度。
949 - `mention_walk_depth`(整数,默认 `10`):`@`-提及补全遍历的最大工作区深度。在深度嵌套的工作区设为 `0` 表示无限深度;在非常大的仓库保持默认,除非需要。
950 - `mention_menu_behavior`(`fuzzy`、`browser`;默认 `fuzzy`):控制 `@`-提及补全如何填充。`fuzzy` 搜索工作区并应用提及 frecency。`browser` 只按确定性字母顺序列出当前输入目录段的直接子项。
951 - `show_thinking`(on/off)
952 - `thinking_default_expanded`(on/off,默认 off):启用 `show_thinking` 时,让思考块初始展开渲染。Space 仍可折叠所选块,所以把它设为 `true` 会反转默认而不移除逐块折叠。这在 Space 绑定可能被拦截的 SSH/tmux 环境中很有用。
953 - `thinking_preview_lines`(整数,默认 `2`):**折叠**的已完成思考仍显示多少正文行。`0` 仅头部;`10` 是较旧的完整显示。实时流式预览不变。用 Space 展开块,或设置 `thinking_default_expanded` 打开每个块。
954 - `help_expand_groups`(on/off,默认 off):让帮助/快捷键从每个组展开开始。默认折叠长尾(Grok 风格);输入过滤仍展开匹配。
955 - `pin_last_prompt`(on/off,默认 on):在最后一条用户提示滚出后,把它固定在转录视口顶部。
956 - `show_tool_details`(on/off)
957 - `inline_diffs`(`full`、`summary` 或 `off`;默认 `full`):控制成功的结构化文件变更的内联呈现。`full` 显示有界的红/绿 diff 和语义统计,`summary` 只保留统计,`off` 保持平静的变更文件结果。三种都保留所选 File 回执的 Alt/Option+V 详情中的确切已应用变更。失败和取消从不渲染成功 diff。用 `/config inline_diffs <mode> --save` 保存选择。
958 - `locale`(`auto`、`en`、`ja`、`zh-Hans`、`zh-Hant`、`pt-BR`、`es-419`、`vi`、`ko`;默认 `auto`):UI chrome 区域设置。`auto` 检查 `LC_ALL`、`LC_MESSAGES`,然后 `LANG`;不支持的区域设置选择解析为英语。每个随附的语言包都持有完整的 `en.json` 对等,所以没有字符串回退到英语。运行时还在系统提示中把解析出的区域设置作为 V4 推理和回复的回退自然语言暴露,当最新用户消息有歧义时。清晰用户语言仍优先;中文回合应产生中文 `reasoning_content` 和中文最终回复,即使解析出的区域设置是英语。
959 - `background_color`(`#RRGGBB`、`RRGGBB` 或 `default`):可选的主 TUI 背景色,应用于根、头部、转录和底部表面,同时保留面板对比。
960 - `cost_currency`(`usd`、`cny`;默认 `usd`):底部栏、上下文面板、`/cost`、`/tokens` 和长回合通知摘要使用的货币。别名 `rmb` 和 `yuan` 规范化为 `cny`。
961 - `default_mode`(`agent`、`plan` 或 `operate`;旧值为了迁移被接受,但不是活动模式词汇)
962 - `launch_screen`(`on`/`off`;默认 `off`):显示会话前的 Work/Chat/Resume/Worktree 菜单。Work 在配置的审批策略下使用当前文件夹;Chat 开始只读对话。启动屏幕关闭时,Codewhale 直接进入新会话;resume 在会话内保持可用。
963 - `sidebar_focus`(旧版,仅迁移):这个键配置的经典右侧栏已在 0.9.4 rail 统一中移除。该键仍被读取一次,让旧设置向前迁移,然后折叠进实时键:`pinned`/`work`/`plan`/`todos` 变成 `rail_panel = "pinned"`,`agents`/`subagents` 变成 `rail_panel = "agents"`,`context`/`session` 变成 `rail_panel = "context"`,`tasks`/`auto`(旧默认)变成 `tasks` 面板,`sessions` 启用 `sessions_rail`,`hidden` 通过 `work_surface_placement = "off"` 关闭工作栏。文件中的显式 `rail_panel` 总是胜过迁移值。用 `rail_panel` 和 `work_surface_placement` 配置工作栏,不要用这个键。
964 - `sessions_rail`(`on`/`off`;默认 `off`):在侧栏面板栈中显示持久 Sessions rail。行列出该工作区最近的未归档会话,新的在前,活动的标记;激活一行会打开预选它的会话选择器(`/sessions open <id>`),所以 resume 保持单一实现。行从缓存会话元数据投影——rail 从不逐帧读取转录,从不联系 provider。
965 - `session_auto_resume`(`on`/`off`;默认 `off`):Codewhale 启动时重新附加到该工作区最近的会话。默认关闭,所以普通的 `codewhale` 保持全新启动。`--resume`、`--continue` 和 `--fresh` 总是优先。开启时,启动仍拒绝恢复已归档、加载失败或记录在另一个工作区的会话;每个都回退到全新转录,并说明跳过了哪个会话及原因。它只适用于交互式启动——`codewhale "<prompt>"` 和 `codewhale exec` 从不被静默加上先前对话前缀。
966 - `max_input_history`(已提交输入历史条目数;清除的草稿也保留在本地供输入区历史搜索)。注意拼写:磁盘上的 serde 字段是 `max_input_history`(`crates/tui/src/settings.rs:426`,默认 100)。`max_history` 是 `/config set` 和 `settings.set()`(`settings.rs:1388`)接受的键名,不是 settings.toml 键——把 `max_history` 写进文件会被静默忽略。
967 - `default_model`(模型名覆盖)
968
969 `/task digest`(别名 `/tasks digest`)以纯文本渲染规范的 Work Graph 操作和四状态待办列表,运行中的工作优先。它读取与样式化 Work 面相同的快照,不拥有并行的进度状态。
970
971 Plan 和 Act 是 UI 中的日常可见模式;Operate 是显式预览入口,其 Workflow 控制面仍在构建中。用 `/mode` 切换。为了兼容,较旧设置文件中的 `default_mode = "normal"` 仍作为 `agent` 加载。
972
973 本地化范围在 [LOCALIZATION.md](../LOCALIZATION.md) 中跟踪。v0.7.6 核心包只覆盖高可见性 TUI chrome;provider/工具 schema、个性提示和完整文档保持英语,除非之后显式翻译。
974
975 可读性语义:
976
977 - 选择在转录、输入区菜单和模态框中使用统一样式。
978 - 底部提示使用专用语义角色(`FOOTER_HINT`),这样提示文本跨主题保持可读。
979
980 ### Token 数量与驱动项
981
982 DeepSeek V4 前缀缓存让 token 标签变得重要。这些数量保持分离:
983
984 | 数量 | 含义 | 允许驱动 |
985 |---|---|---|
986 | 活动请求输入估算 | 下一个请求实时系统提示和转录负载的保守估算。 | 头部/底部上下文百分比、自动压缩触发、选择加入 Flash seam 触发、紧急溢出预检。 |
987 | 预留响应裕量 | 每条路由上的有效请求上限加 `1024` 安全 token。常规无覆盖请求从 `65536` 开始;更小的路由/provider 上限收窄该值,显式输出覆盖只在解析后的路由窗口和输出上限内提高它。同一上限到达线路并驱动预检;推理努力不会增加第二个隐藏预留。单独发布的路由输入上限独立钳制可花费输入预算。 | 仅紧急溢出预算检查。 |
988 | 累计 API 用量 | provider 报告的输入加输出 token 跨已完成 API 调用求和;多工具回合可能多次计入同一稳定前缀。 | 仅会话用量和近似成本遥测。 |
989 | 提示缓存命中/未命中 | 可用时最近一次调用的 provider 缓存遥测。 | 仅缓存命中显示和成本估算;从不触发压缩或 seam。 |
990 | 上下文百分比 | 活动请求输入估算除以模型上下文窗口。 | 仅显示;它镜像上下文防护所用的活动输入基础。 |
991 | 成本估算 | 来自 provider 用量和已配置 DeepSeek 费率的近似花费。 | 仅显示。 |
992
993 对于已知上下文窗口的模型(包括 1M 类 V4 模型),替换式压缩默认启用,除非用户显式配置 `auto_compact = false`。它在活动模型的压缩阈值触发,用最近的用户上下文加一条普通检查点消息替换旧历史。常驻系统提示保持不变。未知模型 id 保持选择加入。
994
995 ### 命令迁移说明
996
997 如果你从更旧的版本升级:
998
999 - 旧:`/codewhale` 新:`/links`(别名:`/dashboard`、`/api`)
1000 - 旧:`/set model deepseek-reasoner` 新:`/config` 并把 `model` 行编辑为 `deepseek-v4-pro` 或 `deepseek-v4-flash`
1001 - 旧:可见 `Normal` 模式或 `default_mode = "normal"` 新:使用 `Agent` / `default_mode = "agent"`;旧 `normal` 仍映射到 `agent`
1002 - 旧:在斜杠 UX/帮助中发现 `/set` 新:编辑用 `/config`,只读检查用 `/settings`
1003
1004 ## 键参考(Key Reference)
1005
1006 ### Kimi Code 会员模型 ID
1007
1008 精确的 `https://api.kimi.com/coding/v1` 端点接受 `k3`、`k3-256k`、`kimi-for-coding` 和 `kimi-for-coding-highspeed`。用 `k3-256k` 获得固定的 262,144-token K3 窗口;只有在会员计划包含 1M 资格(entitlement)时才用裸 `k3` 搭配 `context_window = 1048576`。两个 K3 id 使用相同的推理契约,且四个会员 id 都省略通用采样字段。
1009
1010 ### 核心键(供 TUI/引擎使用)
1011
1012 - `provider`(字符串,可选):`deepseek`(默认)、`deepseek-anthropic`、`nvidia-nim`、`openai`、`atlascloud`、`wanjie-ark`、`volcengine`、`openrouter`、`xiaomi-mimo`、`novita`、`fireworks`、`siliconflow`、`arcee`、`siliconflow-CN`、`moonshot`、`sglang`、`vllm`、`ollama`、`ollama-cloud`、`huggingface`、`modelscope`、`together`、`qianfan`、`openai-codex`、`anthropic`、`openmodel`、`zai`、`stepfun`、`minimax`、`deepinfra`、`sakana`、`longcat`、`opencode-go`、`meta`、`mistral`、`telecomjs`、`xai`、`orcarouter`、`modelstudio-token-plan`、`google`、`antigravity`、`edenai` 或 `custom`。旧 `deepseek-cn` 配置仍作为 `deepseek` 的别名被接受;DeepSeek 在全球使用同一个官方主机 [`https://api.deepseek.com`](https://api-docs.deepseek.com/)。`deepseek-anthropic` 使用 `DEEPSEEK_API_KEY` 指向 DeepSeek 的 Anthropic Messages 兼容端点 `https://api.deepseek.com/anthropic`;`nvidia-nim` 通过 `https://integrate.api.nvidia.com/v1` 指向 NVIDIA NIM 托管的 DeepSeek 端点;`openai` 指向通用 OpenAI 兼容端点,默认 `https://api.openai.com/v1`;`atlascloud` 指向 AtlasCloud 的 OpenAI 兼容端点 `https://api.atlascloud.ai/v1`;`wanjie-ark` 指向 Wanjie Ark 的 OpenAI 兼容端点 `https://maas-openapi.wanjiedata.com/api/v1`;`volcengine` 指向火山方舟(Volcengine Ark)的 OpenAI 兼容编码端点 `https://ark.cn-beijing.volces.com/api/coding/v3`;`openrouter` 指向 `https://openrouter.ai/api/v1`;`xiaomi-mimo` 指向小米 MiMo 的 OpenAI 兼容端点,Token Plan key(`tp-...`)默认用 `https://token-plan-sgp.xiaomimimo.com/v1`,按量付费 key 用 `https://api.xiaomimimo.com/v1`。对于新加坡默认之外的 Token Plan 账号,显式设置 `base_url` 或对中国的账号用 `mode = "token-plan-cn"`,对欧洲/阿姆斯特丹用 `mode = "token-plan-ams"`;`novita` 指向 `https://api.novita.ai/openai/v1`;`fireworks` 指向 `https://api.fireworks.ai/inference/v1`;`siliconflow` 指向 SiliconFlow,默认 `https://api.siliconflow.com/v1`;`arcee` 指向 Arcee AI 的 OpenAI 兼容端点 `https://api.arcee.ai/api/v1`;`siliconflow-CN` 通过 `[providers.siliconflow_cn]` 指向 SiliconFlow 中国区域端点;`moonshot` 指向 Moonshot/Kimi,默认 `https://api.moonshot.ai/v1`;`sglang` 指向自托管 OpenAI 兼容端点,默认 `http://localhost:30000/v1`;`vllm` 指向自托管 vLLM OpenAI 兼容端点,默认 `http://localhost:8000/v1`;`ollama` 指向 Ollama 的 OpenAI 兼容端点,默认 `http://localhost:11434/v1`;`huggingface` 指向 Hugging Face Inference Providers `https://router.huggingface.co/v1`;`modelscope` 指向魔搭社区的 OpenAI 兼容推理 API `https://api-inference.modelscope.cn/v1`;`together` 指向 Together AI `https://api.together.xyz/v1`;`qianfan` 指向百度千帆 `https://api.baiduqianfan.ai/v1`;`openai-codex` 指向 ChatGPT/Codex OAuth;`anthropic` 指向 Claude 的原生 Messages API;`openmodel` 指向 OpenModel 的 Anthropic 兼容 Messages API `https://api.openmodel.ai`;`zai` 指向 Z.ai `https://api.z.ai/api/coding/paas/v4`;`stepfun` 指向 StepFun `https://api.stepfun.ai/v1`;`minimax` 指向 MiniMax `https://api.minimax.io/v1`;`deepinfra` 指向 DeepInfra `https://api.deepinfra.com/v1/openai`;`sakana` 指向 Sakana AI Fugu `https://api.sakana.ai/v1`;`longcat` 指向美团 LongCat `https://api.longcat.chat/openai/v1`;`opencode-go` 指向订阅支撑的 OpenCode Go Chat Completions 路由 `https://opencode.ai/zen/go/v1`;`meta` 指向 Meta Model API;`mistral` 指向 Mistral AI 的 OpenAI 兼容端点 `https://api.mistral.ai/v1`;`telecomjs` 指向 TelecomJS TokenHub `https://aigw.telecomjs.com/v1`;`xai` 指向 xAI 的 API key 或 OAuth 路由。
1013 - `opencode-zen`(字符串 provider 值):通过 `[providers.opencode_zen]` 选择模型感知的 OpenCode Zen 网关。默认 base URL 是 `https://opencode.ai/zen/v1`,默认模型 `gpt-5.6`,凭据来自 `api_key`、`OPENCODE_ZEN_API_KEY` 或回退 `OPENCODE_API_KEY`——绝不是 ChatGPT/Codex OAuth。接受 `OPENCODE_ZEN_BASE_URL` 和 `OPENCODE_ZEN_MODEL`。所选模型通过精选的 Zen 目录解析:GPT 用 Responses,Claude/Qwen 用 Anthropic Messages,记录的 DeepSeek/MiniMax/GLM/Kimi/Grok/free 行用 Chat Completions。Gemini 和未知模型失败关闭,因为 Codewhale 对它们没有经过验证的受支持线契约。确切当前模型组见 [`PROVIDERS.md`](PROVIDERS.md#opencode-zen-protocol-catalog)。
1014 - `minimax-anthropic`(字符串 provider 值):通过 `[providers.minimax_anthropic]` 选择 MiniMax 的 Anthropic 兼容 Messages 路由。默认 Base URL 是 `https://api.minimax.io/anthropic`;中国区域设置 `https://api.minimaxi.com/anthropic`。保留 `/anthropic` 后缀,因为 Codewhale 会追加 `/v1/messages`。该路由使用 `MINIMAX_API_KEY`,默认 `MiniMax-M3`;`MiniMax-M2.7` 也已注册。官方 M3 输入模态是文本、图像和视频,带自适应或禁用思考。M2.7 仅文本,总是保持思考启用。
1015 - `api_key`(字符串,托管 provider 必填):对 DeepSeek/托管 provider 必须非空(或设置 provider API key 环境变量)。自托管 SGLang、vLLM 和本地 `ollama` 可省略。`ollama-cloud` 需要为该 provider 保存的密钥或由 `OLLAMA_CLOUD_API_KEY` 提供,然后 `OLLAMA_API_KEY`。
1016 - `auth_mode`(字符串,可选的 provider 表键):选择 provider 特有的认证契约。Kimi Code 会员使用 `auth_mode = "api_key"`(或省略该字段),在 [Kimi Code 控制台](https://www.kimi.com/code/console) 创建的 key,`base_url = "https://api.kimi.com/coding/v1"`,K3 用裸 `model = "k3"`。Codewhale 给该路由安全的 262,144-token 基线;只有 Kimi Code 计划包含 1M 访问(Allegretto 及以上)时才设置 `context_window = 1048576`。`k3[1m]` 是仅 Claude Code 的约定,不是 API 模型 ID,Codewhale 会拒绝它,而不是静默改变线模型或假定资格。`model = "kimi-for-coding"` 仍是所有 Kimi Code 会员可用的有效 K2.7 兼容路由。旧 `auth_mode = "kimi_oauth"` 以 API key 指引失败关闭,从不探测、读取、刷新或重写 `kimi_cli`/`kimi_code_cli` 凭据文件。一等 OAuth 需要 Codewhale 自己的厂商注册客户端身份,仍在 #4417 跟踪。
1017 - `base_url`(字符串,可选):DeepSeek 的 OpenAI 兼容 Chat Completions API 默认 `https://api.deepseek.com/beta`,包括旧 `provider = "deepseek-cn"` 配置。其他默认:`deepseek-anthropic` 是 `https://api.deepseek.com/anthropic`,`nvidia-nim` 是 `https://integrate.api.nvidia.com/v1`,`openai` 是 `https://api.openai.com/v1`,`atlascloud` 是 `https://api.atlascloud.ai/v1`,`wanjie-ark` 是 `https://maas-openapi.wanjiedata.com/api/v1`,`volcengine` 是 `https://ark.cn-beijing.volces.com/api/coding/v3`,`openrouter` 是 `https://openrouter.ai/api/v1`,`xiaomi-mimo` 在 API key 以 `tp-...` 开头时是 `https://token-plan-sgp.xiaomimimo.com/v1`,否则 `https://api.xiaomimimo.com/v1`,`novita` 是 `https://api.novita.ai/openai/v1`,`fireworks` 是 `https://api.fireworks.ai/inference/v1`,`siliconflow` 是 `https://api.siliconflow.com/v1`,`siliconflow-CN` 是 `https://api.siliconflow.cn/v1`,`arcee` 是 `https://api.arcee.ai/api/v1`,`moonshot` 是 `https://api.moonshot.ai/v1`,`minimax` 是 `https://api.minimax.io/v1`,`openmodel` 是 `https://api.openmodel.ai`,`zai` 是 `https://api.z.ai/api/coding/paas/v4`,`stepfun` 是 `https://api.stepfun.ai/v1`,`deepinfra` 是 `https://api.deepinfra.com/v1/openai`,`sakana` 是 `https://api.sakana.ai/v1`,`huggingface` 是 `https://router.huggingface.co/v1`,`modelscope` 是 `https://api-inference.modelscope.cn/v1`,`together` 是 `https://api.together.xyz/v1`,`qianfan` 是 `https://api.baiduqianfan.ai/v1`,`openai-codex` 是 `https://chatgpt.com/backend-api`,`anthropic` 是 `https://api.anthropic.com`,`mistral` 是 `https://api.mistral.ai/v1`,`sglang` 是 `http://localhost:30000/v1`,`vllm` 是 `http://localhost:8000/v1`,`ollama` 是 `http://localhost:11434/v1`,`ollama-cloud` 是 `https://ollama.com/v1`。中国区域小米 MiMo Token Plan 账号设置 `base_url = "https://token-plan-cn.xiaomimimo.com/v1"`,欧洲/阿姆斯特丹账号设置 `base_url = "https://token-plan-ams.xiaomimimo.com/v1"`。Mistral 特有的推理字段和多态重放只在记录的官方 HTTPS `/v1` 主机上启用;自定义 Mistral base URL 保持通用 Chat 语义。显式设置 `https://api.deepseek.com` 或 `https://api.deepseek.com/v1` 可选择退出 DeepSeek beta 功能。
1018 - `ollama-cloud` 路由:选择 `provider = "ollama-cloud"`,覆盖默认 `https://ollama.com/v1` / `gpt-oss:120b` 元组时配置 `[providers.ollama_cloud]`,并用 `codewhale auth set --provider ollama-cloud` 从 [Ollama 账号设置](https://ollama.com/settings/keys) 保存 key。环境优先级是 `OLLAMA_CLOUD_API_KEY`,然后 `OLLAMA_API_KEY`;任意 Ollama 模型 ID 原样透传。
1019 - 旧 Ollama Cloud 迁移:规范化的 `[providers.ollama].base_url` 恰好是 `https://ollama.com/v1` 的已发布 `provider = "ollama"` 配置,会在内存中升级为 `ollama-cloud` 运行时身份。只有那个确切元组可以读取其旧的 `ollama` provider 表和秘密槽位。配置和秘密从不被重写,相邻路径、HTTP 降级、仿冒主机或显式 `ollama-cloud` 选择从不消费该回退。
1020 - `telecomjs` base URL 与目录:`[providers.telecomjs]` 默认 `https://aigw.telecomjs.com/v1`;`TELECOMJS_BASE_URL` 覆盖它。有 `TELECOMJS_API_KEY` 时,`/models` 刷新 key 作用域的目录,而不会把行混入另一个 provider。
1021 - `edenai` 网关:选择 `provider = "edenai"`;`[providers.edenai]` 默认 `https://api.edenai.run/v3` 和 `deepseek/deepseek-v4-pro`。接受 `EDENAI_API_KEY`、`EDENAI_BASE_URL` 和 `EDENAI_MODEL`。Eden AI 记录的欧盟端点用 `EDENAI_BASE_URL = "https://api.eu.edenai.run/v3"`;默认 `deepseek/deepseek-v4-pro` 只列在全局目录中,所以把欧盟端点与欧盟列表中的模型(如通过 `EDENAI_MODEL` 或 `model` 的 `qwen/deepseek-v4-pro`)配对。该 provider 刷新 Eden AI 的 `/models` 目录,但保留模型特有的推理控制不动,因为网关横跨多个模型家族。
1022 - `mistral` 模型与推理契约:`[providers.mistral]` 默认 `mistral-code-latest`;`MISTRAL_MODEL` 覆盖它,两者都设置时通用 `CODEWHALE_MODEL` 覆盖胜出。当前选择器还列出 `mistral-medium-latest`、`mistral-small-latest` 和 `mistral-large-latest`。在确切的官方 HTTPS `/v1` 路由上,Medium 和 Small 只接受 `reasoning_effort = "none" | "high"` 并重放多态思考块。弃用的原生 Magistral ID 仍可显式配置,保持始终推理,绝不接收可调努力字段。
1023 - `context_window`(整数,可选的 provider 表键):当 OpenAI 兼容网关、托管模型别名或自托管运行时的上限与 Codewhale 的静态模型表不同时,覆盖活动 `[providers.<name>]` 路由的总上下文窗口。例如,`[providers.openai] context_window = 1000000` 让 OpenAI 兼容的 DashScope/Qwen 路由按 1M-token 窗口做预算,而不是保守回退。对 Kimi Code K3,保持 `model = "k3"`,只在会员计划包含 1M 访问时设置 `[providers.moonshot] context_window = 1048576`;否则省略它,以保留 262,144-token 安全基线。该值必须大于 0,影响提示上下文备注、压缩阈值、上下文压力检查和请求输出上限。完整解析顺序,以及如何看到哪一级产生了当前窗口:[上下文长度(context window)](#上下文长度context-window)。
1024 - `path_suffix`(字符串,可选的 provider 表键):覆盖不为 `/v1/chat/completions` 服务的 OpenAI 兼容网关的聊天补全路径。例如,`[providers.openai] path_suffix = "/chat/completions"` 把聊天请求发送到未版本化的 base URL 加 `/chat/completions`;`models` 和 `beta/*` 请求保持正常路由。
1025 - `reasoning_stream_style`(字符串,可选的 provider 表键):覆盖活动 provider 路由如何把流式推理与答案文本分开。用 `separate_field` 处理 `reasoning_content` / `reasoning` 增量,`inline_tags` 用于在 `delta.content` 内流式 `<think>...</think>` 的网关,`none` 则把传入内容完全按答案文本渲染。
1026 - `[providers.<name>.auth]`(表,可选):provider 作用域的认证源元数据。`source = "command"` 存储命令 argv 加可选 `timeout_ms`;`source = "secret"` 存储 `secret_id`。这个切片让 provider 就绪、`/provider` 和 doctor JSON 报告认证源类别,而不暴露命令 argv 输出或秘密值;执行命令和解析外部秘密材料由后续的解析器工作处理。
1027 - `insecure_skip_tls_verify`(bool,可选的 provider 表键):旧兼容键,默认禁用。活动 provider 表上为 true 时,provider 客户端拒绝该配置,而不是跳过 TLS 证书验证。企业或私有 CA 包用 `SSL_CERT_FILE`;`codewhale doctor` 报告此设置的过期使用。
1028 - `default_text_model`(字符串,可选):DeepSeek 和 `deepseek-anthropic` 默认 `deepseek-v4-pro`,OpenAI 是 `gpt-5.6`,xAI 是 `grok-4.6`,NVIDIA NIM 是 `deepseek-ai/deepseek-v4-pro`,AtlasCloud 是 `deepseek-ai/deepseek-v4-flash`,Wanjie Ark 是 `deepseek-reasoner`,火山方舟是 `DeepSeek-V4-Pro`,OpenRouter 和 Novita 是 `deepseek/deepseek-v4-pro`,小米 MiMo 是 `mimo-v2.5-pro`,Fireworks 是 `accounts/fireworks/models/deepseek-v4-pro`,SiliconFlow 和 DeepInfra 是 `deepseek-ai/DeepSeek-V4-Pro`,Arcee AI 是 `trinity-large-thinking`,Moonshot 是 `kimi-k2.7-code`,MiniMax 是 `MiniMax-M3`,Z.ai 是 `GLM-5.3`,StepFun 是 `step-3.7-flash`,千帆是 `ernie-4.0-turbo-8k`,Sakana AI 是 `fugu`,SGLang/vLLM 是 `deepseek-ai/DeepSeek-V4-Pro`,本地 Ollama 是 `deepseek-v4-flash`,Ollama Cloud 是 `gpt-oss:120b`。Hugging Face 和 Together AI 都默认 `deepseek-ai/DeepSeek-V4-Pro`;`openai-codex` 默认 `gpt-5.6`;`anthropic` 默认 `claude-sonnet-4-6`;`openmodel` 默认 `deepseek-v4-flash`。当前公开 DeepSeek ID 是 `deepseek-v4-pro` 和 `deepseek-v4-flash`,两者都是 1M 上下文窗口、384K 最大输出、默认启用思考模式。DeepSeek 的实时定价/模型页现在把 Pro 后端标为 `DeepSeek-V4-Pro-0813`;可调用的 API ID 仍是 `deepseek-v4-pro`,所以 Codewhale 不发送后端标签或 Claude Code 特有的 `deepseek-v4-pro[1m]` 选择器。DeepSeek 于 2026 年 7 月 24 日退役 `deepseek-chat` 和 `deepseek-reasoner`;直接官方路由把两者迁移到 `deepseek-v4-flash`,省略的推理设置保留它们之前的不思考(`off`)和思考(`high`)意图。显式 `reasoning_effort` 胜出,Wanjie Ark、聚合器、自托管运行时和自定义端点上的 provider 自有 id 不会全局重写。SiliconFlow 保留自己的映射:`deepseek-reasoner` 和 `deepseek-r1` 选择其 Pro 模型,而 `deepseek-chat` 和 `deepseek-v3` 选择 Flash。Provider 特有映射在受支持处把 `deepseek-v4-pro` / `deepseek-v4-flash` 翻译成每个 provider 的模型 ID。OpenRouter 还识别最近的较大 ID,如 `arcee-ai/trinity-large-thinking`、`minimax/minimax-m3`、`minimax/minimax-m2.7`、`xiaomi/mimo-v2.5-pro`、`qwen/qwen3.6-flash`、`qwen/qwen3.6-35b-a3b`、`qwen/qwen3.6-max-preview`、`qwen/qwen3.6-27b`、`qwen/qwen3.6-plus`、`qwen/qwen3.7-max`、`google/gemma-4-31b-it`、`moonshotai/kimi-k2.7-code`、`moonshotai/kimi-k2.6`、`nvidia/nemotron-3-nano-omni-30b-a3b-reasoning:free` 和 `nvidia/nemotron-3-ultra-550b-a55b`;直接 Arcee 用 `trinity-large-thinking` 和 `trinity-large-preview` 这样的裸 ID;直接 Moonshot 识别 `kimi-k3`、`kimi-k2.7-code` 和 `kimi-k2.6`。确切的 Kimi Code 端点识别 K3 的裸 `k3` 和 K2.7 的 `kimi-for-coding`;这些会员 ID 与直接 Moonshot ID 不同,从不跨路由重写。直接 MiniMax 识别 `MiniMax-M3` 和记录的 M2.x 聊天模型 ID;直接 Z.ai 识别 `GLM-5.3`(默认)、`GLM-5.2`、`GLM-5.1` 和 `GLM-5-Turbo`,OpenRouter 识别匹配的 `z-ai/glm-5.1`、`z-ai/glm-5.2`、`z-ai/glm-5.3` 和 `z-ai/glm-5-turbo` ID——`GLM-5.3` 自 2026-08-13 起在 Z.ai Coding Plan 上线;它从 `GLM-5.2` 继承其目录元数据,直到 Z.ai 发布不同的 5.3 数字,不携带价格,显式 `GLM-5.2` 选择保持自己的 id;直接 Sakana 识别 `fugu` 和 `fugu-ultra-20260615`;直接小米 MiMo 识别聊天 ID `mimo-v2.5-pro`、`mimo-v2.5-pro-ultraspeed` 和 `mimo-v2.5`,而 TTS ID 通过 `codewhale speech` / `tts` 选择。通用 `openai`、`atlascloud`、`wanjie-ark`、`xiaomi-mimo`、`arcee`、`moonshot`、`minimax`、`openmodel`、`zai`、`stepfun`、`qianfan`、`sakana`、本地 Ollama 和 Ollama Cloud 模型 ID 在已知别名规范化后原样透传。带自定义 `base_url` 的 OpenRouter 和 SiliconFlow provider 配置也保留显式模型值,这让 OpenAI 兼容网关能接受裸模型 ID。用 `/models` 或 `codewhale models` 从你的配置端点发现实时 ID。`CODEWHALE_MODEL` 为单个进程覆盖它;`DEEPSEEK_MODEL` 是旧别名。
1029 - TelecomJS 只把 `deepseek-v4-pro` 用作刷新前的保守回退。其 key 作用域 `/models` 目录可用后,选择器使用那些实时行;Codewhale 在该路由上省略不支持的推理请求字段。
1030 - `reasoning_effort`(字符串,可选):`off`、`low`、`medium`、`high`、`max`、`xhigh` 或 `ultracode`;默认已配置的 UI 层级。DeepSeek Platform 收到顶层 `thinking` / `reasoning_effort` 字段。Ollama Cloud 的 OpenAI 兼容 Chat Completions 路由保留其记录的 `none` / `low` / `medium` / `high` / `max` 阶梯(`off` 作为 `none` 发送;`xhigh` 和 `ultracode` 规范化为 `max`)。确切 `https://api.x.ai/v1` 上的直接 xAI `grok-4.6` 收到顶层 `reasoning_effort = "low" | "medium" | "high" | "xhigh"`;`off` 规范化为 `high`,`max`/`ultracode` 为 `xhigh`,`auto` 让字段省略,这样 xAI 记录的默认 `high` 生效。自定义 xAI 兼容 `base_url` 不继承该方言。确切 `https://api.moonshot.ai/v1` 上的直接 Moonshot `kimi-k3` 始终思考,只收到顶层 `reasoning_effort = "low" | "high" | "max"`;`off` 规范化为 `low`,`medium` 为 `high`。确切 `https://api.kimi.com/coding/v1` 上的 Kimi Code 会员 `k3` 改为收到嵌套 `thinking.effort`,其 `off` 设置也规范化为启用的 `low`。常规调度 `auto` 使用 Codewhale 的自动推理选择器,发送具体的路由规范化层级;只有省略推理设置时才让 provider 默认值控制。相邻网关和模型/端点组合保留通用 Moonshot 契约。OpenAI Codex 把过期 `off` 规范化为 `low`,把 `max` / `ultracode` 作为 Responses `xhigh` 发送。Z.ai 收到记录的 `thinking` 控制,把启用思考视为 GLM coding high/max 通道。NVIDIA NIM 通过 `chat_template_kwargs` 收到等效设置。
1031 - `verbosity`(字符串,可选):`normal` 或 `concise`。`normal` 保持默认的对话式提示。`concise` 追加一块提示纪律,用于直接、少废话的输出;CLI 非交互命令(`exec` 和 `eval`)默认 `concise`,除非 config/环境/CLI 覆盖它。用 `CODEWHALE_VERBOSITY` 或旧别名 `DEEPSEEK_VERBOSITY` 按进程覆盖。
1032 - `telemetry`(bool,可选):当前 0.9.12 源码中匿名使用计数**默认 `true`**。第 `5` 版告知列明 Codewhale 和 PostHog,说明默认开启且可退出;不会代替用户记录同意。此前明确退出的选择继续有效。这里的 `false` 是持久退出:删除随机安装 id、清空缓冲和 dry-run 记录并写入持续生效的 tombstone,优先于命令行或环境中的 `true`。在 `/settings` 中明确重新开启,或执行 `codewhale config set telemetry true`,会更新现有偏好和隐私记录,供新会话使用。`CODEWHALE_TELEMETRY=0`(旧别名 `DEEPSEEK_TELEMETRY`)或 `--telemetry false` 只关闭本次运行而不擦除用户状态。仓库本地配置不能修改这个偏好。`codewhale config telemetry` 显示告知,`codewhale config get telemetry` 报告偏好和隐私状态。完整 schema 和退出规则:[`TELEMETRY.md`](TELEMETRY.md)。
1033 - `telemetry_endpoint`(字符串,可选):批次 POST 到哪。保持未设置会选择随附默认 **`https://telemetry.codewhale.net/v1/telemetry`**——[`TELEMETRY.md`](TELEMETRY.md) 中描述的第一方接入服务,其源码在 `telemetry-ingest/`。这个键只决定*被允许的会话*发送到哪里;它不能覆盖选择退出。把它设为**空字符串**是保持启用且不联系任何人的方式:每个批次随后写入 `$CODEWHALE_HOME/telemetry/dryrun.jsonl`,完全不构造 HTTP 客户端,所以你可以读到原本会发送的确切内容。任何其他值直接替换默认值。要求 `https://`;普通 `http://` 只对 loopback 主机接受,并且没有环境变量可以覆盖该拒绝。被拒绝的端点会让遥测在本次运行关闭,而不是回退到明文或默认值。用 `CODEWHALE_TELEMETRY_ENDPOINT`(旧别名 `DEEPSEEK_TELEMETRY_ENDPOINT`)按进程覆盖,其中空值意味着同样的"不联系任何人"。仓库本地的 `.codewhale/config.toml` 不能设置它。
1034 - `allow_shell`(bool,可选):在交互式 TUI Agent 会话中,省略它会保持 shell 工具可用但带审批提示;设为 `false` 会隐藏 shell 工具。无头、持久任务和其他非交互 profiles 保持保守的省略字段默认,需要 `allow_shell = true` 才暴露 shell。Plan 模式总是隐藏 shell;Full Access 启用 shell 和自动批准。
1035 - `approval_policy`(字符串,可选):`on-request`、`untrusted` 或 `never`。`/config` 中的运行时 `approval_mode` 编辑也接受 `on-request` 和 `untrusted` 别名。
1036 - `[approval] default_selection`(字符串,可选):审批卡片首次出现时高亮哪个选项——`deny`(默认)或 `allow_once`。`deny` 意味着在没读过的卡片上反射性按 Enter 会拒绝调用。设置 `allow_once` 恢复 v0.9.6 之前的 Enter 即批准肌肉记忆(#5293)。它只移动高亮:哪些调用会被提示仍由 `approval_policy` 加 `permissions.toml` 中的规则决定。
1037
1038 ```toml
1039 [approval]
1040 default_selection = "allow_once"
1041 ```
1042 - `sandbox_mode`(字符串,可选):`read-only`、`workspace-write`、`danger-full-access`、`external-sandbox`。平台支持不完全相同。macOS 在其运行时探测成功时使用 Seatbelt。Linux 只在 `prefer_bwrap = true` 且 `/usr/bin/bwrap` 可执行时使用 bubblewrap;没有该选择加入时,它报告无 OS 命令沙箱。Windows 目前不宣传 OS 沙箱;其计划中的辅助程序契约从进程树包含开始,在实现之前不得被描述为只读文件系统隔离、workspace-write 强制、网络阻断、注册表隔离或 AppContainer 隔离。
1043 - 模式准入、hooks、注册工具要求、类型化规则、自动审查、仓库法、人工审批和执行沙箱之间的跨层关系定义在[授权顺序](../AUTHORIZATION_ORDER.md)。
1044 - `permissions.toml`(同级文件,可选):与 `config.toml` 相邻加载的类型化权限规则记录,例如 `~/.codewhale/permissions.toml`。这个活动用户文件是今天唯一的权限规则来源;项目配置覆盖不加载项目本地的 `permissions.toml`。规则的 `workspace` 可选字段是它的仓库作用域,不是第二个来源。手工编写的 `[[rules]]` 条目接受 `tool`、可选 `command` 或 `path`、可选绝对 `workspace`、可选 `command_exact = true` 和可选 `action = "deny" | "ask" | "allow"`;省略 `action` 默认 `"ask"`。`workspace` 把规则限制到该仓库,而 `command_exact = true` 把命令规则从历史的 arity 感知前缀匹配改为完整命令匹配。`deny` 在基于模式的审批处理之前阻止匹配调用,`allow` 跳过匹配调用的审批,`ask` 只在可以提示的模式中强制审批。在 TUI 自动批准路径之外,`approval_policy = "never"` 下匹配的 `ask` 规则被拒绝,因为没有提示可显示。在 Full Access / 自动批准会话中,`ask` 规则不会将会话降级为提示或阻断;显式 `deny` 规则仍按当前执行策略逻辑阻断。
1045
1046 在受支持的审批卡片中,按 `S` 允许该请求一次,并把精确的 `action = "ask"` 规则追加到这个文件。对于符合条件的安全请求,选择**始终允许本仓库中的这条确切规则**(快捷键 `P`)来追加带当前绝对 `workspace` 作用域的 `action = "allow"` 规则。记住的 shell 授予设置 `command_exact = true`,所以之后带额外参数的命令不会继承该授予。文件和补丁授予保留现有验证路径产生的精确工作区相对路径。受支持的保存刻意很窄:`exec_shell` 存储确切批准的命令字符串;`write_file` 和 `edit_file` 存储确切工作区相对文件路径;`apply_patch` 为 apply-patch 预检验证过的每个触碰文件存储一条确切的工作区相对 `path` 规则。现有 exec 命令匹配对手工编写的前缀规则保持 arity 感知;审批卡片允许授予使用完整命令匹配。文件路径规范化为运行时匹配使用的同一工作区相对形式。
1047
1048 `read_file` 规则仍可手工编写,当你希望未来对特定路径的读取询问、允许或拒绝时,但审批 UI 不保存 `read_file` 规则。被分类为需要审批或危险的命令、关键审批卡片和仓库法提示不能保存允许授予,继续需要审查。
1049
1050 `/permissions`(或 `/permissions list`)是窄规则管理面。它列出每个编号规则,带活动用户文件来源、确切有效匹配器(工具级、命令前缀、确切命令或确切规范化路径)、全局或仓库作用域,以及该作用域是否在当前工作区应用。`/config ask-rules` 仍是同一列表的兼容入口。
1051
1052 删除受审查门控:`/permissions remove <number>` 只预览所选规则并打印一条确认命令。该命令携带绑定到确切文件字节和规则索引的不透明 token;如果另一个写入者改变了 `permissions.toml`,确认会失败,而不是删除移入旧位置的规则。确认删除和审批卡片追加共享相邻的 `permissions.toml.lock`,保留不相关的 TOML 注释和格式,并原子替换文件。运行中的 TUI 重新加载用户规则集,不清除会话仅有的批准。
1053
1054 这个编辑器刻意不创建或重写规则、不持久化审批卡片的拒绝选择、不展开 glob、不创建宽泛的目录/递归规则。需要时手工编写那些受支持的确切/前缀记录。
1055 - `[[hotbar]]`(表数组,可选):TUI 热栏的用户自有 1-8 槽位绑定。每个条目有 `slot`、`action` 和可选 `label`。省略 `hotbar` 使用内置默认八个槽位。设置 `hotbar = []` 禁用所有默认槽位。存在一个或多个 `[[hotbar]]` 表时,该列表替换默认值;缺失槽位保持空。`1..=8` 之外的无效槽位带警告跳过,重复槽位用后一条目,未知动作 ID 被保留,这样 UI 能显示禁用/未知单元格,而不是静默删除用户配置。受信任用户配置、profiles 和受管配置替换整个列表;项目覆盖不能改变热栏绑定。持久化热栏绑定的 Setup 或向导流程把同一 schema 写入解析出的 `~/.codewhale/config.toml` 路径,只在那个回退文件已是活动配置时保留旧 `~/.deepseek/config.toml`。
1056
1057 ```toml
1058 [[hotbar]]
1059 slot = 1
1060 action = "mode.plan"
1061 label = "Plan"
1062
1063 [[hotbar]]
1064 slot = 2
1065 action = "session.compact"
1066 ```
1067 - `[auto_review]`(表,可选):工具调用审查策略——确定性底线加模型守卫层。这一层位于现有权限姿态之上;它可以拦住或阻断工具调用,但不是自动推送、自动合并或托管审查服务。先检查阻断规则,然后是内置安全底线,再是允许规则。在 Ask 中,安全拦阻打开审批;在 Auto-Review、Full Access 或非交互 `never` 姿态中,它作为硬阻断失败关闭。即使 allow 规则匹配,安全底线仍覆盖类似发布的动作和破坏性的后台/无头动作。
1068
1069 ```toml
1070 [[auto_review.allow]]
1071 id = "read-only-inspection"
1072 action_kind = "read"
1073 reason = "Read-only inspection is safe to run automatically."
1074
1075 [[auto_review.block]]
1076 id = "no-release-publish"
1077 action_kind = "publish"
1078 reason = "Release and publish actions require maintainer review."
1079 ```
1080
1081 规则匹配器是精确 `tool` 和/或 `action_kind`。至少需要一个匹配器。`action_kind` 接受六个决策相关种类 `read`、`write`、`shell`、`external`、`publish` 和 `destructive`。无效名称让配置验证失败,而不是静默扩大到另一个策略类。在阻断规则中,旧名称保持保守兼容别名:`network`、`git`、`mcp_action`、`browser` 和 `unknown` 映射到 `external`;`secret` 映射到 `destructive`;`mcp_read` 映射到 `read`。允许规则中退役的窄种类验证失败,而不是扩大到更宽类别。退役的 `text_contains` 匹配器同样验证失败,而不是静默扩大旧的意图依赖规则。交互式 Auto-Review 中的回退拦阻升级为一次无状态守卫请求。请求包含确切被拦调用和确定性观察作为独立 JSON 字段。对话历史、技能指令、附加文件内容和其它展开的模型上下文被排除。守卫不推断用户意图,不算授权分数。它不暴露工具,返回风险级别、允许/拒绝和理由。高或关键风险即使模型说允许也不能自动运行。过大的确切调用被拒绝而不是截断。只做一次审查请求;不完整或格式错误的输出、超时、取消、provider 失败或空理由都失败关闭。确定性底线从不被模型审查,无头适配器使用仅确定性层级。固定的 Codex、Kimi 和 DeepSeek 源边界从[权限姿态](MODES.md#permission-posture)链接。审查结果发出 `tool.auto_review` 审计事件,`gate = "guardian"`。
1082
1083 自动审查决策在启用工具审计日志时发出 `tool.auto_review` 审计事件,`gate = "deterministic"`。未来的 PreToolUse/PostToolUse hooks 可以在这层周围添加观察者输入,但配置的自动审查策略在工具调用被允许继续之前评估。
1084 - `managed_config_path`(字符串,可选):用户/环境配置之后加载的受管配置文件。
1085 - `requirements_path`(字符串,可选):用于强制允许的审批/沙箱值的需求文件。
1086 - `max_subagents`(int,可选):默认 `64`,钳制到 `1..=128`。
1087 - `subagents.*`(可选兼容表):`agent` 的按 Fleet 角色模型默认。显式工具 `model` 值胜出,然后角色覆盖,然后父运行时模型。支持的便捷键是 `default_model`、`worker_model`、`scout_model`、`planner_model`、`reviewer_model`、`custom_model`、`max_concurrent`、`max_admitted`、`launch_concurrency`、`token_budget`、`api_timeout_secs` 和 `heartbeat_timeout_secs`。v0.9.x 键 `explorer_model`、`awaiter_model` 和 `review_model` 仍作为别名接受。`[subagents] max_concurrent` 值覆盖顶层 `max_subagents`,也钳制到 `1..=128`。`[subagents] max_admitted`(别名:`max_total`、`admission_limit`)是排队加运行子智能体的有界总数;默认 `1024`(`MAX_SUBAGENT_ADMISSION`,`crates/tui/src/config/subagent_limits.rs:21`,在 `config.rs:6400` 应用),所以高扇出回合可以排队并排空,同时运行时启动压力保持有界,并钳制到 `max_concurrent..=1024`。`[subagents] launch_concurrency` 设置一次直接启动多少子智能体,其余排队等启动槽位;默认解析出的 `max_subagents` 上限,钳制到 `1..=max_subagents`(弃用的 `interactive_max_launch` 键作为别名接受,两者都设置时新键胜出)。`[subagents] token_budget` 是每个根 `agent` 运行及其后代的可选聚合 token 上限;未设置或 `0` 保留无限制的旧行为。`[subagents] api_timeout_secs` 控制子智能体模型调用的每步 API 超时,钳制到 `1..=3600`,`0` 或未设置保留 600 秒默认;超时尝试用指数退避重试(最多 5 次),然后步骤以保留检查点中断。`[subagents] heartbeat_timeout_secs` 控制过期运行智能体清理,默认 `300`,钳制到 `30..=3600`,同时保持在解析出的 API 超时之上。`[subagents.providers.<provider>]` 接受同样的扇出、深度、预算和超时旋钮(`enabled`、`max_concurrent`、`max_admitted`、`launch_concurrency`、`max_depth`、`token_budget`、`api_timeout_secs`、`heartbeat_timeout_secs`),并为省略的键继承全局 `[subagents]` 值。Provider 键接受 `deepseek`、`zai`、`openrouter`、`anthropic` 这样的规范名,加 `glm`(Z.ai)和 `deepseek_api`(直接 DeepSeek)这样的便捷别名:
1088
1089 ```toml
1090 [subagents]
1091 max_concurrent = 20
1092 launch_concurrency = 20
1093 max_admitted = 200
1094 max_depth = 6
1095
1096 [subagents.providers.deepseek]
1097 max_concurrent = 20
1098 launch_concurrency = 20
1099 max_admitted = 200
1100
1101 [subagents.providers.glm]
1102 max_concurrent = 4
1103 launch_concurrency = 3
1104 max_admitted = 12
1105 max_depth = 2
1106
1107 [subagents.providers.openrouter]
1108 max_concurrent = 5
1109 launch_concurrency = 3
1110 max_admitted = 20
1111 ```
1112
1113 `/config subagents status` 打印全局值和活动 provider 的解析 profile,这样速率限制调整在 TUI 中可见。`[subagents.models]` 接受小写 Fleet 角色键,如 `worker`、`scout`、`planner`、`reviewer`、`builder` 和 `verifier`;旧类型键在 v0.9.x 期间仍被接受。值在派生时对照活动 provider 验证;直接 DeepSeek 需要 DeepSeek ID,而 OpenAI 兼容/自定义 provider 路由把显式模型 ID 透传给该 provider。要把子智能体路由到不同于父会话的 provider,保存带显式 `provider` 和 `model` 字段的 Fleet/AgentProfile(包括 `lm-studio` 这样的用户命名自定义 provider),并调用 `agent(profile: "...")`;见 [SUBAGENTS.md](SUBAGENTS.md)。
1114 - `skills_dir`(字符串,可选):默认 `~/.codewhale/skills`(每个技能是包含 `SKILL.md` 的目录)。存在时优先使用工作区本地的 `.agents/skills` 或 `./skills`;运行时还发现全局 agentskills.io 兼容的 `~/.agents/skills` 和更广的 Claude 生态系统 `~/.claude/skills`。首次启动为常见工作流安装带版本的捆绑技能,包括技能创建、委派、MCP/插件脚手架、文档、演示文稿、电子表格、PDF 和飞书/Lark。只有 CodeWhale 自有的根(`<workspace>/.codewhale/skills` 和 `~/.codewhale/skills`)是可写安装/导入目标;兼容 harness 根保持只读。裸 `/skills` 打开技能管理器(仅自有,零网络)。管理器、审计状态、来源标记和变更规则见 [SKILLS.md](SKILLS.md),可移植 `SKILL.md` 包与 Claude Code 插件运行时之间的受支持边界见 [CLAUDE_PLUGIN_COMPAT.md](../CLAUDE_PLUGIN_COMPAT.md)。
1115 - `[skills].scan_codewhale_only`(bool,默认 `false`):为 `true` 时,会话技能发现忽略跨工具根,如 `.claude/skills`、`.opencode/skills`、`.cursor/skills` 和 `~/.agents/skills`。Codewhale 仍扫描 `<workspace>/.codewhale/skills`、`~/.codewhale/skills` 和任何显式 `skills_dir` 覆盖。技能管理器仍可独立于这个运行时旋钮切换本地兼容审计扫描——见 [SKILLS.md](SKILLS.md)。
1116 - `[skills].registry_url` / `[skills].max_install_size_bytes`(可选):`/skills --remote`、`/skills suggest <task>`、`/skills sync` 和 `/skill install|update` 使用。默认管理器打开路径不联系 registry。
1117 - `[verifier].enabled`(bool,默认 `false`):该运行时触发点激活后启用自动的"已完成"声明验证器预览。`false` 时手动 `run_verifiers` 工具仍可用。
1118 - `[verifier].verdict_policy`(字符串,默认 `"hunt"`):把验证器 `pass` / `partial` / `fail` 映射到目标裁决词汇 `hunted` / `wounded` / `escaped`。`"hunt"` 是今天唯一发布的策略;未知值被拒绝,这样未来策略可以刻意添加。
1119 - `mcp_config_path`(字符串,可选):默认 `~/.codewhale/mcp.json`,Codewhale 路径缺失时旧 `~/.deepseek/mcp.json` 回退。自定义路径必须绝对;相对值回退到用户全局路径,这样改变启动目录不能静默改变 MCP 池。它在 `/config` 中可见,可从 TUI 更改。新路径被 `/mcp` 立即使用,但重建模型可见的 MCP 工具池需要重启 TUI。
1120 - `notes_path`(字符串,可选):默认 `~/.codewhale/notes.txt`,Codewhale 路径缺失时旧 `~/.deepseek/notes.txt` 回退,由模型可见的 `note` 工具使用。
1121 - `[memory].enabled`(bool,可选):默认 `false`。为 `true` 时,TUI 把用户记忆文件加载进 `<user_memory>` 提示块,在输入区启用 `# foo` 快速捕获,浮现 `/memory` 斜杠命令,并注册 `remember` 工具。同一开关可通过 `DEEPSEEK_MEMORY=on` 使用。
1122 - `memory_path`(字符串,可选):锚定原生记忆存储。配置的文件名**不是**被写入的文件。在 Native 后端(唯一后端)下,存储被重新根到 `<parent-of-memory_path>/memory/global/MEMORY.md`——所以默认 `~/.codewhale/memory.md` 产生 `~/.codewhale/memory/global/MEMORY.md`(加工作区作用域文件和可重建的 SQLite FTS5 索引)。完整功能面见 [`MEMORY.md`](../MEMORY.md)(`# foo` 输入区前缀、`/memory` 斜杠命令、`remember` 工具、选择加入开关)。
1123 - `snapshots.*`(可选):用于文件回滚的 side-git 工作区快照:
1124 - `[snapshots].enabled`(bool,默认 `true`)
1125 - `[snapshots].max_age_days`(int,默认 `7`)
1126 - 快照位于 `~/.codewhale/snapshots/<project_hash>/<worktree_hash>/.git`,旧 `~/.deepseek/snapshots/...` 仅在旧状态存在时回退,从不使用工作区自己的 `.git` 目录
1127 - `context.*`(可选):
1128 - `[context].enabled`(bool,默认 `false`)
1129 - `[context].project_pack`(bool,默认 `false`):在稳定提示前缀中包含确定性的项目上下文包(大型美化打印的目录列表)(#4781)。对弱工具调用模型有用;模型可以用一次 `File` 调用重建同样信息。
1130 - 前 seam 管理器键(`verbatim_window_turns`、`l1_threshold`、`l2_threshold`、`l3_threshold`、`seam_model`)被**忽略**——为向后兼容解析,但自 2026-07-23 起任何地方都不读。
1131 - `retry.*`(可选):API 请求的重试/退避设置:
1132 - `[retry].enabled`(bool,默认 `true`)
1133 - `[retry].max_retries`(int,默认 `3`)
1134 - `[retry].initial_delay`(float 秒,默认 `1.0`)
1135 - `[retry].max_delay`(float 秒,默认 `60.0`)
1136 - `[retry].exponential_base`(float,默认 `2.0`)
1137 - `[notifications].method`(字符串,可选):`auto`、`osc9`、`bel` 或 `off`。默认 `auto`。TUI 在已完成的(成功)回合其经过时间达到 `threshold_secs` 时触发它;失败和取消回合静默。`auto` 对 `iTerm.app`、`Ghostty` 和 `WezTerm`(通过 `$TERM_PROGRAM` 检测)解析为 `osc9`。否则回退是 `bel`;在 Windows 上 BEL 路径通过 `MessageBeep(MB_OK)` 路由。
1138 - `[notifications].threshold_secs`(int,可选):默认 `30`。只有经过时间达到或超过此值的已完成回合触发通知。
1139 - `[notifications].include_summary`(bool,可选):默认 `false`。为 `true` 时,通知正文包含经过时长和回合在配置显示货币下的成本。
1140 - `[notifications].completion_sound`(字符串,可选):`off`、`beep`、`bell` 或 `file`。默认 `beep`。`file` 在 Windows 上播放 `[notifications].sound_file` 的 WAV 路径。
1141 - `[notifications].sound_file`(路径,可选):`completion_sound = "file"` 时使用的自定义 WAV 文件路径。
1142 - `[notifications].quiet`(bool,可选):默认 `false`。安静模式——抑制每个桌面通知(所有类别、所有投递方式)和配对的 `event_sound` 提示,不改变 `method` 或逐类别开关。回合完成提示音(`completion_sound`)单独管辖。
1143 - `[notifications.events]`(表,可选):逐类别桌面通知开关;每个键默认 `true`。键:`turn-complete`、`subagent-terminal`、`approval-needed`、`input-needed`、`elevation-needed`、`model-notify`。禁用的类别在每个投递机制(OSC 9、Kitty、Ghostty、BEL、macOS 通知中心)上被抑制。
1144 - `[notifications.event_sound]`(表,可选):选择加入、确定性的逐事件声音提示。键:`enabled`(bool,默认 `false`)、`events`(kebab-case 事件名数组,默认 `["turn-complete", "approval-needed"]`)、`min_interval_ms`(int,默认 `2000`)、`quiet`(bool,默认 `false`)。见下方"事件声音提示"。
1145 - `tui.alternate_screen`(字符串,可选,默认 `auto`):交互式会话启动时使用哪个屏幕。`auto` 和 `always` 在 TUI 拥有的备用屏幕上启动;`never` 以内联模式启动——与终端等高、不使用备用屏幕的 ratatui 视口,因此 shell 的回滚缓冲在会话期间保持完好,退出后仍可滚动。`/fullscreen` 与 `/inline` 在进程内切换;终端拒绝的切换会回滚并说明原因。内联模式在其视口内绘制整个转录——会话运行期间不会向宿主回滚缓冲写入任何内容。
1146 - `tui.mouse_capture`(bool,可选,非 Windows 终端和备用屏幕活动时的 Windows Terminal/ConEmu/Cmder 上默认 `true`;旧 Windows 控制台和 JetBrains JediTerm 内部——PyCharm/IDEA/CLion 等——为 `false`,那里鼠标事件转义作为乱码文本漏进输入流,见 #878 / #898):启用内部鼠标滚动、转录选择、右键上下文动作和转录滚动条拖动。TUI 拥有的拖拽选择只复制转录文本,从段落中移除视觉换行列断点,保持选择限于转录窗格。设为 `false` 或带 `--no-mouse-capture` 运行使用原始终端选择;设为 `true` 或带 `--mouse-capture` 运行可在任何默认关闭处选择加入。在原始终端选择上,尤其是旧 Windows 控制台或鼠标捕获禁用时,选择可能跨越右侧栏并包含视觉换行,因为选择由终端而不是 TUI 拥有。
1147 - `tui.terminal_probe_timeout_ms`(int,可选):兼容旧配置而保留的设置,现已不再使用。启动时在检查终端所有权后直接设置原始模式,不再因工作线程调度延迟而中止启动。
1148 - `tui.stream_chunk_timeout_secs`(int,可选,默认 `900`):流式模型响应的每 SSE 块空闲超时。慢的本地或兼容服务器可以用 `/config stream_chunk_timeout_secs <seconds>` 提高;`0` 映射到默认,显式值必须 `1..=3600`。省略该键时旧 `DEEPSEEK_STREAM_IDLE_TIMEOUT_SECS` 环境变量仍被遵循。
1149 - `tui.osc8_links`(bool,可选,macOS/Linux 默认开启,Windows 默认关闭):在转录输出的 URL 周围发出 OSC 8 转义序列,这样支持的终端(iTerm2、Terminal.app 13+、Ghostty、Kitty、WezTerm、Alacritty、较新的 gnome-terminal/konsole)可以用终端的链接手势打开它们——通常是 macOS 上的 Cmd-click,Linux/Windows 上的 Ctrl-click。没有 OSC 8 支持的终端渲染普通标签并忽略转义。转义带外发出(不在缓冲区单元格内),所以列损坏不是问题;只在终端错误渲染 OSC 8 终止符本身时设 `false`。Windows 旧控制台默认关闭;用 `true` 选择加入。
1150 - `transcript.prose_measure`(正整数,可选,默认缺省 = 全宽):实时转录中散文单元格——用户消息、助手回答和推理/思考块——的换行上限,以列为单位(#5436)。缺省(或 `0`)使用全部内容宽度,与工具/状态单元格和 #5322 宽帧决策一致;前 105 列散文栏已移除。在超宽终端上设置正整数(例如 `[transcript]` 下的 `prose_measure = 120`)恢复有界的阅读度量。窄终端总是保持内容宽度——上限只从上方钳制。工具、diff 和状态单元格从不继承这个上限。无效值(负或非整数)在启动时以 `transcript.prose_measure` 配置错误被拒绝。每次渲染遍解析一次,所以主转录缓存和全屏覆盖层总是就有效宽度达成一致。
1151 - `hooks`(可选):生命周期 hooks 配置(见 `config.example.toml`)。
1152 - `features.*`(可选):功能标志覆盖(见下文)。
1153
1154 ### 工作区笔记
1155
1156 `/note` 在当前工作区的 `.codewhale/notes.md` 管理一个简单的笔记文件(旧 `.deepseek/notes.md` 是尚不存在 `.codewhale/notes.md` 时的回退路径)。现有的 `/note <text>` 用法仍追加笔记。管理形式:
1157
1158 | 命令 | 动作 |
1159 |---|---|
1160 | `/note <text>` | 追加笔记(旧简写) |
1161 | `/note add <text>` | 显式追加笔记 |
1162 | `/note list` | 列出笔记,带临时的从 1 开始编号 |
1163 | `/note show <n>` | 显示编号 `n` 的完整笔记 |
1164 | `/note edit <n> <text>` | 用新文本替换笔记 `n` |
1165 | `/note remove <n>` | 删除笔记 `n`;`rm` 和 `delete` 是别名 |
1166 | `/note clear` | 清空工作区笔记文件 |
1167 | `/note path` | 显示解析出的工作区笔记路径 |
1168
1169 `/note list` 显示的编号不存储在文件中;它们每次读取笔记时从当前顺序派生。这让文件格式与现有的 `---` 分隔笔记兼容。
1170
1171 ### 用户记忆
1172
1173 用户记忆拆分为一个顶层路径设置和一个选择加入开关表:
1174
1175 ```toml
1176 # 只锚定存储——实际写入发生在
1177 # ~/.codewhale/memory/global/MEMORY.md(见 MEMORY.md)。
1178 memory_path = "~/.codewhale/memory.md"
1179
1180 [memory]
1181 enabled = true
1182 ```
1183
1184 注意:
1185
1186 - `memory_path` 保持在顶层,紧挨 `notes_path` 和 `skills_dir`;它不嵌套在 `[memory]` 下。
1187 - 配置的路径是**锚点**:它的父目录获得 `memory/global/MEMORY.md`、工作区作用域文件和 `index.db`。把 `memory_path` 指向原生布局路径本身会双重嵌套(`…/memory/global/memory/global/MEMORY.md`);保持旧式锚文件名。
1188 - `DEEPSEEK_MEMORY_PATH` 从环境覆盖锚路径。
1189 - `DEEPSEEK_MEMORY=on`(也 `1`、`true`、`yes`、`y` 或 `enabled`)不编辑 `config.toml` 就翻转功能开启。
1190 - 禁用时功能惰性:不注入文件,`# foo` 落到普通消息提交,模型看不到 `remember` 工具。
1191 - 示例和完整 `/memory` 命令面见 [`MEMORY.md`](../MEMORY.md)。
1192
1193 ### 目标循环(`[goal]`)
1194
1195 Operate 模式目标以无默认 token、时间或继续上限运行到完成门(#5052)。显式提供的 token/时间预算只是遥测,不停止目标。想要断路器的人可以选择加入一个:
1196
1197 ```toml
1198 [goal]
1199 # 自动目标继续轮的可选安全兜底(backstop)。
1200 # 默认:0(无限)。设正值选择加入上限。
1201 max_continuations = 100
1202
1203 # 成功回合之间的可选可取消安静期。这对应以节奏轮询的协调器目标很有用,
1204 # 而不是让一个 provider 回合一直开着。默认:0(立即继续)。
1205 continuation_delay_seconds = 300
1206 ```
1207
1208 有效延迟上限 86,400 秒(24 小时);比每天一次更不频繁的调度用自动化。
1209
1210 显式兜底触发时,目标以状态消息暂停,命名 `[goal] max_continuations`,并记录警告;检查进度后恢复目标,或提高/禁用兜底。
1211
1212 延迟只在显式创建的目标仍活动时,在成功回合之后开始。`/goal pause`、`/goal done`、`/goal blocked`、`/goal clear`、Esc 或 Ctrl+C 在另一个 provider 请求开始前取消待定继续。失败回合和策略/路由失败从不安排另一个回合。配置中只存储数字节奏;循环不持久化提示、凭据或秘密。
1213
1214 ### 通知
1215
1216 TUI 可以在回合**成功完成**且用时超过阈值时发出桌面通知(OSC 9 转义或普通 BEL),这样长任务运行时你可以切走。失败或取消回合刻意静默——通知是"你的任务好了"提示,不是通用 ping。配置位于 `[notifications]`:
1217
1218 ```toml
1219 [notifications]
1220 method = "auto" # auto | osc9 | bel | off
1221 threshold_secs = 30 # 仅当回合耗时 >= 该秒数时通知
1222 include_summary = false # 通知正文包含经过时间 + 成本
1223 completion_sound = "beep" # off | beep | bell | file
1224 sound_file = "E:\\google\\downloads\\notify.wav" # 用于 completion_sound = "file"
1225 quiet = false # true 抑制每个桌面通知
1226
1227 [notifications.events] # 逐类别开关;全部默认 true
1228 turn-complete = true # agent 回合完成
1229 subagent-terminal = true # 子智能体到达终态
1230 approval-needed = true # 工具调用被你的审批阻断
1231 input-needed = true # 智能体问了问题并被阻断
1232 elevation-needed = true # 沙箱拒绝工具,需要决定
1233 model-notify = true # 模型调用 `notify` 工具
1234 ```
1235
1236 `quiet = true` 是一键"别打断我"开关:它让每个类别在每个投递机制上静音,同时保留通知配置的其余部分,所以翻回去会恢复你确切之前的策略。`[notifications.events]` 以同样方式禁用单个类别——禁用类别在发射路径被抑制,所以它不能通过某个特定协议泄漏。被抑制的通知也抑制它配对的 `[notifications.event_sound]` 提示(没有为你关闭的事件留下孤儿铃声);回合完成提示音(`completion_sound`)单独管辖。
1237
1238 方法语义:
1239
1240 - `auto`(默认)——为 `iTerm.app`、`Ghostty` 和 `WezTerm`(通过 `$TERM_PROGRAM` 检测)选 `osc9`。否则回退到 `bel`;在 Windows 上该 BEL 路径通过 `MessageBeep(MB_OK)` 路由。
1241 - `osc9`——发出 `\x1b]9;<msg>\x07`。在 tmux 内序列包裹在 DCS 透传中,所以它到达外层终端。
1242 - `bel`——发出单个 `\x07` 字节。只在你想主动要回提示音时在 Windows 使用。
1243 - `off`——完全禁用回合后通知。
1244
1245 在已知 OSC-9 终端(如 Windows 上的 WezTerm)内运行的 Windows 用户继续收到 OSC-9 通知。设置 `method = "off"` 可完全禁用基于阈值的桌面通知。
1246
1247 `completion_sound = "file"` 面向想要每应用完成音、又不想改变全局 Windows 声音方案的 Windows 用户。它通过原生 Windows 音频 API 异步播放配置的 WAV `sound_file`。
1248
1249 #### 事件声音提示
1250
1251 `[notifications.event_sound]` 是选择加入、确定性的策略,在特定通知事件触发时发出终端铃级提示(审批提示、被输入阻断、子智能体完成等)。它**默认关闭**;`enabled = false` 时不发出任何东西,这是平台安全的空操作回退。
1252
1253 ```toml
1254 [notifications.event_sound]
1255 enabled = false # 默认:off(选择加入)
1256 events = ["turn-complete", "approval-needed"] # 默认允许列表
1257 min_interval_ms = 2000 # 每事件限速
1258 quiet = false # true 静音一切,不编辑允许列表
1259 ```
1260
1261 提示表是固定的——提示是基于 BEL 的功能信号,不是为悦耳设计的音频,每个提示是一或两个 `\x07` 字节(在忽略 BEL 的终端上惰性,所以处处是平台安全空操作):
1262
1263 | 事件 | 提示 |
1264 |---|---|
1265 | `turn-complete` | BEL(`\x07`) |
1266 | `subagent-terminal` | BEL(`\x07`) |
1267 | `approval-needed` | 双 BEL(`\x07\x07`) |
1268 | `input-needed` | BEL(`\x07`) |
1269 | `elevation-needed` | 双 BEL(`\x07\x07`) |
1270 | `model-notify` | BEL(`\x07`) |
1271
1272 决策顺序:禁用 → 安静模式 → 事件不在 `events` 中 → `turn-complete` 在该通道活动时推迟到 `completion_sound` 通道(所以两者绝不双响)→ 每事件限速(`min_interval_ms` 距该事件上次播放)→ 播放。`events` 中的未知字符串被忽略。
1273
1274 #### 通知可以包含什么
1275
1276 桌面通知是扫一眼的表面:在 macOS 上它可以出现在锁屏上,在每个平台上它对机器附近任何人都可见。因此 Codewhale 从带固定逐事件披露策略的类型化负载构建通知,而不是从手头任何文本:
1277
1278 | 事件 | 显示 | 绝不显示 |
1279 |---|---|---|
1280 | 回合完成 | 状态行(`include_summary` 时加经过/成本),助手回复预览 | — |
1281 | 子智能体完成 | 状态行、agent id、子智能体摘要行预览 | — |
1282 | 需要审批 | 工具名 | 工具描述、命令、参数 |
1283 | 需要输入 | "在终端回答该问题以继续" | 问题 |
1284 | 需要沙箱提权 | 工具名和拒绝原因 | 命令 |
1285 | `notify` 工具 | 模型提供的标题和正文 | — |
1286
1287 每个字段有上限(状态行 80 字符,标识符 120,预览 200),剥离控制字节和转义序列,并经过一个把凭据形态字符串替换为 `[redacted]`、把绝对本地路径缩减为 `…/basename`、把原始工具 JSON 替换为 `[details hidden]` 的脱敏器。脱敏器刻意过度积极:40 字符的无断运行没有词结构,所以即使它不是秘密也会被脱敏。
1288
1289 #### macOS:为什么横幅说 "Script Editor"
1290
1291 在没有自带通知转义的 macOS 终端上——Apple Terminal、VS Code 和 JetBrains 内嵌终端、没有 `LC_TERMINAL` 的普通 tmux——`method = "auto"` 回退到 `osascript` 的 `display notification`。该命令代表*捆绑的*宿主进程发帖,而 `/usr/bin/osascript` 未捆绑,所以 macOS 把横幅归因于 `com.apple.ScriptEditor2`。该归因提供脚本编辑器图标,并拥有系统设置 → 通知条目(提醒样式、预览、勿扰)。`display notification` 没有图标参数,所以这无法从通知代码修复;它需要 Codewhale 发布真正的 `.app` 包。在 [#4834](https://github.com/Hmbown/CodeWhale/issues/4834) 中跟踪。与此同时,iTerm2、WezTerm、Ghostty 和 kitty 先被匹配,使用它们自己的通知协议,`method = "osc9"` / `"bel"` / `"off"` 显式选择退出 `osascript` 路径。
1292
1293 ## 工具目录(Tool Catalog)
1294
1295 Codewhale 默认加载一个小型核心原生工具目录,把不太常见的原生工具留给 ToolSearch 发现。要让特定原生工具在每个请求都加载,把它们加到 `[tools].always_load`:
1296
1297 ```toml
1298 [tools]
1299 always_load = ["Git", "notify"]
1300 ```
1301
1302 ## 功能标志(Feature Flags)
1303
1304 功能标志位于 `[features]` 表下,跨 profiles 合并。内置工具默认启用,所以你只需要设置想强制开或关的条目。
1305
1306 ```toml
1307 [features]
1308 shell_tool = true
1309 subagents = true
1310 web_search = true # 启用延迟 Web;标志名保留用于配置兼容
1311 apply_patch = true
1312 mcp = true
1313 exec_policy = true
1314 ```
1315
1316 你也可以为单次运行覆盖功能:
1317
1318 - `codewhale --enable web_search`
1319 - `codewhale --disable subagents`
1320
1321 用 `codewhale features list` 检查已知标志和它们的有效状态。原生 `/config` 视图还包含一个只读的**实验性(Experimental)**区,用于实验性功能标志。它显示每个标志的有效启用/禁用状态,以及该状态来自默认还是配置覆盖。在 `[features]` 或 `--enable` / `--disable` 中更改功能标志;`/config` 区是审计面,不是稳定性承诺。目标和工作流预览行可能作为保留条目出现在那里,直到那些工作流在真实门控标志后面毕业。
1322
1323 ## 网页搜索 Provider
1324
1325 `web_search` 默认使用无 key 的 Firecrawl。运行时失败或耗尽无 key 配额会通过 DuckDuckGo 和 Bing 可见地降级。中国部署可以显式选择百度、秘塔、火山引擎或受信任的 SearXNG 端点;Codewhale 不从区域设置或模型 provider 猜测地理位置。
1326
1327 配置的 API provider 先被尝试。运行时失败或空结果通过 DuckDuckGo 然后 Bing 可见地降级;结构化搜索回执记录每一步。缺失配置和网络策略拒绝失败关闭,不把查询发送到另一个 provider。
1328
1329 对服务 DuckDuckGo 兼容 HTML 的私有/内部搜索服务,保持 `provider = "duckduckgo"` 并设置 `base_url`;Codewhale 把 `q` 查询参数追加到该端点,并把网络策略应用到它的主机。自定义端点不回退到公共 Bing。`CODEWHALE_SEARCH_BASE_URL` 可按进程覆盖;`DEEPSEEK_SEARCH_BASE_URL` 仍作为旧别名接受。
1330
1331 **SearXNG**([docs](https://docs.searxng.org/dev/search_api.html))使用配置实例的 JSON API。设置 `provider = "searxng"` 和 `base_url = "https://your-searxng.example"`;Codewhale 调用 `/search?q=...&format=json`。Codewhale 默认不使用公共 SearXNG 实例,因为公共实例常禁用 JSON 输出或对 API 流量限速。
1332
1333 把它作为独立进程自托管(Docker 即可);Codewhale 不内嵌也不管理搜索引擎本身:
1334
1335 - 在实例上启用 JSON(`settings.yml` 的 `search.formats` 必须包含 `json`)并重启。仅 HTML 的实例会对 API 返回 HTTP 403;Codewhale 会把它作为 SearXNG 这一跳的 JSON/API 访问问题报告出来,而不是静默返回空结果。
1336 - 绑定到 loopback,或绑定到你的网络策略允许的主机和端口。实例自带引擎列表、限流器和限额。
1337 - 用 `[search] provider = "searxng"` 和 `base_url` 指向它(必填;根 URL 或 `/search` 端点均可)。不随任何默认实例发布,也不会自动发现实例。
1338 - `codewhale doctor --probe-search` 只对该 origin 发送一个传输层 `HEAD`——不带 `q=`、不带凭据、不跟随重定向、不写审计回执——所以探测通过只证明可达性和网络策略放行,不证明 JSON 已开启。
1339
1340 在假定是 Codewhale 的 bug 之前,先用直接请求确认 JSON API 本身:
1341
1342 ```sh
1343 curl -sS "$BASE/search?q=codewhale&format=json" | jq '.results[0] | {title,url,score}'
1344 ```
1345
1346 Codewhale 按 `score` 从高到低排序返回行,再对排序结果应用 `max_results`;实例未给出可用分数的行保持原始相对顺序。
1347
1348 **秘塔(Metaso)**([metaso.cn](https://metaso.cn))需要用户提供的 key。设置 `METASO_API_KEY` 或 `[search] api_key`;Codewhale 不提供共享 key。
1349
1350 **Firecrawl**([docs](https://docs.firecrawl.dev/sdks/cli))用其有界的按 IP 每日配额无 key 搜索 Firecrawl Cloud。设置 `FIRECRAWL_API_KEY` 或 `[search] api_key` 用于认证限额。Codewhale 在无 key 模式不发送 `Authorization` 头。
1351
1352 **百度(Baidu)**使用百度 AI 搜索 `https://qianfan.baidubce.com/v2/ai_search/web_search`。设置 `BAIDU_SEARCH_API_KEY` 或 `[search] api_key`。这只是搜索工具后端;它不添加百度模型 provider。
1353
1354 **Sofya**([sofya.co](https://sofya.co))返回完整提取页面内容而不是片段。把 `[search] api_key` 设为你的 `ay_live_...` key,或用 `SOFYA_API_KEY` 环境变量。这只是搜索工具后端;它不添加 Sofya 模型 provider。
1355
1356 **Serply**([serply.io](https://serply.io))返回 Google 自然搜索结果,包含标题、URL 和摘要片段。把 `[search] api_key` 设为你的 Serply key,或用 `SERPLY_API_KEY` 环境变量。这只是搜索工具后端;它不添加 Serply 模型 provider。
1357
1358 **Tavily**([tavily.com](https://tavily.com))在存在 Tavily key 且没有固定 provider 时自动选中:设置了 `TAVILY_API_KEY`,或 `[search] api_key` / `CODEWHALE_SEARCH_API_KEY` 属于 `tvly-` 家族。doctor 会把这种情况报告为 `source: tavily key`。自动检测只在运行时生效——Codewhale 不会为它写入 `[search] provider`,也不会把 `TAVILY_API_KEY` 合并进 `[search] api_key`。显式的 `[search] provider` 或 `CODEWHALE_SEARCH_PROVIDER` 始终优先,所以即使环境里有 Tavily key,`provider = "firecrawl"` 仍然是 Firecrawl。固定为 `tavily` 时接受任何非空的 `[search] api_key`,由该 key 或 `TAVILY_API_KEY` 提供配置;两者都为空时直接失败关闭。
1359
1360 ```toml
1361 [search]
1362 provider = "firecrawl" # 也 duckduckgo | bing | tavily | bocha | metaso | searxng | baidu | volcengine | sofya | serply
1363 # base_url = "https://search.example/" # provider = "duckduckgo" 时可选;"searxng" 时必填
1364 # api_key = "YOUR_KEY" # firecrawl 可选;其他 API 提供商必填
1365 ```
1366
1367 ## 本地媒体附件
1368
1369 在输入区用 `@path/to/file` 给下一条消息添加本地文本文件或目录上下文。本地图像/视频媒体路径用 `/attach <path>`,或 `Ctrl+V` 从本地剪贴板或显式转发的 X11/Wayland 剪贴板附加图像。没有转发图形显示的 SSH 终端粘贴仅文本;使用本地终端的粘贴命令(macOS 的 `Cmd+V`,Linux/Windows 的 `Ctrl+Shift+V`),远程图像文件用 `/attach <path>`。OpenSSH loopback X11 显示自动检测。对显式转发的 Wayland 或非 loopback X11 显示,设置 `CODEWHALE_SSH_CLIPBOARD=graphical`;设为 `terminal` 强制终端传输而不是环境远程显示。DeepSeek 的公共 Chat Completions API 目前接受文本消息内容,所以媒体附件作为显式本地路径引用发送,而不是原生图像/视频负载。附件行在提交前出现在输入区上方;移到输入区开头,按 `↑` 选择附件行,然后按 `Backspace` 或 `Delete` 移除它,不用手工编辑示例文本。
1370
1371 ## 受管配置与需求(Managed Configuration and Requirements)
1372
1373 codewhale 支持策略分层模型:
1374
1375 1. 用户配置 + profile + 环境覆盖
1376 2. 受管配置(若存在)
1377 3. 需求验证(若存在)
1378
1379 Unix 上默认:
1380 - 受管配置:`/etc/deepseek/managed_config.toml`
1381 - 需求:`/etc/deepseek/requirements.toml`
1382
1383 需求文件形态:
1384
1385 ```toml
1386 allowed_approval_policies = ["on-request", "untrusted", "never"]
1387 allowed_sandbox_modes = ["read-only", "workspace-write"]
1388 ```
1389
1390 如果配置值违反需求,启动以描述性错误失败。
1391
1392 ## 关于 `codewhale doctor` 的说明
1393
1394 `codewhale doctor` 遵循与 TUI 其余部分相同的配置解析规则。这意味着 `--config`、`CODEWHALE_CONFIG_PATH` 和旧 `DEEPSEEK_CONFIG_PATH` 都被尊重,MCP/skills 检查使用解析出的 `mcp_config_path` / `skills_dir`(含环境覆盖)。
1395
1396 要引导缺失的 MCP/skills 路径,运行 `codewhale setup --all`。你也可以运行 `codewhale setup --skills --local` 创建工作区本地的 `./skills` 目录。
1397
1398 普通 `codewhale doctor` 和 `doctor --json` 都是结构性的,默认离线。它们不检查 release 服务、托管 provider API、本地 provider 端点或 MCP 进程,也不加载工作区凭据 `.env`。用 `--check-updates`、`--probe-api`、`--probe-local` 或 `--probe-mcp` 选择加入对应的实时边界;`--probe-local` 可能启动 Ollama 这样的桌面托管服务。只有显式 API/local 探测路径可以加载工作区凭据 `.env` 值。实时标志与 `--json` 冲突,所以机器可读 doctor 输出总是离线。顶层键包括 `version`、`paths`、`secret_backend`、`config_path`、`config_present`、`workspace`、`api_key.source`、`api_key.availability`、`base_url`、`default_text_model`、`mcp`、`skills`、`tools`、`plugins`、`sandbox`、`platform`、`api_connectivity` 和 `capability`。CI 消费者应依赖 `api_key.source`(`config_declared`/`env_declared`/`external_auth_declared`/`secret_store_unprobed`/`secret_store_unavailable`/`oauth_unprobed`/`external_consent`/`none`/`local_runtime`/`unknown`)和 `api_key.availability`(`present`/`not_required`/`not_probed`/`unavailable`/`unknown`),而不是解析人类可读的 `doctor` 文本。Source 是声明元数据,不是凭据存在或工作的证明。只有非空、非哨兵的字面配置值才在结构上 `present`;无认证和本地路由是 `not_required`。环境、外部认证、OAuth、consent 和 secret-store 声明保持 `not_probed`,不能让结构 Setup 或 Fleet 就绪成为真。被禁止使用共享存储的命名/自定义端点上的 secret-store 哨兵是 `secret_store_unavailable`/`unavailable`,而 `unknown` 保留给缺乏受支持结构结论的情况。确切和空白包裹的旧哨兵从不被当作字面凭据。结构加载器仍遵循安全环境路由/模型/策略字段,但从不物化环境 HTTP 头、沙箱 API key 或搜索 API key;只有显式 API/local 探测切换到正常凭据加载路径。选择加入的更新检查也只发出类型化通用失败:不可信 release 元数据和传输错误不被回显。
1399
1400 如果配置加载或验证失败,`doctor --json` 返回非零,并打印带 `status = "error"` 和 `error.kind = "config_validation"` 的有界 JSON 错误信封。它对无效配置不发出正常路由或能力报告——也不发出可能敏感的底层错误。
1401
1402 除非运行显式 MCP 命令,MCP 条目是配置诊断。`mcp.probe_scope` 是 `configuration`,`mcp.live_health_checked` 为 false,每个服务器把 `checks.configuration` / `checks.command` 与 `checks.process_reachable`、`checks.protocol_initialized` 和 `checks.backend_tool_health` 分开。后三者在 doctor 输出中保持 `not_checked`。运行 `codewhale mcp validate` 显式启动启用的服务器并验证协议初始化/发现;后端健康仍需适当的显式工具调用。Doctor 只报告安全的结构性 MCP 字段:URL userinfo/path/query/fragment、原始命令参数、环境值、头值和 token 材料被省略。Provider URL 遵循同样规则,只暴露 `scheme://host[:explicit-port]`。
1403
1404 `capability` 键包含从静态知识(release 文档、API 指南)派生的按 provider 能力信息,而不是实时 API 探测。顶层子键:`resolved_provider`、`resolved_model`、`context_window`、`max_output`、`thinking_supported`、`cache_telemetry_supported` 和 `request_payload_mode`。
1405
1406 在 CI 脚本中用 `capability.context_window` 和 `capability.max_output` 做模型上限检查;不要把 `capability.max_output` 当作每回合请求预算。用 `capability.thinking_supported` 决定是否配置推理努力。
1407
1408 ## Setup 状态、清理与扩展目录
1409
1410 `codewhale setup` 接受除现有 `--mcp`、`--skills`、`--local`、`--all` 和 `--force` 之外的几个标志:
1411
1412 - `--status`——打印紧凑的单屏状态(api key、base URL、模型、MCP/skills/tools/plugins 计数、沙箱、`.env` 存在)。只读且无网络;在 CI 中安全。如果工作区中 `.env` 缺失而 `.env.example` 存在,状态输出指向 `cp .env.example .env`。
1413 - `--tools`——用描述自描述 frontmatter 约定(`# name:` / `# description:` / `# usage:`)的 `README.md` 和一个遵循它的 `example.sh`,搭建 `~/.codewhale/tools/`。该目录刻意不自动加载;通过 MCP、hooks 或 skills 把单个脚本接入智能体。
1414 - `--plugins`——用 `README.md` 和 `example/plugin.toml` 加一个命名空间示例 Skill 搭建 `~/.codewhale/plugins/`。包被只读、不可信、禁用地发现;启用前通过 `/plugin` 审查。v0.9.1 只激活声明的 Skills 和 MCP 服务器。见 [PLUGIN_BUNDLES.md](../PLUGIN_BUNDLES.md)。
1415 - `--all` 现在一起搭建 MCP + skills + tools + plugins。
1416 - `--clean`——列出 `~/.codewhale/sessions/checkpoints/latest.json` 和 `offline_queue.json`(若存在)。旧 `~/.deepseek/sessions/checkpoints/` 文件不自动扫描;一次性旧版清理设置 `CODEWHALE_HOME=~/.deepseek`。传 `--force` 才实际移除匹配文件。这从不触碰真实会话历史或任务队列。
1417
1418 `--status` 和 `--clean` 与搭建标志互斥。
1419
1420 ## 为什么引擎剥离 XML/`[TOOL_CALL]` 文本
1421
1422 codewhale 只通过 API 工具通道(结构化 `tool_use` / `tool_call` 项)发送和接收工具调用。`crates/tui/src/core/engine.rs` 中的流循环识别一组固定的假包装开始标记——`[TOOL_CALL]`、`<codewhale:tool_call`、`<tool_call`、`<invoke `、`<function_calls>`——并把它们从可见助手文本中擦除,从不让它们变成结构化工具调用。包装被剥离时,循环每回合发出一条紧凑 `status` 通知,让用户看到可见文本为何缩小。把任何重新启用基于文本工具执行的更改视为回归;`crates/tui/tests/integration/protocol_recovery.rs` 中的协议恢复测试锁定该契约。
1423
1423 lines MARKDOWN