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.
Enforces MetaSaver TypeScript standards (SOLID, DRY, KISS, YAGNI) with AppError hierarchy and Pino logging. Use when implementing features, refactoring, or reviewing code for compliance.
/plugin marketplace add metasaver/metasaver-marketplace/plugin install core-claude-plugin@metasaver-marketplaceThis 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";
// ✅ ENSURE: Use explicit exports for tree-shaking and clarity (not wildcard re-exports)
// Wildcard re-exports make tree-shaking harder and hide what's exported
// export * from './user.service.js'; // ❌ Only use if absolutely necessary
Import paths:
// ✅ GOOD: Use path aliases for clean imports
import { UserService } from "@/services/user.service.js";
import { validateUser } from "@/utils/validation.js";
// ✅ ENSURE: Use path aliases instead of deep relative paths for maintainability
// Relative paths beyond parent directory are harder to maintain
// import { UserService } from '../../../services/user.service.js'; // ❌ Use @/ alias instead
Library APIs:
// ✅ GOOD: Use current, non-deprecated APIs
const response = await fetch(url, { signal: controller.signal });
// ✅ ENSURE: Use modern fetch API instead of deprecated patterns
// Older patterns like on() callbacks are no longer recommended
// request.on('response', callback); // ❌ Use fetch API instead
Import directly from source files for optimal treeshaking and explicit dependency tracking.
// Direct import from source file (optimal)
import { validateUser } from "#/users/validation.js";
import type { User } from "#/users/types.js";
import { AuthService } from "#/services/auth.js";
// Package subpath imports (external packages)
import { prisma } from "@metasaver/database/client";
import type { UserSchema } from "@metasaver/contracts/users/schemas";
#/ path alias pointing to ./src@metasaver/contracts/users/types)See also: Coder agent (core-claude-plugin:generic:coder) for full import/export patterns
| 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)export *)@/ alias (instead of deep relative paths)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 domain/monorepo-audit - Monorepo structure validation/skill cross-cutting/serena-code-reading - Progressive code analysis