I build SvelteKit apps, and I lean on AI PR review like everyone else. But I kept noticing the generic reviewers green-lighting things that would absolutely break in production — because they parse a .svelte file as if it were a .js file and miss the framework rules entirely. So I built a reviewer that actually knows Svelte 5. Here's the footgun that pushed me over the edge.
The problem
SvelteKit has a hard rule: anything from $env/static/private (or $env/dynamic/private) must never reach client code. The compiler enforces it in a lot of cases, but not all — and the moment a private value flows through a regular module or a shared util, it can end up bundled into the browser.
Here's a snippet that looks completely innocent in a PR diff:
<!-- src/routes/contact/+page.svelte -->
<script>
import { SENDGRID_API_KEY } from '$env/static/private';
async function submit(e) {
e.preventDefault();
// "just calling the API directly from the component, ship it"
await fetch('https://api.sendgrid.com/v3/mail/send', {
method: 'POST',
headers: { Authorization: `Bearer ${SENDGRID_API_KEY}` },
body: new FormData(e.target)
});
}
</script>
<form on:submit={submit}>
<input name="email" type="email" />
<button>Send</button>
</form>
A generic AI reviewer reads this and sees: an import, a fetch, a form handler. Looks fine. It might even compliment your error handling.
What it misses: this is a .svelte component — it runs in the browser. SENDGRID_API_KEY gets shipped to every visitor's devtools. That's not a style nit, that's your provider key in plaintext on the public internet.
Same category of misses I kept seeing:
<script>
// crashes SSR — window doesn't exist on the server
const theme = localStorage.getItem('theme');
</script>
<!-- XSS: user-controlled string rendered as raw HTML -->
{@html comment.body}
<script>
// reactivity silently lost — destructuring breaks the $state proxy
let { count } = $state({ count: 0 });
// mutating `count` now updates nothing
</script>
None of these are exotic. They're the everyday mistakes you make at 1am, and they all pass a JS-shaped review.
How it works
Svelte Autopilot is a GitHub Action that runs on every pull request. It's specialized for Svelte 5 / SvelteKit, so it reviews .svelte files with the framework's actual rules in mind, not generic JS lint:
-
Private env in client code — flags
$env/static/private/$env/dynamic/privatereaching anything that ships to the browser. -
SSR-unsafe top-level access —
window,document,localStorageat module/component top level. -
{@html}on user input — XSS surface. -
Rune reactivity bugs — destructured
$statelosing reactivity,$effectused where$derivedis correct, and similar Svelte 5 rune mistakes.
It posts findings as a normal PR review with the line and the why. I tested it deliberately: gpt-4o catches all four categories above; generic reviewers and gpt-4o-mini miss them. That gap is the whole reason the product exists.
Try it
Free GitHub Action on the Marketplace — drop it in your workflow and it reviews your next PR. There's also a hosted Pro app if you'd rather not manage the workflow and keys yourself: https://svelte.useautopilot.dev
Repo + source: https://github.com/isabellehuecloser-ctrl/svelte-autopilot
If you ship SvelteKit, I'd genuinely like to know whether it catches something real in your repo. Build-in-public, so feedback is the point.
Top comments (0)