Skip to content

Overview

Covenant solves the most common friction in full-stack development: calling your backend from your frontend without losing type safety, duplicating types, or guessing at API shapes.

It accomplishes this with three core ideas:

  • Covenant files — a shared contract imported by both frontend and backend. It only contains validation schemas, never implementation. This means an AI agent (or human) can work on either side knowing only the covenant.
  • Resources — every procedure declares which data it touches. When a mutation runs, listeners automatically refetch. Cache invalidation becomes declarative.
  • Sidekick — an optional WebSocket service that extends resource invalidation across clients and enables realtime bidirectional channels.

A Covenant app has three parts:

sequenceDiagram
participant C as Client
participant S as Server
participant SK as Sidekick (optional)
C->>S: POST /api/covenant (procedure call)
S->>C: Response + resource list
Note over C: Mutation triggers local refetch of listeners
C->>SK: WebSocket subscribe to resources
SK->>C: Push update when resource changes
C->>S: Refetch procedure

The covenant file sits at the center — both sides import it for types, but they never import each other:

covenant.ts
/ \
server.ts client.ts
(backend) (frontend)

This hard separation makes Covenant AI-friendly: an agent working on the frontend only needs to read covenant.ts, not the server implementation.

Every Covenant app follows the same pattern:

  1. DeclaredeclareCovenant({ procedures, channels }) in a shared file
  2. ImplementCovenantServer with defineProcedure() / defineChannel() on the server
  3. CallCovenantClient or CovenantReactClient on the frontend

See Quickstart for a complete working example.