首页
/ Caveman `/caveman:init` 命令深度解析:一条命令为全部 IDE Agent 写入常驻精简规则

Caveman `/caveman:init` 命令深度解析:一条命令为全部 IDE Agent 写入常驻精简规则

2026-09-05 14:35:35作者:江焘钦

/caveman:init 是 caveman 仓库("why use many token when few token do trick")中一个面向多 IDE 的按仓库初始化工具:它以 Claude Code 斜杠命令的形式定义,底层调用自包含的 Node 脚本 caveman-init.js,把"always-on caveman"精简沟通规则一次性写入 Cursor、Windsurf、Cline、GitHub Copilot、OpenCode、AGENTS.md 等各个 Agent 的规则位置。读完本文,你将掌握该命令的两种运行路径(仓内运行与 curl | node 独立运行)、完整的目标文件清单与写入模式、幂等/围栏/原子写的底层实现,以及 --dry-run--force--only 三个参数的实际行为边界。

命令定义与用途

该命令以 Claude Code 命令文件格式存放于 commands/caveman-init.md,其 frontmatter 声明了命令元数据:

---
description: Drop the always-on caveman activation rule into the current repo for every IDE agent
argument-hint: "[--dry-run|--force] [--only <agent>]"
---

命令正文只描述了三件事:

  1. 把每仓库的 caveman 规则文件(Cursor、Windsurf、Cline、Copilot、AGENTS.md)写入当前仓库,并汇报结果;
  2. 按"取第一个适用项"的策略选择运行方式:
    • 若当前仓库存在 src/tools/caveman-init.js(即你正处在一个 caveman 检出目录中),运行 node src/tools/caveman-init.js $ARGUMENTS
    • 否则下载独立脚本执行——该脚本自包含、支持 stdin 执行:curl -fsSL https://raw.githubusercontent.com/JuliusBrussee/caveman/main/src/tools/caveman-init.js | node - $ARGUMENTS
  3. 如果用户没有传 --force,先使用 --dry-run,确保绝不悄悄覆盖已有规则文件。

同一命令还有 commands/caveman-init.toml 版本(其他 Agent 使用的 TOML 格式命令定义),内容与 .md 版等价。

这里的"always-on 规则"解决的是一个具体问题:Caveman 技能(npx skills add JuliusBrussee/caveman)默认是逐会话按需激活的,而 Cursor、Windsurf、Cline、Copilot 这类 Agent 没有 hook 系统,想要"常驻精简模式"只能靠静态规则文件。init 命令就是这条常驻路径的按仓库分发器——这一点在 INSTALL.md 的 "always-on" 章节中也有对应说明,且两者的规则内容共用同一份单一事实源。

规则内容从哪来:单一事实源

写入各 IDE 的规则正文并非散落在各处,脚本采用"仓库内源优先、内嵌副本兜底"的双保险策略。从 src/tools/caveman-init.jsloadRuleBody() 可以看到:

function loadRuleBody() {
  // Prefer the in-repo source-of-truth when available.
  try {
    const local = path.join(__dirname, '..', 'rules', 'caveman-activate.md');
    if (fs.existsSync(local)) return fs.readFileSync(local, 'utf8').trimEnd() + '\n';
  } catch (e) {}
  return RULE_BODY;
}
  • 首选读取 src/rules/caveman-activate.md——仓库中规则正文的唯一权威来源;
  • 若该文件不存在(即 curl | node 独立运行场景),回退到脚本内嵌的 RULE_BODY 常量(src/tools/caveman-init.js),源码注释明确要求两者保持同步。

规则正文本身定义了精简沟通的行为契约:

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.

要点包括:保留全部技术实质、只删虚词与客套;支持 lite | full | ultra 及对应文言档位切换;安全警告、不可逆操作、用户困惑时自动恢复正常措辞(Auto-Clarity);代码/commit/PR 永远按正常风格书写。仓库的维护约定(见 CLAUDE.md)也明确:改自动激活规则应编辑 src/rules/caveman-activate.md,不要编辑任何用户机器上的 per-agent 规则副本。

完整写入目标:7 个 Agent、两种写入模式

命令文档摘要中列出 Cursor/Windsurf/Cline/Copilot/AGENTS.md 五类目标,而源码中的 AGENTS 注册表(src/tools/caveman-init.js)实际覆盖了 7 个目标,每个目标由"文件路径 + frontmatter + 模式"三元组描述:

agent id 目标文件 写入模式 附加 frontmatter
cursor .cursor/rules/caveman.mdc replace(整文件覆盖) description: ... + alwaysApply: true
windsurf .windsurf/rules/caveman.md replace trigger: always_on
cline .clinerules/caveman.md replace
copilot .github/copilot-instructions.md append(追加围栏块)
opencode .opencode/AGENTS.md append
agents AGENTS.md append
openclaw ~/.openclaw/workspace/{skills/caveman/, SOUL.md} 特殊 installer 分支 见下文

两种模式的分工在源码中有清晰注释(src/tools/caveman-init.js):

  • replace 模式:目标文件是 caveman 独占的单用途文件(如 .cursor/rules/caveman.mdc),直接由 frontmatter + 规则正文组成,caveman 完整拥有该文件;
  • append 模式:目标文件(AGENTS.mdcopilot-instructions.md 等)是用户自己也在维护的共享文件,因此 caveman 的贡献必须用 HTML 注释围栏包裹:
const FENCE_BEGIN = '<!-- caveman-begin -->';
const FENCE_END = '<!-- caveman-end -->';

没有这对围栏,规则块既无法在升级时原地刷新,也无法在卸载时干净移除——源码里把这个后果形容为"fossilize in the user's repo"(化石化在用户仓库里)。

OpenClaw 特殊分支

OpenClaw 是全局工作区工具而非按仓库安装,且需要写两个目标(技能目录 + SOUL.md 引导块),因此它不走"文件/frontmatter/模式"三元组,而是通过 installer: 'openclaw' 回调逃生舱转交给共享助手 bin/lib/openclaw.jssrc/tools/caveman-init.js 中的 loadOpenclawHelper() 惰性加载)。注意:在 curl | node 独立模式下磁盘上没有这个助手文件,此时该目标会报告 unsupported-standalone 状态并提示改用 npx 方式运行——这是独立模式的已知边界。

幂等性设计:状态机与损坏围栏防御

caveman-init.js 文件头注释第一句就是 "Idempotent. Safe to re-run.",processAgent()src/tools/caveman-init.js)实现了一台相当细致的状态机。核心识别机制是哨兵字符串:

const SENTINEL = 'Respond terse like smart caveman';

append 模式的状态流转

  1. 文件不存在 → 写入围栏块,状态 added+);
  2. 文件存在且围栏配对完整caveman-begincaveman-end 各恰好出现一次且 begin 在 end 之前):
    • 块内容与期望完全一致 → skipped-already-installed=),不做任何写入;
    • 块内容过期(规则正文变了)→ 原地刷新,仅替换围栏之间的字节,围栏两侧的用户内容原样保留,状态 refreshed~);
  3. 围栏损坏(孤儿 BEGIN、BEGIN/END 数量不为 1、END 出现在 BEGIN 之前)→ skipped-damaged-fence!),一个字节都不写。源码注释解释了为什么必须如此:一个孤儿 BEGIN 若被"聪明地"与后面块的 END 配对,刷新会替换两者之间的全部字节——包括用户自己的内容;把损坏标记当作损坏处理、报告并停手,才能保证第二次运行不会让损失复利;
  4. 旧版无围栏安装(文件里只有裸的哨兵文本)→ skipped-legacy-unfenced?):无法区分哪些字节是 caveman 写的、哪些是用户改的,静默重写被跟踪的仓库文件比留一个过期块更糟;
  5. 全新共享文件(既无围栏也无哨兵)→ 追加围栏块,状态 appended~)。

replace 模式的状态流转

replace 模式的文件没有围栏,哨兵命中无法可靠区分"我们装过的旧规则"和"用户恰好引用了规则原文的文件",因此策略更保守:

  • 文件不存在 → added
  • 文件已存在且含哨兵 → skipped-already-installed(不做猜测性覆盖);
  • 文件已存在、无哨兵、且用户传了 --force → 整文件覆盖,状态 overwritten!)——--force 是 replace 模式下唯一的重置路径;
  • 其余情况 → skipped-exists?)。

这套状态机与命令文档中"先 --dry-run、不悄悄覆盖"的原则互为表里:默认路径下,任何已有文件都只会被"跳过"或"围栏内原地刷新",绝不被整文件覆盖。

原子写与跨平台落盘细节

规则文件最终落在用户仓库的受跟踪路径上,一次中断的半截写入会破坏用户已提交的文件。writeAtomic()src/tools/caveman-init.js)因此采用"临时文件 + rename"策略,并针对同步盘做了重试:

for (let attempt = 0; ; attempt++) {
  try {
    fs.renameSync(tmp, fullPath);
    break;
  } catch (error) {
    const transient = error.code === 'EPERM' || error.code === 'EBUSY' ||
                      error.code === 'EACCES' || error.code === 'EEXIST';
    if (!transient || attempt >= 2) throw error;
    Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 10 * (attempt + 1));
  }
}

从源码注释可知:rename 到已存在的目标需要 DELETE 访问权,而 OneDrive/Dropbox 同步客户端和杀毒扫描器恰好持有带 FILE_SHARE_DELETE 之外的句柄;对瞬态错误按 10ms 递增退避重试最多两次,失败则清理临时文件并抛出。这与 caveman-config.jssafeWriteFlag() 采用同一策略。

命令行参数与输出格式

参数解析在 parseArgs()src/tools/caveman-init.js):

参数 含义
[target-dir] 位置参数,指定目标仓库目录;缺省为当前工作目录
--dry-run 只报告将发生的变更,不写任何文件
--force / -f 覆盖已存在的规则文件(默认:跳过)
--only <id> 仅为一个 agent 安装,id 取自目标清单
-h / --help 打印用法,含完整目标清单

一个值得注意的健壮性细节:--only 的值缺失或拼错(如 --only nope)时,脚本会直接以退出码 2 报错 caveman-init: --only requires one of: cursor, windsurf, cline, copilot, opencode, agents, openclaw。源码注释解释了动机——这类错误过去会"看起来像成功":要么静默退化为全量安装,要么匹配不到目标而报告一个全零的假成功。

main() 的输出格式为逐行状态 + 汇总计数:

🪨 caveman init — /path/to/repo (dry run)

  + .cursor/rules/caveman.mdc (added)
  ~ AGENTS.md (appended)
  ...

N added, N appended, N refreshed, N overwritten, N skipped
(dry run — no files were written)

状态到计数的归并规则(src/tools/caveman-init.js):added/installed/would-add 计入 added,appendedrefreshedoverwritten 各自单列,其余状态(各类 skipped)计入 skipped。

独立运行的隐藏坑:stdin 执行守卫

curl … | node - 是命令文档指定的独立运行路径,但脚本末尾的执行守卫比经典的 require.main === module 多写了一半(src/tools/caveman-init.js):

// Run when executed directly AND when piped via `curl … | node -` (the
// documented standalone path, #603): under stdin execution require.main is
// undefined and module.id is '[stdin]', so the classic guard alone silently
// no-ops with exit code 0 — the worst kind of failure.
if (require.main === module || (!require.main && module.id === '[stdin]')) main();

在 stdin 管道执行下 require.mainundefinedmodule.id'[stdin]',经典守卫会导致脚本静默什么都不做且退出码为 0。仓库内还有回归测试守着这一行为:tests/installer/slash-commands.test.mjs 中 issue #603 的断言要求 commands/caveman-init.md / .toml 凡引用仓库相对路径 src/tools/caveman-init.js,必须同时提供 raw.githubusercontent.com … caveman-init.js 的 curl 独立回退,防止命令对"已安装用户"(他们本地没有 src/tools/ 目录)整体失效。

测试对关键行为的验证

tests/test_caveman_init.js 是一组 fixture 式端到端测试(node tests/test_caveman_init.js 即可运行),覆盖了状态机的主要分支,可作为行为验收清单:

  • greenfield:全新目录一次写入全部规则文件,且 frontmatter 正确(.cursoralwaysApply: true.windsurftrigger: always_on);
  • 幂等:对刚装好的目录重跑,输出 7 skipped,无 added;
  • append 不替换:已含用户内容的 AGENTS.md 追加规则后原文 Do not delete me. 仍在;
  • --force 不覆盖:预置的 .cursor/rules/caveman.mdc 内容逐字节不变;
  • --force 覆盖:同样文件被替换为带 frontmatter 的新规则;
  • --dry-run:输出 (dry run)6 added,但六个目标路径一个都不存在;
  • --only cline:只生成 .clinerules/caveman.md
  • 哨兵检测:手写了含哨兵的 cline 文件 → skipped-already-installed
  • 围栏刷新:围栏块内容过期时原地刷新,caveman-begin 标记数量保持 1(不叠加第二块),围栏两侧用户内容保留;
  • --only nope / 裸 --only:退出码 2,错误信息 --only requires one of
  • 孤儿 BEGIN 标记:连续重跑 3 次均报 skipped-damaged-fence,文件与初始内容逐字节一致;
  • END 在 BEGIN 之前:同样拒绝处理。

测试还通过把 OPENCLAW_WORKSPACE 指向 fixture 内不存在的目录,确保 openclaw 分支不会触碰开发者真实的 ~/.openclaw/workspace

--with-init 安装器的关系

/caveman:init 斜杠命令并不是唯一的入口,它是同一脚本的"命令面"。完整安装器 bin/install.js--with-init 标志走同一条路:INSTALL.md 的参数表说明 --with-init 会"Drop always-on rule files into the current repo(.cursor/.windsurf/.clinerules/.github/copilot-instructions.md.opencode/AGENTS.mdAGENTS.md),并在检测到 OpenClaw 时追加 ~/.openclaw/workspace/SOUL.md 引导块",规则单一事实源同样是 src/rules/caveman-activate.md。卸载文档亦说明:--with-init 写出的这些按仓库规则文件属于可选残留,需要时手动删除即可。

实操建议:推荐的运行顺序

结合命令文档的约束与源码行为,在目标仓库中启用 always-on caveman 的稳妥流程是:

  1. 先干跑node src/tools/caveman-init.js --dry-run(仓内)或 curl -fsSL https://raw.githubusercontent.com/JuliusBrussee/caveman/main/src/tools/caveman-init.js | node - --dry-run(任意仓库),确认 added/refreshed/skipped-* 明细符合预期;
  2. 正式执行:去掉 --dry-run 再跑一次;共享文件(AGENTS.md 等)会以围栏块追加或原地刷新,独占文件直接生成;
  3. 只装一个 Agent:加 --only <id>,id 必须取自帮助输出中的清单,否则以退出码 2 失败;
  4. 确需重置独占规则文件:显式加 --force——这是唯一会覆盖非 caveman 内容的路径,故命令文档要求"用户未传 --force 时先 dry-run";
  5. 遇到 skipped-damaged-fence / skipped-legacy-unfenced:这是防御性停手而非故障。前者需要人工检查 AGENTS.md 等文件里的围栏标记(孤儿或错序的 <!-- caveman-begin -->/<!-- caveman-end -->),后者需要手动删掉旧规则块后重跑以获得围栏化安装。

总体而言,/caveman:init 虽然只有几行命令文档,其背后的 caveman-init.js 实现把"往用户受跟踪仓库里写文件"这件事的边角——幂等重跑、共享文件围栏、损坏标记防御、原子落盘、stdin 静默失败——都做了显式处理,并配有逐分支的 fixture 测试,是 caveman 常驻规则分发链中值得细读的一环。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.12 K
2.72 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
528
588
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
906
1.83 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
854
1.34 K
docsdocs
暂无描述
Markdown
891
5.78 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.53 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.34 K
1.45 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
987
506
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
540
384