bryantleft/bruhs-skills

bruhs

End-to-end development lifecycle for AI coding agents — scaffold projects, plan and build features, create Linear tickets, open and review PRs, clean up after merge, audit codebases, and improve UI polish/motion quality.

查看源码

使用方法

  1. 复制安装命令,在自己的智能体环境安装前先检查源码包。
  2. 从原始文档核对所需工具、凭据和支持的宿主。
  3. 说明输入材料与期望交付物,并对照来源检查输出。
npx skills add https://github.com/bryantleft/bruhs-skills --skill bruhs

开始前需了解

  • 安装不包含模型订阅、API 额度或访问文件的权限。
  • 仓库星数和安装量反映活跃情况,不等于独立质量或安全测试。
仓库原始内容

按源仓库内容呈现,保留标题、案例、代码、表格、链接以及原文引用的演示图片。

bruhs

Index

|commands|spawn,claim,cook,verify,yeet,walk,land,peep,dip,slop,doodle,deepen,drill,recap |practices|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 |config|CLAUDE.md + AGENTS.md (bruhs:state and bruhs:rules blocks)

Commands Quick Reference

|spawn|Create project or add to monorepo|commands/spawn.md |claim|Initialize config for existing project|commands/claim.md |cook|Plan + Build feature end-to-end|commands/cook.md |verify|Prove a claim with falsifiable evidence (VERIFIED/NOT VERIFIED/INCONCLUSIVE)|commands/verify.md |yeet|Ship: Linear ticket → Branch → Commit → PR|commands/yeet.md |walk|Generate reviewer walkthrough (markdown or interactive HTML canvas)|commands/walk.md |land|Watch PR checks and iterate on CI failures until green|commands/land.md |peep|Address PR review comments, or self-review with linked context, evidence gates and a ship verdict, then merge|commands/peep.md |dip|Clean up after merge, switch to base branch|commands/dip.md |slop|Deep codebase analysis, AI slop cleanup (--quick for branch-diff only)|commands/slop.md |doodle|Visualize architecture as tldraw diagrams (PRs, modules, deps, compare, map, freeform)|commands/doodle.md |deepen|Find shallow modules, propose architectural deepenings (explore → candidates → grill)|commands/deepen.md |drill|Find missing/weak test-infra layers, propose adoptions (explore → candidates → grill)|commands/drill.md |recap|Status update from git log over a time window (bugfix/tech-debt/net-new)|commands/recap.md

Lifecycle Map

Commands compose into an end-to-end loop. Typical flow:

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

Out-of-band, any time:

  • slop — deep codebase audit
  • doodle / deepen / drill — structural / test-infra investigation
  • recap — status update for standup or retro

Invocation

  • /bruhs → Interactive menu (AskUserQuestion)
  • /bruhs:<command> → Direct to command
  • /bruhs:cook <feature> or /bruhs:cook TICKET-123 → With argument
  • /bruhs:verify [claim | PR#] [--keep-artifacts] → Falsifiable verification
  • /bruhs:walk [PR#] [--canvas|--post|--commit-body] → Reviewer walkthrough
  • /bruhs:land [PR#] [--no-fix|--max-iterations N] → Watch CI to green
  • /bruhs:peep [PR# | TICKET] [--land|--resolve-conflicts] → Address review comments
  • /bruhs:slop [path] [--quick|--fix|--report] [--severity ...] → Codebase analysis
  • /bruhs:doodle <mode> [args] [--out|--gist|--commit|--pr-comment|--format|--depth] → Render diagram (modes: pr, module, deps, dependents, compare, map, freeform)
  • /bruhs:deepen [path | module-name] [--no-explore] → Find shallow modules, propose deepenings
  • /bruhs:drill [path | layer-name] [--no-explore] → Find missing/weak test-infra layers, propose adoptions
  • /bruhs:recap [window] [--all-authors|--linear|--branch <name>] → Status update from git log

Engineering Doctrine

Every command uses this shared vocabulary:

TermMeaning
LandmineA harmless-looking decision that creates a delayed failure
ReceiptInspectable evidence or reasoning behind a decision
TripwireAn executable guardrail that fails actionably when an assumption breaks
SimpleLogic that decomposes naturally and removes complexity
ObviousCode whose purpose, state, errors, and next change are visible in one pass

The governing rules:

  • Think from first principles. Preserve invariants and user outcomes, not accidental complexity.
  • No receipt, no operational number. Timeouts, retries, memory budgets, concurrency limits, queue bounds, cache sizes, and similar values must be derived from measurements, quotas, capacity math, research, incidents, contracts, or an explicit user requirement.
  • Fail loudly and actionably. State what failed, why, which assumption or limit was violated, and what fixes it. Degraded behavior must be explicit and observable.
  • Turn assumptions into tripwires. Comments describe; validation, constraints, exhaustive handling, assertions, and CI enforce.
  • Understand before optimizing. Remove unnecessary work and pathological shapes first; measure when an optimization introduces a real trade-off.
  • Prefer obvious over clever. Use direct control flow, narrow interfaces, explicit state, and domain language.
  • Minimize hidden state. Make mutation, caching, retries, fallbacks, I/O, and lifecycle ownership visible.
  • Design for maintenance. Delete obsolete code. Add abstractions only when they centralize an invariant, remove duplication, or hide real complexity.

Read practices/engineering-principles.md before planning, implementing, reviewing, or verifying. It wins when another practice conflicts with it.


Type-Driven Design

A function's type signature should tell you everything about what it does.

Priority Hierarchy (fix in this order)

  1. Missing/wrong type signatures - Types ARE documentation
  2. Hidden side effects - Signature lies about behavior
  3. any types - Type system disabled
  4. ! or as on external data - Compiler trust violated
  5. Fast-path violations - await in loops, N+1 queries, sync-in-async, per-request client construction (see Performance below)
  6. Other implementation issues - Secondary to type correctness

Checklist

Signatures:

  • [ ] Explicit return types on public functions
  • [ ] No any - use unknown + validation
  • [ ] No ! - handle null explicitly
  • [ ] No as for external data - validate instead
  • [ ] Errors in return type, not thrown silently
  • [ ] readonly parameters signal no mutation
  • [ ] Discriminated unions for state (not multiple booleans)

Errors:

  • [ ] Errors visible in return type (Result<T,E> or union)
  • [ ] Typed errors, not strings
  • [ ] Handle at call site, not deferred
  • [ ] No empty catch blocks

Immutability:

  • [ ] Prefer const over let
  • [ ] Don't mutate parameters
  • [ ] Return new objects instead of mutating

Patterns

typescript
// ❌ 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 }

For full patterns → practices/type-driven-design.md


Architectural Deepening

A deep module hides a lot of behaviour behind a small interface. A shallow module's interface is nearly as complex as its implementation.

Use the /bruhs:deepen command to find shallow modules and propose deepenings. Distinct from /bruhs:slop (line-level audit) — this is structural.

Vocabulary (use these terms exactly)

TermMeaning
ModuleAnything with an interface and an implementation (function, class, package, slice)
InterfaceEverything a caller must know — types, invariants, ordering, errors, configuration
DepthBehaviour-per-unit-of-interface. Deep = lots of behaviour behind a small interface
SeamA place where you can alter behaviour without editing in that place (Feathers)
AdapterA concrete thing that satisfies an interface at a seam
LeverageCaller-side benefit of depth — capability per unit of interface learned
LocalityMaintainer-side benefit — change/bugs/tests concentrate in one place

Core principles

  • Depth is a property of the interface, not the implementation. Internal seams are fine; don't expose them.
  • The deletion test. Imagine deleting the module. If complexity vanishes → pass-through, merge it. If it scatters across N callers → the module earns its keep.
  • The interface is the test surface. If you want to test past it, the module is the wrong shape.
  • One adapter means a hypothetical seam. Two adapters means a real one. Don't add a port for a single implementation.

When to invoke /bruhs:deepen

  • A codebase feels like it bounces between many small files for one operation
  • Tests feel like they're testing the wrong thing (mocks everywhere, brittle to refactors)
  • Callers must learn implementation details (transport, encoding, storage) to use a "domain" module
  • Same invariant repeats across N call sites
  • During /bruhs:slop you keep flagging "architecture" — promote to /bruhs:deepen for structural treatment

For full glossary, dependency categories, seam discipline, design-it-twice mechanics → practices/architecture-deepening.md


Testing Infrastructure

A test suite is a layered safety net. Each layer catches a different bug class. A missing layer isn't covered by the others — it's just where bugs ship from.

Use the /bruhs:drill command to find missing or weak layers and propose adoption plans. Companion to /bruhs:deepen: deepen modules, drill tests.

The 8 layers

#LayerCatches
1Acceptance specsIntent drift — no executable definition of "done"
2Unit testsRegressions in module behaviour at the interface
3Coverage gateUntested code landing (measured on changed lines per PR, not total)
4Mutation runnerTests that exist but assert nothing meaningful — the kill ratio is the only number that proves coverage is doing work
5Complexity compositeHigh-complexity / low-coverage hotspots (the worst-of-both — Savoia's "CRAP")
6Architecture checkerLayer / dependency rule violations — encodes ADRs so they're enforced, not just documented
7Test-code linterRot in test files themselves; AI-generated test code becoming a second untyped codebase
8CI orchestratorDiscipline collapse — runs every layer as hard gates. The 8th is load-bearing

Core principles

  • Hard gate, advisory, or ratchet — pick one, defend it. Indefinite advisory is decoration. Ratchet ("no worse than baseline") is honest about legacy debt and locks in improvement.
  • The orchestrator is load-bearing. Layers 1–7 without a real CI gate are theatre. continue-on-error: true on a gated layer is advisory regardless of what the config claims.
  • Replace, don't layer. Old advisory checks become waste once a hard gate exists. Old shallow-module tests become waste once the deeper module's interface is tested. Delete; don't preserve out of guilt.
  • The "what would slip through" test. Don't propose adopting a layer unless you can name a concrete bug class it catches in this codebase.

When to invoke /bruhs:drill

  • Tests pass but bugs still ship — the suite isn't catching what it claims to catch
  • Coverage is high but feels meaningless (no mutation kill ratio measured)
  • ADRs exist but get violated; "clean architecture" decisions erode unenforced
  • AI-generated test files are accumulating without review
  • CI is green; the build still feels unreliable — likely an advisory orchestrator
  • During /bruhs:slop you keep flagging "no test for X" — promote to /bruhs:drill for safety-net treatment

For full layer specs, diagnostics, gating posture, rejected framings → practices/testing-infrastructure.md


Common Rules

Naming

TypeConventionExample
ComponentsPascalCaseUserCard.tsx
HookscamelCase + useuseAuth.ts
UtilitiescamelCaseformatDate.ts
ConstantsSCREAMING_SNAKEMAX_RETRIES
Booleansis/has/can/shouldisLoading, hasPermission
Functionsverb + noungetUser, createOrder
Handlershandle/on prefixhandleSubmit, onUserClick

Code Organization

  • Functions do ONE thing
  • If you need comments to separate sections → extract functions
  • Treat length as a signal, not a rule. Split only when doing so makes responsibilities and state more obvious.
  • Do not introduce line-count limits without a repository-specific receipt.

Error Handling

  • Specific messages: User "${id}" not found not Something went wrong
  • Validate at boundaries, trust internal code
  • Never swallow errors (empty catch blocks)

Git

<type>: <description>

Fixes TICKET-123

Assisted-by: Claude:claude-opus-5-5

Types: feat|fix|refactor|chore|docs|test

Every agent-written commit (including land/peep/doodle fixups) carries Assisted-by: <Agent>:<model-id> with the running model, never Co-Authored-By. Details → practices/_common.md → AI Attribution.

Branch: <type>/<ticket-id>-<short-description>

Stacked PRs → commands/yeet.md → Stacked PRs.

Comments

  • ✅ WHY (business logic, workarounds, non-obvious decisions)
  • ❌ WHAT (code already says what it does)
  • ❌ Commented-out code
  • ❌ TODO without ticket reference
  • ❌ Plan IDs, people, line numbers (provenance goes in the commit or PR body)

Writing

Anything a person reads (PR bodies, tickets, review replies, commits, recaps): fewest words that keep the meaning, point first, lowercase in chat and sentence case in documents, no AI text tells. Scan practices/writing.md before sending.

Design docs: 1–3 pages, the problem explained cold with evidence, one labelled diagram, only hard-to-reverse decisions. Shape and gates → practices/design-docs.md.

External Searches

Always include current year in WebSearch queries for fresh results.

For full guidelines → practices/_common.md


Performance (Fast-Path-By-Default)

Pick the fast path by default. You don't need a benchmark to avoid an anti-pattern.

Philosophy

  • Correctness first, but equivalent-correctness patterns are not equivalent. When two patterns solve the same problem, pick the faster one — even without a measurement.
  • Obvious perf wins don't require benchmarks. N+1 queries, await in a loop, sync I/O on the event loop, per-request client construction — these are anti-patterns, not "premature optimization."
  • Measure when the tradeoff is real (readability cost, complexity cost, risk of regression). Don't measure to justify avoiding an anti-pattern.
  • Measure at boundaries, not inside — p50/p95/p99 at ingress/egress; internal timers lie about contention.
  • Operational bounds need receipts. Never copy a concurrency, timeout, retry, or cache value from these examples into production without deriving it from the real system.

Universal Defaults

  • Batch at boundaries. One round-trip of N beats N round-trips (DB, HTTP, IPC, GPU, syscalls).
  • Stream, don't buffer. Start bytes moving before you have them all — SSR, JSON, file I/O, LLM tokens.
  • Don't block the hot loop. Event loop, render thread, request handler — push CPU off, I/O async, never sync-in-async.
  • Colocate data with consumer. Query next to its route, fetch next to its RSC, cache next to its reader.
  • Built-ins beat rewrites. Array.prototype, itertools, std::collections, platform fetch.
  • Bound concurrency on user input. p-limit, asyncio.Semaphore, buffer_unordered(n) — unbounded Promise.all over user data is a DoS.
  • Singleton clients. Never new Client() per request — it defeats connection pooling.

LLM-Common Traps (flag these in review)

  1. await in a for loop over independent items → Promise.all / gather / join!
  2. .map().filter().reduce() chains over large arrays → one pass or lazy iterator
  3. N+1 ORM access in "clean" code → eager/join loading
  4. useMemo/useCallback sprinkled without a measured re-render problem
  5. JSON.parse(JSON.stringify(x)) for deep clone → structuredClone or targeted copy
  6. Unbounded Promise.all / recursion over user input → clamp concurrency
  7. Sync hashing/crypto in request path → worker / threadpool
  8. Per-request client construction (new PrismaClient, httpx.AsyncClient(), reqwest::Client::new()) → singleton
  9. Full-body logging in hot paths → structured log fields
  10. Parsing config / reading env per request → load once at boot

Per-stack performance patterns → practices/<stack>.md (Performance section in each)


Source as Ground Truth

Code is the best ground truth over docs.

Whenever the work touches a third-party package, repo, or dependency, resolve its real behavior from the installed source, not from training memory or docs that may have drifted. Docs orient; the source decides. When they disagree, the version in the lockfile wins.

Use `opensrc` to pull a package's source on demand:

bash
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

Reach for it before citing an API you're unsure of, when docs are thin or contradict behavior, when an error points into a dependency, or when a review finding hinges on what a library actually does. Reading source is not running it — execute untrusted / AI-generated code in a sandbox, never your host (see Config → stack sandboxing).

For full guidance (version-matching, context7-vs-source, fallbacks) → practices/source-ground-truth.md


Command Details

Each command's full workflow lives in its own file. Read the specific file when executing that command:

CommandFile
cookcommands/cook.md
verifycommands/verify.md
yeetcommands/yeet.md
walkcommands/walk.md
landcommands/land.md
peepcommands/peep.md
dipcommands/dip.md
spawncommands/spawn.md
claimcommands/claim.md
slopcommands/slop.md
doodlecommands/doodle.md
deepencommands/deepen.md
drillcommands/drill.md
recapcommands/recap.md

Interactive Menu

When /bruhs is invoked without arguments, present the command list via AskUserQuestion and route to the selected command's file. Options: spawn, claim, cook, yeet, peep, doodle, dip, deepen, drill. slop is intentionally excluded from the menu — invoke directly with /bruhs:slop.


Config Reference

Project state lives in two marker-bounded blocks inside CLAUDE.md and AGENTS.md (mirrored). The model reads them every session — no separate config file to keep in sync. Hand-written rules live outside the blocks and are never touched.

Block 1 — bruhs:state (auto-maintained JSON)

markdown
<!-- bruhs:state:begin v1 -->
<!-- AUTO-MAINTAINED BY /bruhs. Edits inside this block will be overwritten. -->

### Project State (managed by /bruhs)

{ "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"] } }

<!-- bruhs:state:end -->

Block 2 — bruhs:rules (stack-derived behavioral rules)

markdown
<!-- bruhs:rules:begin v1 -->
<!-- AUTO-MAINTAINED BY /bruhs. Stack-specific rules derived from detected stack. -->

### 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'`.
- ...
<!-- bruhs:rules:end -->

Rules are derived from the detected stack via scripts/derive_stack_rules.py — short, high-signal, and only stack-specific. Universal behavioral rules (the kind that map to your failure modes) should be hand-written by you, outside the bruhs blocks.

Scripts

ScriptPurpose
scripts/sync_bruhs_block.pyAtomically write a bruhs:state or bruhs:rules block into CLAUDE.md + AGENTS.md.
scripts/read_bruhs_block.pyRead the JSON state (or rules markdown) back out. Falls back to legacy .claude/bruhs.json for --kind state during the transition.
scripts/derive_stack_rules.pyGiven state JSON on stdin, emit the markdown rules body to pipe into sync_bruhs_block.py --kind rules.

Migration from .claude/bruhs.json

Legacy .claude/bruhs.json is still read by read_bruhs_block.py as a fallback. /bruhs:claim detects the legacy file and offers to port it into the marker blocks, then prompts before deleting the old file.


Linear MCP

Tool format: mcp__<mcpServer>__linear_<method>

Common tools:

ToolPurpose
linear_get_teamsList teams (includes labels)
linear_get_userCurrent user (for assigneeId)
linear_create_issueCreate ticket
linear_edit_issueUpdate status
linear_get_issueFetch ticket by ID

Multi-workspace: Each project's bruhs:state block points to its Linear workspace via mcpServer.

Example:

javascript
// 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"

按任务相关推荐