Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Baseline cross-project coding conventions for naming, readability, immutability, and code-quality review. Use detailed frontend or backend skills for framework-specific patterns.
.claude/skills/heidihowilson-coding-standards/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-06 | ✗→✓ | ▲ Improved | 134% | 0% |
| case-10 | ✗→✓ | ▲ Improved | 115% | 0% |
| case-02 | ✓→✓ | = Same ✓ | 168% | 0% |
| case-11 | ✓→✓ | = Same ✓ | 195% | 0% |
| case-12 | ✓→✓ | = Same ✓ | 193% | 0% |
Baseline coding conventions applicable across projects.
This skill is the shared floor, not the detailed framework playbook.
frontend-patterns for React, state, forms, rendering, and UI architecture.backend-patterns or api-design for repository/service layers, endpoint design, validation, and server-specific concerns.rules/common/coding-style.md when you need the shortest reusable rule layer instead of a full skill walkthrough.Activate this skill for:
Do not use this skill as the primary source for:
typescript// PASS: GOOD: Descriptive names const marketSearchQuery = 'election' const isUserAuthenticated = true const totalRevenue = 1000 // FAIL: BAD: Unclear names const q = 'election' const flag = true const x = 1000
typescript// PASS: GOOD: Verb-noun pattern async function fetchMarketData(marketId: string) { } function calculateSimilarity(a: number[], b: number[]) { } function isValidEmail(email: string): boolean { } // FAIL: BAD: Unclear or noun-only async function market(id: string) { } function similarity(a, b) { } function email(e) { }
typescript// PASS: ALWAYS use spread operator const updatedUser = { ...user, name: 'New Name' } const updatedArray = [...items, newItem] // FAIL: NEVER mutate directly user.name = 'New Name' // BAD items.push(newItem) // BAD
typescript// PASS: GOOD: Comprehensive error handling async function fetchData(url: string) { try { const response = await fetch(url) if (!response.ok) { throw new Error(`HTTP ${response.status}: ${response.statusText}`) } return await response.json() } catch (error) { console.error('Fetch failed:', error) throw new Error('Failed to fetch data') } } // FAIL: BAD: No error handling async function fetchData(url) { const response = await fetch(url) return response.json() }
typescript// PASS: GOOD: Parallel execution when possible const [users, markets, stats] = await Promise.all([ fetchUsers(), fetchMarkets(), fetchStats() ]) // FAIL: BAD: Sequential when unnecessary const users = await fetchUsers() const markets = await fetchMarkets() const stats = await fetchStats()
typescript// PASS: GOOD: Proper types interface Market { id: string name: string status: 'active' | 'resolved' | 'closed' created_at: Date } function getMarket(id: string): Promise<Market> { // Implementation } // FAIL: BAD: Using 'any' function getMarket(id: any): Promise<any> { // Implementation }
typescript// PASS: GOOD: Functional component with types interface ButtonProps { children: React.ReactNode onClick: () => void disabled?: boolean variant?: 'primary' | 'secondary' } export function Button({ children, onClick, disabled = false, variant = 'primary' }: ButtonProps) { return ( <button onClick={onClick} disabled={disabled} className={`btn btn-${variant}`} > {children} </button> ) } // FAIL: BAD: No types, unclear structure export function Button(props) { return <button onClick={props.onClick}>{props.children}</button> }
typescript// PASS: GOOD: Reusable custom hook export function useDebounce<T>(value: T, delay: number): T { const [debouncedValue, setDebouncedValue] = useState<T>(value) useEffect(() => { const handler = setTimeout(() => { setDebouncedValue(value) }, delay) return () => clearTimeout(handler) }, [value, delay]) return debouncedValue } // Usage const debouncedQuery = useDebounce(searchQuery, 500)
typescript// PASS: GOOD: Proper state updates const [count, setCount] = useState(0) // Functional update for state based on previous state setCount(prev => prev + 1) // FAIL: BAD: Direct state reference setCount(count + 1) // Can be stale in async scenarios
typescript// PASS: GOOD: Clear conditional rendering {isLoading && <Spinner />} {error && <ErrorMessage error={error} />} {data && <DataDisplay data={data} />} // FAIL: BAD: Ternary hell {isLoading ? <Spinner /> : error ? <ErrorMessage error={error} /> : data ? <DataDisplay data={data} /> : null}
GET /api/markets # List all markets
GET /api/markets/:id # Get specific market
POST /api/markets # Create new market
PUT /api/markets/:id # Update market (full)
PATCH /api/markets/:id # Update market (partial)
DELETE /api/markets/:id # Delete market
# Query parameters for filtering
GET /api/markets?status=active&limit=10&offset=0typescript// PASS: GOOD: Consistent response structure interface ApiResponse<T> { success: boolean data?: T error?: string meta?: { total: number page: number limit: number } } // Success response return NextResponse.json({ success: true, data: markets, meta: { total: 100, page: 1, limit: 10 } }) // Error response return NextResponse.json({ success: false, error: 'Invalid request' }, { status: 400 })
typescriptimport { z } from 'zod' // PASS: GOOD: Schema validation const CreateMarketSchema = z.object({ name: z.string().min(1).max(200), description: z.string().min(1).max(2000), endDate: z.string().datetime(), categories: z.array(z.string()).min(1) }) export async function POST(request: Request) { const body = await request.json() try { const validated = CreateMarketSchema.parse(body) // Proceed with validated data } catch (error) { if (error instanceof z.ZodError) { return NextResponse.json({ success: false, error: 'Validation failed', details: error.errors }, { status: 400 }) } } }
src/
├── app/ # Next.js App Router
│ ├── api/ # API routes
│ ├── markets/ # Market pages
│ └── (auth)/ # Auth pages (route groups)
├── components/ # React components
│ ├── ui/ # Generic UI components
│ ├── forms/ # Form components
│ └── layouts/ # Layout components
├── hooks/ # Custom React hooks
├── lib/ # Utilities and configs
│ ├── api/ # API clients
│ ├── utils/ # Helper functions
│ └── constants/ # Constants
├── types/ # TypeScript types
└── styles/ # Global stylescomponents/Button.tsx # PascalCase for components
hooks/useAuth.ts # camelCase with 'use' prefix
lib/formatDate.ts # camelCase for utilities
types/market.types.ts # camelCase with .types suffixtypescript// PASS: GOOD: Explain WHY, not WHAT // Use exponential backoff to avoid overwhelming the API during outages const delay = Math.min(1000 * Math.pow(2, retryCount), 30000) // Deliberately using mutation here for performance with large arrays items.push(newItem) // FAIL: BAD: Stating the obvious // Increment counter by 1 count++ // Set name to user's name name = user.name
typescript/** * Searches markets using semantic similarity. * * @param query - Natural language search query * @param limit - Maximum number of results (default: 10) * @returns Array of markets sorted by similarity score * @throws {Error} If OpenAI API fails or Redis unavailable * * @example * ```typescript * const results = await searchMarkets('election', 5) * console.log(results[0].name) // "Trump vs Biden" * ``` */ export async function searchMarkets( query: string, limit: number = 10 ): Promise<Market[]> { // Implementation }
typescriptimport { useMemo, useCallback } from 'react' // PASS: GOOD: Memoize expensive computations const sortedMarkets = useMemo(() => { return markets.sort((a, b) => b.volume - a.volume) }, [markets]) // PASS: GOOD: Memoize callbacks const handleSearch = useCallback((query: string) => { setSearchQuery(query) }, [])
typescriptimport { lazy, Suspense } from 'react' // PASS: GOOD: Lazy load heavy components const HeavyChart = lazy(() => import('./HeavyChart')) export function Dashboard() { return ( <Suspense fallback={<Spinner />}> <HeavyChart /> </Suspense> ) }
typescript// PASS: GOOD: Select only needed columns const { data } = await supabase .from('markets') .select('id, name, status') .limit(10) // FAIL: BAD: Select everything const { data } = await supabase .from('markets') .select('*')
typescripttest('calculates similarity correctly', () => { // Arrange const vector1 = [1, 0, 0] const vector2 = [0, 1, 0] // Act const similarity = calculateCosineSimilarity(vector1, vector2) // Assert expect(similarity).toBe(0) })
typescript// PASS: GOOD: Descriptive test names test('returns empty array when no markets match query', () => { }) test('throws error when OpenAI API key is missing', () => { }) test('falls back to substring search when Redis unavailable', () => { }) // FAIL: BAD: Vague test names test('works', () => { }) test('test search', () => { })
Watch for these anti-patterns:
typescript// FAIL: BAD: Function > 50 lines function processMarketData() { // 100 lines of code } // PASS: GOOD: Split into smaller functions function processMarketData() { const validated = validateData() const transformed = transformData(validated) return saveData(transformed) }
typescript// FAIL: BAD: 5+ levels of nesting if (user) { if (user.isAdmin) { if (market) { if (market.isActive) { if (hasPermission) { // Do something } } } } } // PASS: GOOD: Early returns if (!user) return if (!user.isAdmin) return if (!market) return if (!market.isActive) return if (!hasPermission) return // Do something
typescript// FAIL: BAD: Unexplained numbers if (retryCount > 3) { } setTimeout(callback, 500) // PASS: GOOD: Named constants const MAX_RETRIES = 3 const DEBOUNCE_DELAY_MS = 500 if (retryCount > MAX_RETRIES) { } setTimeout(callback, DEBOUNCE_DELAY_MS)
Remember: Code quality is not negotiable. Clear, maintainable code enables rapid development and confident refactoring.
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-02 | pass→pass | 8,614 | 5,547 | -36% | 1 | 1 | 0% | 1,571 | 4,205 | +168% | 0 | 0 | — |
case-11 | pass→pass | 7,600 | 4,062 | -47% | 1 | 1 | 0% | 1,376 | 4,058 | +195% | 0 | 0 | — |
case-12 | pass→pass | 7,857 | 5,185 | -34% | 1 | 1 | 0% | 1,482 | 4,338 | +193% | 0 | 0 | — |
case-13 | pass→pass | 5,875 | 5,396 | -8% | 1 | 1 | 0% | 1,155 | 4,505 | +290% | 0 | 0 | — |
case-01 | pass→pass | 9,452 | 6,004 | -36% | 1 | 1 | 0% | 1,743 | 4,299 | +147% | 0 | 0 | — |
case-03 | pass→pass | 7,306 | 5,664 | -22% | 1 | 1 | 0% | 1,382 | 4,473 | +224% | 0 | 0 | — |
case-04 | pass→pass | 7,243 | 4,010 | -45% | 1 | 1 | 0% | 1,385 | 4,045 | +192% | 0 | 0 | — |
case-05 | pass→pass | 7,032 | 5,742 | -18% | 1 | 1 | 0% | 1,402 | 4,426 | +216% | 0 | 0 | — |
case-06 | fail→pass | 11,287 | 8,684 | -23% | 1 | 1 | 0% | 2,144 | 5,019 | +134% | 0 | 0 | — |
case-07 | pass→pass | 12,299 | 7,194 | -42% | 1 | 1 | 0% | 2,213 | 4,878 | +120% | 0 | 0 | — |
case-08 | pass→pass | 11,155 | 7,573 | -32% | 1 | 1 | 0% | 2,390 | 4,902 | +105% | 0 | 0 | — |
case-09 | pass→pass | 5,864 | 4,254 | -27% | 1 | 1 | 0% | 1,018 | 4,103 | +303% | 0 | 0 | — |
case-10 | fail→pass | 10,117 | 5,533 | -45% | 1 | 1 | 0% | 2,016 | 4,342 | +115% | 0 | 0 | — |
case-14 | pass→pass | 8,125 | 5,941 | -27% | 1 | 1 | 0% | 1,485 | 4,481 | +202% | 0 | 0 | — |
case-15 | pass→pass | 7,887 | 5,614 | -29% | 1 | 1 | 0% | 1,469 | 4,421 | +201% | 0 | 0 | — |
case-16 | pass→pass | 3,606 | 3,394 | -6% | 1 | 1 | 0% | 641 | 3,852 | +501% | 0 | 0 | — |
case-17 | pass→pass | 10,723 | 3,943 | -63% | 1 | 1 | 0% | 1,844 | 4,148 | +125% | 0 | 0 | — |
case-18 | pass→pass | 7,761 | 3,492 | -55% | 1 | 1 | 0% | 1,409 | 4,056 | +188% | 0 | 0 | — |
case-19 | pass→pass | 9,000 | 5,750 | -36% | 1 | 1 | 0% | 1,604 | 4,345 | +171% | 0 | 0 | — |
case-20 | pass→pass | 23,713 | 23,425 | -1% | 1 | 1 | 0% | 4,935 | 8,333 | +69% | 0 | 0 | — |
case-21 | pass→pass | 25,277 | 24,282 | -4% | 1 | 1 | 0% | 4,856 | 8,781 | +81% | 0 | 0 | — |
case-22 | pass→pass | 16,329 | 12,906 | -21% | 1 | 1 | 0% | 3,373 | 6,011 | +78% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +9 percentage points is the difference between those two pass rates over the 22 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.