首页
/ Caveman 开源贡献指南:DCO 签名、MIT/BSL 双轨许可与 PR 前置检查

Caveman 开源贡献指南:DCO 签名、MIT/BSL 双轨许可与 PR 前置检查

2026-09-06 14:49:40作者:凌朦慧Richard

Caveman 是一个通过"史前人类式"压缩语言把 AI 编码助手的 token 消耗降低约 65% 的 Claude Code skill 与配套压缩引擎。本文基于仓库贡献文档 CONTRIBUTING.md 及其引用的 LICENSING.mddocs/CONTRIBUTING_PROFILES.md,系统讲清向该项目提交代码的完整路径:从 DCO 提交签名的含义,到 MIT 与 BSL-1.1 按目录划分的许可边界,再到维护者的审查关注点和提交 PR 前的自查清单,并深入源码说明"新增一个压缩器"这一核心贡献类型的真实代码契约。读完本文,你能独立判断某次改动落在哪个许可区域、如何正确签名提交,以及如何在动手前满足项目的字节安全与测试要求。

项目接受哪些贡献

CONTRIBUTING.md 开宗明义:PR 欢迎五类贡献——新的压缩器(compressors)、集成(integrations)、agent recipe、bug 修复和文档。其中内容类型压缩器是被单独点名的贡献方向,因为每一个新压缩器都让 Caveman 对一整类新的 payload 形态产生价值。文档列举的候选方向包括 CSV、HTML、SQL dump、notebook 输出和 OpenAPI spec,并给出明确的工作方式:engine/ 目录下现有的一个压缩器起步,复制它的形状

从源码结构看,这个"复制它的形状"有严格的接口依据。所有压缩器实现同一个接口,定义在 engine/compressors/compressor.go

// Compressor compresses one content type. Every compressor is structural,
// deterministic, idempotent, and fail-closed: on any parse problem it returns
// ok=false and the caller forwards the original bytes unchanged.
type Compressor interface {
    // ContentType is the type this compressor handles (e.g. "json").
    ContentType() string
    // SafetyClass is the compressor's inherent class on the S0–S4 ladder.
    SafetyClass() safety.Class
    // Compress returns the compressed bytes with ok=true on success.
    Compress(input []byte) (out []byte, ok bool)
}

接口的注释即是对贡献者的硬约束:每个压缩器必须是结构性的、确定性的、幂等的、fail-closed 的——任何解析问题都必须返回 ok=false,由调用方把原始字节原样转发出去。这正是 CONTRIBUTING 中"byte-safe"要求的实现层落点,详见后文 PR 前置检查一节。

同文件中的 Default() 注册表展示了当前引擎内置的全部压缩器,这也是新压缩器"起步参考"的候选清单:

  • 自动检测可达:jsonlogcode(构建期选择 cgo/tree-sitter 或纯 Go go/ast 实现)、diffsearchresulttexthtmltabularconfigterminal
  • 仅通过强制 Options.Type 可达:tool-schema、无损 tool-schematoonaxtreerepetition

新压缩器只需实现三个方法,经 Registry.Register 注册后即可被内容类型路由消费;包级注释也明确说明"加一个压缩器就是一个新文件加它的测试",因为压缩器是纯字节变换,不数 token、不存恢复句柄、不碰网络——这些职责由 engine core 在压缩器外围承担。

DCO:用一行签名替代 CLA

该项目不要求签署 CLA 或填写任何表格,而是采用 Developer Certificate of Origin(DCO)机制。DCO 是一行承诺:这段代码是你写的,或者你有权将其贡献出来。操作方式是对每个 commit 添加 sign-off:

git commit -s -m "your message"

-s 参数会在 commit message 末尾追加一个 Signed-off-by: Your Name <your@email> 的 trailer。docs/CONTRIBUTING_PROFILES.md 中对纯 profile 贡献也重复了同一要求,说明 DCO 签名是覆盖全仓库、不分 MIT 区还是 BSL 区的统一前置条件。

许可划分:MIT 与 BSL-1.1 按目录双轨运行

Caveman 采用按目录分裂的许可模型,这是理解任何贡献行为边界的关键。LICENSING.md 是逐目录许可的权威来源,根目录 LICENSE 是 MIT 文本加一段范围说明(指向 Engine-linked 目录使用 LICENSE.BSL),LICENSE.BSL 则是引擎相关代码的 BSL-1.1 规范文本。

MIT 目录:进出的许可对称

以下区域为 MIT:packages/{agent,create-caveman-agent,cli,sdk,subagent-tax}/packages/shared/contracts/shared/provider-catalog/、extension 外壳、skill 本体。规则简单:inbound = outbound——你的贡献以同样的 MIT 条款许可出去,无附加义务。

BSL-1.1 目录:贡献附带再许可授予

以下区域为 BSL-1.1:engine/proxy/cacheengine/rewriter/browse/mcp/shrink/、cavemem 的 Go core、shared/platform/。CONTRIBUTING.md 明确指出,向这些区域贡献时你同时授予 Julius Brussee 以商业或 OEM 条款再许可你的贡献的权利。其目的是保持 open-core 模型的连贯性:社区对引擎的改进可以随商业产品和 OEM 伙伴出货,而不是让代码库分裂成两半。你的贡献在公开仓库中保持 BSL-1.1,并和引擎其余部分在同一个 Change Date 日落转为 Apache-2.0。

对照 LICENSE.BSL 的参数段可以确认具体条款:

参数 取值
Licensor Julius Brussee
Licensed Work Caveman Engine (c) 2026
Additional Use Grant 允许内部评估、本地开发、CI 测试、集成以及自有第一方流量的自托管生产使用;不允许以托管/管理/嵌入式服务形式向第三方提供功能,此类用途需商业许可
Change Date 2030-06-21
Change License Apache License, Version 2.0

LICENSING.md 进一步把 Change Date 表述为"2030-06-21 与该版本首次以 BSL 公开发布满四年之日孰早"。

如果你不舒适 BSL 的再许可授予,CONTRIBUTING.md 给出的出路很直接:贡献 MIT 部分

逐目录许可速查

以下为 LICENSING.md 中许可表的完整内容(路径相对仓库根目录):

路径 许可 说明
skills/ MIT 既有 Caveman skill 保持 MIT 不变
packages/agent/ MIT Agent 运行时、构建编译器、Claude lane、框架适配器与 coding-agent API
packages/create-caveman-agent/ MIT 零运行时依赖的 Agent SDK 初始化器
packages/cli/ MIT 入口/上手层;会启动 BSL 二进制但不包含引擎代码
packages/sdk/typescript/ MIT 薄客户端与结构化 SDK 表面
packages/sdk/python/ MIT 薄客户端;发行名 caveman-sdk
packages/subagent-tax/ MIT 本地零 provider 调用的 harness 前缀度量工具
extension/ MIT 外壳 manifest、popup、content script 与 UI 为 MIT;内嵌 engine.wasm 是 BSL-1.1,因此包含它的外壳产物就组合整体携带 BSL 条款
packages/shared/contracts/ MIT 公开 wire schema 与生态契约
shared/provider-catalog/ MIT 公开 provider/model 元数据与 catalog schema
mem/js/mem/py/ MIT cavemem 的薄 JS/Python 客户端
engine/ BSL-1.1 核心压缩 IP 与 CCR
cacheengine/ BSL-1.1 Provider 原生 prompt-cache 规划器与 wire 引擎
rewriter/ BSL-1.1 引擎关联的反思改写器与恢复门
browse/ BSL-1.1 本地浏览器驱动;内嵌引擎,vendored MIT chromedp 模块
proxy/ BSL-1.1 独立网关与 provider 适配器
mcp/ BSL-1.1 Go 二进制内嵌引擎
shrink/ BSL-1.1 Go 二进制/包内嵌引擎的 tool-schema 压缩器
mem/ Go core BSL-1.1 Go core 内嵌引擎;JS/Python 客户端仍为 MIT
shared/platform/ BSL-1.1 静态链接进 BSL Go 二进制

该文件还给出新模块的默认规则:任何 import、链接、内嵌或以 Engine-linked 运行时一部分形式出货的新模块,默认为 BSL-1.1,除非后续决策明确将其归类为 MIT 采用面。这对评估"我的新文件该放哪、受什么约束"是直接的判断依据。

变更落在哪里:PR 审查与生成物规则

所有变更以 pull request 形式提交到本仓库。维护者会针对受影响目录检查四件事:许可范围、测试、生成产物(generated artifacts)、安全边界

Profile-only 变更走窄流程

只改 agent profile 的 PR 遵循更窄的流程,详见 docs/CONTRIBUTING_PROFILES.md。一个纯 profile PR 是向 agents/profiles/ 添加一个 <id>.json,且该 harness 必须满足:说一种既有 wire_protocol、用一种既有 injection.method、使用既有命令或 memory hook 方法(或省略 hooks)、不需要新的 CLI 安装器或网关适配器。标准操作序列:

node agents/compile.mjs
npm install --ignore-scripts --no-audit --no-fund --no-package-lock --prefix packages/cli
npm --prefix packages/cli run build
node --test packages/cli/tests/agent-registry.runtime.mjs packages/cli/tests/agent-shortcut.runtime.mjs packages/cli/tests/porcelain.runtime.mjs

提交时需同时带上 profile 文件与重新生成的 agents/agents.jsonpackages/cli/src/agents.generated.ts。该文档还列出了 profile 编译器的四条安全边界(injection.env 键名白名单正则、环境值只允许指定模板 token、profile 路径必须留在 ~/.<profile-id>/ 内、profile id 与二进制名不得与保留命令冲突),这些控制由 node agents/compile.mjs 强制执行,没有 force 开关也没有逐 profile 例外。

生成文件与源同 PR

CONTRIBUTING.md 有一条容易被忽略但很硬的规则:生成文件必须与其源放在同一个 PR 中提交,并且保留 commit 作者身份与 DCO 签名。上面 profile 流程中"提交 profile + 重新生成的两个文件"正是这条规则的具体实例——CI 会重跑编译器来核对生成物是否与源一致,缺了生成文件更新就是 CI 红灯。

提交 PR 前的自查清单

CONTRIBUTING.md 给出三条提交前检查,结合仓库各技术栈的实际测试入口,可以落地为如下可执行清单:

1. 构建并测试你碰过的包

文档原话是按目录选择命令:go test ./...pnpm testpytest。对照仓库实际配置:

  • Go 模块engine/proxy/mcp/shrink/ 等,模块名见 go.mod):go test ./...
  • TypeScript 工作区:根 package.json 的 test 脚本为 node --test --test-force-exit tests/installer/*.test.mjs tests/hooks/*.test.mjs;子包如 packages/agent/package.json 的 test 脚本是 tsc 类型检查加 node --test 运行 tests/*.runtime.mjspackages/cli/package.json 则先跑一系列生成脚本再执行测试;
  • Pythonevals/benchmarks/ 等):pytest

原则是"测你碰过的包",不必为一次局部改动跑全仓。

2. 保持 byte-safe:宁可不压,不可压坏

这是压缩器贡献的核心纪律,原文要求:压缩器必须 round-trip 或优雅降级(degrade gracefully),绝不能静默损坏 payload;任何解析问题,把字节原样通过

这条纪律在源码中是接口级契约而非口号。engine/compressors/compressor.goCompress 方法注释写明:解析问题(malformed input、不支持的形态)时返回 (nil-or-input, false),"caller MUST forward the original unchanged"。包级注释进一步说明字节安全是由压缩器的 safety class(S0–S4 阶梯)推导出来的,而不是对每个压缩器单独假设。配套实现如 engine/compressors/invariants.go 展示了这种保守设计的极端形态:当被省略行无法提取字段、或枚举会退化为"看起来完整实则不全"的列表时,标记整体不出、摘要整体不生成——宁可少省一点 token,也不暗示一个未经核实的事实。

3. 贴合周边风格,PR 小而聚焦

"Match the surrounding style. Small, focused PRs review fastest."——与周边代码风格保持一致、保持 PR 小而聚焦。从各压缩器"一类型一文件 + 对应 *_test.go"的布局(如 engine/compressors/tabular.goengine/compressors/tabular_test.go)可以推断出项目的风格基线:新压缩器同样应遵循单文件实现加同目录测试的结构。

有问题的渠道

CONTRIBUTING.md 给出的官方沟通渠道是:开一个 discussion,或发邮件至 hello@caveman.sodocs/CONTRIBUTING_PROFILES.md 对 profile 类贡献重复了同一渠道,说明这两个入口覆盖所有贡献类型。

小结

向 Caveman 贡献的路径可以压缩为四步:先按 LICENSING.md 的逐目录表判断目标目录属于 MIT 还是 BSL-1.1 区域,理解 BSL 区域附带的再许可授予(不舒适就转向 MIT 部分);每次提交用 git commit -s 完成 DCO 签名;动手前对齐目标目录的接口契约与测试入口,压测 byte-safe 底线;最后保持 PR 小而聚焦,生成文件与源同 PR 提交。对新贡献者而言,MIT 区域(CLI、SDK、contracts、provider catalog、profile)的门槛最低,而向 engine/ 添加一个遵循 fail-closed 契约的内容类型压缩器,则是文档点名推荐、且能直接扩大 Caveman 覆盖面的高价值方向。

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