Platform Compiler — Contract Model¶
Document: 2 of 4 Status: Canonical Depends on: Core Object Model (arch_01) Required by: Projection Model, Receipt & Provenance Model
Purpose¶
This document defines how contracts are structured, stored, versioned, and consumed by the Platform Compiler. It establishes the strict boundary between what is authored (owned by Bluefly), what is imported (owned by external authorities), and what is generated (owned by the compiler). It also retires ai.json as a source of truth.
The Schema / Instance Distinction¶
Schemas define shape. Objects instantiate schemas.
These are not the same thing and must not live in the same place.
contracts/ ← Schema definitions. Humans author these.
objects/ ← Object instances conforming to those schemas.
providers/ ← External authority contracts. Imported, not authored.
generated/ ← Compiler output. Never authored or edited.
A Capability schema lives in contracts/. A specific capability like platform.capability.compliance is instantiated as an object in objects/capabilities/. The compiler reads the schema to validate the object, then reads the object to generate projections.
Registry Directory Structure¶
api-schema-registry/
│
├── contracts/
│ ├── schemas/
│ │ ├── authority.schema.yaml
│ │ ├── capability.schema.yaml
│ │ ├── contract.schema.yaml
│ │ ├── deployment.schema.yaml
│ │ ├── provider.schema.yaml
│ │ ├── runtime.schema.yaml
│ │ ├── platform.schema.yaml
│ │ ├── tunnel.schema.yaml
│ │ ├── projection.schema.yaml
│ │ └── receipt.schema.yaml
│ │
│ └── bluefly/ ← Bluefly-authored interface contracts
│ ├── platform/
│ │ ├── compliance/
│ │ │ └── openapi.yaml
│ │ ├── authentication/
│ │ │ └── oidc.yaml
│ │ ├── agent-ui/
│ │ │ └── ag-ui.yaml ← AG-UI protocol contract
│ │ ├── tool-access/
│ │ │ └── mcp.yaml ← MCP protocol contract
│ │ ├── agent-federation/
│ │ │ └── a2a.yaml ← A2A protocol contract
│ │ └── workflow-engine/
│ │ └── openapi.yaml
│ ├── ossa/
│ │ ├── agent-contract/
│ │ ├── agent-communication/
│ │ └── agent-discovery/
│ ├── portfolio/
│ │ ├── product/
│ │ ├── offering/
│ │ └── pack/
│ └── products/
│ ├── copaw/
│ ├── contractplane/
│ ├── drupl/
│ ├── contextcontrol/
│ ├── agentblu/
│ └── blutown/
│
├── objects/
│ ├── authorities/
│ │ ├── bluefly.yaml
│ │ ├── acquia.yaml
│ │ ├── google.yaml
│ │ ├── anthropic.yaml
│ │ ├── apple.yaml
│ │ └── ...
│ ├── capabilities/
│ │ ├── platform/
│ │ │ ├── compliance.yaml
│ │ │ ├── authentication.yaml
│ │ │ ├── agent-ui.yaml
│ │ │ ├── tool-access.yaml
│ │ │ ├── agent-federation.yaml
│ │ │ ├── workflow-engine.yaml
│ │ │ ├── mesh.yaml
│ │ │ ├── chat.yaml
│ │ │ ├── router.yaml
│ │ │ └── ...
│ │ └── products/
│ │ ├── copaw/
│ │ └── ...
│ ├── deployments/
│ │ ├── oracle/
│ │ │ ├── compliance.yaml
│ │ │ ├── authentication.yaml
│ │ │ ├── mesh.yaml
│ │ │ └── ...
│ │ ├── nas/
│ │ │ ├── storage.yaml
│ │ │ ├── npm-registry.yaml
│ │ │ └── ...
│ │ └── products/
│ │ ├── drupl/
│ │ └── ...
│ ├── runtimes/
│ │ ├── oracle-primary.yaml
│ │ ├── nas-primary.yaml
│ │ └── cloudflare-global.yaml
│ ├── platforms/
│ │ ├── oracle.yaml
│ │ ├── nas.yaml
│ │ └── cloudflare.yaml
│ └── tunnels/
│ ├── oracle-platform.yaml
│ ├── oracle-duadp.yaml
│ └── nas-platform.yaml
│
├── providers/
│ ├── acquia/
│ │ ├── provider.yaml ← Provider metadata (required)
│ │ └── imports/
│ │ ├── source/
│ │ │ ├── manifest.yaml ← Import provenance
│ │ │ └── openapi.yaml ← Imported artifact (never modified)
│ │ └── cms/
│ │ ├── manifest.yaml
│ │ └── jsonapi.yaml
│ ├── anthropic/
│ │ ├── provider.yaml
│ │ └── imports/
│ │ └── mcp/
│ │ ├── manifest.yaml
│ │ └── specification.yaml
│ ├── google/
│ │ ├── provider.yaml
│ │ └── imports/
│ │ └── a2a/
│ │ ├── manifest.yaml
│ │ └── specification.yaml
│ ├── apple/
│ │ ├── provider.yaml
│ │ └── imports/
│ │ └── appintents/
│ │ ├── manifest.yaml
│ │ └── schema.yaml
│ ├── cloudflare/
│ │ ├── provider.yaml
│ │ └── imports/
│ │ └── openapi/
│ │ ├── manifest.yaml
│ │ └── openapi.yaml
│ ├── drupal/
│ │ ├── provider.yaml
│ │ └── imports/
│ │ └── jsonapi/
│ │ ├── manifest.yaml
│ │ └── openapi.yaml
│ ├── kubernetes/
│ │ ├── provider.yaml
│ │ └── imports/
│ │ └── crds/
│ ├── openai/
│ │ ├── provider.yaml
│ │ └── imports/
│ │ └── openapi/
│ └── opentelemetry/
│ ├── provider.yaml
│ └── imports/
│ └── otlp/
│
└── generated/ ← Compiler output. Never edit.
├── catalog/
│ ├── capabilities.json ← All capability objects
│ ├── deployments.json ← All deployment objects with state
│ ├── service-catalog.json ← Service discovery catalog
│ └── control-plane.json ← Control plane map
├── indexes/
│ ├── endpoints-index.json ← Flat endpoint index (existing)
│ ├── urls.json ← All service URLs by env (replaces ai.json)
│ └── repository-metadata.json ← Per-repo metadata
├── projections/
│ ├── cloudflare/
│ │ ├── tunnel-config.yml ← Generated tunnel ingress
│ │ └── dns-records.json ← Generated DNS declarations
│ ├── terraform/
│ │ └── cloudflare/
│ │ ├── tunnels.tf ← Generated Terraform
│ │ └── dns.tf
│ ├── docker/
│ │ └── oracle-compose.yml
│ └── tailscale/
│ ├── acl-policy.hujson
│ └── nas-tunnel-config.yml
└── types/
└── *.types.ts ← Generated TypeScript (existing 65 files)
Provider Metadata¶
Every imported provider must have a provider.yaml at the provider root. The compiler reads this to understand the authority behind the contract.
# providers/acquia/provider.yaml
id: provider.acquia
authority: authority.acquia
name: Acquia
trust: vendor
licensing:
type: commercial
url: https://www.acquia.com/legal
contact: https://developers.acquia.com
refresh_cadence: quarterly
version_policy: track-major
imports:
- name: source
type: openapi
source_url: https://...
description: Acquia Source API
- name: cms
type: json-api
source_url: https://...
description: Acquia CMS JSON:API
Every imported artifact must have a manifest.yaml beside it:
# providers/acquia/imports/source/manifest.yaml
import: acquia.source
provider: provider.acquia
type: openapi
version: "3.1"
source_url: https://...
imported_at: 2026-07-14T00:00:00Z
imported_by: platform-compiler
hash: sha256:...
status: verified # imported | verified | outdated | deprecated | removed
notes: >
Imported from Acquia Developer Portal. Covers all Acquia Source API endpoints.
Refresh quarterly or when upstream API version is bumped.
The compiler distinguishes imported contracts from authored contracts by reading these manifests. An imported contract whose status is outdated will emit a compiler warning. An imported contract whose hash does not match the file will fail validation.
Contract Types¶
The type field on a Contract object determines which component of the Compiler (which Reader + Normalizer) processes it.
| Type | Description | Standard |
|---|---|---|
openapi |
REST API contract | OpenAPI 3.x |
graphql |
GraphQL schema | GraphQL SDL |
asyncapi |
Event-driven API | AsyncAPI 3.x |
mcp |
Model Context Protocol | Anthropic MCP |
ag-ui |
Agent-User Interaction | AG-UI Protocol |
a2a |
Agent-to-Agent | Google A2A |
json-schema |
Data shape contract | JSON Schema draft-07+ |
cedar |
Authorization policy | Cedar Policy Language |
opa |
Authorization / governance policy | Rego |
kubernetes-crd |
Kubernetes resource definition | k8s CRD |
gascity-pack |
Gas City capability pack | Gas City Pack v2 |
terraform-module |
Infrastructure module | Terraform 1.x |
grpc-proto |
gRPC service definition | Protocol Buffers 3 |
oidc |
Authentication / identity | OpenID Connect |
Versioning¶
Contracts are versioned semantically. The Compiler enforces compatibility:
| Change | Compatibility policy |
|---|---|
| Add optional field | Backward compatible — no consumer migration |
| Add required field | Breaking — consumer migration required |
| Remove field | Breaking — consumer migration required |
| Rename path/operation | Breaking — consumer migration required |
| Change field type | Breaking — consumer migration required |
Deprecated contract versions remain in the registry with stability: deprecated until all consumers have migrated. The Compiler will warn on consumption of a deprecated contract.
Retiring ai.json¶
ai.json is currently a hand-maintained service map used by config-loader.ts for URL resolution. It has no schema, no validation, and no compiler ownership. It is a fourth source of truth.
Migration:
- All services currently in
ai.jsonbecomeDeploymentobjects inobjects/deployments/ - The compiler generates
generated/indexes/urls.jsonfrom the Deployment objects config-loader.tsreads fromgenerated/indexes/urls.jsonai.jsonis removed from the repository
After migration, URL resolution flows: objects/deployments/*.yaml → Compiler → generated/indexes/urls.json → consumers.
No consumer reads deployment objects directly. No consumer reads ai.json. Everything reads from the generated index.
Existing OpenAPI Directory Migration¶
The current openapi/ directory conflates authored Bluefly contracts with imported vendor schemas. Migration is a rename + add manifests — no content changes.
| Current path | Authority | Destination | Notes |
|---|---|---|---|
openapi/acquia-cms/ |
Acquia | providers/acquia/imports/cms/ |
Add provider.yaml + manifest.yaml |
openapi/acquia-source/ |
Acquia | providers/acquia/imports/source/ |
|
openapi/drupal-cms-jsonapi/ |
Drupal | providers/drupal/imports/jsonapi/ |
|
openapi/drupal-*/ |
Drupal | providers/drupal/imports/*/ |
|
openapi/workflow-engine/ |
Bluefly | contracts/bluefly/platform/workflow-engine/ |
|
openapi/agent-*/ |
Bluefly | contracts/bluefly/platform/*/ |
|
openapi/ossa/ |
OSSA | contracts/bluefly/ossa/ |
|
openapi/openstandardagents/ |
OSSA | contracts/bluefly/ossa/ |
|
openapi/portfolio/ |
Bluefly | contracts/bluefly/portfolio/ |
|
openapi/copaw/ |
Bluefly | contracts/bluefly/products/copaw/ |
|
openapi/contractplane-*/ |
Bluefly | contracts/bluefly/products/contractplane/ |
|
openapi/duadp/ |
DUADP (open standard) | providers/duadp/ |
|
openapi/components/ |
Bluefly | contracts/bluefly/platform/components/ |
shared $ref components |
Migration proceeds only after the new directory structure is committed and CI is updated to read from new paths.
Invariants¶
- Nothing under
generated/is ever edited by a human. - Nothing under
providers/is ever modified — only themanifest.yamlstatus field is updated. - Every file under
providers/*/imports/has a correspondingmanifest.yaml. - Every provider has a
provider.yaml. ai.jsondoes not exist after migration is complete.objects/conform to schemas defined incontracts/schemas/.- Adding a Deployment object is the only way to expose a service — there is no other path.