Skip to content

Commit 456c3db

Browse files
docs: enforce coding standards in AGENTS.md (ban useEffect, as any, effect-based patterns)
- Document Choose Your Bug framing for useEffect misuse - Add Rules 1–6: useMountEffect-only, ban as any, derive state, data-fetching libs, event handlers over effect flags, keys for reset - Cross-reference from ANTI-PATTERNS Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Leo <leoisadev1@users.noreply.github.com>
1 parent f7e1c41 commit 456c3db

1 file changed

Lines changed: 35 additions & 0 deletions

File tree

AGENTS.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,42 @@ openchat/
5151
- Assume dev servers are already running; do not start `bun dev*` unless explicitly requested.
5252
- Prefer build/typecheck/test verification when runtime validation is needed.
5353

54+
## Coding Standards & Banned Patterns
55+
56+
These rules apply to all AI agents and human contributors working in this repository.
57+
58+
### Choose Your Bug — Why We Ban useEffect Misuse
59+
60+
Misusing `useEffect` doesn't help you avoid bugs — it just lets you choose which bug you get. Every effect that syncs state, fetches data, or reacts to user actions is a latent race condition, stale closure, or infinite loop waiting to happen. The rules below eliminate this entire class of bugs.
61+
62+
### Rules
63+
64+
**Rule 1 — BAN direct use of `useEffect`**
65+
66+
Do not use `useEffect` directly. Use `useMountEffect()` only for rare, justified external side-effect syncs (e.g. third-party SDK initialization). Any other use must be approved and documented with a comment explaining why no alternative works.
67+
68+
**Rule 2 — BAN `as any` casts**
69+
70+
Do not use TypeScript `as any` casts. Use proper types, generics, or type guards. If you cannot type something, use `unknown` and narrow it explicitly. `as any` silences the compiler and hides real bugs.
71+
72+
**Rule 3 — Derive state inline, never sync it with effects**
73+
74+
Do not use `useEffect` + `useState` to sync or transform other state. Derive computed values inline during render, or use `useMemo` if the computation is expensive. Effect-based state sync always has at least one render where the derived state is stale.
75+
76+
**Rule 4 — Use data-fetching libraries instead of fetch-in-effect**
77+
78+
Do not fetch data inside `useEffect`. Use `useQuery` (TanStack Query) or an equivalent data-fetching library. These libraries handle caching, deduplication, background refetching, loading states, and error states correctly. Effect-based fetching is a manual reimplementation of these features, done worse.
79+
80+
**Rule 5 — Use event handlers for user actions, not effect flags**
81+
82+
Do not use `useEffect` to react to user interactions by watching a flag or state change. Put the logic directly in the event handler. Effects that watch for 'action triggers' fire one render late and make code impossible to follow.
83+
84+
**Rule 6 — Reset components with keys, not dependency choreography**
85+
86+
Do not use complex `useEffect` dependency arrays to reset or reinitialize component state when an ID or key prop changes. Instead, pass the relevant value as the `key` prop to the component — React will fully remount it, resetting all state cleanly with zero effect logic.
87+
5488
## ANTI-PATTERNS (THIS PROJECT)
89+
- Follow **Coding Standards & Banned Patterns** above for enforced React and TypeScript rules (`useEffect` misuse, `as any`, and related patterns).
5590
- Do not use `NEXT_PUBLIC_*` env vars in web code.
5691
- Do not treat `docs-site/` like a regular workspace; it is a git subtree.
5792
- Do not introduce new logic against deprecated message fields when `chainOfThoughtParts` exists.

0 commit comments

Comments
 (0)