Skip to content

Latest commit

 

History

History
60 lines (49 loc) · 3.75 KB

File metadata and controls

60 lines (49 loc) · 3.75 KB

Module boundaries

The repo is layered — every Python module sits in exactly one layer, and layer flow is one-way. Reverse imports are a CI failure (lint-imports job).

Layer diagram

                 ┌──────────────┐    ┌──────────────┐
                 │  src.api     │    │  src.eval    │   request handlers + eval runner
                 │  /api/v1/*   │    │  pytest eval │
                 └──────┬───────┘    └──────┬───────┘
                        │                   │
                        ▼                   ▼
                 ┌──────────────────────────────┐
                 │       src.agent              │   the LLM loop (tool-calling, CoT)
                 └──────────────┬───────────────┘
                                │
                                ▼
                 ┌──────────────────────────────┐
                 │       src.tools              │   typed tool registry + implementations
                 └──────────────┬───────────────┘
                                │
                                ▼
                 ┌──────────────────────────────┐
                 │        src.data              │   ingestion + queries (DB, files, …)
                 └──────────────┬───────────────┘
                                │
                                ▼
                 ┌──────────────────────────────┐
                 │     src.observability        │   tracing / logging / spans
                 └──────────────┬───────────────┘
                                │
                                ▼
                 ┌──────────────────────────────┐
                 │       src.models             │   Pydantic contracts (StrictModel)
                 │   (depends on nothing in src)│
                 └──────────────────────────────┘

The contracts

Defined in pyproject.toml [tool.importlinter]:

  1. Layered contractapi | eval → agent → tools → data → observability → models. Modules at level N may import modules at level N+1 and below. Anything else fails.

  2. Forbidden contractsrc.models imports nothing from src/. Models are leaf data; they neither know about the API surface nor reach back into observability. Keeping them isolated means schema bugs surface at construction, not via stack traces from deeper modules.

Adding a layer

When the project grows a new layer (cache, queue, persistence-DTO mapper):

  1. Add the package under src/.
  2. Add it to the layers list in [tool.importlinter] in the right position.
  3. Add a tests/test_<layer>.py with at least the unhappy-path tests.
  4. Update the diagram above.
  5. Update EXEMPT_WORKFLOWS in .github/scripts/check_required_contexts.py only if the layer ships its own CI job that should NOT be required.

The frontend (frontend/) is its own tree with its own quality gates (ESLint flat config + Prettier + tsc + Vitest); cross-tree imports are forbidden by build (Vite has no Python module resolver) and reviewed by hand.