Skip to content

Instantly share code, notes, and snippets.

@shreyassanthu77
Created July 25, 2026 00:52
Show Gist options
  • Select an option

  • Save shreyassanthu77/bffd92fb879ead2db964d36d3e6ecac4 to your computer and use it in GitHub Desktop.

Select an option

Save shreyassanthu77/bffd92fb879ead2db964d36d3e6ecac4 to your computer and use it in GitHub Desktop.
my agents file as of july 2026

Package management

ALWAYS use pnpm for package management.

pnpm add <package>
pnpm dlx <executable> # e.g. pnpm dlx drizzle-kit
pnpm <task> # e.g. pnpm check, pnpm format etc.

DO NOT use npm or yarn.

Development and Writing code

  • NEVER use tsc directly. Instead, use pnpm check to check for errors.

  • NEVER run pnpm build to check for build errors. It messes up the running dev server and cache.

  • NEVER use as any or @ts-ignore unless absolutely necessary (which it is not 99.999% of the time). If you do use them, make sure to document why you need to use them in a single crisp line.

  • NEVER run pnpm db:push, pnpm db:generate or pnpm db:migrate automatically. ALWAYS ask the user for explicit confirmation before running any commands that touch the database. Even if it is during local development.

  • ALWAYS use evlog for logging instead of console.log.

    import { useLogger } from "evlog/sveltekit";
    
    // ..in the handler
    const log = useLogger();
    log.set({ userId, userName });
    log.info(
      "Some free form log message. Prefer doing wide events with .set over .info for more structured logs.",
    );

    NOTE: this only works if the function is called from a SvelteKit server handler as it relies on async local storage for the logger context which most of the time is the case but in some really rare cases it might not be.

    • consult the evlog skills for more info.
  • ALWAYS pnpm check followd by pnpm format at the end after finishing with your changes.

  • prefer framework defaults over custom guards/checks. e.g. don't add manual route/domain existence checks when SvelteKit's 404 handles it; don't add manual data refetch when SvelteKit refetches page data on form submit. only add custom logic when the framework default genuinely doesn't work.

  • ALWAYS use sveltekit remote functions and svelte async for server rpc. NEVER use load functions or form actions for data fetching and mutations.

    • ONLY use +server.ts route handler for external integrations. the svelte client must ALWAYS use the remote functions unless absolutely necessary to write regular api endpoints.
    • all remote functions go in *.remote.ts files. these files can be placed anywhere and always run on the server.
    • *.remote.ts files can't export anything other than remote functions. so no exporting a random variable or function that is not a remote function.
    • consult the svelte mcp/siills for details.
    • svelte async let's you use await in anywhere .svelte files and inside runes. again, consult the svelte mcp/siills for details.
    • svelte remote functions forms have a special usage signature, do not assume anything and always consult the svelte mcp/siills on how to use them right.
    • Do NOT manually refresh/set remote queries after remote form submissions unless the user explicitly asks for custom invalidation behavior; SvelteKit refreshes page data by default and that is what we want most of the time.
    • do not forget to key remote forms when using the same one multiple times on the same route. otherwise, it will throw and crash the entire page in production and cause hard to debug issues with route navigation and weird infinite loops.
    • arktype input schemas: "key?": "string" rejects an explicitly passed undefined (? only means the key may be absent). Since callers often pass { key: maybeUndefined }, ALWAYS write optional keys as "key?": "string | undefined" (parenthesize constrained types, e.g. "(number >= 1) | undefined").
  • DO NOT write comments that explain what the code does.

    • only write comments that explains something that is non obvious to understand from the surrounding code/project context.
    • use them to explain non trivial logic.
    • JSDoc on a function/type is ONLY for invariants or sentinel/return-value meanings (e.g. "returns null if not found", what a boolean flag means). Do NOT add JSDoc that just restates what the function does from its name/signature.
  • General code style:

    • long functions are fine if it is easy to understand top to bottom. unnecessarily deep call stacks are worse than a long function.
    • one long file is fine. don't split files if the functions/classes are related.
    • don't abstract into intefaces/wrapper functions if it doesn't help with problem at hand.
    • optimize for readability and understanding, not some future extensibility.
    • business logic should be in one place/dir(s)/files. don't scatter it throughout route files and/or remote functions.
      • one caveat, put single use, trivial db query for a report or something in that route handler if it is obvious and only used once. e.g. a report export query that generates a csv and only needs to be written once.
    • prefer correctness over everything. ALWAYS.
    • be mindful of memory and performance. don't do too many copies. reuse/mutate objects in place if they are only used in that one function/created in that scope. prefer pre allocating arrays when possible.
    • use db transactions when doing multiple db operations in a single function.

Architecture & layering

  • Errors (via @joyful-tools/result taggedError):
    • anything a caller is expected to handle distinctly MUST be its own tagged error type (e.g. SlugTakenError, ContactAlreadyLinkedError), so remotes can branch on error._tag / .orElseMatch.
    • everything else uses the generic shared DatabaseError carrying a cause and a human-readable message for logging. Do NOT overload a generic error's cause with magic strings to signal handled conditions — make a tagged error instead.
    • idempotency: adding a record that already exists, removing one that doesn't, re-linking the same thing, etc. must succeed as a no-op (onConflictDoNothing, no-op deletes, early return), NOT error. Only raise a tagged error when it is genuinely useful for the caller to branch on and surface in the UI.
  • Services (*.server.ts): plain exported functions returning AsyncResult, mirror src/lib/services/workspace.server.ts.
    • do the FEWEST queries possible. prefer a single statement over a read-then-write.
    • create-or-fetch in one query with an upsert: onConflictDoUpdate with a dummy updatedAt: <table>.updatedAt write so the existing row is still returned, and pass a pre-generated id so you can detect created-vs-reused by comparing the returned id (see createWorkspace/createEntity).
    • do NOT write helper functions for a single query. inline it.
  • Queries: prefer batching/specializing a query for the exact shape a page needs over composing many generic CRUD calls.
  • Logging: every remote function should create const log = useLogger() and emit a wide event via log.set({ ... }) (workspace id, user id, operation, relevant ids) plus log.error(...) on failure paths. Prefer .set wide events over scattered .info.
  • Data loading in .svelte: prefer const x = $derived(await someQuery(arg)) (svelte async) over {#await} blocks. You should almost never need {#await}. Gate permission-scoped queries with a ternary, e.g. const contacts = $derived(canRead ? await listContacts({ slug }) : []), so you don't trigger a guard redirect for data the user can't see.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment