Frameworks

State and stores

Decides where front-end state lives and writes stores that stay correct - component state, URL, context, Pinia, Zustand, Redux Toolkit, Svelte runes, Angular signals - with stable selectors and no server data copied into stores. Use when adding or reviewing a store, a selector or shared state, fixing stale or looping UI, or asked where some state should go.

fe-statereact, vue, svelte, angular6 rules71 tokens always loaded, 888 tokens when used, 1490 tokens in references on demand.

Install

init installs this skill when the project uses react, vue, svelte, angular. Pick your agent to see where its files land.

Agent
npx github:dawidolko/frontend-skills init

Without --agents, init finds the agents from what the project already has, and asks when it finds none:

How init finds each of the 17 agents
AgentFound by
Claude CodeCLAUDE.md .claude CLAUDE.local.md
OpenAI Codex.codex AGENTS.override.md
Cursor.cursor .cursorrules
GitHub Copilot.github/copilot-instructions.md .github/instructions .github/skills .github/prompts
Gemini CLIGEMINI.md .gemini
Antigravity CLI.agents/rules .agent/rules
Devin / Windsurf.devin .windsurf .windsurfrules
OpenCodeopencode.json opencode.jsonc .opencode
Cline.clinerules .cline
Zed.rules .zed
JetBrains Junie.junie
Kiro.kiro
Augment.augment .augment-guidelines
Trae.trae
Continue.continue
Amazon Q Developer.amazonq
Aider.aider.conf.yml CONVENTIONS.md

Where fe-state lands for Claude Code

  • .claude/skills/fe-state/SKILL.mdskill
  • .claude/skills/fe-state/references/state.mdskill
  • .claude/rules/fe-state.mdrule file
  • CLAUDE.mdinstruction block

For every agent also: .frontend-skills/profile.json, .frontend-skills/lessons.md and .frontend-skills/install.json.

Planned by the installer itself for the example React project in the repository.

.claude/rules/fe-state.md
---
paths:
  - "**/*.js"
  - "**/*.jsx"
  - "**/*.ts"
  - "**/*.tsx"
  - "**/*.vue"
  - "**/*.svelte"
---

# State and stores (frontend-skills)

Decides where front-end state lives and writes stores that stay correct - component state, URL, context, Pinia, Zustand, Redux Toolkit, Svelte runes, Angular signals - with stable selectors and no server data copied into stores. Use when adding or reviewing a store, a selector or shared state, fixing stale or looping UI, or asked where some state should go.

- Put each value in the narrowest home: derived (computed in render), component, URL, shared parent, context, store; a store only for client state many distant parts share.
- Never copy server data into a store; use the framework loader or a query cache (state/no-server-state-in-store).
- Filters, sort, page, tab and search live in the URL (state/url-state).
- Selectors return existing values, never a new object or array per call; use `useShallow` or `shallowEqual` (state/selector-stable-result).
- In Redux Toolkit or Immer reducers, mutate the draft or return a new state, never both (state/immer-mutate-or-return).
- Use `configureStore` and `createSlice`, not `createStore` (state/redux-toolkit).
- Take Pinia state and getters out with `storeToRefs()`; destructure only actions (state/pinia-store-to-refs).
- Update state immutably outside Immer: new arrays and objects, `signal.update()`, never `push` on a value a framework compares by reference.
- Never keep per-user state in module-level variables of server-rendered code; create stores per request (Pinia, `useState` in Nuxt, context in SvelteKit).

Before larger changes, read the full skill: `.claude/skills/fe-state/SKILL.md`. Explain any rule id with `npx github:dawidolko/frontend-skills explain <id>`.
The real file

Where fe-state lands for OpenAI Codex

  • .agents/skills/fe-state/SKILL.mdskill
  • .agents/skills/fe-state/references/state.mdskill
  • AGENTS.mdinstruction block

For every agent also: .frontend-skills/profile.json, .frontend-skills/lessons.md and .frontend-skills/install.json.

OpenAI Codex has no rule files scoped to file types; it reads the skills and the instruction block.

Planned by the installer itself for the example React project in the repository.

AGENTS.md
## Front-end work (frontend-skills)

- Before front-end work, read `.frontend-skills/profile.json` (the stack) and `.frontend-skills/lessons.md` (confirmed conventions of this project; they win over any skill).
- Use the installed `fe-*` skill that matches the files you edit.
- After changing UI code, run `npx github:dawidolko/frontend-skills audit --changed --json` and fix findings at `serious` and above; `explain <rule id>` gives the reason, the source and the fix.
- Name rule ids (such as `a11y/img-alt`) in reviews and commit messages.
The real file

Where fe-state lands for Cursor

  • .agents/skills/fe-state/SKILL.mdskill
  • .agents/skills/fe-state/references/state.mdskill
  • .cursor/rules/fe-state.mdcrule file
  • AGENTS.mdinstruction block

For every agent also: .frontend-skills/profile.json, .frontend-skills/lessons.md and .frontend-skills/install.json.

Planned by the installer itself for the example React project in the repository.

.cursor/rules/fe-state.mdc
---
description: Decides where front-end state lives and writes stores that stay correct - component state, URL, context, Pinia, Zustand, Redux Toolkit, Svelte runes, Angular signals - with stable selectors and no server data copied into stores. Use when adding or reviewing a store, a selector or shared state, fixing stale or looping UI, or asked where some state should go.
globs: **/*.js, **/*.jsx, **/*.ts, **/*.tsx, **/*.vue, **/*.svelte
alwaysApply: false
---

# State and stores (frontend-skills)

- Put each value in the narrowest home: derived (computed in render), component, URL, shared parent, context, store; a store only for client state many distant parts share.
- Never copy server data into a store; use the framework loader or a query cache (state/no-server-state-in-store).
- Filters, sort, page, tab and search live in the URL (state/url-state).
- Selectors return existing values, never a new object or array per call; use `useShallow` or `shallowEqual` (state/selector-stable-result).
- In Redux Toolkit or Immer reducers, mutate the draft or return a new state, never both (state/immer-mutate-or-return).
- Use `configureStore` and `createSlice`, not `createStore` (state/redux-toolkit).
- Take Pinia state and getters out with `storeToRefs()`; destructure only actions (state/pinia-store-to-refs).
- Update state immutably outside Immer: new arrays and objects, `signal.update()`, never `push` on a value a framework compares by reference.
- Never keep per-user state in module-level variables of server-rendered code; create stores per request (Pinia, `useState` in Nuxt, context in SvelteKit).

Before larger changes, read the full skill: `.agents/skills/fe-state/SKILL.md`. Explain any rule id with `npx github:dawidolko/frontend-skills explain <id>`.
The real file

Where fe-state lands for GitHub Copilot

  • .agents/skills/fe-state/SKILL.mdskill
  • .agents/skills/fe-state/references/state.mdskill
  • .github/instructions/fe-state.instructions.mdrule file
  • AGENTS.mdinstruction block

For every agent also: .frontend-skills/profile.json, .frontend-skills/lessons.md and .frontend-skills/install.json.

Planned by the installer itself for the example React project in the repository.

.github/instructions/fe-state.instructions.md
---
applyTo: "**/*.js,**/*.jsx,**/*.ts,**/*.tsx,**/*.vue,**/*.svelte"
description: "Decides where front-end state lives and writes stores that stay correct - component state, URL, context, Pinia, Zustand, Redux Toolkit, Svelte runes, Angular signals - with stable selectors and no server data copied into stores. Use when adding or reviewing a store, a selector or shared state, fixing stale or looping UI, or asked where some state should go."
---

# State and stores (frontend-skills)

- Put each value in the narrowest home: derived (computed in render), component, URL, shared parent, context, store; a store only for client state many distant parts share.
- Never copy server data into a store; use the framework loader or a query cache (state/no-server-state-in-store).
- Filters, sort, page, tab and search live in the URL (state/url-state).
- Selectors return existing values, never a new object or array per call; use `useShallow` or `shallowEqual` (state/selector-stable-result).
- In Redux Toolkit or Immer reducers, mutate the draft or return a new state, never both (state/immer-mutate-or-return).
- Use `configureStore` and `createSlice`, not `createStore` (state/redux-toolkit).
- Take Pinia state and getters out with `storeToRefs()`; destructure only actions (state/pinia-store-to-refs).
- Update state immutably outside Immer: new arrays and objects, `signal.update()`, never `push` on a value a framework compares by reference.
- Never keep per-user state in module-level variables of server-rendered code; create stores per request (Pinia, `useState` in Nuxt, context in SvelteKit).

Before larger changes, read the full skill: `.agents/skills/fe-state/SKILL.md`. Explain any rule id with `npx github:dawidolko/frontend-skills explain <id>`.
The real file

Where fe-state lands for Gemini CLI

  • .agents/skills/fe-state/SKILL.mdskill
  • .agents/skills/fe-state/references/state.mdskill
  • GEMINI.mdinstruction block

For every agent also: .frontend-skills/profile.json, .frontend-skills/lessons.md and .frontend-skills/install.json.

Gemini CLI: Gemini CLI was replaced by Antigravity CLI for unpaid tiers on 2026-06-18; choose "antigravity" too if you use it.

Gemini CLI has no rule files scoped to file types; it reads the skills and the instruction block.

Planned by the installer itself for the example React project in the repository.

GEMINI.md
## Front-end work (frontend-skills)

- Before front-end work, read `.frontend-skills/profile.json` (the stack) and `.frontend-skills/lessons.md` (confirmed conventions of this project; they win over any skill).
- Use the installed `fe-*` skill that matches the files you edit.
- After changing UI code, run `npx github:dawidolko/frontend-skills audit --changed --json` and fix findings at `serious` and above; `explain <rule id>` gives the reason, the source and the fix.
- Name rule ids (such as `a11y/img-alt`) in reviews and commit messages.
The real file

Where fe-state lands for Antigravity CLI

  • .agents/skills/fe-state/SKILL.mdskill
  • .agents/skills/fe-state/references/state.mdskill
  • .agents/rules/fe-state.mdrule file
  • AGENTS.mdinstruction block

For every agent also: .frontend-skills/profile.json, .frontend-skills/lessons.md and .frontend-skills/install.json.

Planned by the installer itself for the example React project in the repository.

.agents/rules/fe-state.md
---
trigger: glob
globs: "**/*.js, **/*.jsx, **/*.ts, **/*.tsx, **/*.vue, **/*.svelte"
description: "Decides where front-end state lives and writes stores that stay correct - component state, URL, context, Pinia, Zustand, Redux Toolkit, Svelte runes, Angular signals - with stable selectors and no server data copied into stores. Use when adding or reviewing a store, a selector or shared state, fixing stale or looping UI, or asked where some state should go."
---

# State and stores (frontend-skills)

- Put each value in the narrowest home: derived (computed in render), component, URL, shared parent, context, store; a store only for client state many distant parts share.
- Never copy server data into a store; use the framework loader or a query cache (state/no-server-state-in-store).
- Filters, sort, page, tab and search live in the URL (state/url-state).
- Selectors return existing values, never a new object or array per call; use `useShallow` or `shallowEqual` (state/selector-stable-result).
- In Redux Toolkit or Immer reducers, mutate the draft or return a new state, never both (state/immer-mutate-or-return).
- Use `configureStore` and `createSlice`, not `createStore` (state/redux-toolkit).
- Take Pinia state and getters out with `storeToRefs()`; destructure only actions (state/pinia-store-to-refs).
- Update state immutably outside Immer: new arrays and objects, `signal.update()`, never `push` on a value a framework compares by reference.
- Never keep per-user state in module-level variables of server-rendered code; create stores per request (Pinia, `useState` in Nuxt, context in SvelteKit).

Before larger changes, read the full skill: `.agents/skills/fe-state/SKILL.md`. Explain any rule id with `npx github:dawidolko/frontend-skills explain <id>`.
The real file

Where fe-state lands for Devin / Windsurf

  • .agents/skills/fe-state/SKILL.mdskill
  • .agents/skills/fe-state/references/state.mdskill
  • .devin/rules/fe-state.mdrule file
  • AGENTS.mdinstruction block

For every agent also: .frontend-skills/profile.json, .frontend-skills/lessons.md and .frontend-skills/install.json.

Devin / Windsurf: Devin CLI also reads .cursor/rules; with Cursor chosen too, the CLI sees both rule files of a skill.

Planned by the installer itself for the example React project in the repository.

.devin/rules/fe-state.md
---
trigger: glob
globs: "**/*.js,**/*.jsx,**/*.ts,**/*.tsx,**/*.vue,**/*.svelte"
---

# State and stores (frontend-skills)

Decides where front-end state lives and writes stores that stay correct - component state, URL, context, Pinia, Zustand, Redux Toolkit, Svelte runes, Angular signals - with stable selectors and no server data copied into stores. Use when adding or reviewing a store, a selector or shared state, fixing stale or looping UI, or asked where some state should go.

- Put each value in the narrowest home: derived (computed in render), component, URL, shared parent, context, store; a store only for client state many distant parts share.
- Never copy server data into a store; use the framework loader or a query cache (state/no-server-state-in-store).
- Filters, sort, page, tab and search live in the URL (state/url-state).
- Selectors return existing values, never a new object or array per call; use `useShallow` or `shallowEqual` (state/selector-stable-result).
- In Redux Toolkit or Immer reducers, mutate the draft or return a new state, never both (state/immer-mutate-or-return).
- Use `configureStore` and `createSlice`, not `createStore` (state/redux-toolkit).
- Take Pinia state and getters out with `storeToRefs()`; destructure only actions (state/pinia-store-to-refs).
- Update state immutably outside Immer: new arrays and objects, `signal.update()`, never `push` on a value a framework compares by reference.
- Never keep per-user state in module-level variables of server-rendered code; create stores per request (Pinia, `useState` in Nuxt, context in SvelteKit).

Before larger changes, read the full skill: `.agents/skills/fe-state/SKILL.md`. Explain any rule id with `npx github:dawidolko/frontend-skills explain <id>`.
The real file

Where fe-state lands for OpenCode

  • .agents/skills/fe-state/SKILL.mdskill
  • .agents/skills/fe-state/references/state.mdskill
  • AGENTS.mdinstruction block

For every agent also: .frontend-skills/profile.json, .frontend-skills/lessons.md and .frontend-skills/install.json.

OpenCode has no rule files scoped to file types; it reads the skills and the instruction block.

Planned by the installer itself for the example React project in the repository.

AGENTS.md
## Front-end work (frontend-skills)

- Before front-end work, read `.frontend-skills/profile.json` (the stack) and `.frontend-skills/lessons.md` (confirmed conventions of this project; they win over any skill).
- Use the installed `fe-*` skill that matches the files you edit.
- After changing UI code, run `npx github:dawidolko/frontend-skills audit --changed --json` and fix findings at `serious` and above; `explain <rule id>` gives the reason, the source and the fix.
- Name rule ids (such as `a11y/img-alt`) in reviews and commit messages.
The real file

Where fe-state lands for Cline

  • .claude/skills/fe-state/SKILL.mdskill
  • .claude/skills/fe-state/references/state.mdskill
  • .clinerules/fe-state.mdrule file
  • AGENTS.mdinstruction block

For every agent also: .frontend-skills/profile.json, .frontend-skills/lessons.md and .frontend-skills/install.json.

Cline: If .clinerules is a single file rather than a folder, Cline rule files are not written; skills still are.

Planned by the installer itself for the example React project in the repository.

.clinerules/fe-state.md
---
paths:
  - "**/*.js"
  - "**/*.jsx"
  - "**/*.ts"
  - "**/*.tsx"
  - "**/*.vue"
  - "**/*.svelte"
---

# State and stores (frontend-skills)

Decides where front-end state lives and writes stores that stay correct - component state, URL, context, Pinia, Zustand, Redux Toolkit, Svelte runes, Angular signals - with stable selectors and no server data copied into stores. Use when adding or reviewing a store, a selector or shared state, fixing stale or looping UI, or asked where some state should go.

- Put each value in the narrowest home: derived (computed in render), component, URL, shared parent, context, store; a store only for client state many distant parts share.
- Never copy server data into a store; use the framework loader or a query cache (state/no-server-state-in-store).
- Filters, sort, page, tab and search live in the URL (state/url-state).
- Selectors return existing values, never a new object or array per call; use `useShallow` or `shallowEqual` (state/selector-stable-result).
- In Redux Toolkit or Immer reducers, mutate the draft or return a new state, never both (state/immer-mutate-or-return).
- Use `configureStore` and `createSlice`, not `createStore` (state/redux-toolkit).
- Take Pinia state and getters out with `storeToRefs()`; destructure only actions (state/pinia-store-to-refs).
- Update state immutably outside Immer: new arrays and objects, `signal.update()`, never `push` on a value a framework compares by reference.
- Never keep per-user state in module-level variables of server-rendered code; create stores per request (Pinia, `useState` in Nuxt, context in SvelteKit).

Before larger changes, read the full skill: `.claude/skills/fe-state/SKILL.md`. Explain any rule id with `npx github:dawidolko/frontend-skills explain <id>`.
The real file

Where fe-state lands for Zed

  • .agents/skills/fe-state/SKILL.mdskill
  • .agents/skills/fe-state/references/state.mdskill
  • CLAUDE.mdinstruction block

For every agent also: .frontend-skills/profile.json, .frontend-skills/lessons.md and .frontend-skills/install.json.

Zed: Zed reads only the first instruction file of its list; the block is placed in that file.

Zed has no rule files scoped to file types; it reads the skills and the instruction block.

Planned by the installer itself for the example React project in the repository.

CLAUDE.md
## Front-end work (frontend-skills)

- Before front-end work, read `.frontend-skills/profile.json` (the stack) and `.frontend-skills/lessons.md` (confirmed conventions of this project; they win over any skill).
- Use the installed `fe-*` skill that matches the files you edit.
- After changing UI code, run `npx github:dawidolko/frontend-skills audit --changed --json` and fix findings at `serious` and above; `explain <rule id>` gives the reason, the source and the fix.
- Name rule ids (such as `a11y/img-alt`) in reviews and commit messages.
The real file

Where fe-state lands for JetBrains Junie

  • .agents/skills/fe-state/SKILL.mdskill
  • .agents/skills/fe-state/references/state.mdskill
  • AGENTS.mdinstruction block

For every agent also: .frontend-skills/profile.json, .frontend-skills/lessons.md and .frontend-skills/install.json.

JetBrains Junie: Junie reads .agents/skills only in a trusted project.

JetBrains Junie has no rule files scoped to file types; it reads the skills and the instruction block.

Planned by the installer itself for the example React project in the repository.

AGENTS.md
## Front-end work (frontend-skills)

- Before front-end work, read `.frontend-skills/profile.json` (the stack) and `.frontend-skills/lessons.md` (confirmed conventions of this project; they win over any skill).
- Use the installed `fe-*` skill that matches the files you edit.
- After changing UI code, run `npx github:dawidolko/frontend-skills audit --changed --json` and fix findings at `serious` and above; `explain <rule id>` gives the reason, the source and the fix.
- Name rule ids (such as `a11y/img-alt`) in reviews and commit messages.
The real file

Where fe-state lands for Kiro

  • .kiro/skills/fe-state/SKILL.mdskill
  • .kiro/skills/fe-state/references/state.mdskill
  • .kiro/steering/fe-state.mdrule file
  • AGENTS.mdinstruction block

For every agent also: .frontend-skills/profile.json, .frontend-skills/lessons.md and .frontend-skills/install.json.

Planned by the installer itself for the example React project in the repository.

.kiro/steering/fe-state.md
---
inclusion: fileMatch
fileMatchPattern: ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx", "**/*.vue", "**/*.svelte"]
---

# State and stores (frontend-skills)

Decides where front-end state lives and writes stores that stay correct - component state, URL, context, Pinia, Zustand, Redux Toolkit, Svelte runes, Angular signals - with stable selectors and no server data copied into stores. Use when adding or reviewing a store, a selector or shared state, fixing stale or looping UI, or asked where some state should go.

- Put each value in the narrowest home: derived (computed in render), component, URL, shared parent, context, store; a store only for client state many distant parts share.
- Never copy server data into a store; use the framework loader or a query cache (state/no-server-state-in-store).
- Filters, sort, page, tab and search live in the URL (state/url-state).
- Selectors return existing values, never a new object or array per call; use `useShallow` or `shallowEqual` (state/selector-stable-result).
- In Redux Toolkit or Immer reducers, mutate the draft or return a new state, never both (state/immer-mutate-or-return).
- Use `configureStore` and `createSlice`, not `createStore` (state/redux-toolkit).
- Take Pinia state and getters out with `storeToRefs()`; destructure only actions (state/pinia-store-to-refs).
- Update state immutably outside Immer: new arrays and objects, `signal.update()`, never `push` on a value a framework compares by reference.
- Never keep per-user state in module-level variables of server-rendered code; create stores per request (Pinia, `useState` in Nuxt, context in SvelteKit).

Before larger changes, read the full skill: `.kiro/skills/fe-state/SKILL.md`. Explain any rule id with `npx github:dawidolko/frontend-skills explain <id>`.
The real file

Where fe-state lands for Augment

  • .agents/skills/fe-state/SKILL.mdskill
  • .agents/skills/fe-state/references/state.mdskill
  • AGENTS.mdinstruction block

For every agent also: .frontend-skills/profile.json, .frontend-skills/lessons.md and .frontend-skills/install.json.

Augment has no rule files scoped to file types; it reads the skills and the instruction block.

Planned by the installer itself for the example React project in the repository.

AGENTS.md
## Front-end work (frontend-skills)

- Before front-end work, read `.frontend-skills/profile.json` (the stack) and `.frontend-skills/lessons.md` (confirmed conventions of this project; they win over any skill).
- Use the installed `fe-*` skill that matches the files you edit.
- After changing UI code, run `npx github:dawidolko/frontend-skills audit --changed --json` and fix findings at `serious` and above; `explain <rule id>` gives the reason, the source and the fix.
- Name rule ids (such as `a11y/img-alt`) in reviews and commit messages.
The real file

Where fe-state lands for Trae

  • .trae/skills/fe-state/SKILL.mdskill
  • .trae/skills/fe-state/references/state.mdskill
  • .trae/rules/fe-state.mdrule file
  • AGENTS.mdinstruction block

For every agent also: .frontend-skills/profile.json, .frontend-skills/lessons.md and .frontend-skills/install.json.

Trae: Trae reads AGENTS.md only after it is enabled in its settings.

Planned by the installer itself for the example React project in the repository.

.trae/rules/fe-state.md
---
description: "Decides where front-end state lives and writes stores that stay correct - component state, URL, context, Pinia, Zustand, Redux Toolkit, Svelte runes, Angular signals - with stable selectors and no server data copied into stores. Use when adding or reviewing a store, a selector or shared state, fixing stale or looping UI, or asked where some state should go."
globs: **/*.js,**/*.jsx,**/*.ts,**/*.tsx,**/*.vue,**/*.svelte
alwaysApply: false
---

# State and stores (frontend-skills)

- Put each value in the narrowest home: derived (computed in render), component, URL, shared parent, context, store; a store only for client state many distant parts share.
- Never copy server data into a store; use the framework loader or a query cache (state/no-server-state-in-store).
- Filters, sort, page, tab and search live in the URL (state/url-state).
- Selectors return existing values, never a new object or array per call; use `useShallow` or `shallowEqual` (state/selector-stable-result).
- In Redux Toolkit or Immer reducers, mutate the draft or return a new state, never both (state/immer-mutate-or-return).
- Use `configureStore` and `createSlice`, not `createStore` (state/redux-toolkit).
- Take Pinia state and getters out with `storeToRefs()`; destructure only actions (state/pinia-store-to-refs).
- Update state immutably outside Immer: new arrays and objects, `signal.update()`, never `push` on a value a framework compares by reference.
- Never keep per-user state in module-level variables of server-rendered code; create stores per request (Pinia, `useState` in Nuxt, context in SvelteKit).

Before larger changes, read the full skill: `.trae/skills/fe-state/SKILL.md`. Explain any rule id with `npx github:dawidolko/frontend-skills explain <id>`.
The real file

Where fe-state lands for Continue

  • .frontend-skills/skills/fe-state/SKILL.mdskill
  • .frontend-skills/skills/fe-state/references/state.mdskill
  • .continue/rules/fe-state.mdrule file

For every agent also: .frontend-skills/profile.json, .frontend-skills/lessons.md and .frontend-skills/install.json.

Planned by the installer itself for the example React project in the repository.

.continue/rules/fe-state.md
---
name: "State and stores"
description: "Decides where front-end state lives and writes stores that stay correct - component state, URL, context, Pinia, Zustand, Redux Toolkit, Svelte runes, Angular signals - with stable selectors and no server data copied into stores. Use when adding or reviewing a store, a selector or shared state, fixing stale or looping UI, or asked where some state should go."
globs: ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx", "**/*.vue", "**/*.svelte"]
alwaysApply: false
---

# State and stores (frontend-skills)

- Put each value in the narrowest home: derived (computed in render), component, URL, shared parent, context, store; a store only for client state many distant parts share.
- Never copy server data into a store; use the framework loader or a query cache (state/no-server-state-in-store).
- Filters, sort, page, tab and search live in the URL (state/url-state).
- Selectors return existing values, never a new object or array per call; use `useShallow` or `shallowEqual` (state/selector-stable-result).
- In Redux Toolkit or Immer reducers, mutate the draft or return a new state, never both (state/immer-mutate-or-return).
- Use `configureStore` and `createSlice`, not `createStore` (state/redux-toolkit).
- Take Pinia state and getters out with `storeToRefs()`; destructure only actions (state/pinia-store-to-refs).
- Update state immutably outside Immer: new arrays and objects, `signal.update()`, never `push` on a value a framework compares by reference.
- Never keep per-user state in module-level variables of server-rendered code; create stores per request (Pinia, `useState` in Nuxt, context in SvelteKit).

Before larger changes, read the full skill: `.frontend-skills/skills/fe-state/SKILL.md`. Explain any rule id with `npx github:dawidolko/frontend-skills explain <id>`.
The real file

Where fe-state lands for Amazon Q Developer

  • .frontend-skills/skills/fe-state/SKILL.mdskill
  • .frontend-skills/skills/fe-state/references/state.mdskill
  • .amazonq/rules/frontend-skills.mdinstruction block

For every agent also: .frontend-skills/profile.json, .frontend-skills/lessons.md and .frontend-skills/install.json.

Amazon Q Developer: Amazon Q Developer IDE plugins reach end of support on 2027-04-30; AWS points to Kiro.

Amazon Q Developer has no rule files scoped to file types; it reads the skills and the instruction block.

Planned by the installer itself for the example React project in the repository.

.amazonq/rules/frontend-skills.md
## Front-end work (frontend-skills)

- Before front-end work, read `.frontend-skills/profile.json` (the stack) and `.frontend-skills/lessons.md` (confirmed conventions of this project; they win over any skill).
- Use the installed `fe-*` skill that matches the files you edit.
- After changing UI code, run `npx github:dawidolko/frontend-skills audit --changed --json` and fix findings at `serious` and above; `explain <rule id>` gives the reason, the source and the fix.
- Name rule ids (such as `a11y/img-alt`) in reviews and commit messages.

### Skills

- `fe-state` (State and stores): when editing `**/*.js`, `**/*.jsx`, `**/*.ts`, `**/*.tsx`, `**/*.vue`, `**/*.svelte`, first read `.frontend-skills/skills/fe-state/SKILL.md`.
The real file

Where fe-state lands for Aider

  • .frontend-skills/skills/fe-state/SKILL.mdskill
  • .frontend-skills/skills/fe-state/references/state.mdskill
  • CONVENTIONS.mdinstruction block
  • .aider.conf.ymlconfig

For every agent also: .frontend-skills/profile.json, .frontend-skills/lessons.md and .frontend-skills/install.json.

Aider has no rule files scoped to file types; it reads the skills and the instruction block.

Planned by the installer itself for the example React project in the repository.

CONVENTIONS.md
## Front-end work (frontend-skills)

- Before front-end work, read `.frontend-skills/profile.json` (the stack) and `.frontend-skills/lessons.md` (confirmed conventions of this project; they win over any skill).
- Use the installed `fe-*` skill that matches the files you edit.
- After changing UI code, run `npx github:dawidolko/frontend-skills audit --changed --json` and fix findings at `serious` and above; `explain <rule id>` gives the reason, the source and the fix.
- Name rule ids (such as `a11y/img-alt`) in reviews and commit messages.

### Skills

- `fe-state` (State and stores): when editing `**/*.js`, `**/*.jsx`, `**/*.ts`, `**/*.tsx`, `**/*.vue`, `**/*.svelte`, first read `.frontend-skills/skills/fe-state/SKILL.md`.
The real file

How to use it

Once installed, the agent loads the skill by itself when a task matches its description. You can also ask for it in your own words, for example:

And to check and fix the work:

  • Use the fe-state skill on this file.
  • Run the front-end audit on what I changed and fix everything serious.
  • Explain state/selector-stable-result and fix it here.

Rules it teaches

  • state/selector-stable-result

    A store selector returns existing values, not a new object or array on every call; pick fields one by one or use useShallow or shallowEqual.

    seriousstatic

  • state/immer-mutate-or-return

    A Redux Toolkit or Immer reducer either mutates the draft or returns a new state, never both; no arrow that returns a mutation.

    seriousstatic

  • state/pinia-store-to-refs

    State and getters taken out of a Pinia store go through storeToRefs(); plain destructuring freezes them at their first value.

    seriousstatic

  • state/redux-toolkit

    New and maintained Redux code uses Redux Toolkit's configureStore and createSlice, not the legacy createStore.

    minorstatic

  • state/no-server-state-in-store

    Data fetched from a server lives in the framework's loader or a server-state cache, not copied into a client store.

    moderatemanual

  • state/url-state

    State a person would share, bookmark or restore with Back (filters, sort, page, selected tab, search) lives in the URL.

    minormanual

The rule digest

This part is copied into each agent's scoped rule file, so it stands on its own:

  • Put each value in the narrowest home: derived (computed in render), component, URL, shared parent, context, store; a store only for client state many distant parts share.
  • Never copy server data into a store; use the framework loader or a query cache (state/no-server-state-in-store).
  • Filters, sort, page, tab and search live in the URL (state/url-state).
  • Selectors return existing values, never a new object or array per call; use useShallow or shallowEqual (state/selector-stable-result).
  • In Redux Toolkit or Immer reducers, mutate the draft or return a new state, never both (state/immer-mutate-or-return).
  • Use configureStore and createSlice, not createStore (state/redux-toolkit).
  • Take Pinia state and getters out with storeToRefs(); destructure only actions (state/pinia-store-to-refs).
  • Update state immutably outside Immer: new arrays and objects, signal.update(), never push on a value a framework compares by reference.
  • Never keep per-user state in module-level variables of server-rendered code; create stores per request (Pinia, useState in Nuxt, context in SvelteKit).

Steps the agent follows

  1. Find the existing store setup first (stores/, store/, *.store.*, createSlice, defineStore, create( from zustand) and follow it; do not add a second library.
  2. Before adding state, ask: can it be derived, live in the URL, or stay in one component? Model it as one status value ('idle' | 'saving' | 'error') rather than several booleans.
  3. React: useState or useReducer locally, context for rarely changing values (theme, user), Zustand or Redux Toolkit for frequently changing shared client state; subscribe with narrow selectors.
  4. Vue: ref and computed locally, Pinia setup stores (defineStore('cart', () => { … })) for shared state, storeToRefs in components.
  5. Svelte 5: $state and $derived; shared state as a $state object in a .svelte.js module for client-only code, context for anything rendered on the server.
  6. Angular: signal, computed and linkedSignal in services, exposed with asReadonly(); update with set and update.

How the agent checks the work

  • npx github:dawidolko/frontend-skills audit --changed reports unstable selectors, Immer arrows that mutate and return, Pinia destructuring and legacy createStore.
  • Open the store devtools (Redux DevTools, Vue DevTools Pinia tab) and check that every entry is client state and not a copy of an API response.
  • Reload a filtered page and press Back: the filters must survive.

Checked by the audit

The static checks of these rules run in audit; this is a real session on the example project:

Terminal recording: audit lists findings by severity with rule ids and file:line, and fails at serious.
audit: counts by severity, each rule with its first location, the exit code.

Reference files