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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions