Rules packs
Sections for a rules file, grouped by stack. Combine packs into one file with the CLI; each section is scored on its own, each pack as a whole CLAUDE.md. Public domain (CC0).
aibysitter init --packs starter,aspnet-web-api --format claude
Formats: claude, agents, gemini, copilot, cursor, cursorrules, windsurf. A heading in more than one pack becomes one section. CLI: dotnet tool install --global Aibysitter.Cli. Machine-readable: /packs/registry.json.
-
ASP.NET Core web API
Minimal APIs on .NET 10 with EF Core and PostgreSQL: endpoints, errors, data, authorization and tests.
aibysitter init --packs aspnet-web-api --format claude-
Commands A 100
- Build:
dotnet build -warnaserror - Test:
dotnet test - Run:
dotnet run --project src/<App>.Api(listens onhttp://localhost:5080) - OpenAPI document:
GET /openapi/v1.jsonwhile the API is running
- Build:
-
Endpoints A 100
- Group endpoints by resource in
src/<App>.Api/Endpoints/<Resource>Endpoints.cswith aMap<Resource>Endpointsextension method. - Request and response types are records in
Contracts/. Entities never leave the data layer. - Return
TypedResults(Ok,Created,NotFound,ValidationProblem) and declare them in the handler's return type. - Validation failures return 400 with
ValidationProblemand one error per field. - Unknown IDs return 404 with an empty body.
- Routes are lowercase plural nouns:
/items,/items/{id},/items/{id}/movements.
- Group endpoints by resource in
-
Errors A 100
- Unhandled exceptions become RFC 9457 problem details through
app.UseExceptionHandler(). Handlers do not catch exceptions to return 500 themselves. - Optimistic-concurrency failures throw
ConflictException. The exception handler maps it to 409.
- Unhandled exceptions become RFC 9457 problem details through
-
Data A 100
<App>DbContextlives insrc/<App>.Data.- Bulk changes use
ExecuteUpdateAsyncandExecuteDeleteAsync.
-
Authorization A 100
- Every endpoint requires a policy:
.RequireAuthorization(Policies.Read)or.RequireAuthorization(Policies.Write). /healthis the only endpoint withAllowAnonymous.
- Every endpoint requires a policy:
-
Tests A 100
- Integration tests in
tests/<App>.Api.TestsuseWebApplicationFactory<Program>and a Testcontainers PostgreSQL instance. - Each new endpoint gets four tests: success, 400 on invalid input, 404 on an unknown ID, 403 without the required policy.
- Test names follow
Method_Condition_Result.
- Integration tests in
-
Pull requests A 100
- One endpoint or one bug fix per PR.
- Add a line to
CHANGELOG.mdunder the Unreleased heading.
-
-
ASP.NET Core Razor Pages
Razor Pages on .NET 10 with EF Core and SQL Server: layout, pages, data access, logging and tests.
aibysitter init --packs dotnet-razor-pages --format claude-
Layout A 100
src/<App>.Web: Razor Pages, page models,Program.cs.src/<App>.Data:<App>DbContext, entity configurations, migrations.tests/<App>.Web.Tests: xUnit page tests usingWebApplicationFactory<Program>.tests/<App>.Data.Tests: xUnit data tests against SQL Server.
-
Commands A 100
- Build:
dotnet build <App>.slnx -warnaserror - Test:
dotnet test <App>.slnx - Run:
dotnet run --project src/<App>.Web - New migration:
dotnet ef migrations add <Name> --project src/<App>.Data --startup-project src/<App>.Web
- Build:
-
Pages A 100
- One page per file pair:
Pages/<Area>/<Name>.cshtmland<Name>.cshtml.cs. - Page models take dependencies through the primary constructor.
- Bind form input with
[BindProperty]on a dedicated input record. Entities are never bound directly. - Validate with data annotations. Return
Page()whenModelStateis invalid. - A successful POST handler ends with
RedirectToPage(...). - No JavaScript in pages unless the task asks for it.
- One page per file pair:
-
Data access A 100
- Read-only queries use
AsNoTracking(). - Load related data with explicit
Includecalls. Lazy loading is disabled. - One
SaveChangesAsynccall per POST handler. - Schema changes go through a new migration. Do not edit a migration that has been applied.
- Connection strings come from user-secrets locally and environment variables on the server.
appsettings.jsonholds no secrets.
- Read-only queries use
-
Logging A 100
- Use
ILogger<T>with message templates:logger.LogInformation("Order {OrderId} shipped", order.Id). - Do not log email addresses, names, or payment details.
- Use
-
Tests A 100
- Every new page gets a test that requests it through
WebApplicationFactory<Program>and asserts the status code and one piece of rendered text. - Data tests use the SQL Server container started by
tests/<App>.Data.Tests/DatabaseFixture.cs. - Every test asserts a result. A test that calls a method without an assertion is incomplete.
- Every new page gets a test that requests it through
-
Done A 100
dotnet build -warnaserrorpasses.dotnet testpasses.- Changed files are limited to the ones the task names, plus their tests and migrations.
-
-
Go HTTP service
Go service on net/http with PostgreSQL through pgx and sqlc: layout, handlers, errors, logging and tests.
aibysitter init --packs go-http-service --format claude-
Commands A 100
- Build:
go build ./... - Test:
go test -race ./... - Vet:
go vet ./... - Lint:
golangci-lint run - Format check:
gofmt -l .prints nothing - Regenerate queries after editing
db/queries/*.sql:sqlc generate
- Build:
-
Layout A 100
cmd/<app>/main.go: wiring only. Config, logger, server start.internal/http/: handlers and routes.internal/<domain>/: domain logic. Nonet/httpimports.internal/db/: generated sqlc code. Files in this directory are not edited by hand.
-
Handlers A 100
- Routes are registered with method patterns:
mux.HandleFunc("POST /messages", h.createMessage). - JSON bodies are decoded with
json.NewDecoder(r.Body)andDisallowUnknownFields(). - Errors are written with
writeError(w, status, code, message)frominternal/http/errors.go. - Handlers get their dependencies from the
Handlerstruct. No package-level state.
- Routes are registered with method patterns:
-
Errors and context A 100
- Wrap errors with context:
fmt.Errorf("load account: %w", err). Compare them witherrors.Isanderrors.As. - Every function that does I/O takes
ctx context.Contextas its first parameter. - Request paths do not call
context.Background().
- Wrap errors with context:
-
Logging A 100
log/slogwith JSON output. Keys are snake_case:slog.Info("message sent", "message_id", id).- Message bodies and personal data are never logged.
-
Tests A 100
- Table-driven tests with one
t.Runper case. - Handlers are tested with
httptest.NewRecorderand fakes for external clients. - Database tests carry the
//go:build integrationtag and run withgo test -tags integration ./....
- Table-driven tests with one
-
Dependencies A 100
- Add a module only when the task requires it, and name it in the PR description.
-
-
pnpm and Turborepo monorepo
Root rules for a pnpm workspaces and Turborepo monorepo: commands, workspace, scope, versioning and pull requests.
aibysitter init --packs monorepo --format claude-
Commands (from the repo root) A 100
- Install:
pnpm install --frozen-lockfile - Build everything:
pnpm turbo run build - Test one package:
pnpm turbo run test --filter=<package-name> - Test packages changed on this branch:
pnpm turbo run test --filter=...[origin/main] - Lint and type check:
pnpm turbo run lint typecheck
- Install:
-
Workspace A 100
- Packages import each other by package name (
@<scope>/ui). No relative imports across package folders. - Every package lists the dependencies it imports in its own
package.json. - Shared TypeScript settings come from
packages/tsconfig. Package configs extend it and do not copy compiler options. - Add dependencies with
pnpm add <dep> --filter <package-name>.pnpm-lock.yamlis not edited by hand.
- Packages import each other by package name (
-
Scope A 100
- Change only the packages the task names. When another package needs a change, stop and describe the change instead of making it.
turbo.json, rootpackage.jsonscripts, and CI workflows change only on explicit request.
-
Versioning A 100
- Packages under
packages/are versioned with Changesets. A change to a published package includes a changeset frompnpm changeset. - Apps are not versioned.
- Packages under
-
Pull requests A 100
- Title format:
<package-name>: <summary>. - The description lists every package the PR touches.
- Title format:
-
-
Next.js with TypeScript
Next.js App Router, strict TypeScript and Tailwind CSS with pnpm: structure, TypeScript, styling, server code and tests.
aibysitter init --packs nextjs-typescript --format claude-
Commands A 100
- Install:
pnpm install --frozen-lockfile - Dev server:
pnpm dev - Type check:
pnpm tsc --noEmit - Lint:
pnpm lint - Unit tests:
pnpm test(Vitest) - End-to-end tests:
pnpm test:e2e(Playwright)
- Install:
-
Structure A 100
- Routes live in
app/. Shared UI lives incomponents/. Data access lives inlib/data/. - Components are Server Components by default. A component that uses state, effects, or browser APIs starts with
"use client". - Client components receive data as props. Data fetching stays in the Server Component that renders them.
- Mutations are Server Actions in
app/**/actions.tsand callrevalidatePathfor the route they change.
- Routes live in
-
TypeScript A 100
- No
any. Useunknownand narrow it. - No non-null assertions (
!) outside tests. - Form data, route params, and API responses are parsed with the Zod schemas in
lib/schemas/before use.
- No
-
Styling A 100
- Tailwind classes only. No inline
styleattributes and no new CSS files. - Colors come from the theme tokens in
app/globals.css. No raw hex values in components.
- Tailwind classes only. No inline
-
Server code A 100
- Modules that read secrets or the database import
server-onlyon their first line. - Secrets are read from
process.envin server code only. Secret names never start withNEXT_PUBLIC_.
- Modules that read secrets or the database import
-
Tests A 100
- A component with logic gets a Vitest test next to it:
ProductCard.test.tsxforProductCard.tsx. - A new route gets one Playwright test in
e2e/covering its main path.
- A component with logic gets a Vitest test next to it:
-
Before opening a PR A 100
pnpm tsc --noEmit,pnpm lint, andpnpm testpass.- No
console.logcalls remain inapp/,components/, orlib/.
-
-
Python FastAPI service
FastAPI with async SQLAlchemy, PostgreSQL and Alembic, run through uv: layout, API, money, code style and tests.
aibysitter init --packs python-fastapi --format claude-
Commands A 100
- Install:
uv sync - Run:
uv run fastapi dev src/<app>/main.py - Test:
uv run pytest - Lint:
uv run ruff check . - Format:
uv run ruff format . - Type check:
uv run mypy src - New migration:
uv run alembic revision --autogenerate -m "<summary>", then read the generated file before committing it.
- Install:
-
Layout A 100
src/<app>/api/: routers, one module per resource.src/<app>/services/: business logic. No FastAPI imports.src/<app>/db/: models, session, repositories.tests/mirrorssrc/<app>/.
-
API A 100
- Request and response bodies are Pydantic v2 models in
src/<app>/schemas/. ORM models are never returned from a route. - Routes declare
response_modeland an explicitstatus_code. HTTPExceptionis raised only in routers. Services raise domain errors from<app>.errors, andapi/errors.pymaps them to status codes.- Database sessions come from the
get_sessiondependency. Services do not open sessions.
- Request and response bodies are Pydantic v2 models in
-
Money A 100
- Amounts are integers in minor units (cents). No floats for money.
- Every amount is stored with an ISO 4217 currency code next to it.
-
Code style A 100
- Every function signature has type hints.
mypy --strictpasses forsrc/. - Ruff rules live in
pyproject.toml. A# noqacomment always names the rule code. - Timestamps use
datetime.now(tz=UTC). Naive datetimes are a bug.
- Every function signature has type hints.
-
Tests A 100
- pytest with
pytest-asyncio. Async tests use theasync_clientfixture fromtests/conftest.py. - Database tests run against the Postgres container started by
docker compose up -d db. - A bug fix starts with a failing test that reproduces the bug.
- pytest with
-
Done A 100
ruff check,ruff format --check,mypy, andpytestall pass.
-
-
Starter
Stack-neutral template: stack, commands, working rules and a definition of done, with bracketed parts to fill in.
aibysitter init --packs starter --format claude-
Stack A 100
- Language and version: [C# 13 on .NET 10]
- Frameworks: [ASP.NET Core, EF Core]
- Package manager: [NuGet]
-
Commands A 100
- Build:
[build command] - Test:
[test command] - Format or lint:
[format command]
- Build:
-
Rules A 100
- Run the test command before reporting a task complete.
- Change only the files the task names, plus their tests.
- Match the code style of the file being edited.
- Ask before adding a dependency.
- Ask before deleting a file.
- Do not commit secrets, keys, or
.envfiles.
-
Done A 100
- Build and tests pass.
- New behavior has a test that asserts the result.
- The PR description lists what changed and how it was tested.
-
-
WinForms with DevExpress
WinForms desktop app on .NET 10 with DevExpress controls: projects, forms, CSV export, settings and tests.
aibysitter init --packs winforms-devexpress --format claude-
Commands A 100
- Build:
dotnet build <App>.slnx -c Release -warnaserror - Test:
dotnet test <App>.slnx - Publish:
dotnet publish src/<App>.App -c Release -r win-x64 --self-contained false
- Build:
-
Projects A 100
src/<App>.App: forms, user controls,Program.cs.src/<App>.Core: export rules and the CSV writer. No WinForms or DevExpress references.tests/<App>.Core.Tests: xUnit tests for Core.
-
Forms A 100
- Do not edit
*.Designer.csfiles by hand. Describe layout changes in the PR for a person to make in the designer. - Event handlers call a presenter or a Core service. They contain no export logic.
- Long-running work runs through
await Task.Run(...)inside anasync voidevent handler with a try/catch that showsXtraMessageBox. - New forms use DevExpress controls (
GridControl,LookUpEdit,DateEdit) instead of the standard WinForms equivalents. - Grid columns bind to properties by name through
FieldName. No column access by index.
- Do not edit
-
Export format A 100
- Money is
decimal, rounded to 2 places withMidpointRounding.AwayFromZeroat output time only. - Dates use
yyyy-MM-dd. Times use 24-hourHH:mm. - Output is UTF-8 without BOM with CRLF line endings. Fields are quoted only when they contain a comma, a quote, or a line break.
- Column order is defined once, in
ExportColumns.cs.
- Money is
-
Settings A 100
- User settings live in
%LOCALAPPDATA%\<App>\settings.json. - Do not write to the install directory or the registry.
- User settings live in
-
DevExpress A 100
- The DevExpress version is pinned in
Directory.Packages.props. Feature PRs do not change it. - License keys stay on developer machines. Do not commit
licenses.licxor any key.
- The DevExpress version is pinned in
-
Tests A 100
- Every export rule change adds a Core test with a fixture CSV in
tests/<App>.Core.Tests/Fixtures. - Generated CSV is compared to the fixture byte for byte.
- Every export rule change adds a Core test with a fixture CSV in
-