# Nerve Coding Conventions ## Functional-First - `type` over `interface`, `function` over `class` - No `this`, no inheritance, composition over inheritance - Immutability first: `Readonly`, `as const` ## No Optional Properties Never use `?:`. Use `T | null` for nullable fields. Use discriminated unions for mutually exclusive fields. ```ts // ✅ Good type Config = { throttle: string | null } // ❌ Bad type Config = { throttle?: string } ``` ## Error Handling - `Result` for expected failures - `throw` only for programmer errors (bugs) - No try-catch for flow control ### Result Type Defined in `@uncaged/nerve-core` (`packages/core/src/result.ts`): ```ts export type Result = { ok: true; value: T } | { ok: false; error: E }; ``` **Discriminated union** with tagged `ok` field. Helper functions: - `ok(value)` → `{ ok: true, value }` - `err(error)` → `{ ok: false, error }` **Exhaustive handling**: Pattern is `if (!result.ok) { handle error }` then access `result.value`. No compiler enforcement - relies on manual discipline and TypeScript's flow control analysis. ## Naming | Type | Style | |------|-------| | Files | `kebab-case.ts` | | Types | `PascalCase` | | Functions/vars | `camelCase` | | Constants | `UPPER_SNAKE` | ## Exports - Always named exports, never default - One module = one responsibility ### Module Naming Conventions **Primary exports** use descriptive, unambiguous names: - Functions: `createXxx()`, `parseXxx()`, `xxxAgent()` (e.g., `createCursorAdapter`, `cursorAgent`) - Types: Domain-specific prefixes (e.g., `CursorAgentOptions`, `SenseComputeFn`, `ThreadContext`) - Constants: `UPPER_SNAKE_CASE` with context (e.g., `DEFAULT_SENSE_SIGNAL_RETENTION`, `CURSOR_ADAPTER_DEFAULT_MS`) **Avoiding ambiguity**: - Package-scoped naming: `@uncaged/nerve-adapter-cursor` exports `cursorAgent`, `createCursorAdapter` - Factory pattern: `createXxxAdapter()` for configurable instances, `xxxAdapter` for defaults - Descriptive type prefixes prevent collision (e.g., `CursorAgentOptions` vs `HermesAgentOptions`) ## Async - Always `async/await`, never `.then()` chains - Use `AbortSignal` for cancellation: `AbortController` to create signals, pass to long-running operations - `spawn-safe.ts` and adapter functions accept `abortSignal: AbortSignal | null` parameter - On abort: child processes receive `SIGTERM`, async operations should check `signal.aborted` - No enforced Biome/Vitest rules for AbortSignal usage (manual discipline required) ## No Dynamic Import Static `import` only. Exceptions: `sense-runtime.ts`, `workflow-worker.ts` (runtime module paths). ## Toolchain pnpm + TypeScript (strict) + Biome (lint/format) + Vitest (test) ```bash pnpm run check # biome check pnpm test # vitest pnpm run build # full build ```