A living reference for how code is written in this repo. Update this file in place as conventions evolve — don't let it drift from what the code actually does. For why these choices were made, see docs/superpowers/specs/2026-08-25-dev-tooling-and-standards-design.md. For where code goes, see docs/architecture.md.
- TypeScript in
strictmode (tsconfig.json'sstrict: true) — no exceptions. - No
anywithout an inline comment explaining why it's unavoidable. Preferunknownplus explicit narrowing. - Target: Node
>=20, compiler targetES2022.
- Named exports only. No
export default, including single-function files like each primitive insrc/core/primitives/. - Barrel files (e.g.
src/core/primitives/index.ts,src/core/index.ts) re-export explicitly by name — neverexport * from.
-
Public API functions throw typed
Errorsubclasses, never return{ ok, value } | { ok, error }result objects. -
Each error class carries a
codediscriminant field for programmatic handling, e.g.:export class ShapeIdError extends Error { constructor(public readonly code: "bad-format" | "checksum-mismatch" | "primitive-ceiling-overflow", message: string) { super(message); this.name = "ShapeIdError"; } }
-
CLI commands (
src/cli/commands/*.ts) catch errors at the boundary, print a user-facing message, and exit non-zero. They never let a raw stack trace reach the user.
- Filenames: kebab-case (
shape-id.ts, notshapeId.ts). - Functions and variables:
camelCase. - Types, interfaces, classes:
PascalCase. - One primary export concept per file — a file named after what it exports (e.g.
fillet.tsexports thefilletprimitive).
- TSDoc is required on the public API surface:
encodeShapeId,decodeShapeId,renderShape,generateShapeDef,generateShapeId,rampParameterAt,resolveCellTransform, and every exported type (ShapeDef,CellDef,Rotation,Ramp,RampTrack,RampAxis,RampCurve,RampParam) and exported error class. - Internal helpers (primitive path-builders, the shared geometry transform, registry internals) get a comment only where the logic isn't self-evident from reading it — don't blanket-document every internal function.
- vitest. Tests mirror
src/undertest/(e.g.src/core/id.ts→test/core/id.test.ts). - One behavior per
it()block — don't assert multiple unrelated things in one test. - Prefer round-trip/property-style tests where the domain supports it (e.g.
encode(decode(id)) === idacross grid sizes), per the shape-id-codec spec.
- Biome (
biome.json) is the single source of truth for formatting and lint rules. Runnpm run lintandnpm run format— don't hand-debate style in review. npm run lintmust pass before a commit lands.
- Conventional Commits:
feat:,fix:,chore:,docs:,test:, etc. - No enforcement tooling (commitlint/husky) yet — convention plus review, not automation.