House style
Principles
- Removing code is more valuable than adding code.
- Modularity — each package has a single responsibility.
- Runtime-agnostic — no Node.js-specific APIs in domain/core packages; implementation packages (
storage-fs, …) are where runtime-specific code belongs. - Minimal dependencies — keep bundle sizes small; don't add a heavy dependency without discussion.
Naming
- Files:
kebab-case.ts - Classes:
PascalCase - Functions:
camelCase - Tests:
<name>.test.ts, colocated with the code they cover.
Dependencies
- Internal (workspace) dependencies:
workspace:*. - Shared external dependencies:
catalog:references (see thecatalogsblock inpnpm-workspace.yaml) rather than pinning a version directly in a package'spackage.json.
Formatting and linting
dprint fmt/pnpm formatis the formatter (dprint.json: 2-space indent, single quotes, semicolons, 120-char line width for code).pnpm format:checkis the pre-commit gate.- ESLint (
eslint.config.mjs) runs@typescript-eslint/recommendedplus repo rules; notablyno-explicit-anyandno-unused-varsare warnings, not hard errors — still avoidanywhere a real type is easy to write. apps/websiteadditionally bans em dashes (—) in user-visible copy — use a colon, comma, or restructure the sentence.
Layering
Follow the domain/impl/api layering described in Orientation and Architecture: domain packages define interfaces and have no internal deps beyond shared; implementation packages depend on domain, never on another implementation; API packages depend on domain, not on implementations.
Effect-based repositories
Repository methods return LaikaTask<T> (single result) or LaikaStream<T, D> (multiple results with a typed done value) — both Effect-based. Consume them via the laikacms/compat helpers (runTask, collectStream) rather than importing Effect directly in calling code.
When a higher-level repository delegates to a lower-level one, use the forwarding drainers (LaikaTask.runValueForwarding, LaikaStream.runCollectForwarding) so recoverable warnings propagate to the outer caller instead of being dropped at the delegation boundary. runValue / runCollect (non-forwarding) are correct only at a true top-level boundary — an API server draining a task into a Promise, test setup, etc.
Docs
- Organize docs by feature, never by package. Readers don't know or care which package a feature ships in; the only place that difference shows is the install command.
- This
contributing/section anddocs/in general stay evergreen: no dated point-in-time snapshots. Design decisions (ADRs, incident write-ups) are recorded internally, not published here.