Skip to content

PRD: React/UI audit skill suite (audit / review / rules / sync) #1

Description

@tkowalczyk

Problem Statement

As a developer using brainstormer skills to ship Cloudflare Workers + React apps from the Auditmos templates (saas-on-cf, hono-on-cf, tstack-on-cf, tstack-on-cf-onchain), I have no skill that audits the React/UI surface for quality, anti-patterns, or consistency with canonical guidance.

Concretely:

  • AI-generated React code in these projects accumulates useEffect anti-patterns (derived state, fetching in effects, chains of computations, cascades of setState) — exactly the cases enumerated in react.dev/learn/you-might-not-need-an-effect.
  • Re-render performance issues (inline object/array props, missing memo, context that re-renders too broadly) accumulate without surfacing — the failure modes catalogued by react-doctor and Million.
  • shadcn/ui primitives are bypassed (raw Radix where shadcn already wraps it; custom Tailwind instead of cn() + cva variants).
  • UI rules in template repos (.cursor/rules/, CLAUDE.md, AGENTS.md, .github/copilot-instructions.md, etc.) are written once and never reviewed against canonical guidance, so they go stale, contradict canon, or drift from what the code actually does.

I do not want to remember to run a linter manually per anti-pattern. I want skills that an AI agent invokes to scan the surface, file actionable GitHub issues grouped by anti-pattern type, and keep those issues lifecycle-aware across re-runs.

Solution

Four manually invoked Claude Code skills sharing a common rule-card library:

  • /react-audit — Audit a whole repo for React/UI anti-patterns. Smart-scans *.tsx/*.jsx (asks before scanning when ≥50 matching files), runs all rule cards, files grouped issues.
  • /react-review — Review the diff on the current branch against main, including 1-hop import neighbors. Files grouped issues (or attaches to existing PR if present).
  • /react-rules — Audit a single template repo's UI-rules surface against the canonical rule-card library. Detects gaps, conflicts, outdated patterns, vague/unenforceable rules, and drift between rules prose and code reality. Opens grouped issues in the template repo.
  • /react-rules-sync — Fetch react.dev / react-doctor / shadcn / TanStack docs, diff against embedded rule-card content, surface required updates for human review. No auto-apply.

All four skills produce GitHub issues grouped by (skill, rule_id) — one issue per group, labeled <skill>:<rule_id>, deduplicated across re-runs by label, with regressions creating a new issue that backlinks the previously closed one. Severity follows the /agent-cli rubric: Blocker / Friction / Optimization.

The rule-card library is offline-embedded in the plugin (skills/react-shared/references/cards/), one file per rule, with strict frontmatter. Each card is self-contained (id, category, detect strategy, bad snippet, good snippet, citation). Issue bodies embed the full card content so reviewers don't have to click through.

User Stories

  1. As a developer, I want to audit my repo for React/UI anti-patterns by running /react-audit, so that I get a list of findings as GitHub issues with embedded rule explanations and severity classifications.
  2. As a developer, I want /react-audit to use a smart-scan strategy that lists candidate files via git ls-files and asks for confirmation when there are ≥50 matching files, so that I'm never surprised by a 1000-file scan.
  3. As a developer who just made changes on a feature branch, I want to run /react-review to review only my diff (plus 1-hop import neighbors), so that I catch regressions before opening a PR.
  4. As a developer, I want /react-review to also work on a local branch with no open PR, so that I can validate before pushing — output is a standalone issue with the branch ref in the title.
  5. As a developer maintaining a Cloudflare/React template, I want to run /react-rules against my template's repo, so that I find gaps, contradictions, outdated patterns, vague/unenforceable rules, and drift between my UI-rules files and the actual code.
  6. As a developer, I want /react-rules to read every UI-rules surface in the repo (.cursor/rules/*.mdc, CLAUDE.md and nested variants, AGENTS.md, .github/copilot-instructions.md, .windsurfrules, .clinerules, README UI sections), so that I get a complete view regardless of which IDE configuration the template targets.
  7. As a developer, I want /react-rules to also scan source code (e.g., src/components/) so that drift between rules prose and code reality is detected — for example: rule says "use shadcn primitives", code has 5 hand-rolled modal components.
  8. As a developer, I want findings grouped by (skill, rule_id), so that one issue per anti-pattern type aggregates all N occurrences (instead of N noisy issues).
  9. As a developer running audits multiple times, I want issues to be deduplicated by label — <skill>:<rule_id> — so that re-runs update the existing open issue body in place rather than creating duplicates.
  10. As a developer, I want a closed issue that resurfaces (regression) to create a NEW issue with a backlink to the closed one, so that I have full audit trail without reopening history.
  11. As a developer, I want each issue body to embed the full rule-card content (id, severity, detect, bad/good snippets, citation), so that reviewers don't need to follow external links to understand the issue.
  12. As a developer, I want long rule cards (>80 lines or >2 bad/good pairs) to use <details> collapsibles in the issue body, so that issues don't visually overwhelm.
  13. As a developer, I want severity classified as Blocker / Friction / Optimization matching /agent-cli, so that severity vocabulary is consistent across the brainstormer skill suite.
  14. As a developer, I want severity to be assigned per-finding by the skill (not fixed in the card), so that the same anti-pattern in a hot render path can be Blocker while in a settings page it can be Friction.
  15. As a developer, I want all four skills triggered manually only (no hooks), so that I retain control and the skills don't run unexpectedly during commits/pushes.
  16. As a developer, I want rule cards to live offline in the plugin, so that audits work without network access.
  17. As a developer, I want /react-rules-sync as a manually invoked refresh skill that fetches the canonical sources, diffs against embedded cards, and proposes updates as a preview, so that drift between embedded knowledge and external truth stays manageable without scheduled jobs.
  18. As a developer, I want /react-rules-sync to never auto-apply changes, so that I retain final say over card content.
  19. As a developer, I want each finding to list file:line and ~5 lines of code context per occurrence in the issue body, so that I can navigate directly to the code.
  20. As a developer, I want /react-audit and /react-review to open issues in the current repo (the one being audited), so that findings live with the code.
  21. As a developer, I want /react-rules to open issues in the template repo being audited, so that rules-quality findings live with the rules.
  22. As a developer, I want skills to NOT auto-fix or suggest patches in issue bodies, so that I retain authoring control over fixes.
  23. As a developer with TanStack-based templates, I want the rule library to include TanStack-specific cards (Query, Router, Form), so that fetching-in-useEffect is detected when useQuery is the correct primitive.
  24. As a developer using shadcn/ui, I want shadcn-conventions cards (raw Radix where shadcn primitive exists, missing cn()/cva use, custom variants instead of cva, naming components/ui/ vs components/), so that the suite enforces the template's intended idiom.
  25. As a developer, I want a11y-on-Radix cards (label-input pairing, focus traps in Dialog/Sheet, missing aria-label, incorrect forwardRef), so that accessibility regressions are caught.
  26. As a developer working with Cloudflare Workers + RSC/streaming, I want server/client boundary cards ("use client" misuse, hydration mismatches, fetching client-side what should be server-side), so that the boundary is enforced.
  27. As a developer, I want TypeScript-component cards (Readonly/Required props, no any in handlers, correct forwardRef typing, properly typed children), so that the type surface stays clean.
  28. As a developer, I want Tailwind/styling cards (no inline styles, design-token CSS vars over arbitrary values, no inline object styles), so that visual consistency holds.
  29. As a developer, I want the MVP to ship with ~15 hand-authored cards (the 11 anti-patterns from react.dev/learn/you-might-not-need-an-effect plus 4 critical re-render patterns), so that I can validate value before investing in the full ~60-card buildout.
  30. As a developer, I want subsequent cards added inkrementalnie as real audits surface gaps, so that the library grows from real demand rather than upfront speculation.
  31. As a developer, I want cards organized as one file per rule with strict frontmatter (id, category, detect, bad, good, source), so that the skill loads only what it needs (token-efficient).
  32. As a developer, I want a category index file (references/index.md) listing all cards by id and category, so that the skill can do a cheap lookup before loading individual card files.
  33. As a developer, I want detection strategy declared per card (regex / AST / LLM-judge), so that deterministic rules don't waste tokens and semantic rules get LLM treatment.
  34. As a developer, I want all GitHub interactions to use the gh CLI (already configured in my environment), so that auth and access are managed by my existing setup.
  35. As a maintainer of brainstormer, I want shared deep modules — Rule Card Library, Code Scanner, Issue Manager — for reuse across the four skills, so that adding a new category or a new sibling skill doesn't duplicate logic.
  36. As a maintainer, I want /react-rules-sync's Source Sync module isolated from the other three skills' code paths, so that fetch logic doesn't bleed into audit/review/rules paths.
  37. As a maintainer, I want llms.txt updated to index the four new skills and the shared references/cards/ index, so that the brainstormer plugin remains discoverable.

Implementation Decisions

Skill set

  • Four skills, all manually invoked: /react-audit, /react-review, /react-rules, /react-rules-sync.
  • No umbrella branding (avoids name collision with Million's react-doctor).
  • Naming follows existing brainstormer convention (single hyphenated slash-command matching skill folder name).
  • Each skill ships as its own SKILL.md in skills/<name>/ with a mirror copy in plugins/<name>/ for marketplace distribution.

Shared knowledge structure

  • Rule cards live in skills/react-shared/references/cards/.
  • One file per rule; strict frontmatter schema: id (slash-pathed e.g. effects/derived-state), category (one of: effects, rerenders, shadcn, a11y, tanstack, server-client, typescript, styling), detect (strategy: regex / ast / llm-judge), bad (snippet), good (snippet), source (URL with anchor).
  • Index file references/index.md lists all cards by id and category for cheap pre-load lookup.

Severity model

  • Blocker / Friction / Optimization (matches /agent-cli).
  • Skill assigns per-finding contextually based on file path, render hot-path heuristics, and rule defaults.

Issue grouping and lifecycle

  • One GitHub issue per (skill, rule_id) group per re-run.
  • Label <skill>:<rule_id> always present (e.g., react-audit:effects/derived-state).
  • Re-run dedup: if open issue with label exists → update body, preserve human comments. If no findings remain → close with comment. If finding resurfaces after close → new issue with backlink to the closed one.
  • Issue body embeds full card content; cards over ~80 lines or with >2 bad/good pairs use <details> collapsibles.
  • Each finding lists file:line plus ~5 lines of code context.

Scanning strategies

  • /react-audit: smart-scan via git ls-files '*.tsx' '*.jsx'; skip node_modules/, dist/, build/, .next/, coverage/, **/*.test.*, **/*.stories.*. If matching count <50, scan immediately; if ≥50, group by directory and prompt for confirmation.
  • /react-review: changed files vs base branch (default main) plus 1-hop import neighbors (files importing or imported by changed files).
  • /react-rules: full-repo scan of all known rule-source files plus a sample of src/components/ (and equivalents) for drift detection.

Detection strategies

  • Per-card detect field declares strategy:
    • regex for syntactically deterministic anti-patterns (e.g., class extends Component).
    • ast for structural patterns requiring tree analysis.
    • llm-judge for semantic patterns (e.g., "this state is derived from props").
  • LLM-judge calls cached per (file_hash, rule_id) within a single run.

Source content handling

  • Card bodies embed quotes/snippets from canonical sources at authoring time.
  • /react-rules-sync uses Exa MCP for non-GitHub sources and gh CLI for GitHub sources; never live-fetches during normal audit/review/rules runs.
  • Sync output is a preview-only diff against embedded card content; user manually applies updates.

Trigger model

  • All four skills are manually invoked. No Stop, PreToolUse, or PostToolUse hook configuration.
  • Skill metadata describes triggers based on natural-language match.

Out-of-scope (also enumerated below)

  • Cross-template inconsistency analysis was scoped out (skill always operates on a single repo).
  • Authoring/scaffolding mode is out of scope (audit-only).
  • Auto-fix / suggested-diff in issue bodies is out of scope.

Validation Strategy

User stories — verification mapping

  • Stories 1, 2, 19 — /react-audit on a fixture repo with seeded anti-patterns; verify expected issues with smart-scan prompt firing at threshold.
  • Stories 3, 4 — /react-review on a fixture branch; verify changed-files + 1-hop neighbor analysis; verify standalone-issue path when no PR exists.
  • Stories 5, 6, 7 — /react-rules on a fixture template with seeded gaps, conflicts, outdated patterns, vague rules, and drift; verify each category surfaces.
  • Stories 8, 9, 10 — Run audit twice on same fixture; verify dedup-by-label, in-place body update, regression-creates-new-issue with backlink.
  • Stories 11, 12, 19 — Inspect issue body markup on multi-occurrence findings.
  • Stories 13, 14 — Severity assignment verified by inspecting findings on hot-path vs cold-path fixtures of the same rule.
  • Story 15 — Inspect skill metadata to confirm no hook configuration.
  • Stories 17, 18 — /react-rules-sync against a mocked source change; verify diff preview surfaced and no card mutated without confirmation.
  • Stories 20, 21 — Inspect gh issue list repo target during fixture runs.
  • Story 22 — Inspect issue body for absence of patch suggestions.
  • Stories 23–28 — Per-category coverage verified by listing card IDs in references/index.md.
  • Stories 29, 30 — MVP card count verified at first ship; growth pattern documented in further-notes.md of the shared references.
  • Stories 31, 32, 33 — Frontmatter schema and index.md consistency verified by a one-shot validator script.
  • Story 34 — Static check that no curl / fetch / WebFetch calls exist outside /react-rules-sync's Source Sync module.
  • Stories 35, 36, 37 — Code review confirms shared modules are isolated; llms.txt includes the four new skills.

Deep module validation criteria — A, B, C (shared modules)

A. Rule Card LibraryloadCard(id) → Card, listCards(category?) → Card[].

  • Done when:
    • loadCard(id) returns a fully parsed card (frontmatter + body) for any valid id and throws clearly with the missing id name on a miss.
    • listCards(category) returns the filtered list (or all if no category given), with O(1) lookup against the cached index.
    • First call performs disk I/O; subsequent calls in the same process are cache hits.
  • Quality criteria:
    • 100% of shipping cards parse without error.
    • Frontmatter schema enforced: id, category, detect, source mandatory; bad, good optional.
    • Card IDs are unique across the library; index.md consistency verified by script.
  • Acceptance:
    • Golden-test set: load every shipping card, round-trip identical to source.
    • Schema-violation fixtures fail with a clear error (missing field name, invalid category).

B. Code Scannerscan(files, rules) → Finding[].

  • Done when:
    • For every file × rule combination, Finding records include rule_id, file, line, severity, snippet (~5 lines context).
    • Zero false positives on a known-clean fixture.
    • ≥80% true-positive recall on a known-bad fixture seeded with each MVP rule.
  • Quality criteria:
    • LLM-judge calls cached per (file_hash, rule_id) within a single run.
    • Per-rule confidence (pass/fail) reported in scan summary so degraded rules are visible.
    • Severity assignment honors per-finding context (hot-path vs cold-path heuristics).
  • Acceptance:
    • Fixture-based test asserting specific (rule_id, file, line) triples.
    • Rerun on the same fixture deterministically produces the same findings (modulo LLM-judge variability, which the cache eliminates within a run).

C. Issue ManagerupsertIssue(repo, label, findings, severity) → IssueResult.

  • Done when:
    • Creates issue if no issue exists with label.
    • Updates body if an open issue with label exists; preserves any human comments by editing only the issue body.
    • Closes issue with comment if findings is empty for that label and an open issue exists.
    • Creates a new issue with a backlink to the most recently closed issue with the same label when a finding resurfaces.
  • Quality criteria:
    • Label is always present and matches <skill>:<rule_id> exactly.
    • Body always contains the full embedded card content (or <details>-wrapped if oversized).
    • No duplicate issues with the same label exist in the open state at any point.
  • Acceptance:
    • Integration test against a sandbox GitHub repo running through all four lifecycle paths (create / update / close / regression).
    • Label-collision test: two simultaneous runs do not create two issues for the same (skill, rule_id) pair.

Out of Scope

  • Authoring / scaffolding mode — skills do not help write new components. Audit-only.
  • Auto-fix or suggested-diff in issue bodies — read-only findings; user authors all fixes.
  • Cross-template inconsistency analysis/react-rules audits one template at a time; comparing rules across templates is a manual review activity.
  • Hook-based auto-trigger — no PreToolUse, PostToolUse, or Stop integrations. Manual invocation only.
  • Hosted documentation site — cards stay embedded in the plugin; "further reading" links go to original external sources only.
  • Non-React UI frameworks — Vue, Svelte, Solid are out of scope.
  • Backend rules outside the React boundary — raw Hono handlers, CF Workers internals, etc., unless they touch the React render boundary directly.
  • ESLint plugin / linter rule export — cards are LLM/regex hybrid heuristics designed for skill use, not directly compilable to lint rules.
  • Scheduled /react-rules-sync execution — fully manual at v1; GH Actions automation is a future consideration.
  • Authoring all ~60 cards on day 1 — MVP ships with 15; the rest grow inkrementalnie from real audit demand.

Further Notes

MVP card list (15 cards)

Effects (11, sourced from react.dev/learn/you-might-not-need-an-effect):

  • effects/transforming-data-for-render
  • effects/caching-expensive-computation
  • effects/resetting-all-state-on-prop-change
  • effects/adjusting-state-on-prop-change
  • effects/sharing-logic-between-handlers
  • effects/sending-post-request
  • effects/computing-derived-state
  • effects/fetching-data
  • effects/chains-of-computations
  • effects/initializing-application
  • effects/notifying-parent-state-changes

Re-renders (4, sourced from react.doctor / millionco/react-doctor):

  • rerenders/inline-object-prop
  • rerenders/inline-array-prop
  • rerenders/missing-memo-on-list-row
  • rerenders/context-too-broad

Subsequent card categories (added inkrementalnie post-MVP):

  • shadcn/* — primitive bypass, missing cn()/cva, custom variants, naming convention.
  • a11y/* — label-input pairing, focus traps, missing aria-label, forwardRef correctness.
  • tanstack/* — Query (fetch-in-effect), Router (loaders), Form (controlled state).
  • server-client/*"use client" misuse, hydration mismatches, server/client boundary leaks.
  • typescript/*Readonly/Required props, any in handlers, forwardRef typing, children typing.
  • styling/* — inline styles, design-token CSS vars, arbitrary value misuse.

Severity rubric — explicit alignment with /agent-cli

  • Blocker — code is broken or will break: race conditions, hydration mismatch, missing key, fetching without cleanup.
  • Friction — code works but slows devs/users: expensive re-renders, useEffect cascades, custom shadcn variant where cva exists.
  • Optimization — nice-to-have improvements: cleaner idiom, micro-perf, minor a11y enhancements.

Authoring effort estimate

  • 15 MVP cards: ~4–6 hours hand-authoring (reading sources + extracting detect/bad/good/source).
  • Full ~60-card buildout: ~12–15 hours, deferred until MVP validates value.

Templates this targets

saas-on-cf, hono-on-cf, tstack-on-cf, tstack-on-cf-onchain (Auditmos-internal Cloudflare Workers templates). Skills work on any repo containing React/TSX, but rule selection (TanStack, shadcn) reflects these templates' stack.

/react-rules-sync cadence

Fully manual at v1. If automation is later desired, a GitHub Actions workflow in auditmos/brainstormer can poll sources weekly and open a PR when card content drifts — out of scope for v1.

llms.txt updates

Add four new skill entries and the shared references index (skills/react-shared/references/cards/index.md) to the brainstormer llms.txt.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions