Veefore docs

Repository layout

Where everything lives, and the dependency direction that keeps it that way.

An npm workspace monorepo. One package.json at the root with the shared dependencies, and a workspace per package.

text
veefore/
├── packages/
│   ├── types/          shared vocabulary — no runtime dependencies
│   ├── common/         config, logging, redaction, crypto, resilience, telemetry
│   ├── db/             driver, migrations, repositories, schema catalogue
│   ├── identity/       key handling, JWS
│   ├── policy/         evaluator, schema, fields, templates, diff, Rego export
│   ├── sdk-js/         the TypeScript SDK
│   ├── sdk-python/     the Python SDK
│   └── cli/            the `veefore` command
├── services/
│   └── core/           every domain service
├── apps/
│   ├── control-plane/  the management HTTP surface + the worker
│   └── console/        the browser app
├── gateway/            the enforcement HTTP surface
├── docs/               this site
├── examples/           four working programs
├── scripts/            build, verify, migrate, seed, smoke tests, audits
├── tests/              seven suites
└── infrastructure/     docker, kubernetes, helm, terraform

#Dependency direction

Strictly one way. Nothing on the left depends on anything to its right.

text
types ◀── common ◀── db ◀── policy ◀── services/core ◀── control-plane
                                                      ◀── gateway
identity ◀──────────────────────────────────────────────┘

sdk-js, sdk-python, cli   ── depend on types only (and the wire contract)
console                   ── depends on types only

Why the SDKs depend only on `types`

An SDK that imported services/core could, in principle, contain logic that looked like authorization. It would also be enormous, and it would mean publishing server internals to every consumer.

Depending only on the shared vocabulary makes it structurally impossible for the SDK to decide anything. It can only describe a request and interpret a response. → The boundary

The console likewise depends only on types. It cannot evaluate a policy even by accident.

#packages/types

The vocabulary. No runtime dependencies at all.

enums.ts Lifecycle states, decisions, outcomes, stages, severities, signal types
permissions.ts The permission list, roles, high-impact and step-up sets
policy.ts The policy IR, fields, operators, evaluation input and output
domain.ts Domain entities
gateway.ts The gateway wire contract
events.ts Event types, and which are webhook-subscribable
errors.ts ERROR_CODES — the canonical table
api.ts API request and response shapes

Several of these are the source for a generated reference page, which is why they are worth keeping as plain data rather than as logic.

#packages/common

config.ts Environment validation. Invalid config stops the process
logger.ts pino, with redaction applied on ingest
redaction.ts The deny-lists that strip secrets before a line is constructed
crypto.ts Sealing, HMAC, canonical JSON
errors.ts VeeforeError, carrying a code and a safe message
pagination.ts Cursor encoding
rate-limit.ts In-process or Redis-backed
resilience.ts Circuit breakers, timeouts
telemetry.ts Every Prometheus metric
request-context.ts Request and trace id propagation
money.ts Minor-unit arithmetic. Formatting and comparison only
kv.ts, ids.ts, time.ts Small utilities

`money.ts` does arithmetic, not movement

Minor-unit handling for comparing an amount against a threshold without floating-point error. There is nothing in it that transfers anything. → Scope

#packages/db

driver.ts abstracts PostgreSQL and the embedded PGlite behind one interface. Three bugs worth knowing about were fixed here, and each is documented in a comment at the site:

  • pg is CommonJS, so under Node's ESM loader await import('pg') exposes only default. A named { Pool } import was undefined.
  • node-postgres returns an array of results for multi-statement SQL. Reading .rows off the array gave undefined and threw after the DDL committed — so the schema applied but was not recorded.
  • close() on the embedded driver lazily booted a fresh empty database on the next query, which left the gateway's readiness check green with no data behind it. close() is now terminal.

repository.ts and repositories.ts implement the tenant scope guard. Every method takes a scope and refuses without one.

#services/core

One file per domain, and enforcement.ts is the one to read first — it implements the twelve-stage pipeline.

enforcement.ts The pipeline
agents.ts, agent-identity.ts, passport.ts Identity and lifecycle
policies.ts, simulation.ts Authoring, versioning, simulation
delegation.ts Chain resolution and the escalation refusal
risk.ts The thirteen signals
approvals.ts Routing, quorum, expiry
credentials.ts The broker, sealing and leasing
tools.ts, tool-runtime.ts The registry and egress
audit.ts, audit-query.ts The hash chain
trust.ts Evidence
incidents.ts Investigations
a2a.ts Peer connections
jobs.ts The queue
webhooks.ts Signing and delivery
tenancy.ts, team.ts, authorization.ts, auth.ts Tenancy and access control
demo-seed.ts, seed.ts Seeding

#scripts

The ones worth knowing:

verify-all.mjs The 23-stage gate. npm run verify
scope-audit.ts Fails the build if an out-of-scope feature exists
quality-audit.ts Fails it on mock data, hardcoded metrics, auth bypass, fail-open, committed secrets
migrate.ts Apply, or --check against a throwaway database
seed.ts Empty or --demo
smoke.ts, smoke-gateway.ts, smoke-sdk.ts, smoke-python-sdk.ts, smoke-cli.ts, smoke-console.ts Real processes, real HTTP
validate-infrastructure.mjs Container, Kubernetes, Helm, Terraform
lib/isolated-env.ts Test isolation that verifies pinning took effect, and clears ambient VEEFORE_* variables

Why `isolated-env.ts` verifies rather than assumes

A module-scope getLogger() once froze the whole app config at import time, so the smoke tests' isolation was silently ignored and they wrote five organizations into the shared database.

The helper now asserts that pinning actually took effect. Isolation you have not verified is isolation you do not have.

#tests

Seven suites, one Vitest project each: unit, integration, contract, policy, security, e2e, chaos. Plus the Python SDK's own pytest suite and the console's Vitest suite.

→ Testing strategy

#Conventions

Explicit .ts extensions in imports. Node's ESM resolver requires them, and the project does not use a bundler for the backend.

No barrel re-exports across package boundaries except each package's index.ts. Keeps the dependency graph readable.

Comments explain why, not what. Several of the comments in driver.ts and isolated-env.ts document a specific bug, because the next person to touch that code needs the reason, not a restatement of the line.

One file per domain in services/core. Large files, deliberately. The alternative is a service split across eight files where the pipeline is harder to follow than the problem it solves.

Identity, authority, policy and enforcement for autonomous AI agents.