Skip to content

Engineering conventions

AGENTS.md and the accepted ADRs are normative. This document makes the cross-cutting implementation conventions explicit.

Naming

  • Use product glossary terms exactly; do not invent synonyms for core entities.
  • Go packages use short domain nouns and avoid stutter. Exported names describe domain meaning, not implementation technology.
  • IDs are stable opaque values. Display names and paths are not primary keys.
  • APIs use lower-camel JSON fields, kebab-free path segments, and resource nouns. Database names use snake_case.
  • Avoid root packages or modules named utils, common, helpers, manager, or service without a specific domain responsibility.

Errors

  • Domain/application errors have stable codes and safe user summaries.
  • Wrap infrastructure errors with operation context while preserving causes.
  • Transport adapters map errors to RFC 9457-style problem details; handlers do not manufacture business outcomes.
  • Never expose secrets, environment values, raw SQL, or unsafe command details.
  • Cancellation and deadline errors remain distinguishable from failures.

Logging

  • Use log/slog with UTC timestamps and structured attributes.
  • Include component and error code; include operation/project/service IDs when available.
  • Do not log secrets, authentication headers, raw provider prompts, environment values, or command arguments that may contain secrets.
  • User-visible process logs pass through redaction before display, persistence, export, or diagnostics.

Testing

  • Domain tests cover invariants and state transitions.
  • Application tests use focused fakes owned by the consuming package.
  • Adapter tests exercise real SQLite, Git, process, Docker, or platform behavior where applicable.
  • Cover success, validation, failure, cancellation, authorization, idempotency, recovery, and reconciliation paths proportionally to risk.
  • Use deterministic fixtures. Avoid network, random IDs, and wall-clock timing in ordinary unit tests.

Migrations

  • SQLite migrations are embedded, forward-only in releases, and ordered.
  • Every migration applies to an empty database and all maintained upgrade fixtures inside an explicit transaction when SQLite permits it.
  • Destructive changes use expand/migrate/contract steps and documented backup or recovery behavior.
  • Application code never silently edits schema outside the migration runner.
  • Schema state is observable through doctor and support diagnostics.

APIs and generated contracts

  • REST JSON lives under /api/v1; live streams use versioned WebSocket paths.
  • OpenAPI is the HTTP source of truth. Generated Go and TypeScript artifacts are isolated, deterministic, committed only when policy requires it, and never edited manually.
  • Mutations accept idempotency keys and return durable operation IDs when work is asynchronous.
  • Machine-readable CLI and MCP responses use stable, bounded, versioned schemas. Streaming output uses JSON Lines.
  • Browser mutations require a same-origin local session and CSRF token.
  • Unknown input fields fail validation unless a contract explicitly permits extension data.

Time, cancellation, and state

  • Store and compare time in UTC; localize only in presentation adapters.
  • Propagate context.Context through I/O and long-running operations.
  • Persist durable intent and outcomes, not volatile derived convenience state.
  • State derived from live infrastructure includes evidence age and observer availability; unknown and stale are legitimate outcomes.
Use this pageLast verified Jul 17, 2026
Copy-ready MarkdownOpen sourceReport a docs issue