关于 bruhs
bruhs 是一组工程技能与命令,覆盖项目初始化、功能开发、验证、评审和交付。它还提供代码库分析、架构、测试基础设施及工程实践方面的指导。
主要功能
- 01初始化新项目或现有项目
- 02规划并构建功能
- 03用证据验证主张
- 04处理 PR 评审和 CI
- 05分析架构与测试
适用场景
- 01创建项目或将其加入 monorepo
- 02开发并验证一项功能
- 03处理评审意见和 CI 故障
- 04评估代码结构或测试覆盖
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ bryantleft/ bruhs-skills --skill bruhs安装后在 Claude Code 中输入/bruhs确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
LICENSEREADME.md.claude-plugin/marketplace.jsonplugin.jsoncommands/dip.mdclaim.mddeepen.mdcook.mddoodle.mdland.mdrecap.mddrill.mdverify.mdslop.mdpeep.mdwalk.mdspawn.mdyeet.mdevals/claim-marker-and-legacy-both-present.jsonclaim-migration-redetect.jsonclaim-no-linear-mcp.jsonclaim-existing-config.jsonclaim-happy-path.jsonclaim-legacy-bruhs-migration.jsonREADME.mdcook-flag-gated-plan.jsoncook-feature-description.jsoncook-no-receipt-no-number.jsondeepen-happy-path.jsoncook-from-ticket-id.json详细介绍
bruhs
索引
|命令|spawn、claim、cook、verify、yeet、walk、land、peep、dip、slop、doodle、deepen、drill、recap
|实践|engineering-principles、type-driven-design、architecture-deepening、testing-infrastructure、source-ground-truth、_common、writing、design-docs、pr-review、typescript-react、typescript-hono、python、python-fastapi、effect-ts、effect-、rust、rust-、ui-design、design-engineering
|配置|CLAUDE.md + AGENTS.md(bruhs:state 和 bruhs:rules 区块)
命令速查
|spawn|创建项目或添加到 monorepo|commands/spawn.md
|claim|为现有项目初始化配置|commands/claim.md
|cook|端到端规划并构建功能|commands/cook.md
|verify|使用可证伪的证据证明一项声明(VERIFIED/NOT VERIFIED/INCONCLUSIVE)|commands/verify.md
|yeet|发布:Linear 工单 → 分支 → 提交 → PR|commands/yeet.md
|walk|生成审阅者演示说明(Markdown 或交互式 HTML 画布)|commands/walk.md
|land|监控 PR 检查,并持续迭代修复 CI 故障,直到全部通过|commands/land.md
|peep|处理 PR 审阅意见,或结合关联上下文、证据门槛和发布结论进行自我审阅,然后合并|commands/peep.md
|dip|合并后清理并切换到基础分支|commands/dip.md
|slop|深入分析代码库并清理 AI 垃圾代码(--quick 仅检查分支差异)|commands/slop.md
|doodle|将架构可视化为 tldraw 图表(PR、模块、依赖、比较、映射、自由绘制)|commands/doodle.md
|deepen|查找浅层模块并提出架构深化方案(探索 → 候选项 → 评议)|commands/deepen.md
|drill|查找缺失或薄弱的测试基础设施层并提出采用方案(探索 → 候选项 → 评议)|commands/drill.md
|recap|根据一段时间内的 git log 更新状态(bugfix/tech-debt/net-new)|commands/recap.md
生命周期图
命令可组合成端到端循环。典型流程:
spawn / claim → project setup
↓
cook <feature> → plan + build
↓
verify <claim> → prove the behavior changed (recommended for fixes)
↓
slop --quick → clean up branch-diff slop before shipping
↓
yeet → Linear ticket + branch + commit + PR
↓
walk --post → reviewer walkthrough comment (large PRs)
↓
land → watch CI to green
↓
peep → address review comments (compose with land via --land)
↓
dip → post-merge cleanup
随时可执行的循环外命令:
slop— 深度审查代码库doodle/deepen/drill— 调查结构或测试基础设施recap— 为站会或回顾提供状态更新
调用方式
/bruhs→ 交互式菜单(AskUserQuestion)/bruhs:<command>→ 直接调用对应命令/bruhs:cook <feature>或/bruhs:cook TICKET-123→ 指定参数/bruhs:verify [claim | PR#] [--keep-artifacts]→ 可证伪验证/bruhs:walk [PR#] [--canvas|--post|--commit-body]→ 生成审阅者演示说明/bruhs:land [PR#] [--no-fix|--max-iterations N]→ 监控 CI,直至全部通过/bruhs:peep [PR# | TICKET] [--land|--resolve-conflicts]→ 处理审阅意见/bruhs:slop [path] [--quick|--fix|--report] [--severity ...]→ 分析代码库/bruhs:doodle <mode> [args] [--out|--gist|--commit|--pr-comment|--format|--depth]→ 渲染图表(模式:pr、module、deps、dependents、compare、map、freeform)/bruhs:deepen [path | module-name] [--no-explore]→ 查找浅层模块并提出深化方案/bruhs:drill [path | layer-name] [--no-explore]→ 查找缺失或薄弱的测试基础设施层并提出采用方案/bruhs:recap [window] [--all-authors|--linear|--branch <name>]→ 根据 git log 更新状态
工程准则
每条命令都使用以下通用词汇:
| 术语 | 含义 |
|---|---|
| 隐患 | 看似无害,却会引发延迟故障的决策 |
| 依据 | 可检查的证据或决策背后的推理 |
| 防护机制 | 假设失效时会以可执行方式给出明确错误的防护措施 |
| 简单 | 自然拆解并消除复杂性的逻辑 |
| 直观 | 一眼就能看清代码的用途、状态、错误和下一步修改方向 |
基本规则:
- 从第一性原理出发思考。 保留不变量和用户期望的结果,而不是偶然形成的复杂性。
- 没有依据,就不设运行参数。 超时、重试、内存预算、并发限制、队列上限、缓存大小等类似数值,必须依据测量结果、配额、容量计算、研究、事故、合同或明确的用户要求得出。
- 发生故障时明确报告并提供可操作的信息。 说明出了什么问题、原因、违反了哪项假设或限制,以及如何修复。降级行为必须明确且可观测。
- 把假设转化为防护机制。 注释用于描述;验证、约束、穷尽处理、断言和 CI 用于强制执行。
- 先理解,再优化。 先移除不必要的工作和病态结构;只有当优化带来实际权衡时,才进行测量。
- 直观胜于巧妙。 使用直接的控制流、精简的接口、明确的状态和领域语言。
- 尽量减少隐式状态。 让变更、缓存、重试、回退、I/O 和生命周期所有权清晰可见。
- 为可维护性而设计。 删除过时的代码。只有在集中管理不变量、消除重复或隐藏实际复杂性时,才添加抽象。
在规划、实现、审查或验证前,请阅读 practices/engineering-principles.md。若其他实践与之冲突,以本文档为准。
类型驱动设计
函数的类型签名应该清楚说明它的所有行为。
优先级层级(按此顺序修复)
- 缺失或错误的类型签名 - 类型就是文档
- 隐藏的副作用 - 签名对行为的描述不实
- any 类型 - 类型系统被禁用
- 外部数据上的 ! 或 as - 违背了对编译器的信任
- 快速路径违规 - 循环中的
await、N+1 查询、在异步代码中执行同步操作、每个请求都构造客户端(见下文性能部分) - 其他实现问题 - 相较于类型正确性,优先级较低
检查清单
签名:
- 公共函数显式声明返回类型
- 不使用 any - 改用 unknown 并进行验证
- 不使用 ! - 显式处理 null
- 不对外部数据使用 as - 改为验证
- 错误应体现在返回类型中,而不是静默抛出
- readonly 参数表明不会发生变更
- 使用可辨识联合表示状态(而不是多个布尔值)
错误:
- 错误体现在返回类型中(Result<T,E> 或联合类型)
- 使用类型化错误,而不是字符串
- 在调用处处理,而不是延后处理
- 不留空的 catch 块
不可变性:
- 优先使用 const 而不是 let
- 不要修改参数
- 返回新对象,而不是修改原对象
模式
// ❌ Signature hides truth
function getUser(id: string): User // might throw, might be null
// ✅ Signature tells full story
function getUser(id: string): Promise<Result<User, NotFoundError | NetworkError>>
// ❌ Multiple booleans = impossible states
type State = { isLoading: boolean; isError: boolean; data: User | null }
// ✅ Discriminated union = only valid states
type State =
| { status: 'idle' }
| { status: 'loading' }
| { status: 'success'; data: User }
| { status: 'error'; error: Error }
完整模式见 → practices/type-driven-design.md
架构深化
深模块通过精简接口隐藏大量行为。浅模块的接口与其实现几乎一样复杂。
使用 /bruhs:deepen 命令查找浅模块并提出深化方案。此命令不同于 /bruhs:slop(逐行审查)——它关注的是结构。
词汇表(请严格使用这些术语)
| 术语 | 含义 |
|---|---|
| Module | 任何具有接口和实现的事物(函数、类、包、切片) |
| Interface | 调用方必须了解的一切——类型、不变量、顺序、错误、配置 |
| Depth | 单位接口所承载的行为量。深度高 = 小型接口背后有大量行为 |
| Seam | 无需在某处编辑即可改变行为的位置(Feathers) |
| Adapter | 在某个 seam 处满足接口的具体事物 |
| Leverage | 深度为调用方带来的好处——每单位已学习接口所具备的能力 |
| Locality | 深度为维护者带来的好处——变更、Bug 和测试集中在一处 |
核心原则
- **Depth 是接口的属性,而非实现的属性。**内部 seam 没问题;不要将它们暴露出来。
- **删除测试。**设想删除该模块。如果复杂性随之消失 → 通过测试;它只是透传层,应将其合并。如果复杂性分散到 N 个调用方 → 该模块就有存在的价值。
- **接口就是测试面。**如果你想越过接口进行测试,那么这个模块的形态就不对。
- **一个适配器意味着一个假设的 seam。两个适配器意味着一个真实的 seam。**只有一种实现时,不要添加端口。
完整的词汇表、依赖类别、seam 规范和设计两次机制 → practices/architecture-deepening.md
测试基础设施
测试套件是一张分层安全网。每一层都会捕获不同类型的 Bug。缺少的一层无法由其他层弥补——它只会成为 Bug 溜进发布版本的入口。
使用 /bruhs:drill 命令查找缺失或薄弱的层,并提出采用计划。它与 /bruhs:deepen 相辅相成:加深模块,钻研测试。
8 个层级
| # | 层级 | 捕获的问题 |
|---|---|---|
| 1 | 验收规范 | 意图偏移——没有可执行的“完成”定义 |
| 2 | 单元测试 | 模块接口层面的行为回归 |
| 3 | 覆盖率门槛 | 未经测试的代码合入(按每个 PR 的变更行数衡量,而非总行数) |
| 4 | 变异测试运行器 | 测试虽存在,却没有做出有意义的断言——杀死率是唯一能证明覆盖率确实发挥作用的数字 |
| 5 | 复杂度综合指标 | 高复杂度/低覆盖率热点(两者兼具的最糟情况——Savoia 所说的“CRAP”) |
| 6 | 架构检查器 | 层级/依赖规则违规——将 ADR 编码为强制规则,而非仅作记录 |
| 7 | 测试代码检查器 | 测试文件自身的腐化;AI 生成的测试代码变成第二套无类型代码库 |
| 8 | CI 编排器 | 纪律崩塌——将每一层作为硬性门禁运行。第 8 层是承重层 |
核心原则
- **硬性门禁、建议项或棘轮机制——选一种,并为其辩护。**无限期的建议项只是装饰。棘轮机制(“不比基线更差”)能诚实面对遗留债务,并锁定改进成果。
- **编排器是承重层。**没有真正的 CI 门禁,层级 1–7 就只是表演。门禁层上的
continue-on-error: true无论配置声称如何,都是建议项。 - **替换,不要叠加。**存在硬性门禁后,旧的建议性检查就成了负担。更深层模块的接口测试到位后,旧的浅层模块测试也成了负担。删掉它们;不要出于愧疚而保留。
- **“哪些问题会漏过去”测试。**除非你能指出它在此代码库中会捕获的具体 Bug 类型,否则不要建议采用某个层级。
何时调用 /bruhs:drill
- 测试通过了,但缺陷仍然上线——测试套件并未捕捉到它声称能捕捉的问题
- 覆盖率很高,却感觉毫无意义(未测量变异杀死率)
- 已有 ADR,却仍被违反;「整洁架构」决策因缺乏强制执行而逐渐瓦解
- AI 生成的测试文件不断累积,却无人审核
- CI 显示绿色,但构建仍感觉不可靠——很可能是预警式编排器
- 在
/bruhs:slop期间,你总是在标记「X 没有测试」——升级到/bruhs:drill,将其作为安全网处理
完整的分层规范、诊断、门控策略及不采用的表述方式 → practices/testing-infrastructure.md
通用规则
命名
| 类型 | 规范 | 示例 |
|---|---|---|
| 组件 | PascalCase | UserCard.tsx |
| Hook | camelCase + use | useAuth.ts |
| 工具函数 | camelCase | formatDate.ts |
| 常量 | SCREAMING_SNAKE | MAX_RETRIES |
| 布尔值 | is/has/can/should | isLoading、hasPermission |
| 函数 | 动词 + 名词 | getUser、createOrder |
| 处理程序 | handle/on 前缀 | handleSubmit、onUserClick |
代码组织
- 每个函数只做一件事
- 如果需要注释来分隔各个部分 → 提取为函数
- 将长度视为信号,而非规则。只有在拆分后能让职责和状态更清晰时,才进行拆分。
- 没有针对特定代码仓库的依据时,不要设置行数限制。
错误处理
- 使用具体的错误消息:
User "${id}" not found,而不是Something went wrong - 在边界处进行校验,信任内部代码
- 绝不吞掉错误(空的 catch 块)
Git
<type>: <description>
Fixes TICKET-123
Assisted-by: Claude:claude-opus-5-5
类型:feat|fix|refactor|chore|docs|test
每个由 Agent 编写的提交(包括 land/peep/doodle 修复提交)都必须包含 Assisted-by: <Agent>:<model-id>,并填写当前运行的模型,绝不能使用 Co-Authored-By。详情 → practices/_common.md → AI Attribution。
分支:<type>/<ticket-id>-<short-description>
堆叠 PR → commands/yeet.md → Stacked PRs。
注释
- ✅ WHY(业务逻辑、变通方案、不明显的决策)
- ❌ WHAT(代码已经说明了它的作用)
- ❌ 注释掉的代码
- ❌ 没有工单引用的 TODO
- ❌ 计划 ID、人员、行号(来源信息应放在提交或 PR 正文中)
写作
任何供人阅读的内容(PR 正文、工单、评审回复、提交信息、总结):用尽可能少的文字表达完整含义,先说重点;聊天内容用小写,文档使用句首字母大写,不要留下 AI 文本的痕迹。发送前查看 practices/writing.md。
设计文档:1–3 页,开篇即清晰说明问题并提供证据,包含一张带标签的图,只记录难以撤销的决策。结构和门控 → practices/design-docs.md。
外部搜索
使用 WebSearch 查询最新结果时,始终包含当前年份。
完整指南 → practices/_common.md
性能(默认优先快速路径)
默认选择快速路径。避免反模式不需要基准测试。
理念
- 正确性优先,但等价正确的模式并不等效。 两种模式解决同一问题时,选择更快的模式——即使没有测量数据。
- 明显的性能收益无需基准测试。 N+1 查询、循环中的
await、事件循环中的同步 I/O、每个请求都构建客户端——这些都是反模式,不是「过早优化」。 - 权衡确实存在时再测量(可读性成本、复杂度成本、回归风险)。不要为了证明可以不避免反模式而测量。
- 在边界处测量,而不是在内部测量——入口/出口处的 p50/p95/p99;内部计时器无法反映竞争情况。
- 运行边界必须有依据。 未根据真实系统推导前,绝不要将这些示例中的并发数、超时、重试或缓存值直接复制到生产环境。
通用默认规则
- 在边界处批处理。 一次处理 N 项优于 N 次往返(数据库、HTTP、IPC、GPU、系统调用)。
- 使用流式处理,不要缓冲。 在所有数据就绪前就开始传输字节——SSR、JSON、文件 I/O、大模型 token。
- 不要阻塞热循环。 事件循环、渲染线程、请求处理程序——将 CPU 工作移出,I/O 使用异步,绝不在异步代码中同步执行。
- 让数据与使用者就近放置。 查询放在对应路由旁,获取放在对应 RSC 旁,缓存放在读取者旁。
- 内置功能胜过重写。
Array.prototype、itertools、std::collections、平台的fetch。 - 限制用户输入触发的并发。
p-limit、asyncio.Semaphore、buffer_unordered(n)——对用户数据使用不受限制的Promise.all会导致 DoS。 - 客户端使用单例。 切勿为每个请求都执行
new Client()——这会破坏连接池的效果。
大模型常见陷阱(审查时标记)
- 对相互独立的项循环执行
await→ 使用Promise.all/gather/join! - 对大型数组使用
.map().filter().reduce()链式调用 → 一次遍历或惰性迭代器 - 在“整洁”的代码中通过 ORM 进行 N+1 次访问 → 预加载/联接加载
- 未遇到经测量确认的重渲染问题,就到处使用
useMemo/useCallback - 使用
JSON.parse(JSON.stringify(x))深拷贝 → 使用structuredClone或有针对性的复制 - 对用户输入执行不受限制的
Promise.all/ 递归 → 限制并发量 - 在请求路径中同步执行哈希/加密 → 使用工作线程/线程池
- 为每个请求创建客户端(
new PrismaClient、httpx.AsyncClient()、reqwest::Client::new())→ 使用单例 - 在热路径记录完整请求体 → 使用结构化日志字段
- 每个请求都解析配置/读取环境变量 → 在启动时加载一次
各技术栈的性能模式 → practices/<stack>.md(各文件中的 Performance 章节)
以源代码为准
与文档相比,代码是更可靠的事实依据。
只要工作涉及第三方包、代码仓库或依赖项,就应从已安装的源代码中确认其实际行为,而不是依赖训练记忆或可能已经过时的文档。文档用于了解方向;最终以源代码为准。如两者不一致,以锁文件中的版本为准。
使用 opensrc 按需获取包的源代码:
npm install -g opensrc
rg "parse" $(opensrc path zod) # search the real implementation
cat $(opensrc path zod)/src/types.ts # read a specific file
find $(opensrc path pypi:requests) -name "*.py" # non-npm via pypi: prefix
当你不确定某个 API 时、文档内容不足或与实际行为矛盾时、错误指向某个依赖项时,或审查结论取决于某个库的实际行为时,请先查看源代码。阅读源代码不等于运行代码——应在沙箱中执行不可信代码或 AI 生成的代码,切勿在宿主机上运行(参见 Config → stack sandboxing)。
完整指南(版本匹配、context7 与源代码的比较、后备方案)→ practices/source-ground-truth.md
命令详情
每个命令的完整工作流都在其对应文件中。执行命令时请阅读相应文件:
| 命令 | 文件 |
|---|---|
| cook | commands/cook.md |
| verify | commands/verify.md |
| yeet | commands/yeet.md |
| walk | commands/walk.md |
| land | commands/land.md |
| peep | commands/peep.md |
| dip | commands/dip.md |
| spawn | commands/spawn.md |
| claim | commands/claim.md |
| slop | commands/slop.md |
| doodle | commands/doodle.md |
| deepen | commands/deepen.md |
| drill | commands/drill.md |
| recap | commands/recap.md |
交互式菜单
不带参数调用 /bruhs 时,通过 AskUserQuestion 展示命令列表,并跳转到所选命令对应的文件。选项:spawn、claim、cook、yeet、peep、doodle、dip、deepen、drill。slop 特意不包含在菜单中——请直接通过 /bruhs:slop 调用。
配置参考
项目状态保存在 CLAUDE.md 和 AGENTS.md(镜像文件)中由标记界定的两个代码块内。模型每次会话都会读取这些内容——无需另设配置文件并保持同步。手写规则位于代码块之外,不会被改动。
Block 1 — bruhs:state(自动维护的 JSON)
### Project State (managed by /bruhs)
```json
{
"integrations": {
"linear": {
"mcpServer": "linear-<workspace>",
"team": "<team-id>",
"teamName": "Team Name",
"project": "<project-id>",
"projectName": "Project Name",
"labels": { "feat": "Feature", "fix": "Bug", "chore": "Chore", "refactor": "Improvement" }
}
},
"tooling": {
"mcps": ["linear", "notion", "context7"],
"skills": ["superpowers", "shadcn", "vercel-react-best-practices"]
},
"stack": {
"structure": "single|monorepo",
"framework": "nextjs|tanstack-start|astro|hono|...",
"styling": ["tailwind", "shadcn"],
"database": ["drizzle-postgres", "convex", "..."],
"auth": "better-auth|clerk|...",
"gpu": ["modal", "runpod", "lambda"]
}
}
### Block 2 — `bruhs:rules` (stack-derived behavioral rules)
```markdown
### Stack-Specific Rules (managed by /bruhs)
#### Convex
- Convex actions that import the `ai` SDK MUST live in a file whose first line is `'use node'`.
- ...
规则根据检测到的技术栈,通过 scripts/derive_stack_rules.py 生成——简短、信号明确,且仅针对特定技术栈。通用行为规则(对应于你的失败模式)应由你在 bruhs 块之外手动编写。
脚本
| 脚本 | 用途 |
|---|---|
scripts/sync_bruhs_block.py | 将 bruhs:state 或 bruhs:rules 块原子写入 CLAUDE.md 和 AGENTS.md。 |
scripts/read_bruhs_block.py | 读取 JSON 状态(或规则 Markdown)。迁移期间,处理 --kind state 时会回退到旧版 .claude/bruhs.json。 |
scripts/derive_stack_rules.py | 从标准输入读取状态 JSON,生成 Markdown 规则正文,以管道传入 sync_bruhs_block.py --kind rules。 |
从 .claude/bruhs.json 迁移
read_bruhs_block.py 仍会将旧版 .claude/bruhs.json 作为回退读取。/bruhs:claim 会检测旧版文件,并提供将其移植到标记块的选项,然后在删除旧文件前提示确认。
Linear MCP
工具格式:mcp__<mcpServer>__linear_<method>
常用工具:
| 工具 | 用途 |
|---|---|
linear_get_teams | 列出团队(包括标签) |
linear_get_user | 当前用户(用于 assigneeId) |
linear_create_issue | 创建工单 |
linear_edit_issue | 更新状态 |
linear_get_issue | 按 ID 获取工单 |
多工作区:每个项目的 bruhs:state 块通过 mcpServer 指向其 Linear 工作区。
示例:
// Load the tool
ToolSearch(`select:mcp__${config.integrations.linear.mcpServer}__linear_create_issue`)
// Create issue
const issue = call(`mcp__linear-sonner__linear_create_issue`, {
title: "Add leaderboard",
teamId: config.integrations.linear.team,
projectId: config.integrations.linear.project,
assigneeId: user.viewer.id,
labelIds: [labelId]
})
// Use Linear's generated branch name
const branchName = issue.gitBranchName // "sonner-140-add-leaderboard"