Package boundaries

Updated Jul 27, 2026

Roadmap item 1.1.1 establishes explicit package boundaries for new development:

  • frontend/: frontend package boundary for renderer-facing code.
  • backend/: backend package boundary for privileged main-process code.
  • shared/: shared contracts (types, constants, and schemas).

This split is currently an architectural boundary with incremental migration. Runtime modules still live primarily in lib/ (frontend) and app/ (backend). Treat those folders as the active implementation roots until follow-on migration work moves modules under frontend/src and backend/src.

Dependency direction must remain one-way:

  • frontend -> shared
  • backend -> shared

frontend must not import backend, and backend must not import frontend.

Approved exception:

  • lib/components/term.tsx may import ../../app/utils/renderer-utils to reuse createRuntimeLatencyMetrics as the single latency-metrics factory. This exception is explicitly allow-listed in scripts/check-package-boundaries.mjs.

Use shared imports via TypeScript path aliases:

  • @frontend/*
  • @backend/*
  • @shared/*

For app/ main-process runtime modules compiled into dist/app/ via tsgo, TypeScript path aliases are type-checking conveniences only. Do not add bare runtime @shared/* value imports in app/ modules unless the build pipeline also materializes runtime-resolvable modules under dist/app/. Use import type for shared contracts and prefer app-local runtime adapters/constants for main-process runtime dependencies.

Boundary validation is enforced by bun run check:boundaries, which runs as part of bun run lint and therefore make lint.

Follow-up hardening tracked in docs/tracking-issues.md:

  • BOUNDARY-001: include CommonJS require(...) imports in boundary checks.
  • CONTRACT-001: make shared/ schema generation independent of legacy typings/ compatibility re-exports.