Skip to main content
Every application and package in the Reflections monorepo operates under explicit boundary rules. These boundaries exist to enforce the two-plane architecture — keeping the realtime path read-only, preventing privilege escalation from client code, and ensuring that truth-table mutations flow exclusively through the eval-gated background pipeline. Boundaries are enforced mechanically through ESLint import restrictions, architecture guard scripts in CI, and file-scan tests that cannot be bypassed with inline eslint-disable comments.

Layering rule

Before diving into per-plane boundaries, one rule applies everywhere:
apps/* may depend on packages/*. Packages must never depend on apps. Apps consume packages only through published entrypoints — no deep imports from @reflection/*/src/*.

Per-plane boundaries

The realtime plane handles live voice sessions, knowledge retrieval, and session lifecycle.Allowed:
  • Read reflection config, chunks, entities, and facts
  • Write conversations, messages, and retrieval traces (session data)
  • Bootstrap voice sessions with the managed provider
  • Dispatch events to the background plane via Inngest
Forbidden:
  • Writing to sources, chunks, entities, or fact state directly
  • Running background ingestion or eval execution in the realtime process
  • Importing from @reflection/db/queries/admin
  • Running LLM entity extraction in the realtime path
The background plane runs the ingestion pipeline — extraction, evaluation, and patch application.Allowed:
  • Ingestion and candidate fact creation
  • Evaluation and scoring of candidate facts
  • Transactional patch application (promoting candidates to active)
  • Using @reflection/db/queries/admin for write operations
  • Calling LLM APIs for extraction and evaluation via @reflection/vendors
Forbidden:
  • Bypassing the eval/apply gate
  • Setting active truth directly from raw external content without the candidate/eval path
  • Serving user-facing requests or participating in realtime latency paths
The API layer handles authentication, authorization, and request routing.Allowed:
  • Auth and role derivation from Clerk JWTs and bearer tokens
  • Token issuance for voice sessions
  • Dispatch metadata to background workers
  • Reading from @reflection/db/queries/read
Forbidden:
  • Trusting client role claims — roles are always server-derived
  • Exposing database internals directly to clients
  • Importing from @reflection/db/queries/admin
The Next.js web application provides the user-facing dashboard and session interface.Allowed:
  • Session bootstrap through the API via @reflection/api-client
  • Rendering knowledge graph visualizations from API responses
  • Auth via Clerk Next.js SDK
Forbidden:
  • Direct database access of any kind
  • Privileged role assertions — the API determines access
  • Importing from @reflection/db or any server-only package
The native Swift iOS app provides voice interaction and knowledge graph visualization.Allowed:
  • Session bootstrap through the API via the native HTTP client
  • Auth via Clerk iOS SDK
  • Local voice session management with ElevenLabs
Forbidden:
  • Direct database access of any kind
  • Privileged role assertions — the API determines access

Enforcement mechanisms

Boundaries are not advisory — they are enforced at three layers:
LayerMechanismWhat it catches
ESLintno-restricted-imports rules in eslint.config.mjsAdmin query imports from realtime/API, deep imports, direct vendor SDK imports outside packages/vendors, process.env outside designated files
Architecture guardsimplicity-guard.mjs in CIDynamic imports that bypass ESLint, cross-plane violations, vendor SDK isolation, file size budgets
File-scan testsDedicated test files in affected packagesAdmin import violations (cannot be eslint-disabled), process.env isolation
If you need to understand why a specific import is blocked, check eslint.config.mjs at the repo root for the no-restricted-imports configuration. The error messages include the rationale for each restriction.