beads-orchestration 2.0.0

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.
Files changed (40) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +214 -0
  3. package/SKILL.md +263 -0
  4. package/bootstrap.py +928 -0
  5. package/package.json +37 -0
  6. package/scripts/cli.js +64 -0
  7. package/scripts/postinstall.js +71 -0
  8. package/skills/create-beads-orchestration/SKILL.md +263 -0
  9. package/skills/subagents-discipline/SKILL.md +158 -0
  10. package/templates/CLAUDE.md +326 -0
  11. package/templates/agents/architect.md +121 -0
  12. package/templates/agents/code-reviewer.md +248 -0
  13. package/templates/agents/detective.md +101 -0
  14. package/templates/agents/discovery.md +492 -0
  15. package/templates/agents/merge-supervisor.md +119 -0
  16. package/templates/agents/scout.md +100 -0
  17. package/templates/agents/scribe.md +96 -0
  18. package/templates/beads-workflow-injection-api.md +116 -0
  19. package/templates/beads-workflow-injection-git.md +108 -0
  20. package/templates/beads-workflow-injection.md +111 -0
  21. package/templates/frontend-reviews-requirement.md +61 -0
  22. package/templates/hooks/block-orchestrator-tools.sh +98 -0
  23. package/templates/hooks/clarify-vague-request.sh +39 -0
  24. package/templates/hooks/enforce-bead-for-supervisor.sh +32 -0
  25. package/templates/hooks/enforce-branch-before-edit.sh +47 -0
  26. package/templates/hooks/enforce-concise-response.sh +41 -0
  27. package/templates/hooks/enforce-sequential-dispatch.sh +63 -0
  28. package/templates/hooks/inject-discipline-reminder.sh +28 -0
  29. package/templates/hooks/log-dispatch-prompt.sh +39 -0
  30. package/templates/hooks/memory-capture.sh +104 -0
  31. package/templates/hooks/remind-inprogress.sh +14 -0
  32. package/templates/hooks/session-start.sh +121 -0
  33. package/templates/hooks/validate-completion.sh +131 -0
  34. package/templates/hooks/validate-epic-close.sh +84 -0
  35. package/templates/mcp.json.template +12 -0
  36. package/templates/memory/recall.sh +121 -0
  37. package/templates/settings.json +74 -0
  38. package/templates/skills/react-best-practices/SKILL.md +487 -0
  39. package/templates/skills/subagents-discipline/SKILL.md +127 -0
  40. package/templates/ui-constraints.md +76 -0
@@ -0,0 +1,487 @@
1
+ ---
2
+ name: react-best-practices
3
+ description: React and Next.js performance optimization patterns. Use BEFORE implementing any React code to ensure best practices are followed.
4
+ ---
5
+
6
+ # React Best Practices
7
+
8
+ **Version 1.0.0**
9
+ Source: Vercel Engineering (vercel-labs/agent-skills)
10
+
11
+ > **Note:**
12
+ > This document is for agents and LLMs to follow when maintaining,
13
+ > generating, or refactoring React and Next.js codebases. Contains 40+ rules across 8 categories, prioritized by impact.
14
+
15
+ ---
16
+
17
+ ## How to Use This Skill
18
+
19
+ **Before implementing ANY React/Next.js code:**
20
+
21
+ 1. Review the relevant sections based on what you're building
22
+ 2. Apply the patterns as you write code
23
+ 3. Use the "Incorrect" vs "Correct" examples as templates
24
+
25
+ **Priority order:** Eliminating Waterfalls > Bundle Size > Server-Side > Client-Side > Re-renders > Rendering > JS Perf > Advanced
26
+
27
+ ---
28
+
29
+ ## Quick Reference: Critical Rules
30
+
31
+ ### Top 5 Rules (Always Apply)
32
+
33
+ 1. **Promise.all() for independent operations** - Never sequential awaits for independent data
34
+ 2. **Avoid barrel file imports** - Import directly from source files
35
+ 3. **Dynamic imports for heavy components** - Lazy-load Monaco, charts, etc.
36
+ 4. **Parallel data fetching with component composition** - Structure RSC for parallelism
37
+ 5. **Minimize serialization at RSC boundaries** - Only pass needed fields to client
38
+
39
+ ---
40
+
41
+ ## 1. Eliminating Waterfalls
42
+
43
+ **Impact: CRITICAL** - Waterfalls are the #1 performance killer.
44
+
45
+ ### 1.1 Defer Await Until Needed
46
+
47
+ Move `await` into branches where actually used.
48
+
49
+ ```typescript
50
+ // BAD: blocks both branches
51
+ async function handleRequest(userId: string, skipProcessing: boolean) {
52
+ const userData = await fetchUserData(userId)
53
+ if (skipProcessing) return { skipped: true }
54
+ return processUserData(userData)
55
+ }
56
+
57
+ // GOOD: only blocks when needed
58
+ async function handleRequest(userId: string, skipProcessing: boolean) {
59
+ if (skipProcessing) return { skipped: true }
60
+ const userData = await fetchUserData(userId)
61
+ return processUserData(userData)
62
+ }
63
+ ```
64
+
65
+ ### 1.2 Promise.all() for Independent Operations
66
+
67
+ ```typescript
68
+ // BAD: 3 round trips
69
+ const user = await fetchUser()
70
+ const posts = await fetchPosts()
71
+ const comments = await fetchComments()
72
+
73
+ // GOOD: 1 round trip
74
+ const [user, posts, comments] = await Promise.all([
75
+ fetchUser(),
76
+ fetchPosts(),
77
+ fetchComments()
78
+ ])
79
+ ```
80
+
81
+ ### 1.3 Strategic Suspense Boundaries
82
+
83
+ ```tsx
84
+ // BAD: wrapper blocked by data
85
+ async function Page() {
86
+ const data = await fetchData()
87
+ return (
88
+ <div>
89
+ <Sidebar />
90
+ <DataDisplay data={data} />
91
+ <Footer />
92
+ </div>
93
+ )
94
+ }
95
+
96
+ // GOOD: wrapper shows immediately
97
+ function Page() {
98
+ return (
99
+ <div>
100
+ <Sidebar />
101
+ <Suspense fallback={<Skeleton />}>
102
+ <DataDisplay />
103
+ </Suspense>
104
+ <Footer />
105
+ </div>
106
+ )
107
+ }
108
+ ```
109
+
110
+ ---
111
+
112
+ ## 2. Bundle Size Optimization
113
+
114
+ **Impact: CRITICAL** - Reduces TTI and LCP.
115
+
116
+ ### 2.1 Avoid Barrel File Imports
117
+
118
+ ```tsx
119
+ // BAD: loads 1,583 modules
120
+ import { Check, X, Menu } from 'lucide-react'
121
+
122
+ // GOOD: loads only 3 modules
123
+ import Check from 'lucide-react/dist/esm/icons/check'
124
+ import X from 'lucide-react/dist/esm/icons/x'
125
+ import Menu from 'lucide-react/dist/esm/icons/menu'
126
+
127
+ // ALTERNATIVE: Next.js 13.5+ config
128
+ // next.config.js
129
+ module.exports = {
130
+ experimental: {
131
+ optimizePackageImports: ['lucide-react', '@mui/material']
132
+ }
133
+ }
134
+ ```
135
+
136
+ ### 2.2 Dynamic Imports for Heavy Components
137
+
138
+ ```tsx
139
+ // BAD: Monaco bundles with main chunk (~300KB)
140
+ import { MonacoEditor } from './monaco-editor'
141
+
142
+ // GOOD: Monaco loads on demand
143
+ import dynamic from 'next/dynamic'
144
+ const MonacoEditor = dynamic(
145
+ () => import('./monaco-editor').then(m => m.MonacoEditor),
146
+ { ssr: false }
147
+ )
148
+ ```
149
+
150
+ ### 2.3 Defer Non-Critical Libraries
151
+
152
+ ```tsx
153
+ // BAD: blocks initial bundle
154
+ import { Analytics } from '@vercel/analytics/react'
155
+
156
+ // GOOD: loads after hydration
157
+ import dynamic from 'next/dynamic'
158
+ const Analytics = dynamic(
159
+ () => import('@vercel/analytics/react').then(m => m.Analytics),
160
+ { ssr: false }
161
+ )
162
+ ```
163
+
164
+ ### 2.4 Preload on User Intent
165
+
166
+ ```tsx
167
+ function EditorButton({ onClick }: { onClick: () => void }) {
168
+ const preload = () => {
169
+ if (typeof window !== 'undefined') {
170
+ void import('./monaco-editor')
171
+ }
172
+ }
173
+ return (
174
+ <button onMouseEnter={preload} onFocus={preload} onClick={onClick}>
175
+ Open Editor
176
+ </button>
177
+ )
178
+ }
179
+ ```
180
+
181
+ ---
182
+
183
+ ## 3. Server-Side Performance
184
+
185
+ **Impact: HIGH**
186
+
187
+ ### 3.1 Minimize Serialization at RSC Boundaries
188
+
189
+ ```tsx
190
+ // BAD: serializes all 50 fields
191
+ async function Page() {
192
+ const user = await fetchUser() // 50 fields
193
+ return <Profile user={user} />
194
+ }
195
+
196
+ // GOOD: serializes only needed fields
197
+ async function Page() {
198
+ const user = await fetchUser()
199
+ return <Profile name={user.name} avatar={user.avatar} />
200
+ }
201
+ ```
202
+
203
+ ### 3.2 Parallel Data Fetching with Component Composition
204
+
205
+ ```tsx
206
+ // BAD: Sidebar waits for Header's fetch
207
+ export default async function Page() {
208
+ const header = await fetchHeader()
209
+ return (
210
+ <div>
211
+ <div>{header}</div>
212
+ <Sidebar />
213
+ </div>
214
+ )
215
+ }
216
+
217
+ // GOOD: both fetch simultaneously
218
+ async function Header() {
219
+ const data = await fetchHeader()
220
+ return <div>{data}</div>
221
+ }
222
+
223
+ async function Sidebar() {
224
+ const items = await fetchSidebarItems()
225
+ return <nav>{items.map(renderItem)}</nav>
226
+ }
227
+
228
+ export default function Page() {
229
+ return (
230
+ <div>
231
+ <Header />
232
+ <Sidebar />
233
+ </div>
234
+ )
235
+ }
236
+ ```
237
+
238
+ ### 3.3 Per-Request Deduplication with React.cache()
239
+
240
+ ```typescript
241
+ import { cache } from 'react'
242
+
243
+ export const getCurrentUser = cache(async () => {
244
+ const session = await auth()
245
+ if (!session?.user?.id) return null
246
+ return await db.user.findUnique({ where: { id: session.user.id } })
247
+ })
248
+ ```
249
+
250
+ ### 3.4 Use after() for Non-Blocking Operations
251
+
252
+ ```tsx
253
+ import { after } from 'next/server'
254
+
255
+ export async function POST(request: Request) {
256
+ await updateDatabase(request)
257
+
258
+ // Log after response is sent
259
+ after(async () => {
260
+ const userAgent = (await headers()).get('user-agent')
261
+ logUserAction({ userAgent })
262
+ })
263
+
264
+ return Response.json({ status: 'success' })
265
+ }
266
+ ```
267
+
268
+ ---
269
+
270
+ ## 4. Client-Side Data Fetching
271
+
272
+ **Impact: MEDIUM-HIGH**
273
+
274
+ ### 4.1 Use SWR for Automatic Deduplication
275
+
276
+ ```tsx
277
+ // BAD: no deduplication
278
+ function UserList() {
279
+ const [users, setUsers] = useState([])
280
+ useEffect(() => {
281
+ fetch('/api/users').then(r => r.json()).then(setUsers)
282
+ }, [])
283
+ }
284
+
285
+ // GOOD: multiple instances share one request
286
+ import useSWR from 'swr'
287
+ function UserList() {
288
+ const { data: users } = useSWR('/api/users', fetcher)
289
+ }
290
+ ```
291
+
292
+ ---
293
+
294
+ ## 5. Re-render Optimization
295
+
296
+ **Impact: MEDIUM**
297
+
298
+ ### 5.1 Use Functional setState Updates
299
+
300
+ ```tsx
301
+ // BAD: requires state as dependency, risk of stale closure
302
+ const addItems = useCallback((newItems: Item[]) => {
303
+ setItems([...items, ...newItems])
304
+ }, [items])
305
+
306
+ // GOOD: stable callback, no stale closures
307
+ const addItems = useCallback((newItems: Item[]) => {
308
+ setItems(curr => [...curr, ...newItems])
309
+ }, [])
310
+ ```
311
+
312
+ ### 5.2 Use Lazy State Initialization
313
+
314
+ ```tsx
315
+ // BAD: runs on every render
316
+ const [settings] = useState(JSON.parse(localStorage.getItem('settings') || '{}'))
317
+
318
+ // GOOD: runs only once
319
+ const [settings] = useState(() => {
320
+ const stored = localStorage.getItem('settings')
321
+ return stored ? JSON.parse(stored) : {}
322
+ })
323
+ ```
324
+
325
+ ### 5.3 Use Transitions for Non-Urgent Updates
326
+
327
+ ```tsx
328
+ import { startTransition } from 'react'
329
+
330
+ function ScrollTracker() {
331
+ const [scrollY, setScrollY] = useState(0)
332
+ useEffect(() => {
333
+ const handler = () => {
334
+ startTransition(() => setScrollY(window.scrollY))
335
+ }
336
+ window.addEventListener('scroll', handler, { passive: true })
337
+ return () => window.removeEventListener('scroll', handler)
338
+ }, [])
339
+ }
340
+ ```
341
+
342
+ ### 5.4 Narrow Effect Dependencies
343
+
344
+ ```tsx
345
+ // BAD: re-runs on any user field change
346
+ useEffect(() => {
347
+ console.log(user.id)
348
+ }, [user])
349
+
350
+ // GOOD: re-runs only when id changes
351
+ useEffect(() => {
352
+ console.log(user.id)
353
+ }, [user.id])
354
+ ```
355
+
356
+ ---
357
+
358
+ ## 6. Rendering Performance
359
+
360
+ **Impact: MEDIUM**
361
+
362
+ ### 6.1 CSS content-visibility for Long Lists
363
+
364
+ ```css
365
+ .message-item {
366
+ content-visibility: auto;
367
+ contain-intrinsic-size: 0 80px;
368
+ }
369
+ ```
370
+
371
+ ### 6.2 Hoist Static JSX Elements
372
+
373
+ ```tsx
374
+ // BAD: recreates element every render
375
+ function Container() {
376
+ return loading && <div className="animate-pulse h-20 bg-gray-200" />
377
+ }
378
+
379
+ // GOOD: reuses same element
380
+ const loadingSkeleton = <div className="animate-pulse h-20 bg-gray-200" />
381
+ function Container() {
382
+ return loading && loadingSkeleton
383
+ }
384
+ ```
385
+
386
+ ### 6.3 Animate SVG Wrapper, Not SVG Element
387
+
388
+ ```tsx
389
+ // BAD: no hardware acceleration
390
+ <svg className="animate-spin">...</svg>
391
+
392
+ // GOOD: hardware accelerated
393
+ <div className="animate-spin">
394
+ <svg>...</svg>
395
+ </div>
396
+ ```
397
+
398
+ ---
399
+
400
+ ## 7. JavaScript Performance
401
+
402
+ **Impact: LOW-MEDIUM**
403
+
404
+ ### 7.1 Build Index Maps for Repeated Lookups
405
+
406
+ ```typescript
407
+ // BAD: O(n) per lookup
408
+ items.filter(item => allowedIds.includes(item.id))
409
+
410
+ // GOOD: O(1) per lookup
411
+ const allowedSet = new Set(allowedIds)
412
+ items.filter(item => allowedSet.has(item.id))
413
+ ```
414
+
415
+ ### 7.2 Use toSorted() Instead of sort()
416
+
417
+ ```typescript
418
+ // BAD: mutates original array
419
+ const sorted = users.sort((a, b) => a.name.localeCompare(b.name))
420
+
421
+ // GOOD: creates new array
422
+ const sorted = users.toSorted((a, b) => a.name.localeCompare(b.name))
423
+ ```
424
+
425
+ ### 7.3 Early Return from Functions
426
+
427
+ ```typescript
428
+ // BAD: processes all items after finding error
429
+ function validateUsers(users: User[]) {
430
+ let hasError = false
431
+ for (const user of users) {
432
+ if (!user.email) hasError = true
433
+ }
434
+ return hasError ? { valid: false } : { valid: true }
435
+ }
436
+
437
+ // GOOD: returns immediately on first error
438
+ function validateUsers(users: User[]) {
439
+ for (const user of users) {
440
+ if (!user.email) return { valid: false, error: 'Email required' }
441
+ }
442
+ return { valid: true }
443
+ }
444
+ ```
445
+
446
+ ---
447
+
448
+ ## 8. Advanced Patterns
449
+
450
+ **Impact: LOW**
451
+
452
+ ### 8.1 useEffectEvent for Stable Callbacks
453
+
454
+ ```tsx
455
+ import { useEffectEvent } from 'react'
456
+
457
+ function useWindowEvent(event: string, handler: () => void) {
458
+ const onEvent = useEffectEvent(handler)
459
+ useEffect(() => {
460
+ window.addEventListener(event, onEvent)
461
+ return () => window.removeEventListener(event, onEvent)
462
+ }, [event])
463
+ }
464
+ ```
465
+
466
+ ---
467
+
468
+ ## Checklist Before Implementation
469
+
470
+ - [ ] Independent async operations use Promise.all()
471
+ - [ ] Heavy components use dynamic imports
472
+ - [ ] RSC boundaries pass only needed fields
473
+ - [ ] Suspense boundaries isolate data fetching
474
+ - [ ] No barrel file imports for large libraries
475
+ - [ ] State updates use functional form when depending on current state
476
+ - [ ] Effects have narrow dependencies
477
+ - [ ] Repeated lookups use Set/Map
478
+
479
+ ---
480
+
481
+ ## References
482
+
483
+ - [React Documentation](https://react.dev)
484
+ - [Next.js Documentation](https://nextjs.org)
485
+ - [SWR Documentation](https://swr.vercel.app)
486
+ - [Vercel Blog: Package Import Optimization](https://vercel.com/blog/how-we-optimized-package-imports-in-next-js)
487
+ - [Vercel Blog: Dashboard Performance](https://vercel.com/blog/how-we-made-the-vercel-dashboard-twice-as-fast)
@@ -0,0 +1,127 @@
1
+ ---
2
+ name: subagents-discipline
3
+ description: Core engineering principles for implementation tasks
4
+ ---
5
+
6
+ # Implementation Principles
7
+
8
+ ## Rule 0: Read the Bead First
9
+
10
+ Before implementing anything, **read the bead comments** for context:
11
+
12
+ ```bash
13
+ bd show {BEAD_ID}
14
+ bd comments {BEAD_ID}
15
+ ```
16
+
17
+ The orchestrator's dispatch prompt is automatically logged as a DISPATCH comment on the bead. This contains:
18
+ - The investigation findings
19
+ - Root cause analysis (file, function, line)
20
+ - Related files that may need changes
21
+ - Gotchas and edge cases
22
+
23
+ **Use this context.** Don't re-investigate. The comments contain everything you need to implement confidently.
24
+
25
+ If no dispatch or context comments exist, ask the orchestrator to provide context before proceeding.
26
+
27
+ ---
28
+
29
+ ## Rule 1: Look Before You Code
30
+
31
+ Before writing code that touches external data (API, database, file, config):
32
+
33
+ 1. **Fetch/read the ACTUAL data** - run the command, see the output
34
+ 2. **Note exact field names, types, formats** - not what docs say, what you SEE
35
+ 3. **Code against what you observed** - not what you assumed
36
+
37
+ ```
38
+ WITHOUT looking first:
39
+ Assumed: column is "reference_images"
40
+ Reality: column is "reference_image_url"
41
+ Result: Query fails
42
+
43
+ WITH looking first:
44
+ Ran: SELECT column_name FROM information_schema.columns WHERE table_name = 'assets';
45
+ Saw: reference_image_url
46
+ Coded against: reference_image_url
47
+ Result: Works
48
+ ```
49
+
50
+ ## Rule 2: Test Functionally (Close the Loop)
51
+
52
+ **Principle: Optimize for the fastest way to verify your work actually works.**
53
+
54
+ | You built | Fast verification | Slower alternative |
55
+ |-----------|------------------|--------------------|
56
+ | API endpoint | `curl` the endpoint, check response | Write integration test |
57
+ | Database change | Run migration, query the result | Write migration test |
58
+ | Frontend component | Load in browser, interact with it | Write component test |
59
+ | CLI tool | Run the command, check output | Write unit test |
60
+ | Config change | Restart service, verify behavior | N/A — just verify |
61
+
62
+ **Two strategies:**
63
+
64
+ 1. **User Journey Tests** — Test actual behavior as a user experiences it:
65
+ ```bash
66
+ # API: curl with real data
67
+ curl -X POST localhost:3000/api/users -d '{"name":"test"}' -H "Content-Type: application/json"
68
+
69
+ # CLI: run the command
70
+ bd create "Test" -d "Testing" && bd list
71
+
72
+ # Error case: curl with invalid auth
73
+ curl -X POST localhost:3000/api/users -H "Authorization: Bearer invalid"
74
+ ```
75
+
76
+ 2. **Component Tests** — Supplement for regression prevention when fast verification isn't possible:
77
+ - Complex logic with many edge cases
78
+ - Code that runs in environments you can't easily replicate
79
+ - Shared libraries used by multiple consumers
80
+
81
+ **"Close the Loop" principle:** Run the actual thing. Verify it works. Check error cases.
82
+
83
+ Good: "Curled endpoint with invalid auth, got 401 as expected"
84
+ Bad: "Wrote tests, they compile"
85
+
86
+ ## Rule 3: Use Your Tools
87
+
88
+ Before claiming you can't fully test:
89
+
90
+ 1. **Check what MCP servers you have access to** - list available tools
91
+ 2. **If any tool can help verify the feature works**, use it
92
+ 3. **Be resourceful** - browser automation, database inspection, API testing tools
93
+
94
+ ## Rule 4: Log Your Approach (Optional)
95
+
96
+ If you deviated from the orchestrator's suggestion, found a better path, or made a choice future maintainers might question:
97
+
98
+ ```bash
99
+ bd comment {BEAD_ID} "APPROACH: Used X instead of Y because Z"
100
+ ```
101
+
102
+ When to log:
103
+ - Deviated from the suggested fix
104
+ - Multiple valid solutions, chose one for a specific reason
105
+ - Future maintainers might question the approach
106
+
107
+ Skip if the code is self-explanatory. This is not enforced.
108
+
109
+ ---
110
+
111
+ ## For Epic Children
112
+
113
+ If your BEAD_ID contains a dot (e.g., BD-001.2), you're implementing part of a larger feature:
114
+
115
+ 1. **Check for design doc**: `bd show {EPIC_ID} --json | jq -r '.[0].design'`
116
+ 2. **Read it if it exists** - this is your contract
117
+ 3. **Match it exactly** - same field names, same types, same shapes
118
+
119
+ ---
120
+
121
+ ## Red Flags - Stop and Verify
122
+
123
+ When you catch yourself thinking:
124
+ - "This should work..." → run it and see
125
+ - "I assume the field is..." → look at the actual data
126
+ - "I'll test it later..." → test it now
127
+ - "It's too simple to break..." → verify anyway
@@ -0,0 +1,76 @@
1
+ # UI Constraints
2
+
3
+ Apply these opinionated constraints when building interfaces.
4
+
5
+ ## Stack
6
+
7
+ - MUST use Tailwind CSS defaults unless custom values already exist or are explicitly requested
8
+ - MUST use `motion/react` (formerly `framer-motion`) when JavaScript animation is required
9
+ - SHOULD use `tw-animate-css` for entrance and micro-animations in Tailwind CSS
10
+ - MUST use `cn` utility (`clsx` + `tailwind-merge`) for class logic
11
+
12
+ ## Components
13
+
14
+ - MUST use accessible component primitives for anything with keyboard or focus behavior (`Base UI`, `React Aria`, `Radix`)
15
+ - MUST use the project's existing component primitives first
16
+ - NEVER mix primitive systems within the same interaction surface
17
+ - SHOULD prefer [`Base UI`](https://base-ui.com/react/components) for new primitives if compatible with the stack
18
+ - MUST add an `aria-label` to icon-only buttons
19
+ - NEVER rebuild keyboard or focus behavior by hand unless explicitly requested
20
+
21
+ ## Interaction
22
+
23
+ - MUST use an `AlertDialog` for destructive or irreversible actions
24
+ - SHOULD use structural skeletons for loading states
25
+ - NEVER use `h-screen`, use `h-dvh`
26
+ - MUST respect `safe-area-inset` for fixed elements
27
+ - MUST show errors next to where the action happens
28
+ - NEVER block paste in `input` or `textarea` elements
29
+
30
+ ## Animation
31
+
32
+ - NEVER add animation unless it is explicitly requested
33
+ - MUST animate only compositor props (`transform`, `opacity`)
34
+ - NEVER animate layout properties (`width`, `height`, `top`, `left`, `margin`, `padding`)
35
+ - SHOULD avoid animating paint properties (`background`, `color`) except for small, local UI (text, icons)
36
+ - SHOULD use `ease-out` on entrance
37
+ - NEVER exceed `200ms` for interaction feedback
38
+ - MUST pause looping animations when off-screen
39
+ - SHOULD respect `prefers-reduced-motion`
40
+ - NEVER introduce custom easing curves unless explicitly requested
41
+ - SHOULD avoid animating large images or full-screen surfaces
42
+
43
+ ## Typography
44
+
45
+ - MUST use `text-balance` for headings and `text-pretty` for body/paragraphs
46
+ - MUST use `tabular-nums` for data
47
+ - SHOULD use `truncate` or `line-clamp` for dense UI
48
+ - NEVER modify `letter-spacing` (`tracking-*`) unless explicitly requested
49
+
50
+ ## Layout
51
+
52
+ - MUST use a fixed `z-index` scale (no arbitrary `z-*`)
53
+ - SHOULD use `size-*` for square elements instead of `w-*` + `h-*`
54
+
55
+ ## Performance
56
+
57
+ - NEVER animate large `blur()` or `backdrop-filter` surfaces
58
+ - NEVER apply `will-change` outside an active animation
59
+ - NEVER use `useEffect` for anything that can be expressed as render logic
60
+
61
+ ## Design
62
+
63
+ - NEVER use gradients unless explicitly requested
64
+ - NEVER use purple or multicolor gradients
65
+ - NEVER use glow effects as primary affordances
66
+ - SHOULD use Tailwind CSS default shadow scale unless explicitly requested
67
+ - MUST give empty states one clear next action
68
+ - SHOULD limit accent color usage to one per view
69
+ - SHOULD use existing theme or Tailwind CSS color tokens before introducing new ones
70
+
71
+ ## Accessibility
72
+
73
+ - MUST meet WCAG AA color contrast (4.5:1 for text, 3:1 for large text/UI)
74
+ - MUST ensure all interactive elements are keyboard accessible
75
+ - SHOULD provide visible focus indicators
76
+ - MUST use semantic HTML elements where appropriate