@vpxa/aikit 0.1.55 → 0.1.57

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,309 +1,309 @@
1
- ---
2
- name: react
3
- description: "Comprehensive React development patterns — component architecture, React 19 APIs, Server Components, TypeScript integration, and performance optimization."
4
- metadata:
5
- category: domain
6
- domain: react
7
- applicability: on-demand
8
- inputs: [codebase, requirements]
9
- outputs: [component-patterns, code]
10
- relatedSkills: [typescript, frontend-design]
11
- ---
12
-
13
- # React
14
-
15
- > Comprehensive React development patterns — component architecture, React 19 APIs, Server Components, TypeScript integration, and performance optimization. Synthesized from react-dev patterns, react-patterns (React 19), and Vercel React best practices.
16
-
17
- ## When to Use
18
-
19
- **MANDATORY** for the Frontend agent on every React task. Also use when:
20
- - Building React components, hooks, or pages
21
- - Working with Server Components or Server Actions
22
- - Optimizing React performance (re-renders, bundle size, data fetching)
23
- - Reviewing React code for correctness and best practices
24
-
25
- ## React 19 Quick Reference
26
-
27
- | API | Use Case | Key Change |
28
- |-----|----------|------------|
29
- | `ref` as prop | Access DOM/component instance | No more `forwardRef` wrapper |
30
- | `use()` | Read promises/context in render | Replaces `useContext`, enables async |
31
- | `useActionState` | Form submission state + error | Replaces `useFormState` |
32
- | `useOptimistic` | Instant UI feedback | Optimistic updates before server confirms |
33
- | `useTransition` | Non-urgent state updates | `isPending` for loading states |
34
- | `<form action>` | Server Actions in forms | Direct server function binding |
35
- | Server Components | Zero-bundle components | Default in App Router, no `"use client"` |
36
- | Server Actions | Server mutations | `"use server"` functions, form actions |
37
-
38
- ## Component Patterns
39
-
40
- ### Extend Native Elements
41
- ```tsx
42
- type ButtonProps = React.ComponentProps<"button"> & {
43
- variant?: "primary" | "secondary" | "ghost";
44
- size?: "sm" | "md" | "lg";
45
- };
46
-
47
- function Button({ variant = "primary", size = "md", className, ...props }: ButtonProps) {
48
- return <button className={cn(variants[variant], sizes[size], className)} {...props} />;
49
- }
50
- ```
51
-
52
- ### Discriminated Union Props
53
- ```tsx
54
- type ModalProps =
55
- | { variant: "alert"; message: string; onConfirm: () => void }
56
- | { variant: "form"; children: React.ReactNode; onSubmit: (data: FormData) => void };
57
-
58
- function Modal(props: ModalProps) {
59
- switch (props.variant) {
60
- case "alert": return <AlertModal {...props} />;
61
- case "form": return <FormModal {...props} />;
62
- }
63
- }
64
- ```
65
-
66
- ### Generic Components
67
- ```tsx
68
- type TableProps<T> = {
69
- data: T[];
70
- columns: { key: keyof T; header: string; render?: (value: T[keyof T], row: T) => React.ReactNode }[];
71
- onRowClick?: (row: T) => void;
72
- };
73
-
74
- function Table<T extends Record<string, unknown>>({ data, columns, onRowClick }: TableProps<T>) {
75
- // ...
76
- }
77
- ```
78
-
79
- ### Children Typing
80
- ```tsx
81
- // Specific children
82
- type Props = { children: React.ReactElement<TabProps>[] };
83
-
84
- // Render function children
85
- type Props = { children: (data: T) => React.ReactNode };
86
-
87
- // String only
88
- type Props = { children: string };
89
- ```
90
-
91
- ## Ref as Prop (React 19)
92
-
93
- ```tsx
94
- // React 19: pass ref directly, no forwardRef needed
95
- function Input({ ref, ...props }: React.ComponentProps<"input">) {
96
- return <input ref={ref} {...props} />;
97
- }
98
-
99
- // Cleanup function (new in React 19)
100
- function MeasuredDiv({ ref, ...props }: React.ComponentProps<"div">) {
101
- return (
102
- <div
103
- ref={(node) => {
104
- if (node) measureElement(node);
105
- return () => cleanupMeasurement(); // cleanup on unmount
106
- }}
107
- {...props}
108
- />
109
- );
110
- }
111
- ```
112
-
113
- ## Server Components & Actions
114
-
115
- ### Server Component (default — no directive needed)
116
- ```tsx
117
- // app/users/page.tsx — Server Component (default)
118
- import { db } from "@/lib/db";
119
-
120
- export default async function UsersPage() {
121
- const users = await db.query.users.findMany(); // Direct DB access
122
- return <UserList users={users} />; // Pass data to client
123
- }
124
- ```
125
-
126
- ### Client Component (explicit opt-in)
127
- ```tsx
128
- "use client";
129
- import { useState, useOptimistic, useTransition } from "react";
130
-
131
- export function Counter({ initialCount }: { initialCount: number }) {
132
- const [count, setCount] = useState(initialCount);
133
- return <button onClick={() => setCount(c => c + 1)}>{count}</button>;
134
- }
135
- ```
136
-
137
- ### Server Action with Form
138
- ```tsx
139
- // actions.ts
140
- "use server";
141
- import { z } from "zod";
142
-
143
- const schema = z.object({ name: z.string().min(1), email: z.string().email() });
144
-
145
- export async function createUser(_prev: unknown, formData: FormData) {
146
- const result = schema.safeParse(Object.fromEntries(formData));
147
- if (!result.success) return { error: result.error.flatten().fieldErrors };
148
- await db.insert(users).values(result.data);
149
- return { success: true };
150
- }
151
- ```
152
-
153
- ```tsx
154
- "use client";
155
- import { useActionState } from "react";
156
- import { createUser } from "./actions";
157
-
158
- export function CreateUserForm() {
159
- const [state, action, isPending] = useActionState(createUser, null);
160
- return (
161
- <form action={action}>
162
- <input name="name" required />
163
- {state?.error?.name && <p className="text-red-500">{state.error.name}</p>}
164
- <input name="email" type="email" required />
165
- {state?.error?.email && <p className="text-red-500">{state.error.email}</p>}
166
- <button disabled={isPending}>{isPending ? "Creating..." : "Create"}</button>
167
- </form>
168
- );
169
- }
170
- ```
171
-
172
- ### Optimistic Updates
173
- ```tsx
174
- "use client";
175
- import { useOptimistic } from "react";
176
-
177
- function TodoList({ todos, addTodo }: { todos: Todo[]; addTodo: (text: string) => Promise<void> }) {
178
- const [optimisticTodos, addOptimistic] = useOptimistic(
179
- todos,
180
- (state, newTodo: string) => [...state, { id: "temp", text: newTodo, pending: true }]
181
- );
182
-
183
- async function handleAdd(formData: FormData) {
184
- const text = formData.get("text") as string;
185
- addOptimistic(text);
186
- await addTodo(text);
187
- }
188
-
189
- return (
190
- <form action={handleAdd}>
191
- <input name="text" />
192
- <button type="submit">Add</button>
193
- <ul>
194
- {optimisticTodos.map(t => (
195
- <li key={t.id} style={{ opacity: t.pending ? 0.5 : 1 }}>{t.text}</li>
196
- ))}
197
- </ul>
198
- </form>
199
- );
200
- }
201
- ```
202
-
203
- ## Event Handler Types
204
-
205
- ```tsx
206
- // Always use specific event types
207
- onClick: (e: React.MouseEvent<HTMLButtonElement>) => void
208
- onChange: (e: React.ChangeEvent<HTMLInputElement>) => void
209
- onSubmit: (e: React.FormEvent<HTMLFormElement>) => void
210
- onKeyDown: (e: React.KeyboardEvent<HTMLInputElement>) => void
211
- onFocus: (e: React.FocusEvent<HTMLInputElement>) => void
212
- onDrag: (e: React.DragEvent<HTMLDivElement>) => void
213
- ```
214
-
215
- ## Hooks Typing
216
-
217
- ```tsx
218
- // useState with union
219
- const [status, setStatus] = useState<"idle" | "loading" | "error">("idle");
220
-
221
- // useRef for DOM — pass null, get RefObject
222
- const inputRef = useRef<HTMLInputElement>(null);
223
-
224
- // useRef for mutable value — no null, get MutableRefObject
225
- const intervalRef = useRef<number>(0);
226
-
227
- // useReducer with discriminated actions
228
- type Action = { type: "increment" } | { type: "set"; payload: number };
229
- const [count, dispatch] = useReducer((state: number, action: Action) => {
230
- switch (action.type) {
231
- case "increment": return state + 1;
232
- case "set": return action.payload;
233
- }
234
- }, 0);
235
-
236
- // Custom hook: return as const for tuple types
237
- function useToggle(initial = false) {
238
- const [value, setValue] = useState(initial);
239
- const toggle = useCallback(() => setValue(v => !v), []);
240
- return [value, toggle] as const;
241
- }
242
-
243
- // useContext with null guard
244
- const ctx = useContext(ThemeContext);
245
- if (!ctx) throw new Error("useTheme must be used within ThemeProvider");
246
- ```
247
-
248
- ## Performance Rules
249
-
250
- ### Prevent Async Waterfalls
251
- ```tsx
252
- // BAD — sequential fetching
253
- const user = await getUser(id);
254
- const posts = await getPosts(user.id); // Waits for user first
255
- const comments = await getComments(posts[0].id); // Waits for posts
256
-
257
- // GOOD — parallel where possible
258
- const [user, posts] = await Promise.all([getUser(id), getPosts(id)]);
259
- ```
260
-
261
- ### Bundle Size
262
- - `dynamic(() => import("./HeavyComponent"))` — lazy load below-fold components
263
- - Tree-shake: use named exports, avoid `import *`
264
- - Analyze bundle: `@next/bundle-analyzer` to find bloat
265
- - Code-split by route — each page loads only its own JS
266
- - Avoid importing entire libraries: `import { debounce } from "lodash-es"` not `import _ from "lodash"`
267
-
268
- ### Server-Side Performance
269
- - Default to Server Components — zero JS shipped to client
270
- - Stream with Suspense: wrap slow data fetchers in `<Suspense fallback={<Skeleton />}>`
271
- - Cache expensive computations with `"use cache"` directive
272
- - Avoid serializing large objects across server/client boundary
273
-
274
- ### Client-Side Data Fetching
275
- - Use SWR or React Query — automatic caching, revalidation, error retry
276
- - Stale-while-revalidate: show cached data instantly, refresh in background
277
- - Error boundaries: `<ErrorBoundary>` wrapping data-dependent trees
278
- - Prefetch on hover/viewport for likely next navigations
279
-
280
- ### Re-render Optimization
281
- - React Compiler (React 19): auto-memoizes — try this first before manual `useMemo`/`useCallback`
282
- - If no compiler: `useMemo` for expensive computations, `useCallback` for stable function references
283
- - Extract static JSX outside components — constants don't re-create
284
- - Split context: separate frequently-changing state from rarely-changing state
285
- - `React.memo()` on components receiving only primitive props
286
-
287
- ### Rendering Performance
288
- - **Virtualize** lists > 100 items: `@tanstack/react-virtual`, `react-window`
289
- - Defer heavy computations with `useDeferredValue`
290
- - Batch state updates (React 18+ does this automatically in event handlers)
291
- - Avoid reading DOM layout during renders (force sync layout = jank)
292
-
293
- ### Advanced Patterns
294
- - Progressive hydration: load and hydrate components as they enter viewport
295
- - Concurrent features: `useTransition` for non-blocking state updates
296
- - Suspense caching: combine `<Suspense>` with data cache for instant page transitions
297
- - React Compiler adoption: enable gradually, check for unsafe patterns first
298
-
299
- ## Decision Flow
300
-
301
- When implementing a React feature:
302
-
303
- 1. **Server or Client?** → If it uses browser APIs, event handlers, or useState → Client. Everything else → Server.
304
- 2. **Data fetching?** → Server Component for initial data. SWR/React Query for client-side mutations.
305
- 3. **Form?** → Server Action + `useActionState` + Zod validation.
306
- 4. **Optimistic?** → `useOptimistic` for instant feedback.
307
- 5. **Loading?** → `<Suspense>` with skeleton fallback.
308
- 6. **Performance?** → Try React Compiler first. Then manual memo. Then virtualization. Then code splitting.
309
- 7. **Error?** → Error boundaries for rendering errors. try/catch for Server Actions.
1
+ ---
2
+ name: react
3
+ description: "Comprehensive React development patterns — component architecture, React 19 APIs, Server Components, TypeScript integration, and performance optimization."
4
+ metadata:
5
+ category: domain
6
+ domain: react
7
+ applicability: on-demand
8
+ inputs: [codebase, requirements]
9
+ outputs: [component-patterns, code]
10
+ relatedSkills: [typescript, frontend-design]
11
+ ---
12
+
13
+ # React
14
+
15
+ > Comprehensive React development patterns — component architecture, React 19 APIs, Server Components, TypeScript integration, and performance optimization. Synthesized from react-dev patterns, react-patterns (React 19), and Vercel React best practices.
16
+
17
+ ## When to Use
18
+
19
+ **MANDATORY** for the Frontend agent on every React task. Also use when:
20
+ - Building React components, hooks, or pages
21
+ - Working with Server Components or Server Actions
22
+ - Optimizing React performance (re-renders, bundle size, data fetching)
23
+ - Reviewing React code for correctness and best practices
24
+
25
+ ## React 19 Quick Reference
26
+
27
+ | API | Use Case | Key Change |
28
+ |-----|----------|------------|
29
+ | `ref` as prop | Access DOM/component instance | No more `forwardRef` wrapper |
30
+ | `use()` | Read promises/context in render | Replaces `useContext`, enables async |
31
+ | `useActionState` | Form submission state + error | Replaces `useFormState` |
32
+ | `useOptimistic` | Instant UI feedback | Optimistic updates before server confirms |
33
+ | `useTransition` | Non-urgent state updates | `isPending` for loading states |
34
+ | `<form action>` | Server Actions in forms | Direct server function binding |
35
+ | Server Components | Zero-bundle components | Default in App Router, no `"use client"` |
36
+ | Server Actions | Server mutations | `"use server"` functions, form actions |
37
+
38
+ ## Component Patterns
39
+
40
+ ### Extend Native Elements
41
+ ```tsx
42
+ type ButtonProps = React.ComponentProps<"button"> & {
43
+ variant?: "primary" | "secondary" | "ghost";
44
+ size?: "sm" | "md" | "lg";
45
+ };
46
+
47
+ function Button({ variant = "primary", size = "md", className, ...props }: ButtonProps) {
48
+ return <button className={cn(variants[variant], sizes[size], className)} {...props} />;
49
+ }
50
+ ```
51
+
52
+ ### Discriminated Union Props
53
+ ```tsx
54
+ type ModalProps =
55
+ | { variant: "alert"; message: string; onConfirm: () => void }
56
+ | { variant: "form"; children: React.ReactNode; onSubmit: (data: FormData) => void };
57
+
58
+ function Modal(props: ModalProps) {
59
+ switch (props.variant) {
60
+ case "alert": return <AlertModal {...props} />;
61
+ case "form": return <FormModal {...props} />;
62
+ }
63
+ }
64
+ ```
65
+
66
+ ### Generic Components
67
+ ```tsx
68
+ type TableProps<T> = {
69
+ data: T[];
70
+ columns: { key: keyof T; header: string; render?: (value: T[keyof T], row: T) => React.ReactNode }[];
71
+ onRowClick?: (row: T) => void;
72
+ };
73
+
74
+ function Table<T extends Record<string, unknown>>({ data, columns, onRowClick }: TableProps<T>) {
75
+ // ...
76
+ }
77
+ ```
78
+
79
+ ### Children Typing
80
+ ```tsx
81
+ // Specific children
82
+ type Props = { children: React.ReactElement<TabProps>[] };
83
+
84
+ // Render function children
85
+ type Props = { children: (data: T) => React.ReactNode };
86
+
87
+ // String only
88
+ type Props = { children: string };
89
+ ```
90
+
91
+ ## Ref as Prop (React 19)
92
+
93
+ ```tsx
94
+ // React 19: pass ref directly, no forwardRef needed
95
+ function Input({ ref, ...props }: React.ComponentProps<"input">) {
96
+ return <input ref={ref} {...props} />;
97
+ }
98
+
99
+ // Cleanup function (new in React 19)
100
+ function MeasuredDiv({ ref, ...props }: React.ComponentProps<"div">) {
101
+ return (
102
+ <div
103
+ ref={(node) => {
104
+ if (node) measureElement(node);
105
+ return () => cleanupMeasurement(); // cleanup on unmount
106
+ }}
107
+ {...props}
108
+ />
109
+ );
110
+ }
111
+ ```
112
+
113
+ ## Server Components & Actions
114
+
115
+ ### Server Component (default — no directive needed)
116
+ ```tsx
117
+ // app/users/page.tsx — Server Component (default)
118
+ import { db } from "@/lib/db";
119
+
120
+ export default async function UsersPage() {
121
+ const users = await db.query.users.findMany(); // Direct DB access
122
+ return <UserList users={users} />; // Pass data to client
123
+ }
124
+ ```
125
+
126
+ ### Client Component (explicit opt-in)
127
+ ```tsx
128
+ "use client";
129
+ import { useState, useOptimistic, useTransition } from "react";
130
+
131
+ export function Counter({ initialCount }: { initialCount: number }) {
132
+ const [count, setCount] = useState(initialCount);
133
+ return <button onClick={() => setCount(c => c + 1)}>{count}</button>;
134
+ }
135
+ ```
136
+
137
+ ### Server Action with Form
138
+ ```tsx
139
+ // actions.ts
140
+ "use server";
141
+ import { z } from "zod";
142
+
143
+ const schema = z.object({ name: z.string().min(1), email: z.string().email() });
144
+
145
+ export async function createUser(_prev: unknown, formData: FormData) {
146
+ const result = schema.safeParse(Object.fromEntries(formData));
147
+ if (!result.success) return { error: result.error.flatten().fieldErrors };
148
+ await db.insert(users).values(result.data);
149
+ return { success: true };
150
+ }
151
+ ```
152
+
153
+ ```tsx
154
+ "use client";
155
+ import { useActionState } from "react";
156
+ import { createUser } from "./actions";
157
+
158
+ export function CreateUserForm() {
159
+ const [state, action, isPending] = useActionState(createUser, null);
160
+ return (
161
+ <form action={action}>
162
+ <input name="name" required />
163
+ {state?.error?.name && <p className="text-red-500">{state.error.name}</p>}
164
+ <input name="email" type="email" required />
165
+ {state?.error?.email && <p className="text-red-500">{state.error.email}</p>}
166
+ <button disabled={isPending}>{isPending ? "Creating..." : "Create"}</button>
167
+ </form>
168
+ );
169
+ }
170
+ ```
171
+
172
+ ### Optimistic Updates
173
+ ```tsx
174
+ "use client";
175
+ import { useOptimistic } from "react";
176
+
177
+ function TodoList({ todos, addTodo }: { todos: Todo[]; addTodo: (text: string) => Promise<void> }) {
178
+ const [optimisticTodos, addOptimistic] = useOptimistic(
179
+ todos,
180
+ (state, newTodo: string) => [...state, { id: "temp", text: newTodo, pending: true }]
181
+ );
182
+
183
+ async function handleAdd(formData: FormData) {
184
+ const text = formData.get("text") as string;
185
+ addOptimistic(text);
186
+ await addTodo(text);
187
+ }
188
+
189
+ return (
190
+ <form action={handleAdd}>
191
+ <input name="text" />
192
+ <button type="submit">Add</button>
193
+ <ul>
194
+ {optimisticTodos.map(t => (
195
+ <li key={t.id} style={{ opacity: t.pending ? 0.5 : 1 }}>{t.text}</li>
196
+ ))}
197
+ </ul>
198
+ </form>
199
+ );
200
+ }
201
+ ```
202
+
203
+ ## Event Handler Types
204
+
205
+ ```tsx
206
+ // Always use specific event types
207
+ onClick: (e: React.MouseEvent<HTMLButtonElement>) => void
208
+ onChange: (e: React.ChangeEvent<HTMLInputElement>) => void
209
+ onSubmit: (e: React.FormEvent<HTMLFormElement>) => void
210
+ onKeyDown: (e: React.KeyboardEvent<HTMLInputElement>) => void
211
+ onFocus: (e: React.FocusEvent<HTMLInputElement>) => void
212
+ onDrag: (e: React.DragEvent<HTMLDivElement>) => void
213
+ ```
214
+
215
+ ## Hooks Typing
216
+
217
+ ```tsx
218
+ // useState with union
219
+ const [status, setStatus] = useState<"idle" | "loading" | "error">("idle");
220
+
221
+ // useRef for DOM — pass null, get RefObject
222
+ const inputRef = useRef<HTMLInputElement>(null);
223
+
224
+ // useRef for mutable value — no null, get MutableRefObject
225
+ const intervalRef = useRef<number>(0);
226
+
227
+ // useReducer with discriminated actions
228
+ type Action = { type: "increment" } | { type: "set"; payload: number };
229
+ const [count, dispatch] = useReducer((state: number, action: Action) => {
230
+ switch (action.type) {
231
+ case "increment": return state + 1;
232
+ case "set": return action.payload;
233
+ }
234
+ }, 0);
235
+
236
+ // Custom hook: return as const for tuple types
237
+ function useToggle(initial = false) {
238
+ const [value, setValue] = useState(initial);
239
+ const toggle = useCallback(() => setValue(v => !v), []);
240
+ return [value, toggle] as const;
241
+ }
242
+
243
+ // useContext with null guard
244
+ const ctx = useContext(ThemeContext);
245
+ if (!ctx) throw new Error("useTheme must be used within ThemeProvider");
246
+ ```
247
+
248
+ ## Performance Rules
249
+
250
+ ### Prevent Async Waterfalls
251
+ ```tsx
252
+ // BAD — sequential fetching
253
+ const user = await getUser(id);
254
+ const posts = await getPosts(user.id); // Waits for user first
255
+ const comments = await getComments(posts[0].id); // Waits for posts
256
+
257
+ // GOOD — parallel where possible
258
+ const [user, posts] = await Promise.all([getUser(id), getPosts(id)]);
259
+ ```
260
+
261
+ ### Bundle Size
262
+ - `dynamic(() => import("./HeavyComponent"))` — lazy load below-fold components
263
+ - Tree-shake: use named exports, avoid `import *`
264
+ - Analyze bundle: `@next/bundle-analyzer` to find bloat
265
+ - Code-split by route — each page loads only its own JS
266
+ - Avoid importing entire libraries: `import { debounce } from "lodash-es"` not `import _ from "lodash"`
267
+
268
+ ### Server-Side Performance
269
+ - Default to Server Components — zero JS shipped to client
270
+ - Stream with Suspense: wrap slow data fetchers in `<Suspense fallback={<Skeleton />}>`
271
+ - Cache expensive computations with `"use cache"` directive
272
+ - Avoid serializing large objects across server/client boundary
273
+
274
+ ### Client-Side Data Fetching
275
+ - Use SWR or React Query — automatic caching, revalidation, error retry
276
+ - Stale-while-revalidate: show cached data instantly, refresh in background
277
+ - Error boundaries: `<ErrorBoundary>` wrapping data-dependent trees
278
+ - Prefetch on hover/viewport for likely next navigations
279
+
280
+ ### Re-render Optimization
281
+ - React Compiler (React 19): auto-memoizes — try this first before manual `useMemo`/`useCallback`
282
+ - If no compiler: `useMemo` for expensive computations, `useCallback` for stable function references
283
+ - Extract static JSX outside components — constants don't re-create
284
+ - Split context: separate frequently-changing state from rarely-changing state
285
+ - `React.memo()` on components receiving only primitive props
286
+
287
+ ### Rendering Performance
288
+ - **Virtualize** lists > 100 items: `@tanstack/react-virtual`, `react-window`
289
+ - Defer heavy computations with `useDeferredValue`
290
+ - Batch state updates (React 18+ does this automatically in event handlers)
291
+ - Avoid reading DOM layout during renders (force sync layout = jank)
292
+
293
+ ### Advanced Patterns
294
+ - Progressive hydration: load and hydrate components as they enter viewport
295
+ - Concurrent features: `useTransition` for non-blocking state updates
296
+ - Suspense caching: combine `<Suspense>` with data cache for instant page transitions
297
+ - React Compiler adoption: enable gradually, check for unsafe patterns first
298
+
299
+ ## Decision Flow
300
+
301
+ When implementing a React feature:
302
+
303
+ 1. **Server or Client?** → If it uses browser APIs, event handlers, or useState → Client. Everything else → Server.
304
+ 2. **Data fetching?** → Server Component for initial data. SWR/React Query for client-side mutations.
305
+ 3. **Form?** → Server Action + `useActionState` + Zod validation.
306
+ 4. **Optimistic?** → `useOptimistic` for instant feedback.
307
+ 5. **Loading?** → `<Suspense>` with skeleton fallback.
308
+ 6. **Performance?** → Try React Compiler first. Then manual memo. Then virtualization. Then code splitting.
309
+ 7. **Error?** → Error boundaries for rendering errors. try/catch for Server Actions.
@@ -2,12 +2,12 @@
2
2
  name: requirements-clarity
3
3
  description: Clarify ambiguous requirements through focused dialogue before implementation. Use when requirements are unclear, features are complex (>2 days), or involve cross-team coordination. Ask two core questions - Why? (YAGNI check) and Simpler? (KISS check) - to ensure clarity before coding.
4
4
  metadata:
5
- category: cross-cutting
6
- domain: general
7
- applicability: on-demand
8
- inputs: [requirements]
9
- outputs: [scored-requirements, clarifications]
10
- relatedSkills: [brainstorming]
5
+ category: cross-cutting
6
+ domain: general
7
+ applicability: on-demand
8
+ inputs: [requirements]
9
+ outputs: [scored-requirements, clarifications]
10
+ relatedSkills: [brainstorming]
11
11
  ---
12
12
 
13
13
  # Requirements Clarity Skill
@@ -2,13 +2,13 @@
2
2
  name: session-handoff
3
3
  description: "Creates comprehensive handoff documents for seamless AI agent session transfers. Triggered when: (1) user requests handoff/memory/context save, (2) context window approaches capacity, (3) major task milestone completed, (4) work session ending, (5) user says 'save state', 'create handoff', 'I need to pause', 'context is getting full', (6) resuming work with 'load handoff', 'resume from', 'continue where we left off'. Proactively suggests handoffs after substantial work (multiple file edits, complex debugging, architecture decisions). Solves long-running agent context exhaustion by enabling fresh agents to continue with zero ambiguity."
4
4
  metadata:
5
- category: cross-cutting
6
- domain: general
7
- applicability: always
8
- inputs: [session-state, decisions]
9
- outputs: [handoff-document]
10
- requires: [aikit]
11
- relatedSkills: [lesson-learned]
5
+ category: cross-cutting
6
+ domain: general
7
+ applicability: always
8
+ inputs: [session-state, decisions]
9
+ outputs: [handoff-document]
10
+ requires: [aikit]
11
+ relatedSkills: [lesson-learned]
12
12
  ---
13
13
 
14
14
  # Handoff