Sno Station
Sno Station is your agents' workstation: open-source software that turns the AI agents you already run into one squad on your own machine. Two heads are better than one, and they get better with every
See inside your Svelte app: components, reactivity, routes and compiled output, from your Vite dev server.
PluginsTypeScript · SvelteGitHub @baseballyamaOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
Svelte 5 DevTools for Vite: component and reactivity inspection with MCP access, standalone or in the Vite DevTools dock.
Taken from the repository README
Loading the full README. The saved excerpt is shown below.
Svelte DevTools for Vite, built on Devframe. Provides 15 specialized panels for debugging, profiling, and inspecting Svelte/SvelteKit applications. The same tool runs standalone at /.svelte-devtools/ on your dev server, or inside the Vite DevTools dock when @vitejs/devtools is installed.
Status: Early development. APIs may change. This README describes 0.4.0 (Devframe host: standalone or inside the Vite DevTools dock). 0.3.x rendered only inside @vitejs/devtools; see Upgrading from 0.3.x.Read the full README ↗Svelte DevTools for Vite, built on Devframe. Provides 15 specialized panels for debugging, profiling, and inspecting Svelte/SvelteKit applications. The same tool runs standalone at /.svelte-devtools/ on your dev server, or inside the Vite DevTools dock when @vitejs/devtools is installed.
Status: Early development. APIs may change. This README describes 0.4.0 (Devframe host: standalone or inside the Vite DevTools dock). 0.3.x rendered only inside
@vitejs/devtools; see Upgrading from 0.3.x.
$state, $derived and $effect signals (signals created during component init and shared .svelte.js/.ts module state, plus a markup node for reads from the template; edges are "can affect", not a recorded cause, and not the complete app graph)load functions with waterfall visualization+server.ts) directly from DevToolsPanel shots: captured from the UI in dev-mock mode with synthetic data, before the reactivity update (Social preview: a generated SvelteKit test app). Reactivity shots: captured in CI from the real runtime, against the synthetic demo app in examples/sample-app.
Overview: what the counts cover and the most active components:
One component (ReactivePriceChart) and the signals it is directly linked to; edges mean "can affect", not a recorded cause:
$state signals by sampled changes in the timeline buffer:
After the app page reloads, a selected component id may belong to another instance, and the panel says so:
npm install -D vite-devtools-svelte
# optional: show the panels inside the Vite DevTools dock
npm install -D @vitejs/devtools
Register the plugin in your vite.config.ts. svelteDevtools() must come before sveltekit() so that its transforms run before the Svelte compiler.
// vite.config.ts
import { sveltekit } from '@sveltejs/kit/vite'
import { defineConfig } from 'vite'
import { svelteDevtools } from 'vite-devtools-svelte'
export default defineConfig({
plugins: [
svelteDevtools(), // must come before sveltekit()
sveltekit(),
],
})
Start your dev server as usual (npm run dev) and open the URL it prints:
➜ Svelte DevTools: http://localhost:5173/.svelte-devtools/
The first time a browser opens the DevTools it asks for a one-time code: request it from the page, and the dev server prints a 6-digit code plus a link (…/.svelte-devtools/#devframe_otp=…) in the terminal. Opening the link (or typing the code) trusts that browser; the token is remembered across reloads and dev-server restarts.
On a single-user machine where the dev server only listens on localhost, you can turn the code off:
svelteDevtools({ clientAuth: false }) // standalone /.svelte-devtools/
DevTools({ clientAuth: false }) // inside the Vite DevTools dock (@vitejs/devtools)
Without it, any page in your browser that can reach the dev server, and any device on the network when you use --host, can read files in your project through the DevTools. Keep it on if you are unsure. The MCP endpoint keeps its own token either way.
With @vitejs/devtools installed, add its plugin as well. The Svelte tool then mounts as a dock entry instead of standalone (never both), and authentication is handled once by Vite DevTools:
import { DevTools } from '@vitejs/devtools'
export default defineConfig({
plugins: [svelteDevtools(), DevTools(), sveltekit()],
})
Open your app, click the floating Vite DevTools handle and switch to the Svelte tab. The panels are also reachable directly at /.svelte-devtools/.
svelteDevtools({
// Enable component lifecycle tracking (default: true)
componentTracking: true,
// Require the one-time code for the standalone DevTools (default: true).
// In the Vite DevTools dock use DevTools({ clientAuth: false }) instead.
clientAuth: true,
})
svelte/internal/client to track component lifecycle and reactive signals ($state, $derived, $effect). It only polls state / samples FPS while a DevTools tab or an MCP agent is watching.initDevframe on Vite's own HTTP server) or mounted into Vite DevTools (createPluginFromDevframe); the UI connects with connectDevframe() either way.The plugin is development-only — every sub-plugin is apply: 'serve', so nothing of it reaches a production build. In development, the runtime only samples while a DevTools tab or MCP agent is watching (an activity lease), and the dev server keeps its buffers bounded.
The public API is unchanged — still svelteDevtools({ componentTracking }), and the same 15 panels. MCP keeps every existing tool and adds four reactivity tools (see AI access). What changed is how the UI is hosted and how it talks to the dev server:
| 0.3.x | 0.4.0 | |
|---|---|---|
| Host | panels only rendered inside @vitejs/devtools (required) | standalone at /.svelte-devtools/, or inside the Vite DevTools dock when @vitejs/devtools is installed (optional) |
| Transport | DevTools Kit RPC + HTTP fallback (/__svelte-devtools/rpc, /__svelte-devtools/asset) | one Devframe WebSocket RPC (SSE in Vite middleware mode); the HTTP endpoints are removed |
| Auth | per-process token injected into the UI HTML | Devframe one-time code → per-browser token (secure by default); Vite DevTools' own auth when docked |
| Peer deps | vite >= 8.0.0 | vite ^8.3.2 (uses the public closeServer hook), @vitejs/devtools >= 0.7.6 optional |
Static assets in the Assets panel are now served by Vite itself (their public URL) instead of a custom endpoint. The MCP endpoint (/__svelte-devtools/mcp) is unchanged.
$state values are detected after about 1 s (reassignments and primitive changes are picked up on the next 200 ms tick).{#key}, HMR), it is matched by its position in the tree instead. Instances beyond the 50 000 cap are counted but cannot be selected.{#each} rows) are placed under their parent using Svelte internals (checked in a browser on Svelte 5.56.8; the CI compatibility profiles run Svelte 5.57.2); with a different internal layout they would appear as separate top-level entries instead..svelte.js/.ts module body runs (shared state); state created elsewhere (for example in an event handler, or inside a library in node_modules) is not, and a node that depends on such state reports untrackedDeps. Reads of object/array state are attributed through Svelte's dev labels, so the graph shows what the runtime observed, not a static analysis. Render profiles are still sent as a bounded full tail rather than deltas, and behaviour at very large scale (tens of thousands of components) has not been measured.closeServer hook, which is why vite ^8.3.2 is required.The plugin exposes an MCP (Model Context Protocol) endpoint so AI agents such as Claude Code can read performance metrics and run measurement sessions autonomously. The intent: surface the same data the panels show, in a shape an agent can act on — and let the agent's own file-editing tools propose fixes.
On dev-server startup the plugin prints a copy-pasteable registration command:
svelte-devtools MCP ready — register with Claude Code:
claude mcp add --transport http svelte http://localhost:5173/__svelte-devtools/mcp --header x-svelte-devtools-token:<token>
The endpoint is gated by a per-process random token (MCP clients are local processes, not browser tabs, so they don't use the browser login). The token rotates every dev-server start, so you'll re-register after a restart.
The endpoint is served wherever your Vite dev server listens. With the default (localhost) only local processes can reach it; with server.host set to true or 0.0.0.0, other machines on your network can reach it too and only the token protects it. There is no separate Host/Origin check.
| Tool | Purpose |
|---|---|
list_performance_issues | Cross-cuts render / reactive / load / fps and returns ranked issues with suggestedTool for drill-down. Entry point. |
get_component_hotspots | Top components by total render time. |
get_reactive_graph_problems | Classified reactive-graph issues (over-connected effects, orphan deriveds, isolated nodes). |
get_load_waterfall | SvelteKit load timings grouped by route. |
get_fps_drops | FPS samples below threshold. |
get_render_profile | Render profile entries for a specific file. |
get_project_info, get_routes | Package and framework versions; the SvelteKit routes tree (static analysis). |
get_live_components, get_component_relations | Mounted component instances (includeMeta: true adds the page-load epoch the ids belong to, totals and a limit); static import relations between components. |
get_reactive_summary | Busiest component instances from runtime counters (sampled changes and renders in a time window), with totals; does not capture the whole graph. Repeated identical requests may get the same answer for up to 1 s; window.until says when it was computed. stale: true means the app did not answer and an earlier (or empty) answer was returned. |
get_reactive_scope | $state / $derived / $effect nodes of one component instance and their direct neighbours. Edges mean "can affect", not a recorded cause. Repeated identical requests may get the same answer for up to 1 s; computedAt says when the app built it. |
get_state_timeline | Sampled $state changes after a cursor, at most 500 per call, with large values replaced by a size summary. |
get_capture_info | What is held versus what the app reported, per dataset (totals, truncation, dropped counts). |
start_session, end_session, compare_sessions | Bracket a measurement window so the agent can diff before/after a fix. writes the session to . |
Two Claude Code skills ship under node_modules/vite-devtools-svelte/skills/:
vite-devtools-svelte-perf-audit — captures a baseline session, calls list_performance_issues, and presents the top issues for the user to triage.vite-devtools-svelte-perf-fix — one issue per run: baseline → edit → after → compare_sessions, with verdict reported verbatim and an explicit revert path if the change regresses or has no effect.Skill names are prefixed with vite-devtools-svelte- so they don't collide with other skills in your .claude/skills/. They use only lowercase letters and hyphens, and each matches its directory name, as the Agent Skills spec requires, so agents other than Claude Code (e.g. pi) can load them too.
To install for a given project:
mkdir -p .claude/skills
cp -r node_modules/vite-devtools-svelte/skills/* .claude/skills/
What an agent can see: get_state_timeline and get_reactive_scope return values of $state in your running app (each timeline value capped, large ones summarised). Treat the token like any credential that grants read access to your app's state in development.
The MCP server is read + measure only — it never edits files. Editing is left to the agent's own tools (Claude Code's Edit/Write), which keeps the permission boundary clean and lets git own rollback.
Some RPCs read files from disk or open them in your editor, so the DevTools backend is authenticated even though the dev server is normally only reachable from localhost.
svelteDevtools({ clientAuth: false }) (or DevTools({ clientAuth: false }) in the dock) removes this gate; the origin checks below still apply.--host), which blocks cross-site pages and DNS-rebinding attacks.inspect-file, open-in-editor, and open-reactive-in-editor resolve their input through fs.realpath() and refuse anything outside the project root. Symlinks inside the project are followed normally.localhost, *.local and *.internal, and never follow redirects. The dev server's own origins are the only local targets allowed, so the playground can call your app's endpoints.vite build.Trusted-browser tokens are stored in your home directory (~/.svelte-devtools/devframe/auth.json) and shared across projects. The SSRF check resolves hostnames before fetching, so a resolver that changes its answer between that check and the request (DNS rebinding) is not fully excluded. If you bind your dev server to a non-loopback address, only use it on networks you trust.
This is a pnpm monorepo.
# Install dependencies
pnpm install
# Build everything
pnpm build
# Run the playground app with DevTools
pnpm dev
# Run tests (plugin + client UI)
pnpm test
# Watch mode (plugin)
pnpm -C packages/vite-devtools-svelte test:watch
# Lint and format (oxlint / oxfmt)
pnpm lint
pnpm format
A Nix flake is provided so every contributor can pin the exact Node.js toolchain. With Nix installed:
nix develop # drop into a shell with Node 24 + corepack
If you use direnv, direnv allow in the repo root will
do this automatically. The shell uses corepack to materialize the pnpm version
declared by the packageManager field in package.json, so pnpm --version
matches across machines.
├── packages/
│ ├── vite-devtools-svelte/ # The published Vite plugin
│ │ ├── src/
│ │ │ ├── plugin.ts # svelteDevtools(): Vite hooks, middleware, HMR wiring
│ │ │ ├── runtime/ # Browser code served as virtual modules + transforms
│ │ │ ├── server/ # Dev-server side: collector, devframe RPC, mount, security
│ │ │ ├── analyzers/ # Routes, components, assets, build, module graph, OG
│ │ │ └── mcp/ # MCP server for AI agents
│ │ └── test/ # Vitest: unit, reactivity (real Svelte), perf
│ └── client/ # DevTools UI (Svelte 5 SPA), built into the plugin's dist/client
├── playground/ # Demo SvelteKit app for development
├── examples/ # Sample apps (Kit 2, plain Svelte, strict CSP)
├── e2e/ # Browser end-to-end checks: compat matrix, reactivity through MCP
├── perf/ # Opt-in large-app benchmarks
├── scripts/screenshots/ # Doc screenshot and MCP example capture
├── site/ # Documentation site
└── docs/images/ # Screenshots used by the READMEs
Contributions are welcome! Please open an issue first to discuss what you'd like to change.
persist:truenode_modules/.vite-devtools-svelte/sessions/list_sessions, load_session, delete_session | Session inspection / cleanup. The agent owns disposal — the plugin never auto-persists. |