From typescript-services
Enforces functional programming, monadic operations, type safety, and naming conventions for production code in src/ only (NOT test code). Use when writing production code, generating services, or implementing business logic under src/.
npx claudepluginhub andercore-labs/claudes-kitchen --plugin typescript-servicesThis skill uses the workspace's default tool permissions.
**SCOPE:** Production code under `src/` only. Test code has separate standards.
Implements structured self-debugging workflow for AI agent failures: capture errors, diagnose patterns like loops or context overflow, apply contained recoveries, and generate introspection reports.
Monitors deployed URLs for regressions in HTTP status, console errors, performance metrics, content, network, and APIs after deploys, merges, or upgrades.
Provides React and Next.js patterns for component composition, compound components, state management, data fetching, performance optimization, forms, routing, and accessible UIs.
SCOPE: Production code under src/ only. Test code has separate standards.
For T/R/M details → Skill(typescript-services:true-myth-recipe) For Observable/RxJS patterns → Skill(typescript-services:rxjs-recipe)
Domain (sync):
export const create = (params: Params): Result<Entity, Error> =>
validate(params).andThen(build).map(Object.freeze)
Service (async):
create(data: Domain): Task<Domain, Error> {
return fromResult(this.validate(data))
.andThen(this.save)
}
Inbound (unwrap):
async handle(@Body() dto: Dto): Promise<Response> {
return fromResult(this.toDomain(dto))
.andThen(this.service.execute)
.map(this.toDto)
.toPromise()
.then(r => r.unwrapOrElse(e => Promise.reject(e)))
}
Code generation | service implementation | business logic | API endpoints | error handling
| Pattern | Status |
|---|---|
| if/else blocks, for/while loops, let/var | ✗ Imperative |
| map/filter/reduce, ternary in pipelines | ✓ Functional |
| Multiple returns/early returns | ✗ Procedural |
| Single return with pipeline | ✓ Declarative |
| array.push(), obj.prop = x | ✗ Mutation |
| [...array, item], { ...obj, prop: x } | ✓ Immutable |
| console.log, throw | ✗ Side effects |
| NO side effects, Promise.reject in unwrapOrElse only | ✓ Pure |
| let/var | ✗ Mutable |
| const only, Object.freeze | ✓ Immutable |
Conditional patterns:
| Pattern | Status |
|---|---|
if (x) return y; else return z; | ✗ Multiple returns |
return x ? y : z | ✓ Ternary in single return |
Result.ok(x > 0 ? x : 0) | ✓ Ternary in pipeline |
.andThen(v => x ? ok(a) : err(b)) | ✓ Ternary in monadic chain |
✓ Single pipeline:
return validate(input)
.andThen(transform)
.map(compute)
✓ Ternary in pipeline:
return fromResult(
existing.length > 0
? Result.err(new DuplicateError())
: Result.ok(Unit)
)
✗ Multiple returns:
if (!valid) return err
const result = transform(input)
return ok(result)
| Never Allowed | Use Instead |
|---|---|
| //, /* /, /* */, TODO/FIXME | Self-documenting code |
| @ts-ignore, eslint-disable | Fix type errors properly |
| interface | type |
| any | unknown or specific type |
| static members | Pure functions + DI |
| enum | Union types or const objects |
| default export, export * | Named exports |
| namespace declarations | Module exports |
| ! non-null assertion | Maybe or proper typing |
| as any, as unknown as | Proper type definitions |
| <> unspecified generics | Specify concrete types |
| Value objects | Entities only (VOs add no value) |
| Multiple returns/early returns | Single pipeline expression |
| throw | Promise.reject in unwrapOrElse only |
| null/undefined in domain/service | Maybe, [] for collections |
| .match() | .unwrapOrElse() |
For T/R/M operations, invoke true-myth-recipe:
Skill(typescript-services:true-myth-recipe)
T = Task, R = Result, M = Maybe
| Type | Layer | Returns |
|---|---|---|
| R<T, E> | Domain | Sync fallible operations |
| T<T, E> | Service/Outbound | Async fallible operations |
| M | Domain/Service | Optional values (NO null/undefined) |
| Promise | Inbound only | After unwrapOrElse |
Essential operations:
fromPromise(promise, mapper) → Wrap promises
fromResult(result) → R → T
.andThen(fn) → Chain fallible
.map(fn) → Transform success
.unwrapOrElse(fn) → Extract (inbound only)
Violations:
.unwrap()/.match()/.isOk → Use .andThen()/.map()/.unwrapOrElse()
R<M<T>> → R<T, NotFoundError>
null/undefined in domain/service → M<T>
For Observable/reactive operations, invoke rxjs-recipe:
Skill(typescript-services:rxjs-recipe)
| Pattern | Use Case | Example |
|---|---|---|
| Observable | Event streams, async sequences | fromEvent(button, 'click') |
| pipe() | Operator composition | .pipe(map(), filter()) |
| takeUntil(destroy$) | Subscription cleanup | Component lifecycle |
| catchError() | Error handling | Fallback values |
Essential operators:
from()/of() → Create Observables
.pipe(map(fn)) → Transform values
.pipe(switchMap(fn)) → Cancel previous, emit latest
.pipe(takeUntil(destroy$)) → Auto-unsubscribe
.pipe(catchError(fn)) → Handle errors
Violations:
Nested .subscribe() → Use switchMap/mergeMap
Missing takeUntil/unsubscribe → Memory leaks
.subscribe() in domain/service → Return Observable
| Pattern | Status |
|---|---|
| interface | ✗ Use type |
| any | ✗ Use unknown or specific |
| <> unspecified generics | ✗ Use Task<User, Error> |
| enum | ✗ Use Union types |
| ! non-null assertion | ✗ Use M |
| as any | ✗ Use proper typing |
| T | null | ✗ Use M |
| T | undefined | ✗ Use M |
| T? optional | ✗ Use M for values, T[] = [] for collections |
Pattern → Action:
type UserId = Readonly<{ value: string }>
type Resource = Readonly<{ id: ResourceId }>
type Status = 'draft' | 'active' | 'archived'
| Folder | Suffix | Violations |
|---|---|---|
| domain/* | .entity.ts | .domain.ts, .model.ts |
| service/* | .service.ts | .usecase.ts, .orchestrator.ts |
| inbound/* | .controller.ts, .dto.ts, .guard.ts, .consumer.ts | .handler.ts, .middleware.ts |
| outbound/* | .adapter.ts, .dto.ts | .client.ts, .sdk.ts |
| helpers/ | .helper.ts | .util.ts, .utils.ts |
| mocks/ | .mock.ts | .stub.ts, .fake.ts |
| Use | Never |
|---|---|
| Adapter | Client, SDK, Gateway |
| Service | UseCase, Manager, Handler |
| Entity | Model, Domain |
| DTO | Request, Response, Payload |
| Helper | Util, Utils, Tool |
| Controller | Handler, Endpoint |
| Consumer | Listener, Subscriber |
| Guard | Middleware, Interceptor |
Order: Public methods first, then private in call order
export class Service {
public create() { return this.validate().andThen(this.persist) }
public update() { return this.validate().andThen(this.persist) }
private validate() { return this.checkFormat().andThen(this.checkUnique) }
private persist() { ... }
private checkFormat() { ... }
private checkUnique() { ... }
}
Pattern → Action → Outcome:
Unvalidated env → requireEnv() → typed config → @Inject
process.env in logic → CRITICAL violation → inject AppConfig
export type AppConfig = Readonly<{
apiKey: string
timeout: number
}>
@Injectable()
export class ConfigService {
private readonly config: AppConfig
constructor() {
this.config = Object.freeze({
apiKey: this.requireEnv('API_KEY'),
timeout: parseInt(this.requireEnv('TIMEOUT'), 10)
})
}
}
constructor(@Inject('AppConfig') private config: AppConfig) {}
Violations in domain/service:
if (role === 'admin') ✗
if (age > 18) ✗
timeout: 5000 ✗
Pattern → Action:
export const UserRole = {
ADMIN: 'admin',
USER: 'user'
} as const
export type UserRole = typeof UserRole[keyof typeof UserRole]
export const LEGAL_AGE = 18
export const DEFAULT_TIMEOUT_MS = 5000
if (role === UserRole.ADMIN) ✓
if (age > LEGAL_AGE) ✓
Pattern → Action:
All controllers → @ApiOperation/@ApiResponse/@ApiBearerAuth
Missing decorators → CRITICAL violation
@Controller('users')
@ApiTags('users')
export class UserController {
@Post()
@ApiOperation({ summary: 'Create user' })
@ApiResponse({ status: 201, type: UserResponseDto })
@ApiResponse({ status: 400, description: 'Validation error' })
@ApiBearerAuth()
async create(@Body() dto: CreateUserDto) { ... }
}
Pattern → Action:
DTO received → validate BEFORE transformation → toDomain → service
Unvalidated DTO → service → CRITICAL violation
DTO validation decorators:
export class CreateUserDto {
@IsString()
@MinLength(3)
name: string
@IsEmail()
email: string
}
Or Zod schemas:
const schema = z.object({
name: z.string().min(3),
email: z.string().email()
})
Validate BEFORE service call:
fromResult(this.validateDto(dto))
.andThen(this.toDomain)
.andThen(this.service.create)
CHECK:
1. Functional purity → NO imperative (if/else/for/while/let/var/mutations)
2. Circular dependencies → NO circular imports between modules
3. Dependency injection → ALL deps via constructor @Inject
4. Domain constraints → NO async/T/Promise in domain (R/M only)
5. Method ordering → Public first, private in call order
6. Monadic usage → fromPromise/fromResult/andThen used
7. NO match() → ONLY unwrapOrElse for unwrapping
8. NO throwing → NO throw in ANY layer (Promise.reject in unwrapOrElse only)
9. Unwrap usage → ONLY in unwrapOrElse, NEVER standalone .unwrap()
10. Layer pipelines → Correct pipeline pattern per layer
11. Error propagation → R/T/Promise per layer, no throwing
12. Adapter types → NO exported adapter-specific types
13. DTO boundaries → Service uses domain types ONLY, NO DTOs
14. Naming conventions → Correct suffixes, consistent terms
15. Null/undefined → STRICT: NO null/undefined in domain/service
16. Nested monads → NO R<M<T>>, T<M<T>>
17. Input validation → DTOs validated BEFORE transformation
18. API documentation → OpenAPI decorators on ALL controllers
19. Configuration → Injected typed config, NO process.env in logic
20. Magic values → Constants for domain logic
21. Prohibitions → Check ALL absolute prohibitions table
22. All pass → Generate code
ANY fail → REJECT with violation
ALL rules satisfied:
→ Emit code only (no comments, no prose)
ANY rule violated:
→ REJECT: <specific violation>
→ Specify exact line/pattern that violates
→ Suggest functional alternative
→ NO partial code
MANDATORY: Run after generating or reviewing production code.
| Phase | Action |
|---|---|
| 1. Scan | Identify production code files in src/ |
| 2. Validate | Run ALL 22 verification protocol checks → gather violations |
| 3. Report | ✓ ALL pass → Done | ✗ ANY fail → REJECT with violations |
| 4. Fix | Violations → Regenerate → Re-validate |
| 5. Store Metrics | After ALL validation passes, call mcp__agent-orchestrator__store-skill-metrics |
Run ALL 22 checks from Verification Protocol, plus:
Framework Lifecycle (async/cleanup)
| Pattern | Severity | Fix |
|---|---|---|
| constructor() { this.monitorConn().catch(...) } has async | CRITICAL | Use onModuleInit() - errors not propagated in constructor |
| setTimeout/setInterval/EventEmitter but no OnModuleDestroy | CRITICAL | Implement OnModuleDestroy - timers fire after shutdown |
| DB/HTTP connections not closed in onModuleDestroy | MAJOR | Close all connections in onModuleDestroy |
| Critical op (save, send) without await or .catch() | ERROR | await OR handle - swallowed errors |
All pass:
{
"discipline": "production-code",
"timestamp": "ISO8601",
"functional_purity": {"violations": [], "status": "pass"},
"prohibitions": {"violations": [], "status": "pass"},
"domain_constraints": {"violations": [], "status": "pass"},
"monadic_operations": {"violations": [], "status": "pass"},
"type_system": {"violations": [], "status": "pass"},
"naming_conventions": {"violations": [], "status": "pass"},
"method_ordering": {"violations": [], "status": "pass"},
"configuration": {"violations": [], "status": "pass"},
"magic_values": {"violations": [], "status": "pass"},
"api_documentation": {"violations": [], "status": "pass"},
"input_validation": {"violations": [], "status": "pass"},
"framework_lifecycle": {"violations": [], "status": "pass"},
"summary": {"critical": 0, "errors": 0, "warnings": 0}
}
Violations found (REJECT):
{
"discipline": "production-code",
"timestamp": "ISO8601",
"functional_purity": {
"violations": [
{"file": "src/service/user.service.ts", "line": 45, "severity": "critical", "rule": "multiple_returns", "violation": "Multiple return statements", "fix": "Single pipeline with ternary"}
],
"status": "fail"
},
"prohibitions": {
"violations": [
{"file": "src/domain/user.entity.ts", "line": 12, "severity": "critical", "rule": "throw_statement", "violation": "throw new Error()", "fix": "Use Result.err() in domain"}
],
"status": "fail"
},
"summary": {"critical": 2, "errors": 0, "warnings": 0}
}
Review generated/modified code → Gather evidence → Cite file:line
NOT: Re-execute OR invent violations
Re-validation required after fixes. Repeat until ALL checks pass.
See true-myth-recipe for T/R/M patterns See rxjs-recipe for Observable/reactive patterns See examples.md for complete implementations and common violations