The baseline rules Crewbit checks for

Before a stage plans, writes or reviews anything, it reads three files from the repository it is working in. A repository that has never used Crewbit does not have them yet, and you never have to write them yourself.

Guide 2 steps · 3 files

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.