Rules file: .cursor/rules/
SvelteKit moved fast enough that training data contains three incompatible generations of it: Sapper, SvelteKit 1.0, and SvelteKit 2 on Svelte 5. The single most useful thing an agent can know is which Svelte version the project runs and whether runes are enabled, because that decides the syntax of nearly every component it writes. It also needs the universal versus server-only load distinction, since that boundary is enforced by filename rather than by anything visible inside the file.
The content is the same across agents, only the filename differs. Copy this, adapt the commands to your repository, and save it as .cursor/rules/.
# AGENTS.md
This is a SvelteKit application with server rendered routes, form actions, and a Postgres backend.
## Project
Stack: SvelteKit 2, Svelte 5 (runes), TypeScript, Tailwind, Postgres, Vitest, Playwright.
Layout:
- `src/routes/+page.svelte` page markup, `+page.server.ts` server load and form actions
- `src/routes/+layout.svelte` and `+layout.server.ts` shared shell and session
- `src/routes/api/<name>/+server.ts` JSON endpoints
- `src/lib/` shared code, imported through the `$lib` alias
- `src/lib/server/` server only modules, never importable from a component
- `src/lib/components/` presentational components
- `src/hooks.server.ts` session handling and route guards
- `src/app.d.ts` App.Locals and App.PageData types
Rule of thumb: `+page.server.ts` runs on the server only, `+page.ts` runs on both, so anything with a secret or a database call belongs in the former.
Entry points: `src/hooks.server.ts`, `src/routes/+layout.server.ts`, `svelte.config.js`.
## Commands
```bash
pnpm install
pnpm dev # dev server on :5173
pnpm build # production build, must pass before a PR
pnpm preview # serve the build locally
pnpm check # svelte-check, type checks .svelte files too
pnpm lint # eslint and prettier check
pnpm format # prettier write
pnpm test # vitest run
pnpm test src/lib/pricing # one file or directory
pnpm test:e2e # playwright
pnpm exec svelte-kit sync # regenerate ./$types after route changes
pnpm db:migrate # apply database migrations
```
If `./$types` imports fail to resolve, run `pnpm exec svelte-kit sync` before assuming a real type error.
Run `pnpm check` and `pnpm build` before returning work.
## Code style
- Svelte 5 runes only: `$state`, `$derived`, `$props`, `$effect`. No `export let`, no `$:` reactive statements, no legacy stores in new code.
- `$effect` is a last resort. Derive values with `$derived` instead of syncing them in an effect.
- Data comes from a `load` function, never from a fetch inside `onMount` for content that should be server rendered.
- Mutations use form actions with progressive enhancement via `use:enhance`. Do not hand roll a fetch POST for a form.
- `load` returns serializable data. Never return a class instance or a database client.
- Import secrets from `$env/static/private` or `$env/dynamic/private`, only inside `src/lib/server/` or a `.server.ts` file.
- Validate every form action payload and every endpoint body with a schema before use.
- Tailwind utilities in markup. Use `<style>` blocks only for something utilities cannot express.
- Components take props and emit callbacks. No component reaches into a global store for data its parent already has.
- Use `$lib` imports, not relative paths that climb directories.
## Boundaries
Do not touch without explicit instruction:
- `.svelte-kit/` and any `./$types` file, both are generated.
- `svelte.config.js` adapter configuration and `vite.config.ts`.
- `pnpm-lock.yaml`. Add dependencies with `pnpm add`.
- `.env`. New variables are documented in `.env.example`.
- Database migration files that have already been applied.
- `.github/workflows/` and hosting configuration.
Needs human review: `src/hooks.server.ts`, anything that changes session or cookie handling, new public API endpoints, and any change that moves code between server only and shared modules.
Never import from `src/lib/server/` in a `.svelte` file. If that seems necessary, the data should come from `load` instead.
## Testing
- `pnpm test` runs Vitest, `pnpm test <path>` runs one file.
- Required tests: every exported function in `src/lib/`, every form action, and every `+server.ts` endpoint.
- `load` functions are tested by calling them with a stubbed event object.
- Component tests only for components with real logic. Do not test markup structure.
- Playwright covers sign in and the primary conversion flow. Keep the e2e suite small.
- A bug fix ships with a test that fails without it.
## Git workflow
- Branch from `main`: `feat/short-description`, `fix/short-description`.
- Conventional commits: `fix(checkout): validate coupon before creating the session`.
- `pnpm build` and `pnpm check` must pass locally before opening a PR, prerender errors only appear at build time.
- PR description states what changed, why, and how it was verified, plus any new environment variable.
- Never commit to `main`.
These are the failures that repeat across sessions, so each one belongs in .cursor/rules/.
Agents still reach for a session store from $app/stores, a load function that receives page and fetch as a legacy shape, or Sapper's preload. None of that exists any more, and session in particular was removed in favour of event.locals plus data returned from load. Put the version in your rules file and add: 'Load functions live in +page.js or +page.server.js, take a single event argument, and per request state comes from event.locals set in hooks.server.js.'
In a Svelte 5 runes project an agent will still write export let for props and a $: block for derived values, which either fails to compile or silently opts the component out of runes mode. The mix is hard to spot because both syntaxes look correct in isolation. State it plainly: 'Svelte 5 runes mode. Props use $props(), state uses $state(), derived values use $derived(), side effects use $effect(). Never use export let or $: labels.'
A +page.js load runs on the server for the first render and then again in the browser on client navigation, so an agent that queries the database or imports from $env/static/private there ships a build error at best and a leaked secret at worst. Agents pick the wrong file because both are named load. Write the rule as: 'Anything touching the database, private env, or a server-only SDK goes in +page.server.js or a .server.js module. +page.js is browser code too.'
Asked to add a form, agents default to a POST endpoint under routes/api plus a client fetch handler, which throws away progressive enhancement, the built-in validation return shape, and automatic invalidation of load data. It works, so nobody catches it in review. Add: 'Mutations from a form use a named action in +page.server.js with use:enhance on the client. Only create a route under api/ for external consumers or webhooks.'
For internal navigation and post-mutation refreshes, agents write window.location.href or location.reload(), which drops the router, refetches every load, and loses client state. Both are common in generic JavaScript training data and neither is ever correct inside a SvelteKit app. Specify: 'Use goto from $app/navigation for internal navigation and invalidate or invalidateAll to refresh load data. window.location is only for external URLs.'
Agents call items.push(x) or obj.key = v and move on. Under Svelte 5 $state that works because of the proxy, but in a legacy component or on a plain non-reactive value it silently renders nothing, and agents cannot tell which mode a file is in without looking. Make it explicit: state your Svelte version and add 'in legacy components reassign rather than mutate, and never assume a plain module level object is reactive.'
Webapp Testing
Tests local web applications using Playwright for verifying frontend functionality, debugging UI behavior, and capturing screenshots.
docx
Create, edit, analyze Word docs with tracked changes, comments, formatting.
Master Claude for Legal
Skill pack for legal teams. NDA triage, multi-party version diff, citation verifier, meeting brief, and the Friday-newsletter status synthesis pattern. Includes 10 reference docs (privilege, verification, long documents, practice areas) and 3 firm templates. Built from the public Anthropic Claude for Legal Teams webinar dataset.
artifacts-builder
Suite of tools for creating elaborate, multi-component claude.ai HTML artifacts using modern frontend web technologies (React, Tailwind CSS, shadcn/ui).