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.
npx github:dawidolko/frontend-skills init Not tested yet with this runner. npx and pnpm dlx are tested; if this one fails, use one of them.
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
| Agent | Found by |
|---|---|
| Claude Code | CLAUDE.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 CLI | GEMINI.md .gemini |
| Antigravity CLI | .agents/rules .agent/rules |
| Devin / Windsurf | .devin .windsurf .windsurfrules |
| OpenCode | opencode.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 fileCLAUDE.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.
---
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>`.Where fe-state lands for OpenAI Codex
.agents/skills/fe-state/SKILL.mdskill.agents/skills/fe-state/references/state.mdskillAGENTS.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.
## 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.Where fe-state lands for Cursor
.agents/skills/fe-state/SKILL.mdskill.agents/skills/fe-state/references/state.mdskill.cursor/rules/fe-state.mdcrule fileAGENTS.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.
---
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>`.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 fileAGENTS.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.
---
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>`.Where fe-state lands for Gemini CLI
.agents/skills/fe-state/SKILL.mdskill.agents/skills/fe-state/references/state.mdskillGEMINI.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.
## 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.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 fileAGENTS.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.
---
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>`.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 fileAGENTS.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.
---
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>`.Where fe-state lands for OpenCode
.agents/skills/fe-state/SKILL.mdskill.agents/skills/fe-state/references/state.mdskillAGENTS.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.
## 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.Where fe-state lands for Cline
.claude/skills/fe-state/SKILL.mdskill.claude/skills/fe-state/references/state.mdskill.clinerules/fe-state.mdrule fileAGENTS.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.
---
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>`.Where fe-state lands for Zed
.agents/skills/fe-state/SKILL.mdskill.agents/skills/fe-state/references/state.mdskillCLAUDE.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.
## 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.Where fe-state lands for JetBrains Junie
.agents/skills/fe-state/SKILL.mdskill.agents/skills/fe-state/references/state.mdskillAGENTS.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.
## 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.Where fe-state lands for Kiro
.kiro/skills/fe-state/SKILL.mdskill.kiro/skills/fe-state/references/state.mdskill.kiro/steering/fe-state.mdrule fileAGENTS.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.
---
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>`.Where fe-state lands for Augment
.agents/skills/fe-state/SKILL.mdskill.agents/skills/fe-state/references/state.mdskillAGENTS.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.
## 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.Where fe-state lands for Trae
.trae/skills/fe-state/SKILL.mdskill.trae/skills/fe-state/references/state.mdskill.trae/rules/fe-state.mdrule fileAGENTS.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.
---
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>`.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.
---
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>`.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.
## 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`.Where fe-state lands for Aider
.frontend-skills/skills/fe-state/SKILL.mdskill.frontend-skills/skills/fe-state/references/state.mdskillCONVENTIONS.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.
## 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`.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-resultA store selector returns existing values, not a new object or array on every call; pick fields one by one or use useShallow or shallowEqual.
state/immer-mutate-or-returnA Redux Toolkit or Immer reducer either mutates the draft or returns a new state, never both; no arrow that returns a mutation.
state/pinia-store-to-refsState and getters taken out of a Pinia store go through storeToRefs(); plain destructuring freezes them at their first value.
state/redux-toolkitNew and maintained Redux code uses Redux Toolkit's configureStore and createSlice, not the legacy createStore.
state/no-server-state-in-storeData fetched from a server lives in the framework's loader or a server-state cache, not copied into a client store.
state/url-stateState a person would share, bookmark or restore with Back (filters, sort, page, selected tab, search) lives in the URL.
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
useShalloworshallowEqual(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
configureStoreandcreateSlice, notcreateStore(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(), neverpushon 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,
useStatein Nuxt, context in SvelteKit).
Steps the agent follows
- Find the existing store setup first (
stores/,store/,*.store.*,createSlice,defineStore,create(from zustand) and follow it; do not add a second library. - 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. - React:
useStateoruseReducerlocally, context for rarely changing values (theme, user), Zustand or Redux Toolkit for frequently changing shared client state; subscribe with narrow selectors. - Vue:
refandcomputedlocally, Pinia setup stores (defineStore('cart', () => { … })) for shared state,storeToRefsin components. - Svelte 5:
$stateand$derived; shared state as a$stateobject in a.svelte.jsmodule for client-only code, context for anything rendered on the server. - Angular:
signal,computedandlinkedSignalin services, exposed withasReadonly(); update withsetandupdate.
How the agent checks the work
npx github:dawidolko/frontend-skills audit --changedreports unstable selectors, Immer arrows that mutate and return, Pinia destructuring and legacycreateStore.- 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:
audit: counts by severity, each rule with its first location, the exit code.Reference files
references/state.md1490 tokens