# API Contracts in the Oshun Monorepo

This guide documents how API contracts are defined, generated, validated, and
consumed across the Oshun platform. Oshun uses a **contract-first** approach
where API interfaces are defined declaratively before implementation, enabling
type-safe communication between services, clients, and external partners.

For the architectural rationale behind the hybrid approach, see
[ADR-0005: API Contract Approach](../adr/ADR-0005-api-contract-approach.md).

---

## Table of Contents

- [Overview](#overview)
- [Contract Layers](#contract-layers)
  - [TypeScript Contracts (`@oshun/contracts`)](#typescript-contracts-oshuncontracts)
  - [OpenAPI Specifications (`@oshun/openapi`)](#openapi-specifications-oshunopenapi)
  - [Protocol Buffers (`@oshun/proto`)](#protocol-buffers-oshunproto)
  - [Per-Domain Contract Packages](#per-domain-contract-packages)
- [Code Generation Workflow](#code-generation-workflow)
  - [OpenAPI to TypeScript](#openapi-to-typescript)
  - [Proto to TypeScript, Go, Python](#proto-to-typescript-go-python)
  - [JSON Schema from Proto](#json-schema-from-proto)
- [How to Add a New Contract](#how-to-add-a-new-contract)
  - [Adding a New Event Contract](#adding-a-new-event-contract)
  - [Adding a New OpenAPI Spec](#adding-a-new-openapi-spec)
  - [Adding a New Proto Service](#adding-a-new-proto-service)
- [Consuming Contracts in Services](#consuming-contracts-in-services)
  - [Importing TypeScript Schemas](#importing-typescript-schemas)
  - [Using Generated OpenAPI Types](#using-generated-openapi-types)
  - [Using gRPC Clients from Proto](#using-grpc-clients-from-proto)
  - [Event Validation](#event-validation)
- [Validation and Testing](#validation-and-testing)
  - [Zod Runtime Validation](#zod-runtime-validation)
  - [OpenAPI Spec Validation](#openapi-spec-validation)
  - [Proto Linting and Breaking Change Detection](#proto-linting-and-breaking-change-detection)
  - [Contract Tests](#contract-tests)
- [Directory Structure Reference](#directory-structure-reference)

---

## Overview

Oshun employs a hybrid API contract strategy that uses three complementary
layers:

| Layer                  | Package            | Purpose                                               | Format                   |
| ---------------------- | ------------------ | ----------------------------------------------------- | ------------------------ |
| TypeScript Contracts   | `@oshun/contracts` | Shared schemas, event definitions, runtime validation | Zod schemas + TypeScript |
| OpenAPI Specifications | `@oshun/openapi`   | REST API definitions for external clients             | OpenAPI 3.1 YAML         |
| Protocol Buffers       | `@oshun/proto`     | gRPC service definitions for internal communication   | Proto3 + buf tooling     |

The boundary rules are:

- **OpenAPI / REST** -- Public APIs, client SDKs, partner integrations, web
  browser access.
- **Proto / gRPC** -- Internal service-to-service communication, GPU worker
  communication, real-time streaming between services.
- **TypeScript Contracts** -- Cross-domain event schemas and common types shared
  by both REST and gRPC layers within the TypeScript codebase.

```
                ┌─────────────────────────────────────────┐
                │            External Clients              │
                │  (Browsers, Mobile Apps, Partners)       │
                └─────────────────┬───────────────────────┘
                                  │
                       REST/HTTP (OpenAPI)
                                  │
                ┌─────────────────▼───────────────────────┐
                │           API Gateway / BFF              │
                │         (REST → gRPC Translation)        │
                └─────────────────┬───────────────────────┘
                                  │
                        gRPC (Protocol Buffers)
                                  │
     ┌────────────────────────────┼────────────────────────┐
     │                            │                        │
┌────▼────┐                 ┌─────▼─────┐            ┌─────▼─────┐
│  Isis   │                 │  Sophia   │            │  Hathor   │
│ Service │◄───gRPC────────►│  Service  │◄───gRPC───►│  Service  │
└─────────┘                 └───────────┘            └───────────┘
```

---

## Contract Layers

### TypeScript Contracts (`@oshun/contracts`)

**Package**: `libs/contracts/` (`@oshun/contracts`)

This is the foundational contract layer. It defines Zod schemas for common
types, domain events, and validation utilities. All TypeScript services in the
monorepo depend on this package for shared type definitions.

**Exports**:

```typescript
import {
  UUIDSchema,
  UserSchema,
  PaginationRequestSchema,
} from '@oshun/contracts';
import { EventEnvelopeSchema, validateEvent } from '@oshun/contracts/events';
import {
  UserProfileSchema,
  CreateUserRequestSchema,
} from '@oshun/contracts/common';
```

**Common schemas** (`libs/contracts/src/common/`):

| Module          | Contents                                                                        |
| --------------- | ------------------------------------------------------------------------------- |
| `primitives.ts` | UUID, Slug, Timestamp, Pagination, Cursor Pagination, Errors, Response Wrappers |
| `user.ts`       | UserSchema, UserProfileSchema, UserPreferencesSchema, CreateUserRequest, etc.   |
| `asset.ts`      | AssetSchema, AssetMetadata, CreateAssetRequest                                  |
| `project.ts`    | ProjectSchema, ProjectMember, CreateProjectRequest                              |
| `audit.ts`      | AuditLogSchema, AuditEntry                                                      |

**Event schemas** (`libs/contracts/src/events/`):

| Module          | Contents                                                                   |
| --------------- | -------------------------------------------------------------------------- |
| `envelope.ts`   | EventEnvelopeSchema, EventMetadataSchema, createEventSchema factory        |
| `validation.ts` | EventSchemaRegistry, validateEvent, validatePayload, validation middleware |
| `isis.ts`       | 9 event types (job lifecycle, asset generated, workflow, model loaded)     |
| `sophia.ts`     | 9 event types (document lifecycle, index, search, entity, relation)        |
| `hathor.ts`     | 7 event types (world lifecycle, element, narrative, simulation)            |
| `bellona.ts`    | 8 event types (session, build lifecycle, export, asset sync)               |
| `yemaya.ts`     | 12 event types (project lifecycle, member, asset lifecycle, comments)      |
| `lilith.ts`     | 10 event types (meditation, journal, session, progress, teacher, content)  |
| `aphrodite.ts`  | 25+ event types (stream, transaction, user, device, chat, moderation)      |
| `nyx.ts`        | 20+ event types (catalog, compute, render, realtime)                       |
| `psyche.ts`     | 20+ event types (session, avatar, voice, memory, persona, conferencing)    |
| `veritas.ts`    | 20+ event types (article, claim, story cluster, feed, media, NLP)          |

The event envelope provides a standardized structure for all domain events:

```typescript
// Every event follows this envelope structure
const event: EventEnvelope = {
  id: '550e8400-e29b-41d4-a716-446655440000',
  type: 'isis.job.completed',
  source: 'isis',
  timestamp: '2026-01-15T10:30:00.000Z',
  version: '1.0.0',
  priority: 'normal',
  payload: {
    /* domain-specific */
  },
  metadata: {
    correlationId: 'abc-123',
    traceId: 'trace-456',
    userId: '...',
  },
};
```

### OpenAPI Specifications (`@oshun/openapi`)

**Package**: `libs/openapi/` (`@oshun/openapi`)

This package contains OpenAPI 3.1 YAML specifications for all REST APIs exposed
by the platform. Each domain has its own spec file, and the package provides
utilities for loading, validating, and querying specifications.

**Spec files** (`libs/openapi/src/specs/`):

| Domain  | Spec File                  | Description                      |
| ------- | -------------------------- | -------------------------------- |
| Main    | `main.yaml`                | Core platform API (consolidated) |
| Lilith  | `lilith/lilith-api.yaml`   | Consciousness experience APIs    |
| Yemaya  | `yemaya/yemaya-api.yaml`   | Creative studio APIs             |
| Isis    | `isis/isis-api.yaml`       | Generative factory APIs          |
| Sophia  | `sophia/sophia-api.yaml`   | Knowledge engine APIs            |
| Hathor  | `hathor/hathor-api.yaml`   | Worldbuilding APIs               |
| Bellona | `bellona/bellona-api.yaml` | Engine bridge APIs               |
| Nyx     | `nyx/nyx-api.yaml`         | Astronomy APIs                   |

**Generated TypeScript types** (`libs/openapi/src/generated/`):

Each spec produces a generated TypeScript file with fully typed `paths`,
`operations`, and `components` types:

```typescript
// Import generated types for a specific domain
import type { paths as BellonaPaths } from '@oshun/openapi/generated/bellona';
import type { paths as IsisPaths } from '@oshun/openapi/generated/isis';

// Use with openapi-fetch or similar typed HTTP clients
type StartBuildResponse =
  BellonaPaths['/v1/builds']['post']['responses']['201'];
```

**Runtime utilities**:

```typescript
import {
  loadSpec,
  listSpecs,
  mergeSpecs,
  getSpecsByDomain,
  extractEndpoints,
  extractSchemas,
  SPEC_REGISTRY,
} from '@oshun/openapi';

// Load a spec at runtime
const bellonaSpec = await loadSpec('bellona/bellona-api.yaml');

// List all endpoints in a spec
const endpoints = extractEndpoints(bellonaSpec);

// Get all specs for a domain
const nyxSpecs = getSpecsByDomain('nyx');
```

### Protocol Buffers (`@oshun/proto`)

**Package**: `libs/proto/` (`@oshun/proto`)

This package contains Protocol Buffer definitions for gRPC inter-service
communication. It provides `.proto` files, a type-safe loader, and service
metadata.

**Proto definitions** (`libs/proto/src/`):

| Category          | Proto Files                                                                                                      | Services                                                                                           |
| ----------------- | ---------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- |
| Common            | `common/types.proto`                                                                                             | Shared types: UUID, Pagination, Error, RequestContext, Health                                      |
| Core Services     | `ai/`, `agent/`, `asset/`, `auth/`, `collaboration/`, etc.                                                       | AIService, AgentService, AssetService, AuthService, etc.                                           |
| Isis Domain       | `isis/isis.proto`                                                                                                | IsisJobService, IsisWorkflowService, IsisOutputService, IsisModelService                           |
| Sophia Domain     | `sophia/sophia.proto`                                                                                            | SophiaSearchService, SophiaDocumentService, SophiaCitationService, etc.                            |
| Shared Substrates | `shared/evidence.proto`, `shared/memory.proto`, `shared/persona_policy.proto`, `shared/generation_control.proto` | OshunEvidenceService, OshunMemoryService, OshunPersonaPolicyService, OshunGenerationControlService |
| Hathor Domain     | `hathor/hathor.proto`                                                                                            | HathorWorldService, HathorFactionService, HathorCharacterService, etc.                             |
| Rendering & 3D    | `generation3d/`, `rendering/`, `splatting/`, `procedural/`                                                       | Generation3DService, RenderingService, GaussianSplattingService                                    |
| Engine Bridges    | `bridge/blender.proto`, `bridge/godot.proto`, `bridge/unreal.proto`                                              | BlenderBridgeService, GodotBridgeService, UnrealBridgeService                                      |
| Infrastructure    | `health/`, `loadbalancing/`, `reflection/`, `pipeline/`                                                          | HealthService, LoadBalancingService, ReflectionService                                             |

**Buf configuration**:

- `libs/proto/buf.work.yaml` -- Workspace root for the proto module rooted at
  `libs/proto/src/`.
- `libs/proto/src/buf.yaml` -- Lint rules (DEFAULT + COMMENTS) and breaking
  change detection (FILE-level). Depends on `buf.build/googleapis/googleapis`
  for well-known types.
- `libs/proto/buf.gen.yaml` -- Code generation plugins for TypeScript
  (ts-proto), Go (protoc-gen-go + grpc-go), and JSON Schema.

**Loading protos at runtime**:

```typescript
import {
  loadProto,
  loadAllProtos,
  PROTO_PATHS,
  SERVICE_NAMES,
} from '@oshun/proto';

// Load a specific proto
const isisProto = await loadProto(PROTO_PATHS.isis);

// Load all protos
const allProtos = await loadAllProtos();

// Get service metadata
import { getServiceMetadata } from '@oshun/proto';
const meta = getServiceMetadata(SERVICE_NAMES.IsisJob);
// => { name: 'oshun.isis.IsisJobService', protoPath: 'isis/isis.proto', methods: [...] }
```

### Per-Domain Contract Packages

Some domains have dedicated contract packages that extend the base
`@oshun/contracts` with domain-specific schemas:

| Package             | Location                 | Description                                                   |
| ------------------- | ------------------------ | ------------------------------------------------------------- |
| `@psyche/contracts` | `libs/contracts/psyche/` | Psyche domain schemas (AI virtual assistant)                  |
| `@iris/contracts`   | `libs/contracts/iris/`   | Iris domain schemas (voice AI, conversations, memory, agents) |

These packages follow the same Zod-based schema pattern but are scoped to their
domain:

```typescript
import {
  ConversationSchema,
  MessageSchema,
  CreateMessageRequestSchema,
  type Conversation,
  type Message,
} from '@iris/contracts';

// Validate incoming request
const result = CreateMessageRequestSchema.safeParse(req.body);
if (!result.success) {
  throw new ValidationError(result.error.message);
}
```

---

## Code Generation Workflow

### OpenAPI to TypeScript

The `@oshun/openapi` package generates deterministic TypeScript types from YAML
specs using the `openapi-typescript` toolchain. The shared generator also covers
the unified Oshun BFF OpenAPI contract at
`apps/oshun/bff/openapi/oshun-bff.openapi.yaml`.

**To regenerate types**:

```bash
# Generate all tracked OpenAPI artifacts
pnpm codegen:openapi

# Verify generated files are current
pnpm codegen:openapi:check
```

This reads the tracked spec set and produces corresponding TypeScript files in
`libs/openapi/src/generated/`. The generated `index.ts` re-exports all domain
types with namespace aliases:

```typescript
// Auto-generated - libs/openapi/src/generated/index.ts
export * as lilith from './lilith.js';
export * as yemaya from './yemaya.js';
export * as isis from './isis.js';
export * as sophia from './sophia.js';
export * as hathor from './hathor.js';
export * as bellona from './bellona.js';
export * as nyx from './nyx.js';
export * as calliope from './calliope.js';
export * as oshunBff from './oshun-bff.js';
```

**Validation**:

```bash
# Lint OpenAPI specs with Redocly
pnpm nx openapi:validate @oshun/openapi

# Or via package script
cd libs/openapi && pnpm validate
```

### Proto to TypeScript, Go, Python

The `@oshun/proto` package uses `buf` for code generation from `.proto` files.

**To regenerate code and tracked proto artifacts**:

```bash
# Generate the tracked Buf image snapshot used for drift detection
pnpm codegen:proto

# Generate language-specific outputs from buf.gen.yaml
pnpm proto:generate

# Verify the tracked Buf image snapshot is current
pnpm codegen:proto:check
```

The tracked proto artifact is `libs/proto/generated/buf-image.json`, a
deterministic Buf image snapshot used to detect contract drift in review and CI.
The separate `buf.gen.yaml` configuration still produces language-specific code
in three families:

| Plugin                          | Output Directory  | Language    | Options                                           |
| ------------------------------- | ----------------- | ----------- | ------------------------------------------------- |
| `stephenh-ts-proto`             | `gen/ts/`         | TypeScript  | ES module interop, grpc-js services, string enums |
| `protocolbuffers/go`            | `gen/go/`         | Go          | Source-relative paths                             |
| `grpc/go`                       | `gen/go/`         | Go gRPC     | Source-relative paths                             |
| `chrusty-protoc-gen-jsonschema` | `gen/jsonschema/` | JSON Schema | All fields required, no additional properties     |

### JSON Schema from Proto

The buf generation pipeline also produces JSON Schema files from proto
definitions. These can be used for validation in non-TypeScript contexts (Python
services, API gateways, configuration validators):

```bash
# Generated alongside TypeScript and Go output
buf generate  # produces gen/jsonschema/*.schema.json
```

### Prisma Schema Snapshots

Tracked Prisma datamodels also emit generated SQL snapshots so schema changes
cannot land without updating their derived contract artifact.

```bash
# Generate all tracked Prisma schema snapshots
pnpm codegen:schema

# Verify the snapshots are current
pnpm codegen:schema:check
```

Each tracked schema writes an adjacent snapshot at
`libs/<domain>/database/prisma/generated/schema.sql`.

### Unified Drift Check

For CI or pre-merge verification, run the combined contract drift gate:

```bash
# Regenerate every tracked contract artifact
pnpm contracts:generate

# Fail if any OpenAPI, proto, or schema artifact drifted
pnpm contracts:check
```

---

## How to Add a New Contract

### Adding a New Event Contract

1. **Create the event schema** in the appropriate domain file under
   `libs/contracts/src/events/`. For example, to add a new Isis event:

   ```typescript
   // libs/contracts/src/events/isis.ts

   // Add the new event payload schema
   export const IsisModelUnloadedPayloadSchema = z.object({
     modelId: UUIDSchema,
     workerId: z.string(),
     reason: z.enum(['manual', 'timeout', 'error', 'preemption']),
     durationMs: z.number().int().nonnegative(),
   });

   // Create the typed event schema
   export const IsisModelUnloadedEventSchema = createEventSchema(
     'isis.model.unloaded',
     'isis',
     IsisModelUnloadedPayloadSchema
   );
   ```

2. **Add the event type constant** to the `IsisEventTypes` object and to the
   `AllEventTypes.isis` object in `libs/contracts/src/events/index.ts`.

3. **Register in the validation registry** by adding an entry to
   `EventSchemaRegistry` in `libs/contracts/src/events/validation.ts`:

   ```typescript
   ['isis.model.unloaded', {
     type: 'isis.model.unloaded',
     source: 'isis',
     schema: IsisModelUnloadedEventSchema,
     payloadSchema: IsisModelUnloadedEventSchema.shape.payload,
     description: 'Model unloaded from worker',
   }],
   ```

4. **Build and test**:

   ```bash
   pnpm nx test @oshun/contracts
   pnpm nx build @oshun/contracts
   ```

### Adding a New OpenAPI Spec

1. **Create a YAML spec** following OpenAPI 3.1.0 format in the appropriate
   domain directory:

   ```yaml
   # libs/openapi/src/specs/mydomain/mydomain-api.yaml
   openapi: 3.1.0
   info:
     title: My Domain API
     version: 1.0.0
     description: Description of the API
   servers:
     - url: https://api.oshun.io/mydomain
       description: Production
     - url: http://localhost:3000
       description: Local Development
   paths:
     /v1/resources:
       get:
         summary: List resources
         operationId: listResources
         # ...
   components:
     schemas:
       Resource:
         type: object
         # ...
     securitySchemes:
       bearerAuth:
         type: http
         scheme: bearer
         bearerFormat: JWT
   ```

2. **Register in the spec registry** (`libs/openapi/src/utils/registry.ts`):

   ```typescript
   export const SPEC_PATHS = {
     // ... existing paths
     mydomain: {
       api: 'mydomain/mydomain-api.yaml',
     },
   };

   export const SPEC_REGISTRY: Record<string, SpecMetadata> = {
     // ... existing entries
     mydomain: {
       name: 'My Domain API',
       version: '1.0.0',
       description: 'Description of the API',
       specPath: SPEC_PATHS.mydomain.api,
       domain: 'mydomain' as ApiDomain,
       tags: ['mydomain'],
       basePath: '/v1',
     },
   };
   ```

3. **Add the domain to `ApiDomain`** if it is a new domain.

4. **Regenerate TypeScript types**:

   ```bash
   pnpm nx openapi:gen @oshun/openapi
   ```

5. **Validate the spec**:

   ```bash
   pnpm nx openapi:validate @oshun/openapi
   ```

### Adding a New Proto Service

1. **Create a `.proto` file** in the appropriate domain directory:

   ```protobuf
   // libs/proto/src/mydomain/mydomain.proto
   syntax = "proto3";

   package oshun.mydomain;

   option go_package = "github.com/oshun/proto/gen/go/mydomain";

   import "common/types.proto";

   // Service definition
   service MyDomainService {
     // Create a new resource
     rpc CreateResource(CreateResourceRequest) returns (CreateResourceResponse);
     // Get a resource by ID
     rpc GetResource(GetResourceRequest) returns (GetResourceResponse);
     // Stream updates
     rpc StreamUpdates(StreamUpdatesRequest) returns (stream UpdateEvent);
   }

   message CreateResourceRequest {
     oshun.common.RequestContext context = 1;
     string name = 2;
     string description = 3;
   }

   // ... other messages
   ```

2. **Register in the loader** (`libs/proto/src/loader.ts`):

   ```typescript
   export const PROTO_PATHS = {
     // ... existing paths
     mydomain: 'mydomain/mydomain.proto',
   };
   ```

3. **Register in service metadata** (`libs/proto/src/services.ts`):

   ```typescript
   export const SERVICE_NAMES = {
     // ... existing names
     MyDomain: 'oshun.mydomain.MyDomainService',
   };
   ```

4. **Lint and generate**:

   ```bash
   # Lint proto files
   pnpm nx proto:lint @oshun/proto

   # Generate code
   pnpm nx proto:gen @oshun/proto
   ```

---

## Consuming Contracts in Services

### Importing TypeScript Schemas

All TypeScript services can import schemas directly from `@oshun/contracts`:

```typescript
import {
  // Common types
  UUIDSchema,
  type UUID,
  PaginationRequestSchema,
  type PaginationRequest,
  ErrorCodes,

  // Domain events
  AllEventTypes,

  // Response helpers
  createDataResponseSchema,
  createPaginatedSchema,
} from '@oshun/contracts';

// Validate a request
const paginationResult = PaginationRequestSchema.safeParse(req.query);
if (!paginationResult.success) {
  return res.status(400).json({
    success: false,
    error: {
      code: ErrorCodes.VALIDATION_ERROR,
      message: 'Invalid pagination parameters',
      details: paginationResult.error.issues,
    },
  });
}

// Create a typed paginated response schema
const PaginatedWidgetsSchema = createPaginatedSchema(WidgetSchema);
type PaginatedWidgets = z.infer<typeof PaginatedWidgetsSchema>;
```

### Using Generated OpenAPI Types

Services that implement REST endpoints can import generated types from
`@oshun/openapi` to ensure their implementations match the spec:

```typescript
import type { paths as BellonaPaths } from '@oshun/openapi/generated/bellona';

// Extract request/response types from the OpenAPI spec
type StartBuildRequest =
  BellonaPaths['/v1/builds']['post']['requestBody']['content']['application/json'];
type StartBuildResponse =
  BellonaPaths['/v1/builds']['post']['responses']['201']['content']['application/json'];

// Use in route handlers
app.post(
  '/v1/builds',
  async (
    req: Request<{}, {}, StartBuildRequest>,
    res: Response<StartBuildResponse>
  ) => {
    // Implementation...
  }
);
```

### Using gRPC Clients from Proto

Internal services use `@oshun/proto` to create gRPC clients:

```typescript
import {
  loadProto,
  PROTO_PATHS,
  SERVICE_NAMES,
  createCredentials,
  DEFAULT_CHANNEL_OPTIONS,
} from '@oshun/proto';

// Load the Isis proto definitions
const isisProto = await loadProto(PROTO_PATHS.isis);

// Create a gRPC client
const credentials = createCredentials(false); // insecure for local dev
const isisJobClient = new isisProto.oshun.isis.IsisJobService(
  'localhost:50051',
  credentials,
  DEFAULT_CHANNEL_OPTIONS
);

// Make an RPC call
isisJobClient.SubmitJob(request, (error, response) => {
  if (error) {
    console.error('gRPC error:', error);
    return;
  }
  console.log('Job submitted:', response);
});
```

### Event Validation

The contracts package provides a complete event validation system:

```typescript
import {
  validateEvent,
  validatePayload,
  validateEventOrThrow,
  isEventTypeRegistered,
  getEventTypesByDomain,
  createValidationMiddleware,
  createPublishValidator,
} from '@oshun/contracts';

// Validate a full event envelope
const result = validateEvent(incomingEvent);
if (!result.success) {
  console.error('Invalid event:', result.errors);
}

// Validate just the payload for a known event type
const payloadResult = validatePayload('isis.job.completed', payload);

// Throw on invalid (for strict mode)
validateEventOrThrow(incomingEvent);

// Create middleware for event processing pipelines
const middleware = createValidationMiddleware({
  strict: true,
  onError: (error, event) => {
    logger.error('Event validation failed', { error, event });
  },
});

// Create a pre-publish validator for event bus
const validator = createPublishValidator({ strict: true, warnOnUnknown: true });
const validatedPayload = validator('isis.job.completed', payload);
```

---

## Validation and Testing

### Zod Runtime Validation

All `@oshun/contracts` schemas use [Zod](https://zod.dev) for runtime
validation. This means every schema can be used both as a TypeScript type (via
`z.infer`) and as a runtime validator:

```typescript
import { UserSchema, type User } from '@oshun/contracts';

// Compile-time type
const user: User = {
  /* ... */
};

// Runtime validation
const result = UserSchema.safeParse(untrustedInput);
if (result.success) {
  // result.data is typed as User
  processUser(result.data);
} else {
  // result.error contains detailed validation issues
  console.error(result.error.issues);
}
```

### OpenAPI Spec Validation

OpenAPI specs are validated using Redocly CLI:

```bash
# Validate all specs
pnpm nx openapi:validate @oshun/openapi

# Validate specific domain specs only
cd libs/openapi && pnpm validate

# Validate all specs including the consolidated main spec
cd libs/openapi && pnpm validate:all
```

You can also check for breaking changes between spec versions:

```bash
# Diff specs against the last committed version
cd libs/openapi && pnpm diff

# Check for breaking changes (exits non-zero if breaking changes found)
cd libs/openapi && pnpm diff:check
```

### Proto Linting and Breaking Change Detection

Proto files are linted and checked for breaking changes using
[buf](https://buf.build):

```bash
# Lint all proto files
pnpm nx proto:lint @oshun/proto

# Or directly via buf
cd libs/proto && buf lint

# Check for breaking changes against the last committed version
cd libs/proto && buf breaking --against '.git#branch=main'
```

The buf lint configuration enforces:

- **DEFAULT** rules (standard protobuf best practices)
- **COMMENTS** (all public elements must have comments)
- `enum_zero_value_suffix: _UNSPECIFIED` (enum zero values end in
  `_UNSPECIFIED`)
- No same request/response types for different RPCs
- Google protobuf empty requests/responses are allowed

The breaking change detection uses **FILE**-level granularity, meaning it
detects field renumbering, type changes, and removal of fields or services.

### Contract Tests

The `@oshun/contracts` package includes a test suite that validates all schemas
are well-formed and that the event registry is consistent:

```bash
pnpm nx test @oshun/contracts
```

The test file at `libs/contracts/src/contracts.spec.ts` covers:

- All primitive schemas accept valid inputs and reject invalid inputs
- Event schemas match their registry entries
- The `AllEventTypes` constant is consistent with registered schemas
- Validation functions return correct results for valid and invalid events
- Middleware and validator factories work correctly

---

## Directory Structure Reference

```
libs/
├── contracts/                      # @oshun/contracts - TypeScript schemas
│   ├── package.json
│   ├── project.json
│   ├── src/
│   │   ├── index.ts                # Root export (common + events)
│   │   ├── contracts.spec.ts       # Contract tests
│   │   ├── common/
│   │   │   ├── index.ts            # Common schema exports
│   │   │   ├── primitives.ts       # UUID, Slug, Timestamp, Pagination, Errors
│   │   │   ├── user.ts             # User schemas
│   │   │   ├── asset.ts            # Asset schemas
│   │   │   ├── project.ts          # Project schemas
│   │   │   └── audit.ts            # Audit log schemas
│   │   └── events/
│   │       ├── index.ts            # Event export barrel + AllEventTypes
│   │       ├── envelope.ts         # EventEnvelope, EventMetadata, createEventSchema
│   │       ├── validation.ts       # EventSchemaRegistry, validateEvent, middleware
│   │       ├── isis.ts             # Isis domain events
│   │       ├── sophia.ts           # Sophia domain events
│   │       ├── hathor.ts           # Hathor domain events
│   │       ├── bellona.ts          # Bellona domain events
│   │       ├── yemaya.ts           # Yemaya domain events
│   │       ├── lilith.ts           # Lilith domain events
│   │       ├── aphrodite.ts        # Aphrodite domain events
│   │       ├── nyx.ts              # Nyx domain events
│   │       ├── psyche.ts           # Psyche domain events
│   │       └── veritas.ts          # Veritas domain events
│   ├── iris/                       # @iris/contracts - Per-domain package
│   │   ├── package.json
│   │   ├── project.json
│   │   └── src/
│   │       ├── index.ts
│   │       ├── common/
│   │       ├── conversation/
│   │       ├── memory/
│   │       └── agent/
│   ├── psyche/                     # @psyche/contracts - Per-domain package
│   │   ├── package.json
│   │   ├── project.json
│   │   └── src/
│   │       ├── index.ts
│   │       └── common/
│   └── veritas/                    # Veritas contracts (placeholder)
│       └── .gitkeep
│
├── openapi/                        # @oshun/openapi - OpenAPI specifications
│   ├── package.json
│   ├── project.json
│   └── src/
│       ├── index.ts                # Loader + registry exports
│       ├── openapi.spec.ts         # Spec validation tests
│       ├── utils/
│       │   ├── loader.ts           # loadSpec, loadSpecSync, listSpecs, mergeSpecs
│       │   └── registry.ts         # SPEC_PATHS, SPEC_REGISTRY, helper functions
│       ├── specs/                   # OpenAPI 3.1 YAML specifications
│       │   ├── main.yaml
│       │   ├── lilith/lilith-api.yaml
│       │   ├── yemaya/yemaya-api.yaml
│       │   ├── isis/isis-api.yaml
│       │   ├── sophia/sophia-api.yaml
│       │   ├── hathor/hathor-api.yaml
│       │   ├── bellona/bellona-api.yaml
│       │   └── nyx/nyx-api.yaml
│       └── generated/              # Auto-generated TypeScript types
│           ├── index.ts
│           ├── lilith.ts
│           ├── yemaya.ts
│           ├── isis.ts
│           ├── sophia.ts
│           ├── hathor.ts
│           ├── bellona.ts
│           ├── nyx.ts
│           ├── calliope.ts
│           └── oshun-bff.ts
│
└── proto/                          # @oshun/proto - Protocol Buffer definitions
    ├── package.json
    ├── project.json
    ├── buf.work.yaml               # Buf workspace root for src/
    ├── buf.gen.yaml                # Code generation plugins
    ├── generated/
    │   └── buf-image.json          # Deterministic Buf image snapshot
    └── src/
        ├── buf.yaml                # Buf module config + breaking change rules
        ├── index.ts                # Proto loader + service exports
        ├── proto.spec.ts           # Proto loading tests
        ├── loader.ts               # loadProto, loadAllProtos, PROTO_PATHS
        ├── services.ts             # SERVICE_NAMES, getServiceMetadata
        ├── common/types.proto      # Shared types (UUID, Pagination, Error, Health)
        ├── shared/common.proto     # Shared substrate enums + version descriptors
        ├── shared/evidence.proto   # OSHUN grounded evidence substrate
        ├── shared/memory.proto     # OSHUN memory and continuity substrate
        ├── shared/persona_policy.proto
        ├── shared/generation_control.proto
        ├── ai/ai.proto             # AI generation services
        ├── agent/agent.proto       # Agent management
        ├── asset/asset.proto       # Asset management
        ├── auth/auth.proto         # Authentication
        ├── collaboration/collaboration.proto
        ├── project/project.proto
        ├── user/user.proto
        ├── isis/isis.proto         # Isis domain (4 services)
        ├── sophia/sophia.proto     # Sophia domain (5 services)
        ├── hathor/hathor.proto     # Hathor domain (7 services)
        ├── generation3d/generation3d.proto
        ├── rendering/rendering.proto
        ├── splatting/gaussian_splatting.proto
        ├── procedural/procedural.proto
        ├── bridge/blender.proto
        ├── bridge/godot.proto
        ├── bridge/unreal.proto
        ├── health/health.proto
        ├── loadbalancing/loadbalancing.proto
        ├── reflection/reflection.proto
        └── pipeline/autonomous_pipeline.proto

libs/<domain>/database/prisma/
└── generated/
    └── schema.sql                  # Deterministic Prisma schema snapshot
```

---

## Related Documentation

- [ADR-0005: API Contract Approach](../adr/ADR-0005-api-contract-approach.md) --
  Architectural decision record explaining the hybrid approach
- [ADR-0004: Eventing Strategy](../adr/ADR-0004-eventing-strategy.md) -- Event
  bus and eventing patterns (complements the event contract layer)
- [Cross-Domain Integration](cross-domain-integration.md) -- How domains
  communicate using contracts
- **OSHUN V1 Subsystem Ownership Matrix** (program governance doc, maintained
  outside this repo) -- Authoritative OSHUN V1 ownership reference
- **OSHUN Metis Subsystem Ownership Matrix** (program governance doc, maintained
  outside this repo) -- Canonical Metis-to-substrate ownership and signoff
  reference
- **When To Call Which Subsystem Guide** (program governance doc, maintained
  outside this repo) -- Operational call-routing guide for OSHUN V1 subsystem
  composition
- **OSHUN V1 Program Charter** (program governance doc, maintained outside this
  repo) -- Current OSHUN V1 shell and subsystem ownership boundaries
- **OSHUN Unified Consumer, Admin, and Core Systems PRD** (program governance
  doc, maintained outside this repo) -- Current end-state OSHUN V1 ownership and
  adapter requirements
- **Data Ownership Matrix** (legacy pre-V1 snapshot, no longer tracked in this
  repo) -- Legacy pre-V1 service/domain ownership snapshot
- [API Authentication](../api/authentication.md) -- Authentication flows for
  REST and gRPC
