关于 kamae
kamae 是用于 TypeScript 函数式领域建模的技能,指导开发者处理领域类型、状态转换、错误与边界校验,并按任务和项目依赖选择相关指南。
主要功能
- 01用判别联合建模领域状态
- 02用纯函数表达状态转换
- 03指导基于 Result 的业务错误处理
- 04要求在外部边界执行运行时校验
- 05根据项目库选择指南
适用场景
- 01设计 TypeScript 领域模型
- 02实现具编译期约束的状态转换
- 03校验 API、数据库或文件输入
- 04沿用项目已有的 Result 与模式库
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ iwasa-kosui/ kamae-ts --skill kamae安装后在 Claude Code 中输入/kamae确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
boundary-defense.mddeclarative-style.mddomain-modeling.mderror-handling.mdstate-modeling.mdtest-data.mdexamples/sensitive-type-arktype.tssensitive-type-valibot.tssensitive-type.tstaxi-request-arktype.tstaxi-request-valibot.tstaxi-request.tsresult-libraries/byethrow.mdfp-ts.mdneverthrow.mdoption-t.mdvalidation-libraries/arktype.mdvalibot.mdzod.md详细介绍
Kamae — 使用 TypeScript 进行功能性领域建模
六个主题文件涵盖了相关原则。只阅读与当前任务相关的文件。result-libraries/ 和 validation-libraries/ 下的库指南,会根据项目的 package.json 按需读取。
步骤 0:加载适用规则
在执行任何其他步骤之前,按优先级顺序 glob 并读取规则:
.claude/rules/*.md(工作树根目录中的项目级覆盖规则)~/.claude/rules/*.md(用户全局偏好)- 相对于此
SKILL.md的../../rules/defaults/*.md(插件默认规则)
对于每个文件:
- 读取 YAML frontmatter。如果
applies-to不是kamae或*,则跳过此规则。 - 按
name分组。对于每个name,只保留优先级最高的实例(1 > 2 > 3);在同一优先级内,保留文件名按字典序排序最后的实例。 - 在后续步骤中始终应用每条保留规则的正文。
library-preference规则会覆盖步骤 1 中的检测方式;convention规则会影响生成的代码;override规则会替换特定主题文件中的指导。
如果未找到规则,则使用 ../../rules/defaults/ 中已记录的插件默认规则。
请参阅 ../../rules/README.md 了解规则格式。
应用主题和库指南之前,请检查同一软件包中的邻近文件,了解其既有且一致的代码风格和导入风格。如果存在此类惯例,请遵循;仅当仓库未规定相关惯例时,才采用 Kamae 指南中的惯例。
步骤 1:检测项目库
读取一次 package.json。记录项目中使用的 Result 库和验证库:
- Result 库——按优先级
neverthrow>byethrow>fp-ts>option-t,匹配第一个已安装的库。如果任务涉及错误处理,则加载result-libraries/下对应的指南。 - 验证库——按优先级
zod>valibot>arktype,匹配第一个已安装的库。如果任务涉及边界或品牌类型,则加载validation-libraries/下对应的指南。
如果都未安装,请在继续之前询问用户。
步骤 2:应用与任务相关的主题
以下每个主题对应一个文件。按需阅读——只读取当前任务所需的文件。
类型驱动的领域建模 — domain-modeling.md
使用以 kind 作为统一判别字段的可辨识联合来表示状态。使用 type(而非 interface)、伴生对象模式、通过项目验证库实现的品牌类型、Readonly<>、函数属性表示法,以及每个文件一个概念的结构。
将读取契约(解析器)与写入契约(存储)分开,并优先采用每个契约一个方法的设计。只向每个消费者提供其所需的操作;事件存储不需要解析器或 CRUD 仓库。在工作流边界处理 I/O,并将值传入纯领域决策。
将面向领域的这些端口放在领域层中与其服务概念相邻的位置。不要引入专门的 port/ 或 ports/ 目录,包括 domain/ 内的目录。将具体的 I/O 适配器置于领域之外;用例和适配器导入由领域拥有的契约。定义依赖契约或选择其文件位置时,请阅读领域建模指南。
状态转换 — state-modeling.md
使用纯函数表示转换。参数类型限定有效的源状态;返回类型明确目标状态。无效转换会导致编译错误。使用 assertNever 确保穷尽性。
错误处理 — error-handling.md
- 将预期的业务失败建模为特定用例的
Result错误联合类型。 - 仅当工作流有明确记录的恢复决策时,才将外部失败纳入领域
Result错误联合类型。 - 让意外的基础设施故障以及契约/不变量违规到达应用错误边界。遵守库的契约:fp-ts 在
TaskEither中使用独立的执行失败通道,并在原生Promise边界重新抛出意外故障;请参阅 fp-ts 指南。 - 允许使用私有控制流哨兵,但关联边界只能捕获该哨兵,并重新抛出所有其他错误。
边界防御 — boundary-defense.md
在运行时使用架构验证每个外部输入(API 请求、DB 结果、文件/队列/环境变量)。在领域内部信任类型。不要使用类型断言——仅允许使用 as const 和 as const satisfies Type;类型未知时,应通过验证库的架构进行解析。将 Sensitive<T> 应用于 PII 字段;验证架构会自动为其包装。
如果运行时架构已定义边界表示,应从架构派生其 TypeScript 类型,而不是重复声明相同的结构。
声明式风格 — declarative-style.md
使用 filter / map / reduce 搭配伴随对象谓词,而不是命令式循环。将领域事件建模为不可变记录。
测试数据 — test-data.md
使用 as const satisfies Type 定义测试固件,以保留判别字面量类型并防止类型扩大。
示例
端到端示例请见 examples/。仅当主题指南引用了特定示例时,才阅读这些示例。
应用这些原则
这些是建议,而非硬性规则。请根据上下文自行判断。如果偏离某项原则,请在注释中说明原因。合理的原因包括:外部库要求类继承、不可变对象的创建成本经测量确认会影响性能,或团队已达成一致并采用了其他模式。