Non-negotiable rules:
- Read
references/stack.mdfirst to determine the runtime (Node.js or Bun), framework, and locked decisions. - Then load only the references needed for the actual task.
- TypeScript strict mode — no
any, no implicit returns, no unchecked index access. - All async functions must handle errors — no unhandled promise rejections. Use try/catch or
.catch()at every boundary. - Input validation at system boundaries — Zod schemas on every external input (request bodies, query params, env vars, CLI args). Never trust
req.body. - Structured logging via pino — no
console.login production code. JSON to stdout, parsed by log aggregators. - Graceful shutdown — handle SIGTERM/SIGINT, drain connections, finish in-flight work, close DB pools.
- No secrets in code or logs — env vars validated at startup, never logged, never in error responses.
nodejs
Inputs
$request: The backend task, subsystem, bug, or feature being worked on
Goal
Route Node.js/Bun backend work through the project's conventions so implementation follows the established patterns for server architecture, data access, error handling, and deployment.
Step 0: Read the stack contract
Always start with:
references/stack.md
That establishes: runtime (Node.js or Bun), framework (Express/Fastify/Hono/none), ORM, test runner, package manager, and locked dependency choices.
If bun.lockb or bunfig.toml exists, the runtime is Bun — also load references/bun-runtime.md for native API differences.
Success criteria: The project's runtime, framework, and toolchain choices are explicit before implementation starts.
Step 1: Load only the relevant references
Use the routing table to pick reference files. Do not bulk-load the full reference tree.
| Task | Read |
|---|---|
| Runtime, TypeScript, package manager, locked deps | references/stack.md |
| Folder conventions, entry points, monorepo layout | references/project-structure.md |
| Express/Fastify/Hono patterns, middleware, routing | references/http-server.md |
| REST conventions, versioning, pagination, error responses | references/api-design.md |
| Zod/AJV input validation, DTO patterns | references/validation.md |
| Prisma/Drizzle/Knex, migrations, connection pooling | references/database.md |
| JWT, sessions, OAuth2, RBAC, middleware guards | references/auth.md |
| Error classes, async error boundaries, HTTP error responses | references/error-handling.md |
| pino structured logging, request correlation, log levels | references/logging.md |
| vitest/jest/bun test, supertest, test factories, coverage | references/testing.md |
| Promises, streams, worker threads, AbortController, shutdown | references/async-patterns.md |
| helmet, CORS, rate limiting, input sanitization, dep audit | references/security.md |
| Redis, in-memory caching, cache invalidation patterns | references/caching.md |
| BullMQ, job patterns, retry strategies, dead-letter queues | references/queues-jobs.md |
| Env validation, dotenv, config modules, secrets management | references/config.md |
| OpenTelemetry, health checks, metrics, distributed tracing | references/observability.md |
| Multi-stage Dockerfile,.dockerignore, prod vs dev images | references/docker.md |
| ws/Socket.io, connection lifecycle, scaling, rooms | references/websockets.md |
| commander/yargs, argument parsing, exit codes, stdin/stdout | references/cli.md |
| Bun-native APIs, bun test, bun build, Bun.serve, Bun.$ | references/bun-runtime.md |
Multiple tasks? Read multiple files. The references are self-contained.
Success criteria: Only the task-relevant backend conventions are in play.
Step 2: Implement with the core backend guardrails
Keep these rules active:
- TypeScript strict mode with
noUncheckedIndexedAccess - all external input validated at the boundary (Zod schemas)
- errors are typed, caught, and returned as structured HTTP responses
- logging via pino child loggers with request correlation IDs
- database access through the project's ORM/query builder, not raw SQL strings
- mutations wrapped in transactions where atomicity matters
- graceful shutdown: SIGTERM handler drains server, closes pools, exits cleanly
- env vars validated at startup — fail fast on missing required config
- no
any, noastype assertions unless justified with a comment - if Bun runtime: prefer
Bun.serve(),Bun.file(),bun testover Node.js equivalents
Success criteria: The change matches the project's backend architecture instead of generic defaults.
Step 3: Verify the affected surface
Use the narrowest relevant verification:
- unit tests (
vitest run,jest, orbun test) - integration tests with supertest or actual HTTP calls
- type checking (
tsc --noEmit) - linting (
eslint.) - if Docker: build the image and verify it starts
Success criteria: The changed backend surface still builds, type-checks, and passes tests.
Guardrails
- Do not inline the whole Node.js handbook in
SKILL.md. - Do not skip
references/stack.md. - Do not use
console.login production code — use pino. - Do not bypass input validation at API boundaries.
- Do not leave unhandled promise rejections.
- Do not hardcode secrets, ports, or environment-specific values.
- Do not add
disable-model-invocation; this is a normal domain skill.
When To Load References
references/stack.mdAlways.references/bun-runtime.mdWhen the project uses Bun (detected viabun.lockborbunfig.toml).- then only the task-relevant files under
references/
Output Contract
Report:
- which references were loaded
- the architecture pattern chosen
- the change made
- the verification run