<!-- skill: SvelteKit | version: 1.0.0 | description: Svelte 5 runes, SvelteKit loads, actions and adapters | category: Web -->
## Instructions
- Svelte 5 runes only: `$state()` for reactive vars, `$derived()` for computed, `$effect()` for side-effects, `$props()` for component inputs; no legacy `$:` labels in new code.
- Routing: `src/routes/+page.svelte` + `+layout.svelte` + `+page.ts/+page.server.ts` loaders; `+server.ts` for API endpoints; `[...slug]` rest, `(group)` layout groups that vanish from URL.
- Load functions: `+page.server.ts load()` for secrets/DB (cookies, fetch server-side), `+page.ts load()` for client-safe; return plain serializable data, `error(404)` / `redirect(302, '/login')` from `@sveltejs/kit`.
- Forms: `<form method="POST" action="?/update" use:enhance>` progressive enhancement; `+page.server.ts export const actions = { update: async ({request, cookies}) => {...} }` returning `fail(400, {errors})`.
- Auth/session: httpOnly cookie `session` set in login action, `hooks.server.ts handle()` populates `event.locals.user`, `+layout.server.ts` exposes `data.user` to all pages.
- Styling: scoped `<style>` per component, global `src/app.css` tokens, Tailwind via `@tailwindcss/vite` plugin; `src/app.html` shell with `%sveltekit.head%` + `%sveltekit.body%`.
- Data mutation: prefer form actions over JSON APIs for page-owned data; use `fetch` `+server.ts` endpoints only for JS-driven widgets, webhooks, external clients.
- Validation: `zod` parse inside actions/loads, return `fail(400)` with field errors + `values` to repopulate; client `superforms` optional for rich UX.
- Static assets: `static/` served verbatim (favicon, robots), `src/lib/assets` imported for hashing; `<img srcset>` or `@sveltejs/enhanced-img` for responsive images.
- Type safety: `ParamMatcher`, `PageData/ActionData` generated types via `./$types`; `npm run check` (svelte-check) must pass; `locals` typed in `src/app.d.ts`.
- Adapters: `@sveltejs/adapter-node` (VPS), `adapter-static` (SSG + `prerender`), `adapter-vercel`/`adapter-cloudflare`; one adapter per deploy target in `svelte.config.js`.
- SEO: `<svelte:head><title>` per page or `data.title` from load; `src/routes/sitemap.xml/+server.ts` + `robots.txt` route; prerender marketing pages for instant TTFB.
## Examples
- Blog: `+page.server.ts` loads post by slug from CMS, `+page.svelte` renders with `$derived` TOC, prerendered via `export const prerender = true` on index.
- Auth app: login `?/login` action sets cookie, `hooks.server.ts` guards `/app/*` with redirect, `+layout.server.ts` passes user, logout `?/logout` clears cookie.
- Interactive widget: `+page.ts` loads public data client-side, `+server.ts` JSON endpoint for polling, `use:enhance` form for mutations without full reload.
## Workflows
1. Scaffold: `npm create svelte@latest` (skeleton, TS), add adapter matching host, configure `svelte.config.js` + `app.d.ts`.
2. Build routes: layouts/pages/loaders/actions, shared `src/lib/components`, `hooks.server.ts` auth population.
3. Add data: server loads for secrets, universal loads for public, actions with `fail()` errors, `enhance` for no-JS fallback.
4. Style + SEO: app.css tokens, per-page `<svelte:head>`, sitemap/robots routes, image srcsets.
5. Harden: `npm run check` + `npm run lint`, `npm run build` preview, Playwright smoke of forms + guarded routes.
## Templates
- Server load + page with runes:
```svelte
<!-- src/routes/blog/[slug]/+page.svelte -->
<script lang="ts">
  let { data } = $props();
  let tocOpen = $state(false);
  let wordCount = $derived(data.post.html.split(/\s+/).length);
</script>
<svelte:head><title>{data.post.title}</title></svelte:head>
<article><h1>{data.post.title}</h1><p>{wordCount} words</p>
<button onclick={() => (tocOpen = !tocOpen)}>TOC</button>
{@html data.post.html}</article>
```
```ts
// src/routes/blog/[slug]/+page.server.ts
import { error } from '@sveltejs/kit';
export async function load({ params, fetch }) {
  const r = await fetch(`https://cms.example.com/posts/${params.slug}`);
  if (r.status === 404) throw error(404, 'Not found');
  return { post: await r.json() };
}
```
- Form action with enhance:
```svelte
<!-- src/routes/login/+page.svelte -->
<script lang="ts">import { enhance } from '$app/forms'; let { form } = $props();</script>
<form method="POST" use:enhance>{#if form?.error}<p>{form.error}</p>{/if}
<input name="email" type="email" required /><input name="password" type="password" required />
<button>Log in</button></form>
```
```ts
// src/routes/login/+page.server.ts
import { fail, redirect } from '@sveltejs/kit';
export const actions = {
  default: async ({ request, cookies }) => {
    const fd = await request.formData();
    if (fd.get('password') !== 'secret-demo') return fail(401, { error: 'Bad credentials' });
    cookies.set('session', 'sess_123', { path: '/', httpOnly: true, sameSite: 'lax', secure: true, maxAge: 86400 });
    throw redirect(302, '/app');
  }
};
```
- hooks + adapter config:
```ts
// src/hooks.server.ts
import { redirect } from '@sveltejs/kit';
export async function handle({ event, resolve }) {
  event.locals.user = event.cookies.get('session') ? { id: 'u1' } : null;
  if (event.url.pathname.startsWith('/app') && !event.locals.user) throw redirect(302, '/login');
  return resolve(event);
}
// svelte.config.js
import adapter from '@sveltejs/adapter-node';
export default { kit: { adapter: adapter() } };
```
## Tools
- SARAH shell_run for `npm run dev/build/preview/check`, `svelte-check`, Playwright form tests.
- SARAH file_write for routes/layouts/actions/hooks; web_fetch for SvelteKit + Svelte 5 runes docs.
## Advanced
- Streaming: return `streamed` promises from `load()` + `<await>` blocks / `{@const}` for slow sections; `depends('app:projects')` + `invalidate()` for targeted refetch after actions.
- Caching headers: `setHeaders({ 'cache-control': 'public, max-age=300' })` in loads for CDN, `export const prerender = true` for docs/marketing, `export const ssr = false` for client-only islands.
- Scale: adapter-node `BUILD` + `node build` behind Nginx; Cloudflare adapter with `platform.env` bindings; CSRF `checkOrigin` true in production, rate-limit actions via `server/utils/limiter.ts`.
## Documentation
- https://kit.svelte.dev/docs
- https://svelte.dev/docs/svelte/$state
- https://kit.svelte.dev/docs/load
- https://kit.svelte.dev/docs/form-actions
- https://kit.svelte.dev/docs/adapters
