[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6NQEE3V8S4HEVMFVFW7SEQ4":3,"skill-same:01M6NQEE3V8S4HEVMFVFW7SEQ4":64},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":18,"publishedAt":36,"linkOnly":37,"markdownContent":38,"markdownBody":39,"frontMatter":40,"refName":43,"commitSha":44,"skillDirectory":45,"forksCount":14,"repositoryHtmlUrl":46,"repositoryHomepageUrl":47,"ownerHtmlUrl":48,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":49,"install":50,"resources":63},"01M6NQEE3V8S4HEVMFVFW7SEQ4","store-pattern",null,"Choose the right state management approach for a use case. Decide between component-local state, derived state, runes-based stores, SvelteKit load, or URL state.","C360Studio\u002Fsemteams","C360Studio","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F107274645?v=4","01M6NQ809JZG513TZ7FJX8SAKQ","Complete 360 Studio","01M6NQ80DRB447R1H9W554K7V8",0,"MIT","https:\u002F\u002Fgithub.com\u002FC360Studio\u002Fsemteams\u002Fblob\u002Fmain\u002Fui\u002F.claude\u002Fskills\u002Fstore-pattern\u002FSKILL.md",[],[19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35],"pattern","store pattern","store","sveltekit","choose","decide","management","use","component","local","case","state","URL","load","for","managed","state management","2026-11-10 10:12:30",false,"---\nname: store-pattern\ndescription: Choose the right state management approach for a use case. Decide between component-local state, derived state, runes-based stores, SvelteKit load, or URL state.\nargument-hint: [description of the state being managed]\n---\n\n# State Management Pattern Selection\n\n## What state are you managing?\n\n$ARGUMENTS\n\n## Quick Decision\n\n```\nWhere is this state used?\n\n  One component only           --> $state (component-local)\n  Computed from other state    --> $derived\n  Shared across components     --> Store (factory + runes)\n  Loaded from backend on nav   --> SvelteKit load function\n  Should survive refresh       --> URL state ($page.url)\n  Multiple of the above        --> Combine patterns (see below)\n```\n\n## The 5 Patterns\n\n### 1. Component-Local `$state`\n\n**Use for:** UI state owned by a single component (open\u002Fclosed, selected tab, input value).\n\n```svelte\n\u003Cscript lang=\"ts\">\n  let isOpen = $state(false);\n  let selectedTab = $state\u003Cstring>(\"overview\");\n  let searchQuery = $state(\"\");\n\u003C\u002Fscript>\n```\n\n**Not for:** Data that other components need, or data from the backend.\n\n### 2. `$derived` \u002F `$derived.by`\n\n**Use for:** Anything computed from other reactive values. Always prefer over `$state` + `$effect`.\n\n```svelte\n\u003Cscript lang=\"ts\">\n  let items = $state\u003CItem[]>([]);\n  let searchQuery = $state(\"\");\n\n  \u002F\u002F Simple expression\n  let count = $derived(items.length);\n\n  \u002F\u002F Multi-line computation\n  let filtered = $derived.by(() => {\n    if (!searchQuery) return items;\n    const q = searchQuery.toLowerCase();\n    return items.filter(i => i.name.toLowerCase().includes(q));\n  });\n\u003C\u002Fscript>\n```\n\n**Anti-pattern:** Using `$effect` to set derived state:\n\n```svelte\n\u002F\u002F WRONG — never do this\nlet filtered = $state([]);\n$effect(() => {\n  filtered = items.filter(i => i.active);  \u002F\u002F Use $derived instead\n});\n```\n\n### 3. Store (Factory + Runes)\n\n**Use for:** State shared across multiple components. This is the established pattern in this codebase.\n\n```typescript\n\u002F\u002F src\u002Flib\u002Fstores\u002FmyStore.svelte.ts\nimport { SvelteMap } from \"svelte\u002Freactivity\";\n\nfunction createMyStore() {\n  let items = $state\u003CItem[]>([]);\n  let selectedId = $state\u003Cstring | null>(null);\n  let itemMap = new SvelteMap\u003Cstring, Item>();\n\n  let selected = $derived(items.find((i) => i.id === selectedId) ?? null);\n\n  return {\n    get items() {\n      return items;\n    },\n    get selected() {\n      return selected;\n    },\n    get itemMap() {\n      return itemMap;\n    },\n\n    setItems(newItems: Item[]) {\n      items = newItems;\n    },\n    select(id: string) {\n      selectedId = id;\n    },\n\n    addItem(item: Item) {\n      items = [...items, item];\n      itemMap.set(item.id, item);\n    },\n  };\n}\n\nexport const myStore = createMyStore();\n```\n\n**Key rules:**\n\n- File must be `.svelte.ts` (runes require this)\n- Use `SvelteMap`\u002F`SvelteSet` from `svelte\u002Freactivity` for reactive collections\n- Expose state via getters (read-only from outside)\n- Expose mutations via methods (controlled writes)\n\n### 4. SvelteKit Load Function\n\n**Use for:** Data fetched from the backend that initializes a page.\n\n```typescript\n\u002F\u002F src\u002Froutes\u002Fflows\u002F+page.ts\nimport type { PageLoad } from \".\u002F$types\";\n\nexport const load: PageLoad = async ({ fetch }) => {\n  const response = await fetch(\"\u002Fflowbuilder\u002Fflows\");\n  const flows = await response.json();\n  return { flows };\n};\n```\n\n```svelte\n\u003C!-- src\u002Froutes\u002Fflows\u002F+page.svelte -->\n\u003Cscript lang=\"ts\">\n  let { data } = $props();\n  \u002F\u002F data.flows is available, typed from load function\n\u003C\u002Fscript>\n```\n\n**Key rules:**\n\n- Use `fetch` from the load function (not global `fetch`) — SvelteKit handles SSR transforms\n- For server-only data, use `+page.server.ts`\n- `src\u002Fhooks.server.ts` transforms fetch URLs for SSR\n\n### 5. URL State\n\n**Use for:** State that should survive page refresh or be shareable via URL.\n\n```svelte\n\u003Cscript lang=\"ts\">\n  import { page } from '$app\u002Fstores';\n  import { goto } from '$app\u002Fnavigation';\n\n  let activeTab = $derived($page.url.searchParams.get('tab') ?? 'overview');\n\n  function setTab(tab: string) {\n    const url = new URL($page.url);\n    url.searchParams.set('tab', tab);\n    goto(url.toString(), { replaceState: true });\n  }\n\u003C\u002Fscript>\n```\n\n## Common Combinations\n\n| Scenario                     | Pattern                                      |\n| ---------------------------- | -------------------------------------------- |\n| Flow builder graph state     | Store (shared across panel, canvas, toolbar) |\n| Modal open\u002Fclosed            | Component-local `$state`                     |\n| Filtered list in a component | `$derived` from store + local search query   |\n| Component types from backend | SvelteKit load → store on first use          |\n| Active flow tab              | URL state (survives refresh)                 |\n| Runtime health data          | Store with periodic fetch via `$effect`      |\n| Computed node positions      | `$derived.by` from graph store data          |\n\n## Migration from Svelte 4\n\n| Svelte 4                   | Svelte 5                                     |\n| -------------------------- | -------------------------------------------- |\n| `writable(value)`          | `$state(value)` in factory function          |\n| `derived(store, fn)`       | `$derived(fn)` or `$derived.by(() => {...})` |\n| `$store` auto-subscription | Use getter: `store.value`                    |\n| `store.subscribe(fn)`      | `$effect(() => { \u002F* read store.value *\u002F })`  |\n| `store.set(value)`         | `store.setValue(value)` method               |\n\n## Decision Checklist\n\n- [ ] State location chosen (local, derived, store, load, URL)\n- [ ] No `$effect` used for derived state\n- [ ] Store file uses `.svelte.ts` extension\n- [ ] Reactive collections use `SvelteMap`\u002F`SvelteSet`\n- [ ] State exposed via getters (not raw `$state` variables)\n- [ ] SSR considered (no `window`\u002F`document` at module level)\n","# State Management Pattern Selection\n\n## What state are you managing?\n\n$ARGUMENTS\n\n## Quick Decision\n\n```\nWhere is this state used?\n\n  One component only           --> $state (component-local)\n  Computed from other state    --> $derived\n  Shared across components     --> Store (factory + runes)\n  Loaded from backend on nav   --> SvelteKit load function\n  Should survive refresh       --> URL state ($page.url)\n  Multiple of the above        --> Combine patterns (see below)\n```\n\n## The 5 Patterns\n\n### 1. Component-Local `$state`\n\n**Use for:** UI state owned by a single component (open\u002Fclosed, selected tab, input value).\n\n```svelte\n\u003Cscript lang=\"ts\">\n  let isOpen = $state(false);\n  let selectedTab = $state\u003Cstring>(\"overview\");\n  let searchQuery = $state(\"\");\n\u003C\u002Fscript>\n```\n\n**Not for:** Data that other components need, or data from the backend.\n\n### 2. `$derived` \u002F `$derived.by`\n\n**Use for:** Anything computed from other reactive values. Always prefer over `$state` + `$effect`.\n\n```svelte\n\u003Cscript lang=\"ts\">\n  let items = $state\u003CItem[]>([]);\n  let searchQuery = $state(\"\");\n\n  \u002F\u002F Simple expression\n  let count = $derived(items.length);\n\n  \u002F\u002F Multi-line computation\n  let filtered = $derived.by(() => {\n    if (!searchQuery) return items;\n    const q = searchQuery.toLowerCase();\n    return items.filter(i => i.name.toLowerCase().includes(q));\n  });\n\u003C\u002Fscript>\n```\n\n**Anti-pattern:** Using `$effect` to set derived state:\n\n```svelte\n\u002F\u002F WRONG — never do this\nlet filtered = $state([]);\n$effect(() => {\n  filtered = items.filter(i => i.active);  \u002F\u002F Use $derived instead\n});\n```\n\n### 3. Store (Factory + Runes)\n\n**Use for:** State shared across multiple components. This is the established pattern in this codebase.\n\n```typescript\n\u002F\u002F src\u002Flib\u002Fstores\u002FmyStore.svelte.ts\nimport { SvelteMap } from \"svelte\u002Freactivity\";\n\nfunction createMyStore() {\n  let items = $state\u003CItem[]>([]);\n  let selectedId = $state\u003Cstring | null>(null);\n  let itemMap = new SvelteMap\u003Cstring, Item>();\n\n  let selected = $derived(items.find((i) => i.id === selectedId) ?? null);\n\n  return {\n    get items() {\n      return items;\n    },\n    get selected() {\n      return selected;\n    },\n    get itemMap() {\n      return itemMap;\n    },\n\n    setItems(newItems: Item[]) {\n      items = newItems;\n    },\n    select(id: string) {\n      selectedId = id;\n    },\n\n    addItem(item: Item) {\n      items = [...items, item];\n      itemMap.set(item.id, item);\n    },\n  };\n}\n\nexport const myStore = createMyStore();\n```\n\n**Key rules:**\n\n- File must be `.svelte.ts` (runes require this)\n- Use `SvelteMap`\u002F`SvelteSet` from `svelte\u002Freactivity` for reactive collections\n- Expose state via getters (read-only from outside)\n- Expose mutations via methods (controlled writes)\n\n### 4. SvelteKit Load Function\n\n**Use for:** Data fetched from the backend that initializes a page.\n\n```typescript\n\u002F\u002F src\u002Froutes\u002Fflows\u002F+page.ts\nimport type { PageLoad } from \".\u002F$types\";\n\nexport const load: PageLoad = async ({ fetch }) => {\n  const response = await fetch(\"\u002Fflowbuilder\u002Fflows\");\n  const flows = await response.json();\n  return { flows };\n};\n```\n\n```svelte\n\u003C!-- src\u002Froutes\u002Fflows\u002F+page.svelte -->\n\u003Cscript lang=\"ts\">\n  let { data } = $props();\n  \u002F\u002F data.flows is available, typed from load function\n\u003C\u002Fscript>\n```\n\n**Key rules:**\n\n- Use `fetch` from the load function (not global `fetch`) — SvelteKit handles SSR transforms\n- For server-only data, use `+page.server.ts`\n- `src\u002Fhooks.server.ts` transforms fetch URLs for SSR\n\n### 5. URL State\n\n**Use for:** State that should survive page refresh or be shareable via URL.\n\n```svelte\n\u003Cscript lang=\"ts\">\n  import { page } from '$app\u002Fstores';\n  import { goto } from '$app\u002Fnavigation';\n\n  let activeTab = $derived($page.url.searchParams.get('tab') ?? 'overview');\n\n  function setTab(tab: string) {\n    const url = new URL($page.url);\n    url.searchParams.set('tab', tab);\n    goto(url.toString(), { replaceState: true });\n  }\n\u003C\u002Fscript>\n```\n\n## Common Combinations\n\n| Scenario                     | Pattern                                      |\n| ---------------------------- | -------------------------------------------- |\n| Flow builder graph state     | Store (shared across panel, canvas, toolbar) |\n| Modal open\u002Fclosed            | Component-local `$state`                     |\n| Filtered list in a component | `$derived` from store + local search query   |\n| Component types from backend | SvelteKit load → store on first use          |\n| Active flow tab              | URL state (survives refresh)                 |\n| Runtime health data          | Store with periodic fetch via `$effect`      |\n| Computed node positions      | `$derived.by` from graph store data          |\n\n## Migration from Svelte 4\n\n| Svelte 4                   | Svelte 5                                     |\n| -------------------------- | -------------------------------------------- |\n| `writable(value)`          | `$state(value)` in factory function          |\n| `derived(store, fn)`       | `$derived(fn)` or `$derived.by(() => {...})` |\n| `$store` auto-subscription | Use getter: `store.value`                    |\n| `store.subscribe(fn)`      | `$effect(() => { \u002F* read store.value *\u002F })`  |\n| `store.set(value)`         | `store.setValue(value)` method               |\n\n## Decision Checklist\n\n- [ ] State location chosen (local, derived, store, load, URL)\n- [ ] No `$effect` used for derived state\n- [ ] Store file uses `.svelte.ts` extension\n- [ ] Reactive collections use `SvelteMap`\u002F`SvelteSet`\n- [ ] State exposed via getters (not raw `$state` variables)\n- [ ] SSR considered (no `window`\u002F`document` at module level)\n",{"name":5,"description":7,"argument-hint":41},[42],"description of the state being managed","main","9b1ec2f24adbbc9121f3d9322f9d414fdc16e016","ui\u002F.claude\u002Fskills\u002Fstore-pattern","https:\u002F\u002Fgithub.com\u002FC360Studio\u002Fsemteams","https:\u002F\u002Fc360studio.github.io","https:\u002F\u002Fgithub.com\u002FC360Studio","2026-11-11 01:13:46",{"source":8,"skillName":5,"commands":51,"prompt":61,"zipAvailable":62},[52,55,58],{"tool":53,"command":54},"npx","npx skills add C360Studio\u002Fsemteams --skill store-pattern",{"tool":56,"command":57},"bunx","bunx skills add C360Studio\u002Fsemteams --skill store-pattern",{"tool":59,"command":60},"pnpm","pnpm dlx skills add C360Studio\u002Fsemteams --skill store-pattern","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FC360Studio\u002Fsemteams\u002Fblob\u002Fmain\u002Fui\u002F.claude\u002Fskills\u002Fstore-pattern\u002FSKILL.md",true,[],[65,86,120,131,150,157],{"skillNo":66,"name":67,"nameZh":6,"description":68,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":69,"categories":70,"keywords":71,"publishedAt":36},"01M6NQE4Z802R8B8PBE23JRR5W","new-component","Step-by-step checklist for adding a new Svelte 5 component with proper patterns, tests, and TypeScript types. Use when creating new UI components.","https:\u002F\u002Fgithub.com\u002FC360Studio\u002Fsemteams\u002Fblob\u002Fmain\u002Fui\u002F.claude\u002Fskills\u002Fnew-component\u002FSKILL.md",[],[72,27,73,74,75,76,26,77,78,79,80,81,82,83,84,33,85],"new","new component","typescript","components","ui","svelte 5","checklist","patterns","svelte","tests","ui components","types","with","when",{"skillNo":87,"name":88,"nameZh":6,"description":89,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":90,"categories":91,"keywords":102,"publishedAt":36},"01M6NQDYRKF89279J9A2D9Q892","backend-integration","Connect the UI to semstreams backend APIs. Covers proxy routing, fetch patterns, SSR considerations, and real-time data. Use when adding new backend integrations or debugging API issues.","https:\u002F\u002Fgithub.com\u002FC360Studio\u002Fsemteams\u002Fblob\u002Fmain\u002Fui\u002F.claude\u002Fskills\u002Fbackend-integration\u002FSKILL.md",[92,97],{"categoryNo":93,"categoryName":94,"taxonomyType":95,"taxonomyTypeDesc":96},"01JBSEEDCAT000000000000010","后端与接口","SCENARIO","使用场景",{"categoryNo":98,"categoryName":99,"taxonomyType":100,"taxonomyTypeDesc":101},"01JBSEEDCAT000000000000030","开发工程师","PROFESSION","适用职业",[103,104,105,26,106,79,107,108,109,110,85,111,112,72,113,114,115,116,117,118,76,119],"backend integration","backend","integration","api endpoint","time","fetch","backend integrations","integrations","proxy","api","real-time","ssr","debugging","connect","routing","issues","data",{"skillNo":121,"name":122,"nameZh":6,"description":123,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":124,"categories":125,"keywords":126,"publishedAt":36},"01M6NQDW39CHJMCCQZA696N1Y7","review-pr","Adapter for review-pr.","https:\u002F\u002Fgithub.com\u002FC360Studio\u002Fsemteams\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Freview-pr\u002FSKILL.md",[],[127,128,129,130,33,122],"review","review pr","pr","adapter",{"skillNo":132,"name":133,"nameZh":6,"description":134,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":135,"categories":136,"keywords":140,"publishedAt":36},"01M6NQD8CX3BCRHN8BRFTVJJ01","query-pattern","Choose the right query access pattern (GraphQL, MCP, NATS Direct) for a use case. Use when designing query APIs, adding new access points, or choosing between gateway types.","https:\u002F\u002Fgithub.com\u002FC360Studio\u002Fsemteams\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Fquery-pattern\u002FSKILL.md",[137],{"categoryNo":138,"categoryName":139,"taxonomyType":95,"taxonomyTypeDesc":96},"01JBSEEDCAT000000000000023","Skill与智能体开发",[141,19,142,83,143,144,145,146,147,23,26,148,149,29,33,85,72],"query pattern","query","MCP","gateway","GraphQL","access","direct","nats","scenario",{"skillNo":151,"name":152,"nameZh":6,"description":153,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":154,"categories":155,"keywords":156,"publishedAt":36},"01M6NQD73AJADQC2G9005KPNPN","preflight","Adapter for preflight.","https:\u002F\u002Fgithub.com\u002FC360Studio\u002Fsemteams\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Fpreflight\u002FSKILL.md",[],[152,130,33],{"skillNo":158,"name":159,"nameZh":6,"description":160,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":161,"categories":162,"keywords":163,"publishedAt":36},"01M6NQD3GNDS4XGY991BWD9NP4","ponytail","Adapter for ponytail.","https:\u002F\u002Fgithub.com\u002FC360Studio\u002Fsemteams\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Fponytail\u002FSKILL.md",[],[159,130,33]]