agentleFS
1337hero1337hero/faster-chat/.claude/skill/frontend-philosophy/SKILL.md

frontend-philosophy

Skill175 starsChanged 6 months agoMITView on GitHub

Frontend design philosophy and coding conventions for React/Preact applications. Enforces DHH-inspired simplicity, 8-section component structure, TanStack Query server state management, and strict anti-patterns (no useCallback, no useEffect for state sync, no barrel files, no TypeScript). Use when: (1) scaffolding new frontend projects, (2) building React/Preact components, (3) implementing features with state management, (4) reviewing or refactoring frontend code, (5) setting up project structure and file organization. Triggers on: "scaffold", "new project", "build a component", "create a page", "add a feature", "frontend", "React", "Preact", or any frontend implementation task.

We split this skill into the rules it gives an agent

5 rules. About 0 are common, 4 are distinctive, and 1 is very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈4

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 1

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Every component follows this order.

    line 74
  2. Distinctive:

    Only for UI concerns: modals, theme, sidebar, filters, form inputs.

    line 131
  3. Distinctive:

    Never refetch in children: when parent has the data

    line 149
  4. Very specific:

    Use cn() from @/lib/utils for class merging

    line 191
  5. Distinctive:

    Use CVA (class-variance-authority) for component variants

    line 192

≈ “Common” is an estimate: at least 1 in 5 of the 308,232 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Frontend Philosophy

Authoritative conventions for all React/Preact work. These are not suggestions — they are the standard. When in doubt, choose the simpler path.

"Every line of code is a liability. The best code is no code. The second best is simple, boring code that obviously works."

Core Principles

  1. Simplicity over cleverness — Write code a junior dev understands
  2. Convention over configuration — Follow existing patterns, don't invent
  3. Optimize for understanding — Code is read 10x more than written
  4. Embrace the monolith — Colocate related concerns, don't split prematurely
  5. Performance through simplicity — Fastest code is code that doesn't run

Stack Defaults

PurposeDefaultNotes
Runtime/pkgBunFallback: npm. Never pnpm/yarn
BundlerViteWith @/ path alias
FrameworkReact or Preact+ TanStack Query/Router
StylingTailwind CSSUtility-first, cn() for merging
UI primitivesshadcn/ui patternCVA for variants, Radix primitives
Server stateTanStack QueryONLY source of truth for API data
Client stateZustand or Preact SignalsUI state only (modals, theme, filters)
Icons@remixicon/reactRi*Line for outline, Ri*Fill for solid
TypesNo TypeScript.jsx components, .js utilities

Why No TypeScript

Speed over ceremony. Type gymnastics add grief, not joy. Runtime validation at system boundaries, shared constants, JSDoc for complex functions.

File Conventions

src/
├── components/
│   ├── ui/              # Base UI (shadcn pattern)
│   ├── billing/         # Feature-based grouping
│   ├── support/         # NOT type-based (lists/, forms/, displays/)
│   └── common/          # Shared across features
├── hooks/               # Custom hooks (use* prefix)
├── stores/              # Zustand stores
├── constants/           # Shared constants
├── lib/                 # Utilities (cn, formatters)
├── pages/               # Route-level components
└── api/                 # API client

Naming rules:

  • .jsx components, .js utilities — always
  • PascalCase component files, camelCase everything else
  • handle* event handlers, use* hooks, render* render methods
  • Feature-based folders, never type-based
  • No barrel files (index.ts/js re-exports) — ever
  • No comments unless logic is truly non-obvious

Component Structure (8 Sections)

Every component follows this order. See references/component-patterns.md for full examples.

const Component = ({ prop1, prop2 }) => {
  // 1. Server state (TanStack Query)
  const { data, isLoading, error } = useQuery({ ... });

  // 2. Global client state (Zustand/signals)
  const { theme } = useThemeStore();

  // 3. Local state (useState)
  const [isOpen, setIsOpen] = useState(false);

  // 4. Refs
  const formRef = useRef(null);

  // 5. Custom hooks
  const { isOnline } = useNetworkStatus();

  // 6. Derived values (compute in render, no useState)
  const isValid = email.includes("@");
  const fullName = `${data?.first} ${data?.last}`;

  // 7. Effects (DOM sync, subscriptions, analytics ONLY)
  useEffect(() => { ... }, [deps]);

  // 8. Event handlers
  const handleSubmit = () => { ... };

  // Return — early returns for loading/error first
  if (isLoading) return <Skeleton />;
  if (error) return <ErrorMessage error={error} />;

  return ( ... );
};

State Management Rules

Server State = TanStack Query ONLY

// CORRECT — single source of truth
const { data: users } = useQuery({
  queryKey: ["users", filters],
  queryFn: () => api.get("/users", { params: filters }),
  staleTime: 5 * 60 * 1000,
  gcTime: 60 * 60 * 1000,    // NOT cacheTime (v5)
});

// WRONG — duplicating server data in local state
const [users, setUsers] = useState([]);
useEffect(() => { fetchUsers().then(setUsers); }, []);

Client State = Zustand or Signals

Only for UI concerns: modals, theme, sidebar, filters, form inputs.

Derive, Don't Duplicate

// CORRECT — derive in render
const hasError = error !== null;
const activeUsers = users?.filter(u => u.isActive);

// WRONG — useState for derived values
const [hasError, setHasError] = useState(false);
useEffect(() => setHasError(error !== null), [error]);

Data Fetching Hierarchy

  1. Pages fetch all required data
  2. Pass data as props to children
  3. Never refetch in children when parent has the data

Critical Anti-Patterns

These are hard rules, not guidelines.

NEVER do thisDo this instead
useEffect for state syncMove logic to event handlers
useCallbackJust define the function (almost never needed)
useState for derived valuesCompute in render
Duplicate server data in useStateTanStack Query is the source of truth
Barrel files (index.ts re-exports)Import directly from the file
useMemo without profiling firstJust compute it
Prop drilling beyond 2 levelsComposition or Zustand
Business logic in componentsExtract to hooks or utilities
Multiple state management libsTanStack Query + ONE client state lib
Inline styles or global CSSTailwind utilities
Premature abstractionRule of 3 — wait for 3+ use cases
Custom wrappers around librariesUse the library directly
Over-commentingSelf-documenting names

Valid useEffect Uses

Only three:

  1. DOM synchronization (focus, scroll, resize listeners)
  2. External subscriptions (WebSocket, event emitters)
  3. Analytics/logging (page views, tracking)

Everything else belongs in an event handler or TanStack Query.

Formatting

Prettier defaults:

  • 2-space indent, double quotes, semicolons
  • 100 char print width, trailing commas ES5
  • Tailwind plugin for class ordering

UI Patterns

  • Buttons: always rounded-full
  • Cards: always rounded-xl
  • Use cn() from @/lib/utils for class merging
  • Use CVA (class-variance-authority) for component variants
  • Composition over configuration — build with children and slots
  • data-slot attributes for CSS targeting
  • Early returns for loading/error states before main render

Code Review Questions

Before shipping, ask:

  1. Can a junior dev understand this?
  2. Is this the simplest solution that works?
  3. Does this follow existing patterns in the codebase?

Download now (ZIP)

  • Other versions1 project uses a version of this.

    Word for word · 0

    None found.

    Edited · 0

    None found.

    Wrote their own version · 1

    1. delorenj/ssbnk★ 2same name

    How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.

  • In this repository5 other files it gives its agents.

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.