How it works

Two things in one repository: a dictionary (skills that tell an agent how to write front-end code, and rules with stable ids) and a command that fits the dictionary to one project.

Terminal recording: init learns a React and Tailwind project, installs the matching skills for Claude Code, writes the profile and runs the first audit.
init on the example project: the stack it found, the skills and files it planned, the first audit.

The project profile

init and learn read the project in one pass with no network: package.json files (and workspaces in a monorepo), lockfiles, config files such as next.config.*, angular.json or tailwind.config.*, and installed versions from node_modules. A folder without package.json that holds HTML, CSS and JavaScript counts as a plain site. The result is .frontend-skills/profile.json, committed with the project:

.frontend-skills/profile.json
{
  "version": 1,
  "packageManager": "pnpm",
  "projects": [
    {
      "path": "apps/web",
      "frameworks": { "next": "16.4.0", "react": "19.3.0" },
      "typescript": "7.0.0",
      "styling": ["tailwind"],
      "testing": ["vitest", "playwright"]
    }
  ],
  "stack": ["web", "react", "next", "typescript", "tailwind", "vitest", "playwright"],
  "helpers": {
    "rem-function": { "name": "rem-calc", "call": "rem-calc(16px)", "file": "src/styles/_functions.scss" }
  },
  "agents": ["claude", "cursor"],
  "skills": ["fe-html", "fe-react", "fe-a11y-forms"],
  "audit": { "failOn": "serious", "ignore": [], "exclude": [] }
}
Example

stack decides which skills are installed: a skill is installed when the profile has any of the keys it requires. The audit object is yours; learn and update keep it.

Your project's own helpers

Rules follow the project's conventions when it has them. The profile records helpers such as a px-to-rem function, generated icon classes, an SVG sprite, design tokens or a set of custom properties, and the rules that depend on them name your helper: "write sizes with rem-calc(16px)" instead of a generic hint. You can correct or add a helper in the profile; your entries survive learn and update.

Files for each agent

A skill is written once as an Agent Skills folder (SKILL.md, references/, scripts/). Each agent has an adapter that knows where that agent looks and in which format. Nobody edits the generated files; update rewrites them and uninstall removes them.

What is written for each agent
AgentSkills folders it readsRule files scoped to file typesAlways-on instructions
Claude Code.claude/skills/.claude/rules/<skill>.mdAGENTS.md *
OpenAI Codex.agents/skills/—AGENTS.md
Cursor.agents/skills/ .cursor/skills/ .claude/skills/ .codex/skills/.cursor/rules/<skill>.mdcAGENTS.md
GitHub Copilot.agents/skills/ .github/skills/ .claude/skills/.github/instructions/<skill>.instructions.mdAGENTS.md *
Gemini CLI.agents/skills/ .gemini/skills/—GEMINI.md
Antigravity CLI.agents/skills/.agents/rules/<skill>.mdAGENTS.md
Devin / Windsurf.agents/skills/ .devin/skills/ .windsurf/skills/ .claude/skills/ .github/skills/ .kiro/skills/ .cursor/skills/ .codex/skills/.devin/rules/<skill>.mdAGENTS.md
OpenCode.agents/skills/ .opencode/skills/ .claude/skills/—AGENTS.md
Cline.claude/skills/ .cline/skills/ .clinerules/skills/.clinerules/<skill>.mdAGENTS.md
Zed.agents/skills/—AGENTS.md *
JetBrains Junie.agents/skills/ .junie/skills/—AGENTS.md *
Kiro.kiro/skills/.kiro/steering/<skill>.mdAGENTS.md
Augment.agents/skills/ .augment/skills/ .claude/skills/—AGENTS.md
Trae.trae/skills/.trae/rules/<skill>.mdAGENTS.md
Continue—.continue/rules/<skill>.md—
Amazon Q Developer——.amazonq/rules/frontend-skills.md
Aider——CONVENTIONS.md

* depends on the files the project already has (for example an existing CLAUDE.md).

Install for your agent

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

What lands where for Claude Code

  • .claude/skills/fe-react/SKILL.mdskill
  • .claude/skills/fe-react/references/react.mdskill
  • .claude/rules/fe-react.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-react.md
---
paths:
  - "**/*.jsx"
  - "**/*.tsx"
---

# React components (frontend-skills)

Writes and reviews React 19 components (also inside Next.js, Vite or React Router apps) - keys, state, effects, events, refs, forms with actions, memoization and React Compiler - so they stay correct, accessible and fast. Use when creating or editing a .jsx or .tsx component or hook, fixing a re-render or stale-state bug, or when asked "review this React code".

- Keys come from the data (`key={item.id}`), never the array index for lists that change (react/no-array-index-key).
- Compute derived values during render; an effect only synchronises with something outside React (react/no-derived-state-effect).
- Declare components at module level; never define a component inside another (react/no-nested-component).
- Keep state minimal and close to where it is used; lift it only as far as the nearest shared parent.
- Handle user actions in event handlers, not in effects that watch state.
- Every effect that subscribes, listens or starts a timer returns a cleanup.
- Interactive elements are `<button>` and `<a>`, not `div` with `onClick` (a11y/no-click-on-static); every `<img>` has `alt` (a11y/img-alt).
- Never mutate state or props; never call hooks conditionally; never read `ref.current` during render.

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

What lands where for OpenAI Codex

  • .agents/skills/fe-react/SKILL.mdskill
  • .agents/skills/fe-react/references/react.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

What lands where for Cursor

  • .agents/skills/fe-react/SKILL.mdskill
  • .agents/skills/fe-react/references/react.mdskill
  • .cursor/rules/fe-react.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-react.mdc
---
description: Writes and reviews React 19 components (also inside Next.js, Vite or React Router apps) - keys, state, effects, events, refs, forms with actions, memoization and React Compiler - so they stay correct, accessible and fast. Use when creating or editing a .jsx or .tsx component or hook, fixing a re-render or stale-state bug, or when asked "review this React code".
globs: **/*.jsx, **/*.tsx
alwaysApply: false
---

# React components (frontend-skills)

- Keys come from the data (`key={item.id}`), never the array index for lists that change (react/no-array-index-key).
- Compute derived values during render; an effect only synchronises with something outside React (react/no-derived-state-effect).
- Declare components at module level; never define a component inside another (react/no-nested-component).
- Keep state minimal and close to where it is used; lift it only as far as the nearest shared parent.
- Handle user actions in event handlers, not in effects that watch state.
- Every effect that subscribes, listens or starts a timer returns a cleanup.
- Interactive elements are `<button>` and `<a>`, not `div` with `onClick` (a11y/no-click-on-static); every `<img>` has `alt` (a11y/img-alt).
- Never mutate state or props; never call hooks conditionally; never read `ref.current` during render.

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

What lands where for GitHub Copilot

  • .agents/skills/fe-react/SKILL.mdskill
  • .agents/skills/fe-react/references/react.mdskill
  • .github/instructions/fe-react.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-react.instructions.md
---
applyTo: "**/*.jsx,**/*.tsx"
description: "Writes and reviews React 19 components (also inside Next.js, Vite or React Router apps) - keys, state, effects, events, refs, forms with actions, memoization and React Compiler - so they stay correct, accessible and fast. Use when creating or editing a .jsx or .tsx component or hook, fixing a re-render or stale-state bug, or when asked \"review this React code\"."
---

# React components (frontend-skills)

- Keys come from the data (`key={item.id}`), never the array index for lists that change (react/no-array-index-key).
- Compute derived values during render; an effect only synchronises with something outside React (react/no-derived-state-effect).
- Declare components at module level; never define a component inside another (react/no-nested-component).
- Keep state minimal and close to where it is used; lift it only as far as the nearest shared parent.
- Handle user actions in event handlers, not in effects that watch state.
- Every effect that subscribes, listens or starts a timer returns a cleanup.
- Interactive elements are `<button>` and `<a>`, not `div` with `onClick` (a11y/no-click-on-static); every `<img>` has `alt` (a11y/img-alt).
- Never mutate state or props; never call hooks conditionally; never read `ref.current` during render.

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

What lands where for Gemini CLI

  • .agents/skills/fe-react/SKILL.mdskill
  • .agents/skills/fe-react/references/react.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

What lands where for Antigravity CLI

  • .agents/skills/fe-react/SKILL.mdskill
  • .agents/skills/fe-react/references/react.mdskill
  • .agents/rules/fe-react.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-react.md
---
trigger: glob
globs: "**/*.jsx, **/*.tsx"
description: "Writes and reviews React 19 components (also inside Next.js, Vite or React Router apps) - keys, state, effects, events, refs, forms with actions, memoization and React Compiler - so they stay correct, accessible and fast. Use when creating or editing a .jsx or .tsx component or hook, fixing a re-render or stale-state bug, or when asked \"review this React code\"."
---

# React components (frontend-skills)

- Keys come from the data (`key={item.id}`), never the array index for lists that change (react/no-array-index-key).
- Compute derived values during render; an effect only synchronises with something outside React (react/no-derived-state-effect).
- Declare components at module level; never define a component inside another (react/no-nested-component).
- Keep state minimal and close to where it is used; lift it only as far as the nearest shared parent.
- Handle user actions in event handlers, not in effects that watch state.
- Every effect that subscribes, listens or starts a timer returns a cleanup.
- Interactive elements are `<button>` and `<a>`, not `div` with `onClick` (a11y/no-click-on-static); every `<img>` has `alt` (a11y/img-alt).
- Never mutate state or props; never call hooks conditionally; never read `ref.current` during render.

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

What lands where for Devin / Windsurf

  • .agents/skills/fe-react/SKILL.mdskill
  • .agents/skills/fe-react/references/react.mdskill
  • .devin/rules/fe-react.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-react.md
---
trigger: glob
globs: "**/*.jsx,**/*.tsx"
---

# React components (frontend-skills)

Writes and reviews React 19 components (also inside Next.js, Vite or React Router apps) - keys, state, effects, events, refs, forms with actions, memoization and React Compiler - so they stay correct, accessible and fast. Use when creating or editing a .jsx or .tsx component or hook, fixing a re-render or stale-state bug, or when asked "review this React code".

- Keys come from the data (`key={item.id}`), never the array index for lists that change (react/no-array-index-key).
- Compute derived values during render; an effect only synchronises with something outside React (react/no-derived-state-effect).
- Declare components at module level; never define a component inside another (react/no-nested-component).
- Keep state minimal and close to where it is used; lift it only as far as the nearest shared parent.
- Handle user actions in event handlers, not in effects that watch state.
- Every effect that subscribes, listens or starts a timer returns a cleanup.
- Interactive elements are `<button>` and `<a>`, not `div` with `onClick` (a11y/no-click-on-static); every `<img>` has `alt` (a11y/img-alt).
- Never mutate state or props; never call hooks conditionally; never read `ref.current` during render.

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

What lands where for OpenCode

  • .agents/skills/fe-react/SKILL.mdskill
  • .agents/skills/fe-react/references/react.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

What lands where for Cline

  • .claude/skills/fe-react/SKILL.mdskill
  • .claude/skills/fe-react/references/react.mdskill
  • .clinerules/fe-react.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-react.md
---
paths:
  - "**/*.jsx"
  - "**/*.tsx"
---

# React components (frontend-skills)

Writes and reviews React 19 components (also inside Next.js, Vite or React Router apps) - keys, state, effects, events, refs, forms with actions, memoization and React Compiler - so they stay correct, accessible and fast. Use when creating or editing a .jsx or .tsx component or hook, fixing a re-render or stale-state bug, or when asked "review this React code".

- Keys come from the data (`key={item.id}`), never the array index for lists that change (react/no-array-index-key).
- Compute derived values during render; an effect only synchronises with something outside React (react/no-derived-state-effect).
- Declare components at module level; never define a component inside another (react/no-nested-component).
- Keep state minimal and close to where it is used; lift it only as far as the nearest shared parent.
- Handle user actions in event handlers, not in effects that watch state.
- Every effect that subscribes, listens or starts a timer returns a cleanup.
- Interactive elements are `<button>` and `<a>`, not `div` with `onClick` (a11y/no-click-on-static); every `<img>` has `alt` (a11y/img-alt).
- Never mutate state or props; never call hooks conditionally; never read `ref.current` during render.

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

What lands where for Zed

  • .agents/skills/fe-react/SKILL.mdskill
  • .agents/skills/fe-react/references/react.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

What lands where for JetBrains Junie

  • .agents/skills/fe-react/SKILL.mdskill
  • .agents/skills/fe-react/references/react.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

What lands where for Kiro

  • .kiro/skills/fe-react/SKILL.mdskill
  • .kiro/skills/fe-react/references/react.mdskill
  • .kiro/steering/fe-react.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-react.md
---
inclusion: fileMatch
fileMatchPattern: ["**/*.jsx", "**/*.tsx"]
---

# React components (frontend-skills)

Writes and reviews React 19 components (also inside Next.js, Vite or React Router apps) - keys, state, effects, events, refs, forms with actions, memoization and React Compiler - so they stay correct, accessible and fast. Use when creating or editing a .jsx or .tsx component or hook, fixing a re-render or stale-state bug, or when asked "review this React code".

- Keys come from the data (`key={item.id}`), never the array index for lists that change (react/no-array-index-key).
- Compute derived values during render; an effect only synchronises with something outside React (react/no-derived-state-effect).
- Declare components at module level; never define a component inside another (react/no-nested-component).
- Keep state minimal and close to where it is used; lift it only as far as the nearest shared parent.
- Handle user actions in event handlers, not in effects that watch state.
- Every effect that subscribes, listens or starts a timer returns a cleanup.
- Interactive elements are `<button>` and `<a>`, not `div` with `onClick` (a11y/no-click-on-static); every `<img>` has `alt` (a11y/img-alt).
- Never mutate state or props; never call hooks conditionally; never read `ref.current` during render.

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

What lands where for Augment

  • .agents/skills/fe-react/SKILL.mdskill
  • .agents/skills/fe-react/references/react.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

What lands where for Trae

  • .trae/skills/fe-react/SKILL.mdskill
  • .trae/skills/fe-react/references/react.mdskill
  • .trae/rules/fe-react.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-react.md
---
description: "Writes and reviews React 19 components (also inside Next.js, Vite or React Router apps) - keys, state, effects, events, refs, forms with actions, memoization and React Compiler - so they stay correct, accessible and fast. Use when creating or editing a .jsx or .tsx component or hook, fixing a re-render or stale-state bug, or when asked \"review this React code\"."
globs: **/*.jsx,**/*.tsx
alwaysApply: false
---

# React components (frontend-skills)

- Keys come from the data (`key={item.id}`), never the array index for lists that change (react/no-array-index-key).
- Compute derived values during render; an effect only synchronises with something outside React (react/no-derived-state-effect).
- Declare components at module level; never define a component inside another (react/no-nested-component).
- Keep state minimal and close to where it is used; lift it only as far as the nearest shared parent.
- Handle user actions in event handlers, not in effects that watch state.
- Every effect that subscribes, listens or starts a timer returns a cleanup.
- Interactive elements are `<button>` and `<a>`, not `div` with `onClick` (a11y/no-click-on-static); every `<img>` has `alt` (a11y/img-alt).
- Never mutate state or props; never call hooks conditionally; never read `ref.current` during render.

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

What lands where for Continue

  • .frontend-skills/skills/fe-react/SKILL.mdskill
  • .frontend-skills/skills/fe-react/references/react.mdskill
  • .continue/rules/fe-react.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-react.md
---
name: "React components"
description: "Writes and reviews React 19 components (also inside Next.js, Vite or React Router apps) - keys, state, effects, events, refs, forms with actions, memoization and React Compiler - so they stay correct, accessible and fast. Use when creating or editing a .jsx or .tsx component or hook, fixing a re-render or stale-state bug, or when asked \"review this React code\"."
globs: ["**/*.jsx", "**/*.tsx"]
alwaysApply: false
---

# React components (frontend-skills)

- Keys come from the data (`key={item.id}`), never the array index for lists that change (react/no-array-index-key).
- Compute derived values during render; an effect only synchronises with something outside React (react/no-derived-state-effect).
- Declare components at module level; never define a component inside another (react/no-nested-component).
- Keep state minimal and close to where it is used; lift it only as far as the nearest shared parent.
- Handle user actions in event handlers, not in effects that watch state.
- Every effect that subscribes, listens or starts a timer returns a cleanup.
- Interactive elements are `<button>` and `<a>`, not `div` with `onClick` (a11y/no-click-on-static); every `<img>` has `alt` (a11y/img-alt).
- Never mutate state or props; never call hooks conditionally; never read `ref.current` during render.

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

What lands where for Amazon Q Developer

  • .frontend-skills/skills/fe-react/SKILL.mdskill
  • .frontend-skills/skills/fe-react/references/react.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-react` (React components): when editing `**/*.jsx`, `**/*.tsx`, first read `.frontend-skills/skills/fe-react/SKILL.md`.
The real file

What lands where for Aider

  • .frontend-skills/skills/fe-react/SKILL.mdskill
  • .frontend-skills/skills/fe-react/references/react.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-react` (React components): when editing `**/*.jsx`, `**/*.tsx`, first read `.frontend-skills/skills/fe-react/SKILL.md`.
The real file

One folder for most agents

Many agents read the shared .agents/skills/ folder, and some read two folders and would list each skill twice. The installer picks the smallest set of folders that every chosen agent reads, with the fewest duplicates, and names any duplicate it could not avoid; doctor checks it again later.

Your instruction files stay yours

Shared files such as AGENTS.md, CLAUDE.md or GEMINI.md get one short block between <!-- frontend-skills:start --> and <!-- frontend-skills:end -->. Text outside the block is never touched, a second run replaces the block in place, and a file is created only when it did not exist.

Rules scoped to file types

Where an agent supports it, each skill also gets a short rule file with the skill's rule digest and the file patterns it is about, so a CSS rule is not loaded while the agent edits a test. Eight formats exist, each with its own key (paths, globs, applyTo, fileMatchPattern…). This is the real file written for Cursor from the fe-react skill:

.cursor/rules/fe-react.mdc
---
description: Writes and reviews React 19 components (also inside Next.js, Vite or React Router apps) - keys, state, effects, events, refs, forms with actions, memoization and React Compiler - so they stay correct, accessible and fast. Use when creating or editing a .jsx or .tsx component or hook, fixing a re-render or stale-state bug, or when asked "review this React code".
globs: **/*.jsx, **/*.tsx
alwaysApply: false
---

# React components (frontend-skills)

- Keys come from the data (`key={item.id}`), never the array index for lists that change (react/no-array-index-key).
- Compute derived values during render; an effect only synchronises with something outside React (react/no-derived-state-effect).
- Declare components at module level; never define a component inside another (react/no-nested-component).
- Keep state minimal and close to where it is used; lift it only as far as the nearest shared parent.
- Handle user actions in event handlers, not in effects that watch state.
- Every effect that subscribes, listens or starts a timer returns a cleanup.
- Interactive elements are `<button>` and `<a>`, not `div` with `onClick` (a11y/no-click-on-static); every `<img>` has `alt` (a11y/img-alt).
- Never mutate state or props; never call hooks conditionally; never read `ref.current` during render.

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

Token budgets

What an agent always pays for is the list of skill names and descriptions, the instruction block and any always-on rule. What it pays per use is a skill's body, a reference file only when needed, and command output. The budgets are enforced by the repository's validator:

Budgets the validator enforces
PartBudgetAgent Skills specification
description400 characters1024
SKILL.md in total120 lines and 1,800 tokensunder 500 lines and 5,000 tokens (recommended)
## Rules digest12 bullets and 450 tokensno limit
one reference file300 lines and 4,000 tokensno limit
instruction block250 tokensno limit

Measured cost of every skill

Always loaded: 4219 tokens for the names and descriptions of all 50 skills. A project gets only the skills its stack needs, so its list is shorter.

SkillAlways loadedSkill body, on useReferences, on demandTotal
fe-a11y-aria91107013722533
fe-a11y-carousel-toast10279111272020
fe-a11y-combobox8287211672121
fe-a11y-core92109727113900
fe-a11y-dialog8284612802208
fe-a11y-forms9287512232190
fe-a11y-keyboard93112715932813
fe-a11y-media8878113422211
fe-a11y-menus8987212712232
fe-a11y-tables9286410431999
fe-a11y-tabs-accordion7982112182118
fe-a11y-visual9499817472839
fe-angular78115220883318
fe-astro7392015012494
fe-audit837787311592
fe-component8497212972353
fe-core-web-vitals10895615182582
fe-css-architecture92105322973442
fe-css-layout8287916662627
fe-css-modern9483918102743
fe-data-fetching7687618032755
fe-fix906708141574
fe-fonts7587513392289
fe-forms8795414722513
fe-html7686912892234
fe-i18n83101015502643
fe-icons8196818572906
fe-images81100817262815
fe-javascript79107019033052
fe-learn807487481576
fe-lighthouse8282014852387
fe-motion7983814322349
fe-nextjs81105319423076
fe-nuxt81113620243241
fe-perf-delivery8183714312349
fe-react8379410701947
fe-responsive93108019713144
fe-review807877891656
fe-sass75101619263017
fe-security9097114502511
fe-seo-metadata9395116892733
fe-state7188814902449
fe-svelte7796315442584
fe-sveltekit77103316372747
fe-tailwind75109715462718
fe-testing9194916362676
fe-tooling8885715192464
fe-typescript87101620903193
fe-vue81107019263077
fe-web-components76107716992852

Tokens are estimates by frontend-skills estimate v1 (calibrated on o200k), measured with frontend-skills tokens --all when this site was built.

Lessons

When you confirm something about your project ("form fields use our Field component"), it is kept as one line in .frontend-skills/lessons.md, and every skill reads that file first. A lesson is at most 300 characters, may name the rule ids it concerns, and is refused when it looks like a secret.

Record a lesson:

npx github:dawidolko/frontend-skills learn --lesson "Form fields use components/ui/Field.tsx" --kind convention
.frontend-skills/lessons.md
- 2026-11-11 · convention · Form fields use components/ui/Field.tsx, which renders label, hint and error. [a11y/input-label]

The audit and its report

audit reads the source and checks it against every rule that has a static check. With --url it also runs Lighthouse and axe-core in your own Chrome, after asking, and maps their results to the same rule ids. Rules a machine cannot judge are listed as a checklist.

In the source

Missing alt, lang, title or viewport; zoom blocked; positive tabindex; click handlers on static elements; unlabelled fields; invalid autocomplete; focus outline removed; images without size; render-blocking scripts; fonts without font-display; oversized images; index keys; 100vh.

In a rendered page

Colour contrast, accessible names computed through components, landmarks and headings of the final page, focus order, target size, Lighthouse performance, SEO and best-practice audits.

By a person

Whether alt text means the right thing, the quality of error messages, reading order, keyboard traps in custom widgets, screen reader announcements, cognitive load.

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.
frontend-report.md

Project: react-vite · 2026-11-11 · 3 files read, 131 static rules run.

criticalseriousmoderateminor
2345

**Result: findings at serious or above.**

Automated checks find only part of the problems; the checklist at the end needs a person.

Critical

a11y/img-alt Every img and area element has an alt attribute; a decorative image has alt="".

Why: Without alt, a screen reader announces the file name or nothing, and the image's meaning is lost; when the image fails to load, nothing replaces it.

Fix: Describe what the image says in this context (alt="Revenue grew 20% in 2026"), not what it looks like. For an image that only decorates, write alt="" so assistive technology skips it. An image inside a link that has no other text needs the link's purpose as its alt.

Sources: WCAG 2.2, Understanding SC 1.1.1 Non-text Content · MDN, the img element (alt) · WAI Images Tutorial, decorative images

  • src/App.tsx:8 <img> has no alt attribute; describe it, or use alt="" if it is decorative.

a11y/input-label Every form field has a programmatic label (label element, aria-label or aria-labelledby); a placeholder is not a label.

Why: A field without a programmatic label is announced only as "edit text": the user does not know what to type.

Fix: Pair a visible <label for="email"> with <input id="email">, or wrap the field in the label. When the design has no visible label (a search field next to its button), use aria-label or aria-labelledby; keep a visible label wherever you can.

Sources: WCAG 2.2, Understanding SC 3.3.2 Labels or Instructions · WCAG 2.2, Understanding SC 1.3.1 Info and Relationships · WAI Forms Tutorial, labeling controls · MDN, the label element

  • src/App.tsx:15 <input type="email"> has no label; add <label for>, wrap it in <label> or use aria-label.

Serious

a11y/focus-visible Never remove the focus outline without drawing a visible replacement for keyboard focus.

Why: Keyboard users see where they are only through the focus indicator.

Fix: Style :focus-visible instead of removing focus styles: button:focus-visible { outline: 2px solid currentColor; outline-offset: 2px; }. If the design needs no ring for mouse clicks, :focus:not(:focus-visible) { outline: none; } is acceptable. With Tailwind, pair outline-none with a focus-visible:ring-* or focus-visible:outline-* class.

Sources: WCAG 2.2, Understanding SC 2.4.7 Focus Visible · MDN, the :focus-visible pseudo-class · Tailwind CSS, outline-style (outline-hidden and outline-none)

  • src/App.tsx:16 outline-none removes the focus indicator; add a focus-visible:ring-* or focus-visible:outline-* class.
  • src/app.css:9 "a:focus" removes the focus outline with no visible replacement.
frontend-report.md, the report audit writes, as a person reads it.

Condensed output for agents

With --json the audit prints one line per rule, with the fix and every location as file:line and no other prose, so an agent spends tokens on findings. This is the real output for the react-vite example project:

$ npx github:dawidolko/frontend-skills audit --json
{"v":1,"failOn":"serious","failed":true,"counts":{"critical":2,"serious":3,"moderate":4,"minor":5},"rules":{"a11y/img-alt":{"s":"critical","fix":"Describe what the image says in this context (alt=\"Revenue grew 20% in 2026\"), not what it looks like.","at":["src/App.tsx:8"]},"a11y/input-label":{"s":"critical","fix":"Pair a visible <label for=\"email\"> with <input id=\"email\">, or wrap the field in the label.","at":["src/App.tsx:15"]},"a11y/focus-visible":{"s":"serious","fix":"Style :focus-visible instead of removing focus styles: button:focus-visible { outline: 2px solid currentColor; outline-offset: 2px; }.","at":["src/App.tsx:16","src/app.css:9"]},"a11y/no-click-on-static":{"s":"serious","fix":"Use <button type=\"button\"> for an action and <a href> for navigation; both are focusable, keyboard operable and announced correctly for free.","at":["src/App.tsx:9"]},"js/asset-import":{"s":"moderate","fix":"Import the file from the source tree (import hero from './hero.jpg') and use the result, or the framework's image component with that import (next/image, Astro <Image>, @nuxt/image, SvelteKit enhanced:img).","at":["src/App.tsx:8"]},"perf/img-dimensions":{"s":"moderate","fix":"Write the image's intrinsic size: <img src=\"hero.jpg\" width=\"1200\" height=\"600\" alt=\"…\">, and let CSS scale it with max-width: 100%; height: auto;.","at":["src/App.tsx:8"]},"react/no-array-index-key":{"s":"moderate","fix":"Use a stable id from the data: key={todo.id}.","at":["src/App.tsx:12"]},"seo/meta-description":{"s":"moderate","fix":"Write one or two sentences per page that say what is on it, in the page's language.","at":["index.html:3"]},"css/asset-url":{"s":"minor","fix":"Keep images and fonts next to the source (src/assets/…) and reference them relatively (url('../assets/hero.jpg')) or through the project's alias (@/assets/…, ~/assets/…).","at":["src/app.css:5"]},"html/button-type":{"s":"minor","fix":"Write type=\"button\" on every button that runs script, and type=\"submit\" on the one that submits, so intent is visible in the markup.","at":["src/App.tsx:16"]},"perf/font-display":{"s":"minor","fix":"Add font-display: swap to show fallback text at once, or font-display: optional when you would rather keep the fallback than shift the layout.","at":["src/app.css:3"]},"responsive/dynamic-viewport-units":{"s":"minor","fix":"Use min-height: 100dvh (follows the visible area) or 100svh (the smallest, stable value).","at":["src/App.tsx:7"]},"ts/isolated-modules":{"s":"minor","fix":"Add \"verbatimModuleSyntax\": true (which implies isolated modules and keeps imports exactly as written) or at least \"isolatedModules\": true, then write import type { User } from './types' for type-only imports.","at":["tsconfig.json:1"]}}}

Exit codes: 0 when nothing is at or above --fail-on (default serious), 1 when something is, 2 for a usage error, 3 when a requested tool is not available.

Terminal recording: explain a11y/img-alt prints the rule, why it matters, the fix, examples and sources.
explain a11y/img-alt: the dictionary entry in the terminal.

Ignoring a finding

Write fs-ignore <rule id> in a comment on the line or the line above, or list rule ids and paths under audit.ignore and audit.exclude in the profile.

Safe by default

Nothing you wrote is overwritten. Every file and block the command writes is recorded in .frontend-skills/install.json with its hash; uninstall removes a file only while its hash still matches and keeps a file you changed. --dry-run shows the plan and writes nothing.