- Favor composition over inheritance, use tsyringe
- Favor SRP, DRY, KISS, YAGNI, SOLID principles
- Use yarn as package manager
- Always
yarn verifyand run related tests after code changes - Favor
@/*path aliases over relative imports; single-level./is fine - Always use
.jsextensions in imports (compiled output), never.ts
- Yarn workspaces + Turbo:
packages/{core, cli, server, slack, web} - Only
@jonit-dev/night-watch-cli(cli) is published; others are private - Cross-package imports:
import { X } from '@night-watch/core/module.js'
- Strict mode enabled, decorators enabled
- Use
interface(nottype) for object shapes — enforced by eslint - Prefix interfaces with
I:IAgentPersona,INightWatchConfig - Unused vars: prefix with
_to suppress warnings - Prefer const arrays over enums:
['claude', 'codex'] as const
- Token-based registration in
packages/core/src/di/container.ts @injectable()on classes,@inject('Token')for non-class deps- Repositories registered as singletons
- Import
reflect-metadataonly at entrypoints (cli.ts, test setup), not in every file getRepositories()factory for backward compat
- File names: kebab-case (
agent-persona.repository.ts,soul-compiler.ts) - Tests: vitest, in
src/__tests__/, files named*.test.ts - Barrel exports: selective re-exports in
index.ts, avoidexport *from subdirs - Separate
export type { }from value exports - Constants centralized in
constants.tswithDEFAULT_*/VALID_*prefixes sort-importsenforced (sort specifiers, not declarations)
- Define interface in
storage/repositories/interfaces.ts - Implement in
storage/repositories/sqlite/ - Wire via DI container or
getRepositories()factory
- Framework: vitest with
forkspool - Import
reflect-metadatafirst in tests using DI - Reset container between tests:
container.reset() - Use temp dirs for DB isolation, clean up in
afterEach