Comprehensive coding standards for MetaSaver TypeScript projects including SOLID principles, DRY/KISS/YAGNI guidelines, error handling with AppError hierarchy, structured logging with Pino, and code organization rules. Use when implementing features, refactoring code, or establishing coding patterns.
Inherits all available tools
Additional assets for this skill
This skill inherits all available tools. When active, it can use any tool Claude has access to.
reference.mdtemplates/dry-kiss-yagni.ts.templatetemplates/error-handling.ts.templatetemplates/logging.ts.templatetemplates/solid-examples.ts.templateSingle source of truth for MetaSaver coding principles and patterns.
Use when:
| Principle | Application |
|---|---|
| SOLID | OOP design principles for class/module design |
| DRY | Extract shared logic; single source of truth |
| KISS | Simplest working solution; no premature abstraction |
| YAGNI | Build for current requirements only; delete unused code |
| Errors | AppError hierarchy with proper status codes |
| Logging | Structured Pino logs with action + context |
Verify each component follows one SOLID principle:
See templates/solid-examples.ts.template for examples of all 5.
See templates/dry-kiss-yagni.ts.template for patterns.
Implement AppError hierarchy:
AppError(message, code, statusCode)ValidationError, NotFoundError, UnauthorizedError, ForbiddenErrorSee templates/error-handling.ts.template for complete setup.
Configure Pino logger with:
{ action, userId, error, correlationId }See templates/logging.ts.template for setup and patterns.
| Standard | Pattern | Example |
|---|---|---|
| Explicit barrel exports | List each export by name | export { UserService } from './user.service.js' |
| Current library APIs | Use latest non-deprecated methods | router.get() not router.addRoute() |
| Path alias imports | Use @/ for src-relative paths | import { User } from '@/types' |
Barrel files (index.ts):
// ✅ GOOD: Explicit exports
export { UserService } from "./user.service.js";
export { UserRepository } from "./user.repository.js";
export type { User, CreateUserDto } from "./user.types.js";
// ❌ AVOID: Wildcard re-exports (harder to tree-shake, hides what's exported)
// export * from './user.service.js';
Import paths:
// ✅ GOOD: Path alias
import { UserService } from "@/services/user.service.js";
import { validateUser } from "@/utils/validation.js";
// ❌ AVOID: Relative paths beyond parent
// import { UserService } from '../../../services/user.service.js';
Library APIs:
// ✅ GOOD: Current API
const response = await fetch(url, { signal: controller.signal });
// ❌ AVOID: Deprecated patterns
// request.on('response', callback); // Use fetch instead
| Type | Ideal | Max | If exceeded |
|---|---|---|---|
| Service | ~100 lines | 200 lines | Split by domain |
| Controller | ~50 lines | 100 lines | Move logic to service |
| Utility | ~50 lines | 100 lines | Split by function |
| Type file | ~50 lines | 150 lines | Group by entity |
Function guidelines:
Before committing code:
any typesexport *)@/ alias (not ../../../)import { NotFoundError } from "../errors/index.js";
import { logger } from "../utils/logger.js";
export class UserService {
private readonly log = logger.child({ service: "UserService" });
async getUser(id: string): Promise<User> {
this.log.debug({ action: "getUser", userId: id });
const user = await this.userRepository.findById(id);
if (!user) throw new NotFoundError("User", id);
return user;
}
async createUser(data: CreateUserDto): Promise<User> {
this.log.info({ action: "createUser", email: data.email });
const existing = await this.userRepository.findByEmail(data.email);
if (existing) throw new ValidationError("Email in use", "email");
try {
const user = await this.userRepository.create(data);
this.log.info({ action: "userCreated", userId: user.id });
return user;
} catch (error) {
this.log.error({ action: "createUser", error, email: data.email });
throw error;
}
}
}
// BAD: Fat interface
interface Worker {
work(): void;
eat(): void;
attendMeeting(): void;
}
// GOOD: Segregated interfaces
interface Workable {
work(): void;
}
class Developer implements Workable, Eatable, MeetingAttendee {
work(): void {}
eat(): void {}
attendMeeting(): void {}
}
class Robot implements Workable {
work(): void {} // Only needs work
}
const emailSchema = z.string().email();
function validateEmail(email: unknown): string {
return emailSchema.parse(email);
}
async function createUser(data: CreateUserDto): Promise<User> {
const email = validateEmail(data.email);
return db.users.create({ ...data, email });
}
async function updateUser(id: string, data: UpdateUserDto): Promise<User> {
const email = validateEmail(data.email); // Reuse validation
return db.users.update(id, { ...data, email });
}
Complete, copy-paste-ready code examples:
templates/solid-examples.ts.template - All 5 SOLID principlestemplates/dry-kiss-yagni.ts.template - DRY, KISS, YAGNI patternstemplates/error-handling.ts.template - AppError hierarchy + middlewaretemplates/logging.ts.template - Pino setup + logging patternsSee reference.md for:
/skill cross-cutting/tool-check - Tool discovery and usage/skill domain/monorepo-audit - Monorepo structure validation/skill cross-cutting/serena-code-reading - Progressive code analysis