Important
ALWAYS plan before implementing.
- Break down tasks into small steps.
- Use
manage_todo_list. - Identify files and dependencies.
- Read code first (
read_file). - Make small, incremental changes.
- Test your changes.
- Use Svelte MCP (
svelte-autofixeris mandatory). - Follow DaisyUI (semantic classes like
btn-primary). - Validate with ESLint.
- Check DB schema (
src/lib/server/db/schema.ts). - Use Drizzle ORM syntax (always prefer
db.select()overdb.queryor rawsqltemplates). - Mark todos complete immediately.
- No raw Tailwind colors.
- No large sweeping changes.
- Don't skip
svelte-autofixer. - Don't ignore TS/ESLint errors.
- No emojis.
- Code implemented & tested.
- Diff is small and focused.
svelte-autofixerpassed.- ESLint passed.
- Types correct.
- DaisyUI conventions followed.
- Todos completed.
- Never Commit: Generated code, dependencies, secrets, IDE settings, OS files, logs.
- Safe to Commit: Source, config, docs, tests, migrations.
- Workflow: Review diff -> Stage specific files -> Commit with conventional commit message.
list-sections: First step to find docs.get-documentation: Fetch relevant sections.svelte-autofixer: Mandatory before finalizing components.playground-link: Offer only after user confirmation.
resolve-library-id->get-library-docs: For external library docs.- Use proactively for new dependencies.
lint-files: Validate changes.
depscore: Check new dependencies.
Stack: SvelteKit (Svelte 5), SQLite + Drizzle, Lucia Auth, DaisyUI, CodeMirror 6, Loro CRDT.
src/
├── lib/
│ ├── assets/ # Static assets
│ ├── components/ # Svelte components
│ ├── editor/ # Editor utilities
│ ├── remote/ # Remote data fetching
│ ├── server/ # Server-only code (Auth, DB, Real-time)
│ ├── types/ # TypeScript types
│ ├── utils/ # Shared utilities
│ ├── crypto.ts # Crypto utils
│ ├── loro.ts # Loro CRDT
│ ├── schema.ts # Shared Effect Schema
│ └── unawaited.ts # Unawaited promise handler
├── routes/
│ ├── (auth)/ # Login/Signup
│ ├── api/ # API endpoints
│ ├── notes/ # Note pages
│ ├── +layout.svelte # Root layout
│ ├── +page.svelte # Home page
│ └── layout.css # Global styles
└── hooks.server.ts # Server hooks
src/lib/server/db/schema.ts: DB Schema (Users, Sessions, Notes).src/lib/server/auth.ts: Lucia-inspired Auth config.src/lib/server/real-time.ts: Loro CRDT sync.src/lib/components/codemirror/: Editor components.
- Type Check:
pnpm check - Format:
pnpm prettier --write path/to/file.ts - Migrations:
pnpm drizzle-kit generate->pnpm drizzle-kit migrate - Lint: Use ESLint MCP.
Use semantic classes. Avoid raw Tailwind colors.
<button class="btn btn-primary">Save</button>
<div class="card bg-base-200">...</div>
<span class="badge badge-error">Error</span><button class="bg-blue-500 text-white">Save</button>
<div class="bg-gray-800">...</div>- Imports
- Props (
$props()) - Functions/Promises
- Effects/State (
$effect,$state) - Derived Async (
$derived(await query))
Use createContext from svelte.
import { createContext } from "svelte";
export const [getLinkContext, setLinkContext] = createContext<LinkContext>();Wrap in $derived for reactivity.
<script lang="ts">
import { getNote } from "$lib/remote/notes.remote";
let { noteId } = $props();
let noteQuery = $derived(getNote(noteId));
let note = $derived(await noteQuery);
</script>Use .updates() with .withOverride().
import { getPosts, createPost } from "$lib/remote/posts.remote";
async function handleSubmit() {
const newPost = { id: "temp", title: "New Post" };
await createPost(newPost).updates(
getPosts().withOverride((posts) => [newPost, ...posts]),
);
}Warning
NEVER use global shared stores (exported writable or $state in module scope).
In SSR, module state is shared across requests. Instead:
- Use
createContextfor component-scoped state. - Pass data via
props.
Use $derived overrides or $state.eager.
<script lang="ts">
let { post, like } = $props();
let likes = $derived(post.likes);
async function onclick() {
likes += 1; // Optimistic update
try {
await like();
} catch {
likes -= 1;
}
}
</script>- No
loadfunctions: Use Remote Functions. - No
{#await}: Use top-levelawaitor<svelte:boundary>s in<script>. - No Stores: Avoid
writable,readable,derivedstores. Use Runes ($state,$derived) instead.