git clone https://github.com/Intense-Visions/harness-engineering
T=$(mktemp -d) && git clone --depth=1 https://github.com/Intense-Visions/harness-engineering "$T" && mkdir -p ~/.claude/skills && cp -r "$T/agents/skills/codex/svelte-stores-pattern" ~/.claude/skills/intense-visions-harness-engineering-svelte-stores-pattern-433a94 && rm -rf "$T"
agents/skills/codex/svelte-stores-pattern/SKILL.mdSvelte Stores Pattern
Share reactive state across any component tree using writable, readable, and derived stores with the Svelte store contract
When to Use
- You need shared state accessible across unrelated components without prop-drilling
- You are in a Svelte 4 codebase or a Svelte 5 project that intentionally uses stores
- You need a readable store driven by an external source (WebSocket, EventSource, timer)
- You are building a custom store with encapsulated update logic
Instructions
writable — mutable shared state:
- Create a writable store with an initial value. Export it for use in any component:
// stores/counter.ts import { writable } from 'svelte/store'; export const count = writable(0); // Helper methods (optional, common pattern) export function increment() { count.update((n) => n + 1); } export function reset() { count.set(0); }
- Subscribe in components using the
auto-subscription prefix — no manual subscribe/unsubscribe needed:$
<script> import { count, increment } from '$lib/stores/counter' </script> <p>Count: {$count}</p> <button onclick={increment}>+</button>
- Two-way bind to a writable store:
<input bind:value={$myStore} />
readable — external data sources:
- Use
for stores driven by external events. The start function runs when the first subscriber attaches; the returned stop function runs when the last subscriber detaches:readable
import { readable } from 'svelte/store'; export const time = readable(new Date(), (set) => { const interval = setInterval(() => set(new Date()), 1000); return () => clearInterval(interval); });
derived — computed from other stores:
- Derive a store from one or more sources:
import { derived } from 'svelte/store'; import { count } from './counter'; export const doubled = derived(count, ($count) => $count * 2); // Multiple sources: export const summary = derived([firstName, lastName], ([$first, $last]) => `${$first} ${$last}`);
- Derived stores with async values — return a stop function and call
when ready:set
export const userData = derived( userId, ($id, set) => { fetchUser($id).then(set); return () => {}; // cleanup if needed }, null ); // initial value while loading
Custom stores — encapsulated logic:
- Implement the store contract (
) to create stores with domain-specific APIs:{ subscribe, set?, update? }
// stores/cart.ts import { writable } from 'svelte/store'; function createCart() { const { subscribe, update, set } = writable<CartItem[]>([]); return { subscribe, addItem(item: CartItem) { update((items) => [...items, item]); }, removeItem(id: string) { update((items) => items.filter((i) => i.id !== id)); }, clear() { set([]); }, }; } export const cart = createCart();
Reading store values outside components:
- Use
fromget
to read a store's value synchronously without subscribing:svelte/store
import { get } from 'svelte/store'; import { count } from './counter'; const current = get(count); // one-time read, no subscription
Details
Store contract:
Any object with a
subscribe method that follows Svelte's store contract is auto-subscribable with $. The contract:
— callssubscribe(fn)
immediately with current value, then on every changefn- Returns an
functionunsubscribe - Optionally has
andset
methodsupdate
This means you can make any reactive primitive a "store" — including RxJS Observables (with an adapter).
Svelte 4 vs. Svelte 5:
In Svelte 5, runes (
$state, $derived) are the preferred reactivity model. Stores still work and are useful for cross-component shared state, but .svelte.ts files with rune-based reactive classes are the emerging pattern:
// Svelte 5 equivalent of a writable store class Counter { count = $state(0); increment() { this.count++; } } export const counter = new Counter();
SSR and stores:
In SvelteKit SSR, module-level stores are shared between all requests on the server — this causes data leakage between users. Use the context API or load functions to pass per-request state instead of module-level stores for user-specific data.
When to use stores vs. context:
- Stores — global singletons, app-wide state (theme, auth token, cart)
- Context — subtree-scoped state, per-instance isolation (form state, modal state)
Debugging stores:
Subscribe in the browser console:
import { cart } from './stores/cart'; cart.subscribe(console.log).
Source
https://svelte.dev/docs/svelte/stores
Process
- Read the instructions and examples in this document.
- Apply the patterns to your implementation, adapting to your specific context.
- Verify your implementation against the details and edge cases listed above.
Harness Integration
- Type: knowledge — this skill is a reference document, not a procedural workflow.
- No tools or state — consumed as context by other skills and agents.
Success Criteria
- The patterns described in this document are applied correctly in the implementation.
- Edge cases and anti-patterns listed in this document are avoided.