conventions
Coding Conventions Skill
Overview
This skill centralizes general coding conventions and best practices that apply across multiple technologies and frameworks. It covers code organization, documentation, naming, and type import strategies.
Objective
Ensure consistent coding practices across the codebase regardless of technology stack. This skill delegates technology-specific conventions to their respective skills (e.g., TypeScript, React, MUI).
When to Use
Use this skill when:
- Establishing general code organization patterns
- Defining naming conventions across technologies
- Setting up documentation standards
- Creating project structure guidelines
- Reviewing code for general best practices
Don't use this skill for:
- Technology-specific patterns (use typescript, react, etc.)
- Accessibility rules (use a11y skill)
- Framework-specific conventions (use framework skill)
- Architecture patterns (use architecture-patterns when project already uses SOLID, Clean Architecture, DDD)
Scope Rule
conventions covers what applies to ALL/MOST technologies. If a convention is specific to one technology (e.g., React hooks rules, TypeScript generics), it belongs in that technology's skill.
Skills That Build on conventions
This skill is a dependency for 40+ skills. Technology skills extend these conventions with their own specifics:
- typescript → Adds strict typing, generics, utility types
- react → Adds component naming, hook rules, JSX patterns
- nodejs → Adds module patterns, error handling, async patterns
- code-quality → Adds linting/formatting tool configuration
- architecture-patterns → Adds layer organization, SOLID, DIP
Critical Patterns
✅ REQUIRED: Consistent Naming Conventions
// ✅ CORRECT: Proper naming by type
const userId = 123; // camelCase for variables
function getUserData() {} // camelCase for functions
class UserService {} // PascalCase for classes
const MAX_RETRY_COUNT = 3; // UPPER_SNAKE_CASE for constants
// ❌ WRONG: Inconsistent naming
const UserID = 123; // Wrong case
function GetUserData() {} // Wrong case
class userService {} // Wrong case
const maxRetryCount = 3; // Wrong case for constant
✅ REQUIRED: Group and Organize Imports
// ✅ CORRECT: Grouped imports
// External libraries
import React from "react";
import { Button } from "@mui/material";
// Internal modules
import { UserService } from "./services/UserService";
import { formatDate } from "./utils/date";
// Types
import type { User } from "./types";
// ❌ WRONG: Random import order
import type { User } from "./types";
import { formatDate } from "./utils/date";
import React from "react";
import { Button } from "@mui/material";
✅ REQUIRED: Single Responsibility Principle
// ✅ CORRECT: Each file has one clear purpose
// UserService.ts - handles user operations
// UserValidator.ts - validates user data
// UserTypes.ts - defines user types
// ❌ WRONG: Everything in one file
// utils.ts - contains validation, API calls, formatting, types...
✅ REQUIRED: Named Imports Over Namespace Imports
// ✅ CORRECT: Named imports — explicit, tree-shakeable
import { readFileSync, existsSync } from 'fs';
import { join, resolve } from 'path';
import { load, dump } from 'js-yaml';
// ❌ WRONG: Namespace import when only using a few exports
import * as fs from 'fs';
import * as path from 'path';
import * as yaml from 'js-yaml';
// ✅ EXCEPTION: Namespace import OK when using many exports (6+)
import * as p from '@clack/prompts'; // uses intro, spinner, select, multiselect, confirm, cancel, note, log, outro
✅ REQUIRED: Separate Type Imports
// ✅ CORRECT: import type for type-only imports
import { UserService } from './services/UserService';
import type { User, UserRole } from './types';
// ✅ CORRECT: Inline type import when mixing values and types
import { Installer, type Model } from '../core/installer';
// ❌ WRONG: Importing types as values (emits unnecessary JS)
import { User, UserRole } from './types';
✅ REQUIRED: No Dead Code
// ❌ WRONG: Unused variables, imports, functions
import { something } from './lib'; // never used
const unused = 42;
function neverCalled() {}
// ✅ CORRECT: Every import, variable, and function is used
import { needed } from './lib';
const count = needed();
✅ REQUIRED: No any Type
// ❌ WRONG: Disables type safety
function process(data: any) { return data.value; }
let presetInfo: any = null;
// ✅ CORRECT: Use specific types or unknown
function process(data: unknown) { /* narrow with guards */ }
let presetInfo: PresetInfo | null = null;
✅ REQUIRED: Avoid Variable Shadowing
// ❌ WRONG: inner `p` shadows outer import
import * as p from '@clack/prompts';
const result = items.find(p => p.id === selected); // shadows p
// ✅ CORRECT: Use distinct names
import * as p from '@clack/prompts';
const result = items.find(item => item.id === selected);
✅ REQUIRED: Prefer Static Imports
// ❌ WRONG: Dynamic import/require when static works
async function doWork() {
const fs = await import('fs'); // unnecessary dynamic import
const yaml = require('js-yaml'); // CJS require in TS
}
// ✅ CORRECT: Static import at module top
import fs from 'fs';
import { load } from 'js-yaml';
Decision Tree
Does this convention apply to ALL/MOST technologies?
→ Yes: Belongs here (conventions)
→ No: Belongs in technology-specific skill
Which concern?
Naming (variables, functions, classes) → See Naming section
Import organization → See Imports section
File/folder structure → See Code Organization
Documentation standards → See Documentation
Type imports (TypeScript) → See Type Imports
React-specific (hooks, JSX) → Use react skill
Architecture (layers, SOLID) → Use architecture-patterns skill
Linting/formatting tools → Use code-quality skill
Quick reference:
- New file? → Check naming (camelCase/PascalCase), place in appropriate directory
- Adding imports? → Group: external → internal → types. Use
import typefor TS - Complex logic? → Comment the "why", not "what". Refactor if SRP violated
- Naming unclear? → Descriptive names revealing intent. No custom abbreviations
- Unused code? → Delete it. No dead code
- Variable name conflict? → Rename to avoid shadowing
- <6 exports? → Named imports. 6+ exports? → Namespace import OK
Edge Cases
Abbreviations: Use well-known abbreviations (HTTP, API, URL, ID) but avoid custom ones. userId is OK, usrId is not.
Acronyms in names: Treat as words: HttpService not HTTPService, apiKey not aPIKey.
File naming: Match export name: UserService.ts exports UserService, index.ts for barrel exports.
Boolean naming: Use is, has, should prefixes: isActive, hasPermission, shouldRender.
Callback naming: Use handle or on prefix: handleClick, onSubmit.
Resources
- naming-conventions.md — Boolean prefixes, acronyms, file naming, descriptive names
- import-organization.md — Grouping, named vs namespace, type imports, barrel exports
- code-structure.md — SRP for files, feature vs layer grouping, colocation
- documentation-standards.md — JSDoc, inline comments, README guidelines
See references/README.md for complete navigation.
Related skills: typescript, code-quality, architecture-patterns