Coding Standards
Tooling
| Concern | Tool | Config |
|---|---|---|
| Formatting | oxfmt — single quotes, sorted imports, Tailwind class sorting | oxfmt.config.ts |
| Linting | oxlint — TypeScript, Vue, Unicorn, Import, OXC plugins, type-aware | oxlint.config.ts |
| Type checking | TypeScript, strict | per-workspace tsconfig.json |
| Testing | Vitest, Node environment | vitest.config.ts |
Type-aware linting is enabled (options: { typeAware: true, typeCheck: true }) — oxlint rules like typescript/no-floating-promises, typescript/await-thenable, and typescript/unbound-method run against real inferred types, not just syntax.
TypeScript configuration
strict: true, verbatimModuleSyntax: true, noUncheckedIndexedAccess: true. The last one means every indexed array/object access (arr[i], record[key]) is typed as possibly undefined — code throughout the repo narrows explicitly rather than asserting a value is present.
Naming and typing conventions
type over interfaceconventiontype declarations.unknown, not anyconventionunknown explicitly. Avoid inventing a generic isRecord helper for this. explicit return typesrequiredstring literal unionsfor small enums'ok' | 'error', as seen throughout (LatticeErrorCode, RoutingStrategy, request statuses). descriptive namesrequireditem, entry, record, status, not i/e/x (conventional numeric indexes excepted). Import conventions
verbatimModuleSyntax requires import type for type-only imports. Import paths use explicit .ts extensions. Path alias ~/* resolves to the repo root (configured in tsconfig.json, used by tests via the Vitest alias).
Style
- Single quotes, sorted imports (oxfmt-enforced import group order: type-import → type-internal → type-parent/sibling/index → value-builtin/external → value-internal → value-parent/sibling/index → unknown).
function name()for named functions and top-level helpers — notconst fn = () => {}. Callbacks (e.g.items.map((item) => item.id)) stay as arrows; that's the one exception.- Destructure one or two properties from an iterated item when it won't collide with another in-scope variable.
- Prefer functions over classes. Existing correct classes aren't rewritten just for style.
- Match the surrounding file's formatting rather than hand-styling a custom layout.
Validation, errors, and responses
- Valibot for environment parsing (as leaves passed to
@xcvzlabs/env), form validation, and request validation — see Shared Packages for@xcvzlabs/envandpackages/api-contract. camelCaseSchemanaming, notPascalCaseSchema.- Composable
v.pipe()schemas with built-in actions, over manual/ad-hoc parsing. - Validate once at the boundary (the route handler), not repeatedly in inner layers.
- Never throw raw strings — always a typed error (
createLatticeErroron the gateway,createErrorelsewhere). - Catch infrastructure errors where graceful degradation is expected (e.g.
touchLastUsedAtfailures are logged, not fatal — see Security). - Clean up temporary resources in
finallyblocks. - Stable error codes in config validation and app-level failures — see the LatticeErrorCode table.
Editing guidance for contributors and agents
- Make the smallest correct change; don't polish unrelated code or expand into a repo-wide refactor unless the task requires it.
- Don't remove correct comments/documentation, or rename broad parts of the codebase, without a reason tied to the task.
- No backward-compatibility shims — remove obsolete paths outright rather than adding fallbacks or migrations for them.
- Choose the simplest implementation that fully meets the current requirement; no speculative abstraction or configuration.
- Grow the system in layers — every change should leave a product that works end to end, never a working product traded for unfinished complexity.
- Lean on dependencies already in the project before writing a new implementation; don't assume a library lacks a capability without checking.
- If a workaround needs a paragraph of comment to justify why it's okay, that's a signal the code is wrong, not that it needs a bigger comment.
Anti-slop lint plugin
tools/oxlint/anti-slop/ is a custom oxlint plugin enforcing patterns that AI-assisted and human contributors alike tend toward under time pressure: chained type assertions, conditional empty-object spreads, widening known values, module mocking in tests, object/unknown-shaped parameters and returns, runtime typeof misuse, unsafe dictionary types, and "widen then assert" patterns. All are error-level. If you hit one, the fix is almost always a narrower, more explicit type or a smaller function signature — not a suppression comment.