Read docs/INDEX.md to find which docs apply to your task. If multiple docs are relevant, read all of them before starting. This is non-negotiable regardless of how simple the change appears.
If the change touches an agent-loop endpoint (/intent, /context, /version-patch, /region, /diff, /tldraw, or POST /annotations), consult docs/agent-loop/ before writing code. See the agent-loop rule.
If the change replicates a tests/fixtures/mockups/<name>.zip fixture (lumen-coffee, helio-pricing, drone-console), follow the mockup-replication rule.
Run every command CI would trigger for your diff. Every command must exit 0 locally before push.
pnpm exec biome check . # lint + format check
pnpm exec tsc --noEmit # typecheck
pnpm test # vitest (102 baseline + new)
pnpm build # next build (catches build-only TS errors)The full list lives in docs/ci.md.
docs/ci.md documents the concrete TypeScript, biome, Prisma, and workflow conventions that any new code must respect.
After every change, evaluate whether the documentation needs to be updated or a new doc needs to be created. If a pattern, convention, or architectural decision changes, the docs must reflect it before the work is considered done.
Prefer updating the docs first — write the contract, then write the code that satisfies it. This avoids the failure mode where docs silently lag behind shipped behaviour.
Any change to an agent-loop endpoint's response shape, auth model, error code, or cache key must update the matching doc in docs/agent-loop/ in the same change-set. These contracts are what automation clients (AI dev assistants, agent frameworks, in-house CI integrations) depend on; silent drift breaks them.
What this looks like:
- New field added to
/intentresponse → extend the response-shape table + show in the example payload - New error code on
/version-patch→ add to the error table with status code + when it fires - Cache key composition changes (e.g. adding
intent_versionto the key) → update the cache-strategy section
Adding or modifying a Prisma model means:
- Update
prisma/schema.prisma - Generate the migration with
pnpm prisma migrate dev --name <description> - Update
docs/data/schema.mdwith the new field/relation - Apply to the test DB:
DATABASE_URL='file:./prisma/test.db' pnpm prisma migrate deploy
The migration file in prisma/migrations/<timestamp>_<name>/migration.sql and the generated client are committed; prisma/dev.db and prisma/test.db are gitignored.
- New routes export
dynamic = 'force-dynamic'(or document the reason if not) - Auth check via
identify(req)returning{kind: 'user' | 'agent', ...} - Error responses match the
{ error: 'snake_case_code' }shape — seedocs/api/routes.md - New integration test under
tests/integration/api/<route>.test.ts
docs/feature-catalog.mdupdated if the change adds, removes, or alters a user-visible surface, interaction, state, or animation- Component states cover
:hover,:focus-visible,:active - New design tokens go in
src/styles/tokens.css, not inline prefers-reduced-motionoverrides accompany every new@keyframesrule- New routes/pages added to
src/app/are client components ('use client') that fetch their data viafetch('/api/…'); co-located helpers (*Client.tsx,*Form.tsx,*Viewer.tsx) handle sub-surfaces. See Frontend INDEX and Data fetching.
- Migration generated and applied to
prisma/dev.dbANDprisma/test.db - Backfill SQL in the migration if existing rows need a non-null value
docs/data/schema.mdupdated with the new field
- Matching doc in
docs/agent-loop/updated first - Integration test covers the new behaviour
- If the cache key changes, the invalidation path is updated in
src/lib/intent/cache.ts
Before declaring a task done, re-read the docs that govern the changed surface and verify the changes are reflected. If you touched two surfaces (e.g. API + frontend), re-read both halves.