docs/architecture/packages.md
Promptfoo still publishes one package today, but the repository is beginning to model the internal boundaries that would support a future multi-package split.
| Layer | Current roots | Intended role |
|---|---|---|
facade | src/index.ts | Public compatibility surface |
contracts | src/contracts | Leaf-safe shared contracts and schemas |
legacy-contracts | src/types, src/validators | Transitional mixed runtime types and validators |
core | assertions, matchers, prompts, scheduler, test-case logic | Evaluation domain logic |
node | database, models, config, storage, src/evaluate.ts, src/node | Node runtime adapters |
providers | src/providers | Concrete provider implementations |
redteam | src/redteam | Red-team workflows |
view-server | src/server | Local server and API routes |
cli | src/main.ts, src/commands | Command-line orchestration |
app | src/app/src | Browser UI |
The source of truth for these temporary private layers is
architecture/layers.json.
Internal modules must not import src/index.ts.
src/index.ts is the public facade. Importing it from inside the product makes
the dependency graph point inward through the public API, which makes later
package extraction harder and can hide cycles.
Run the check with:
npm run architecture:check
src/contracts is the first intentionally leaf-safe surface. It currently owns
the dependency-free-or-zod subset that can plausibly become a future
@promptfoo/schema package:
The older src/types and src/validators paths remain as compatibility shims or
mixed transitional modules. They are useful public/internal surfaces today, but
they are not yet clean enough to call a package boundary.
Leaf layers may import only themselves plus external packages. The same architecture check enforces that rule so this first extracted surface cannot quietly grow back upward into Node, provider, or redteam code.
The dependency report groups direct runtime imports by the private layer that currently uses them:
npm run deps:ownership
The report is intentionally descriptive for now. It gives us the evidence needed to move dependencies into future packages without guessing at ownership.