caveman opencode 插件的 /caveman 命令:七级压缩模式切换的模板机制与解析管线
【免费下载链接】caveman🪨 why use many token when few token do trick — Claude Code skill that cuts 65% of tokens by talking like caveman项目地址: https://gitcode.com/GitHub_Trending/caveman1/caveman
caveman 是一个"用更少的 token 表达同等技术内容"的 Claude Code / opencode 压缩技能,其 opencode 插件通过 src/plugins/opencode/commands/caveman.md 这个斜杠命令模板实现会话级压缩模式切换。本文以该命令文件为主体,完整讲清/caveman的模板语法、七种可选模式级别与行为规则,并向下深入到 plugin.js 的模板展开解析、caveman-parse.js 的单一解析源,以及 caveman-config.js 的防符号链接 flag 文件写入机制——读完你能完整理解一次/caveman ultra从输入到模式落地的全链路。
1. 命令文件全貌:13 行的完整定义
caveman.md 的全部正文如下,frontmatter 与正文一个字符都不少:
--- description: Activate caveman mode (lite | full | ultra | wenyan-lite | wenyan-full | wenyan-ultra | off) --- Activate caveman mode: $ARGUMENTS If no level given, use full. If "off", deactivate. Respond terse like smart caveman. Drop articles, filler, pleasantries, hedging. Fragments OK. Technical terms exact. Code unchanged. Pattern: [thing] [action] [reason]. [next step]. Behavior persists until session ends or user says "stop caveman" / "normal mode". Code, commits, security warnings: write normal English.它由两部分构成:
- YAML frontmatter:
description字段声明命令用途与全部可接受参数(lite | full | ultra | wenyan-lite | wenyan-full | wenyan-ultra | off)。opencode 用该字段在 TUI 的命令补全里展示说明。 - 命令正文:第一行
Activate caveman mode: $ARGUMENTS是参数占位符——用户输入/caveman ultra时,opencode 会把整段正文展开为Activate caveman mode: ultra,替换后再进入插件的chat.message钩子。这一点是理解后文"模板展开"机制的关键:插件拿到的从来不是原始斜杠命令,而是替换后的散文。
正文随后给出四条语义契约:
- 缺省级别:未给参数时按
full处理;显式off表示停用。 - 压缩风格:像聪明的原始人一样简洁作答——去掉冠词、填充词(just/really/basically)、客套与含糊措辞;允许句子片段;技术术语保持精确;代码原样不动。
- 句型模板:
[thing] [action] [reason]. [next step].(对象 + 动作 + 原因,然后下一步)。 - 生命周期与边界:行为持续至会话结束或用户说 "stop caveman" / "normal mode";代码、commit、安全警告一律恢复正常英文。
/caveman不是孤立的:同目录 commands/ 下还有五个姊妹命令,README 将其归纳为"六个斜杠命令提示模板":
| 命令文件 | 作用 |
|---|---|
| caveman.md | 激活/切换会话压缩模式(本文主角) |
| caveman-commit.md | 为暂存区生成 Conventional Commits 风格的极简 commit 信息(subject ≤50 字符、祈使句、小写) |
| caveman-review.md | 单行式代码评审,格式L<行号>: <severity> <问题>. <修复>.,按文件分组并以一行结论收尾 |
| caveman-compress.md | 用 caveman-compress 技能压缩指定 markdown 文件,原文件备份为<file>.original.md |
| caveman-stats.md | 读取~/.config/caveman/.caveman-history.jsonl,输出累计节省 token、会话数、平均压缩比 |
| caveman-help.md | 模式/命令/触发词速查卡 |
2. 模式级别全表:从 30% 压缩到文言压缩
/caveman的参数空间比 frontmatter 一行描述更有结构。结合 caveman-help.md 的速查卡、caveman-config.js 中的VALID_MODES白名单和 caveman-parse.js 的解析逻辑,可以整理出完整的级别表:
| 输入参数 | 效果 | 存储值 |
|---|---|---|
| (无参数) | 激活配置默认级别;未配置时即full | 默认模式 |
lite | 轻度压缩,约 30% token 削减 | lite |
full | 标准压缩(缺省行为) | full |
ultra | 最大压缩 | ultra |
wenyan-lite | 文言文轻度压缩 | wenyan-lite |
wenyan/wenyan-full | 文言文标准压缩 | wenyan(别名归一) |
wenyan-ultra | 文言文最大压缩 | wenyan-ultra |
off/stop/disable | 停用,删除 flag 文件 | —(文件被删除) |
几个值得注意的解析细节(均来自 caveman-parse.js):
wenyan-full是别名:L102-L103 将其归一为wenyan,配置侧只存储wenyan。所以 frontmatter 列出的七个值中,wenyan-full与wenyan等价。- 停用词不止一个:
off、stop、disable三个词都会触发clear(L101),而命令文件正文只提到了 "off"。 - 独立模式不可经此命令选择:
commit、review、compress三个真实存在于VALID_MODES的级别属于INDEPENDENT_MODES(L53),它们由各自的斜杠命令激活;若有人输入/caveman commit,解析器返回unresolved而非静默回落到默认值——这是有意设计,避免"错误的级别被默认值悄悄覆盖"。 - 标点容忍:normalizeModeArg 会剥掉
/caveman ultra;这类粘连的尾随标点与首部引号,保证"ultra"也能解析。 - 裸命令 ≠ 空参数:真正"没写参数"的裸
/caveman才激活默认级别;而/caveman ?这种参数被归一化后为空的情况会返回unresolved,避免把疑似求助的输入直接切换进压缩模式。
3. 行为规则:压缩风格、持久化与自动清晰边界
命令正文声明的规则,其完整版本由安装器写入~/.config/opencode/AGENTS.md(Tier-3 常驻规则集),仓库中的源文件是 src/rules/caveman-activate.md。对照阅读可以补齐命令正文未展开的两条关键机制:
Respond terse like smart caveman. All technical substance stay. Only fluff die. Rules: - Drop: articles (a/an/the), filler (just/really/basically), pleasantries, hedging - Fragments OK. Short synonyms. Technical terms exact. Code unchanged. - Pattern: [thing] [action] [reason]. [next step]. - Not: "Sure! I'd be happy to help you with that." - Yes: "Bug in auth middleware. Fix:" Switch level: /caveman lite|full|ultra|wenyan-lite|wenyan-full|wenyan-ultra Stop: "stop caveman" or "normal mode" Auto-Clarity: drop caveman for security warnings, irreversible actions, user confused. Resume after. Boundaries: code/commits/PRs written normal.命令文件中的Code, commits, security warnings: write normal English.对应这里最完整的两条边界:
- Auto-Clarity(自动清晰):遇到安全警告、不可逆操作或用户困惑时自动退出原始人风格,事后再恢复。也就是说"边界"不仅是静态清单,还包含运行时条件。
- Boundaries(静态边界):代码、commit、PR 一律正常书写——压缩的永远是自然语言,不是代码语义。
- 正反例:规则集直接给出否定例("Sure! I'd be happy to help you with that.")与肯定例("Bug in auth middleware. Fix:"),这是提示词工程中少见的"few-shot by contrast"写法,让模型对"去掉什么"有可对照的锚点。
自然语言开关与斜杠命令等效(caveman-parse.js L150-L207):
| 说法 | 效果 |
|---|---|
| "activate caveman"、"turn on caveman"、"talk like caveman"、"caveman mode on" | 按配置默认级别激活 |
| "less tokens"、"be brief"、"fewer tokens"、"shorter answers" | 同上(简洁请求也视为激活意图,但仅限非限定语境) |
| "stop caveman"、"turn off the caveman"、"caveman off" | 停用 |
| "normal mode"(句首,或含 caveman 上下文) | 停用 |
其中有两处防御值得注意:其一,引用不触发——QUOTED_SPAN_REGEX(L72)在匹配前把引号与反引号包裹的片段空白化,因此粘贴一段引用了 "stop caveman" 的 bug 报告不会误触发停用(这是 #838 修复的真实缺陷场景);其二,问句不激活——以 what/how/does/is 等开头的问句("what is caveman mode?")被排除在激活模式之外。
4. 解析管线:opencode 的模板展开如何被识别
这是理解/caveman在 opencode 中"为什么长这样"的核心。opencode 会在chat.message钩子触发之前,把用户输入的/caveman ultra替换为命令文件的正文,于是插件看到的是:
Activate caveman mode: ultra If no level given, use full. If "off", deactivate. Respond terse like smart caveman. ...原始斜杠形式永远不会抵达插件。plugin.js L170-L178 的chat.message钩子遍历消息的文本 part,对每个 part 调用:
const change = parseModeChange(part.text, { getDefaultMode, expandedTpl: true, unwrapQuotes: true }); if (change) applyModeChange(change);两个选项是 opencode 专属的:
expandedTpl: true:启用"模板展开体"识别。caveman-parse.js L170-L182 先检查三个独立模式的固定前缀(generate a commit message...→ commit、review the current diff→ review、compress the file at:→ compress),然后对 caveman 命令用正则/^activate caveman mode:[ \t]*(\S*)/从未折叠空白的第一行里提取级别——因为第一行尾部就是$ARGUMENTS的落点。该分支必须跑在通用自然语言激活匹配之前,否则 "Activate caveman mode: ultra" 会命中 "activate ... caveman" 触发词,把级别吞掉、按默认值激活(#602 的原始缺陷)。unwrapQuotes: true:非交互的opencode run路径会把整条消息包在字面引号里,先剥掉一层再解析(L121-L124)。
解析结果的消费端是 plugin.js L122-L131 的applyModeChange:clear→ 删除 flag 文件;set→ 经safeWriteFlag写入模式值;unresolved被直接忽略(不覆盖现状、不产生副作用)。
5. 状态落地:flag 文件与四级默认值解析
opencode 插件的全部动态状态就是一个文件:~/.config/opencode/.caveman-active(plugin.js L99-L106,路径从$XDG_CONFIG_HOME或~/.config/opencode推导)。"off" 的表示方式是文件不存在,这一点由readFlag的 null 返回语义保证。
每次模式变化写入前,safeWriteFlag(caveman-config.js L168-L274)执行一套针对"可预测路径被符号链接劫持"的防护:
- 临时文件 + 原子
rename,O_NOFOLLOW | O_CREAT | O_EXCL,权限0600; - 父目录若是符号链接,先解析真实路径并做所有权校验(Unix 校验 uid,Windows 退化为"必须落在用户 home 之下");
- flag 文件本身若是符号链接则直接拒绝;
- Windows 锁竞争(EPERM/EBUSY 等)下三次重试 + 退避,finally 保证临时文件不残留。
读取端readFlag(L289-L319)对称防御:拒符号链接、64 字节硬上限(最长合法值wenyan-ultra仅 12 字节)、且返回值必须命中VALID_MODES白名单,否则一律 null。这意味着即便 flag 文件被写入任意内容,也只会被解释为"模式未激活"。
默认值从哪来?命令文件说 "If no level given, use full",但裸/caveman实际调用的是getDefaultMode(),其解析顺序(caveman-config.js L118-L138,与文件头注释一致)是:
- 环境变量
CAVEMAN_DEFAULT_MODE(值必须在VALID_MODES内); - 仓库级配置——从 cwd 向上逐级查找
.caveman/config.json或.caveman.json(最多 64 层,拒符号链接),让团队可以按项目固定默认模式而不污染每个贡献者的用户配置; - 用户配置:
$XDG_CONFIG_HOME/caveman/config.json(Windows 为%APPDATA%\caveman\config.json)中的defaultMode字段; - 兜底
full——这才是命令文件里 "use full" 的真正含义:它是所有覆盖都不存在时的缺省,而非无条件行为。
因此{"defaultMode": "lite"}写进仓库的.caveman/config.json,之后裸/caveman就会进入 lite 级别;CAVEMAN_DEFAULT_MODE=off则让"会话创建即默认激活"变成 no-op。
6. 会话创建与逐轮强化:三个钩子的分工
plugin.js 通过三个钩子把上面的状态变成持续生效的行为:
插件工厂 +
event钩子(L145-L161):会话启动时按默认模式写 flag。工厂加载时立即写一次,是为覆盖一次性opencode run下"首个session.created先于插件事件分发"的竞态;此后每次session.created事件再重新断言,使长驻 TUI 进程里的新会话也携带正确模式。若默认模式是off,则删除 flag。chat.message钩子:即第 4 节所述的模式变更解析;其返回值被 opencode 忽略,状态变化完全经由 flag 文件完成。experimental.chat.system.transform钩子(L183-L209):每次 LLM 请求前检查 flag;若处于激活且非独立模式,向系统提示词注入一行强化:CAVEMAN MODE ACTIVE (full) — session ruleset applies.注入是幂等重写而非追加:用正则
/CAVEMAN MODE ACTIVE \([a-z-]+\) — session ruleset applies\./g找到已存在的旧行原地替换,找不到才追加到系统提示词末尾。注释(L188-L192)说明了原因——若 opencode 跨轮复用同一 system 数组而无条件追加,系统提示词会无界增长、静默吞噬上下文窗口。
还有一个值得了解的非对称设计(src/plugins/opencode/README.md 的 "What it does NOT do" 一节):插件不从session.created注入系统提示词——opencode 的文档未暴露该钩子的返回形状,所以常驻规则集改由安装器写入~/.config/opencode/AGENTS.md,规则因此不依赖插件运行时是否健康;另外 opencode TUI 没有可写状态栏,模式想显示在 shell 提示符里只能直接读.caveman-active。
7. 适用前提、已知限制与排查
从 plugin.js 头部注释 看,以下事实构成适用边界:
- 版本前提:钩子路由(单一
event处理器按event.type === 'session.created'分发)要求 opencode ≥ 1.15.x;旧版中直接以'session.created'/'tui.prompt.append'为顶层钩子键的写法会被静默忽略(对应 issue #418、#421)。排查"模式没生效"时应先确认版本与事件分发。 - 模块加载限制:opencode 插件运行在编译后的 Bun 二进制里,磁盘文件的
require()被拒、import()一个 CJS 文件得到空命名空间。因此caveman-config.js/caveman-parse.js是以new Function(...)求值加载的(loadConfig),安装时改名为caveman-config.cjs/caveman-parse.cjs(src/plugins/opencode/package.json 声明"type": "module")。解析逻辑刻意保持与 Claude Code 侧的caveman-mode-tracker.js同源共享(#602),两侧不会漂移。 - flag 是尽力而为:
safeWriteFlag在任何文件系统错误下静默失败(可设CAVEMAN_DEBUG=1输出诊断),模式状态丢失不会报错,只能靠readFlag的 null 语义降级为"未激活"。 - 不独立的 npm 包:插件复用主仓库的
caveman-config.js,作为仓内插件随主安装器分发(bin/install.js --only opencode把 src/plugins/opencode 目录连同caveman-config.cjs拷入~/.config/opencode/plugins/caveman/并在opencode.json中追加"plugin"条目),避免第二次发布节奏与第三方opencode-caveman包的命名冲突。
8. 小结
caveman.md 作为 opencode 插件的入口命令,表面上是 13 行提示词,实际上是一个完整状态机的用户面:
- 模板层:frontmatter 的
description支撑命令补全,$ARGUMENTS承载级别参数,正文定义缺省(full)、停用(off)与压缩风格契约; - 解析层:
parseModeChange以单一共享源识别模板展开体、斜杠命令与自然语言三类输入,带引用防误触、问句排除、标点容忍与"拒绝静默覆盖"的防御语义; - 状态层:
.caveman-activeflag 文件 + 四级默认值解析 + 符号链接安全的原子读写; - 行为层:会话创建写 flag、逐轮幂等注入
CAVEMAN MODE ACTIVE (mode)强化行,规则本体则驻留在AGENTS.md中独立于插件运行时存活。
理解这条链路后,你在 opencode 里输入/caveman lite时发生的每一件事——从模板替换、正则提取、模式白名单校验、原子落盘,到下一次请求的系统提示词注入——都是可追踪、可验证的。
【免费下载链接】caveman🪨 why use many token when few token do trick — Claude Code skill that cuts 65% of tokens by talking like caveman项目地址: https://gitcode.com/GitHub_Trending/caveman1/caveman
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考