01What each one is for
planning.md is the shape a plan has to take before you ever see it: which
files change and why, the approach and the alternative it was weighed against, the
steps in order, and the tests it commits to before any of them exist.
ready_for_code.md is what makes an issue workable at all, checked before a
plan is ever attempted: a problem stated apart from its solution, criteria you could
turn into a failing test, and a named surface: a feature, an endpoint, a screen.
testing.md is what counts as a real test here: written before the code it
covers and able to fail, asserting what a change does rather than how it is built
inside, and never waiting on a clock to prove something happened.
02The first run on a new repository adds them for you
Attach a repository that has never used Crewbit, and the next run opens an issue of its own first, titled "Add the baseline rules," and plans it before the one you asked for. Every other issue on that repository waits behind it: the refusal names the issue, or its run, so you always know what it is waiting on rather than guessing.
You review that plan and that pull request the same way you review any other. Once it merges, every later run reads your repository's own copy: editing it there is what changes what the next run checks for, not this page.
.claude/rules/planning.md
# What a plan has to contain A brief another engineer could implement without asking you anything, not a description of the problem and not code. Explore first. **Every path you name must exist**, unless you mark it as a new file: a plan citing a file that is not there was written from imagination. Reuse the helper or convention the codebase already has, and say which. ## The five sections Exactly these, in this order. ### Acceptance criteria Quoted from the Spec, one per testable outcome. A sentence of the body that is an instruction, a warning or an observation is not a criterion: it is context, and belongs in a **Context from the Spec** note. Propose no verification the Spec did not ask for. ### Affected files One line each: the path and what changes about it, so a reviewer sees the blast radius. A file that does not exist yet is marked **new file**: ``` - src/health.ts — new file, the handler ``` More than roughly ten files should be split: say so instead. ### Approach Short. What you are doing and, where a real choice exists, why this one and not the obvious alternative. This is the section a reviewer disagrees with, so make that possible. ### Steps Ordered, each one a change that leaves the tree working. ### Tests & evals (write first) The contract the code stage implements against, covering the acceptance criteria above and the change itself, no more: ``` - [unit] rejects a token whose expiry has passed - [integration] a Job dispatched with no runner connected returns 503 ``` Name the input and the expected outcome, and include the edge cases you found while exploring. ## Two ways to refuse Both are successful outcomes. **Too thin**: exploring did not make the Spec plannable — say what is missing and stop, rather than planning around the gap. **Too big**: propose a split where each piece is independently valuable and separately reviewable. A plan never invents a requirement the Spec does not state, never widens scope, and never includes code.
.claude/rules/ready_for_code.md
# Is this Spec workable? You are judging one thing: can this be worked without guessing? Not whether it is a good idea, not how hard it is, not how you would build it. **Fill the routine gap from the tree, and say so.** A Spec naming "the config" without a path is not thin: read the tree, find the one thing it can mean, and write down that you read it that way. The gap is routine when the tree answers it without a decision. **Ask when the gap is a decision.** Two files could plausibly be "the config", or two readings would lead to materially different work — not yours to guess, and not yours to refuse either: it is a question for whoever wrote the Spec. **Refuse when there is nothing to read.** "Make the system better" names no surface a grep could land on, and no reading of the tree resolves that. ## Required A Spec is workable when all three are present. **A stated problem, distinct from a stated solution.** "Add a Redis cache" is a solution with the problem missing. "The dashboard takes 8 seconds to load for a 500-transaction account" is a problem. A solution is welcome as well, and never sufficient alone. **Testable acceptance criteria.** An outcome that can be turned into a failing test before any code exists. "Should be faster" is not testable; "loads in under 2 seconds for a 500-transaction account" is. **A named surface.** Where in the product this lives, at the granularity the reporter can be expected to know: a feature, an endpoint, a screen, a command. "The billing export" is a surface; "somewhere in the backend" is not. ## Not required Their absence is never a reason to refuse: a design or an architecture, file paths or a module layout, an estimate or a priority, a test plan. ## When something is missing Name the item and what would satisfy it. "Needs more detail" is a rejection nobody can act on. Do not propose the answer: a guess in a question becomes the requirement.
.claude/rules/testing.md
# What counts as a test here One document, because the code stage writes against it and the eval stage judges against it. ## Failing first Write the test, watch it fail, then implement. A test written after the code asserts what the code does, not what was wanted. ## Assert behaviour, not implementation Name an input and an expected outcome, not a private function, a count of calls to a helper, or an intermediate value. Would this test survive a rewrite of the internals that kept the behaviour? Test through the seam the caller uses. ## What to cover Every stated acceptance criterion, one test each. The edge cases you find while implementing: empty input, the second call, the concurrent call, the failure of what you depend on. And the boundary you are trusting: untrusted input, data loss, money, credentials. ## The shape: unit tests carry the coverage, integration proves the flow A unit test needs nothing running, and every branch a module can take is reachable that way: that is where coverage comes from. Integration is the other job: the real components meeting on a completed flow. One per flow is usually enough. Both, never one instead of the other: coverage reached by integration hides the module with no test of its own. ## Waiting: on the event, never on the clock **A test may not sleep, and it may not poll**, `expect.poll` and a `waitFor` helper included. Both put the assertion at a time the test picked rather than when the thing happened. Wait on the event: something caused it, and that is a seam. Two waits are legitimate, and both say so where they sit. **Proving an absence**, where the assertion is that nothing moved. And **state outside this process** that raises no event, such as the process table. ## What does not count A test that cannot fail. A snapshot of unexamined output. A test for what the type system already guarantees. A skipped test. Coverage as a goal. A test genuinely hard to write is a design signal: say so, and why.