Contract
A Contract is the abstract interface that Adapters or Modules with the same role share. Contracts are what enable substitution: any two Adapters declaring the same Contract are drop-in replaceable within a Slot requiring that Contract.
Contract Format
A Contract is identified by a namespaced slug with a mandatory version:
contract:<category>/<contract-name>/v<N>Examples:
contract:persistence/repository/v1contract:auth/identity-provider/v1contract:llm/completion/v1contract:llm/embedding/v1contract:cache/key-value/v1contract:messaging/event-publisher/v1What a Contract Specifies
A Contract definition (stored in the platform’s Contract registry, referenced by Manifests) contains:
contract_id— the namespaced slugcategory— broad categoryabstract_operations— the operations the Contract guarantees, expressed as language-neutral signaturessemantics— natural-language description of what each operation must doerror_modes— how implementations must signal failurerequired_capabilities— Capabilities that any implementor of this Contract must declare
A Contract is interface-shaped. It does not specify implementation; it specifies what code consuming a Contract-implementing Adapter can rely on.
How Adapters Declare Implementation
In an Adapter Manifest:
{ "interface_contracts": [ { "contract_id": "contract:persistence/repository/v1", "binding": "java", "concrete_pattern": "interface {EntityName}Repository extends JpaRepository<{EntityName}, {IdType}>" } ]}contract_id— which Contract this Adapter implementsbinding— the language-specific binding (Java, TypeScript, Python)concrete_pattern— the actual code shape the Adapter exposes for this Contract; used by the Stitcher to generate matching consumer code
The concrete_pattern is critical: it’s how the Stitcher knows what code to write against the resolved Adapter. Two Adapters implementing contract:persistence/repository/v1 will have different concrete_pattern values (Spring Data JPA uses JpaRepository; jOOQ uses a generated DSL), and the Stitcher generates differently-shaped code for each.
Contracts Enable Substitution
The substitution guarantee is this:
If two Adapters declare the same Contract, an Archetype’s Slot requiring that Contract can be filled by either Adapter, and the Stitcher will generate code that works with whichever was chosen.
The Stitcher reads the resolved Adapter’s concrete_pattern and generates accordingly. It does not need to know in advance which Adapter will fill the Slot.
Contract vs Capability
| Contract | Capability |
|---|---|
| Interface shape | Declared feature |
contract:persistence/repository/v1 | capability:persistence/transactions/v1 |
| About the API surface | About what the thing can do |
| Few per Adapter (often one) | Many per Adapter |
| Required by a Slot to ensure substitutability | Required by a Slot to filter on features |
Two Adapters with the same Contract are substitutable. Two Adapters with the same Capability might still have different APIs. A Slot typically requires both — for example, “any Adapter implementing the repository Contract that also declares transactions and pagination Capabilities.”
Contract Versioning
Like Capabilities, Contracts use integer versions:
contract:persistence/repository/v1contract:persistence/repository/v2
A version bump indicates a breaking change to the interface. An Adapter implementing only v1 cannot satisfy a Slot requiring v2.
The platform team manages Contract evolution. Major version bumps require:
- An ADR explaining why the change is necessary
- A migration path for existing Adapters
- A transition period during which both versions are supported
How Contracts Are Created
The Contract registry is governed centrally. New Contracts are proposed when:
- A new category of building block enters the library (e.g., vector databases get
contract:vector-search/v1when the first vector DB Adapter is admitted) - An existing category needs a richer interface than current Contracts express
- Multiple Adapters in a category exist without a shared Contract, and substitution becomes desirable
The proposal-and-admission process mirrors the Capability governance: drafted, reviewed, admitted, documented.
Language Bindings
A single Contract can have multiple language bindings. contract:llm/completion/v1 might have:
- A Java binding (signatures, error types)
- A TypeScript binding (matching signatures, idiomatic TS types)
- A Python binding (Pythonic equivalents)
When an Archetype’s Slot requires this Contract and the surrounding code is Java, the Java binding is used; for TypeScript, the TS binding. The Stitcher generates code in the appropriate language using the appropriate binding.
This is how Almathal handles polyglot Archetypes: the same logical Contract spans multiple languages, and the language-specific Adapter implementations are matched per-language.
Contracts Are Reference Material for the Stitcher
When the Stitcher fills a Seam that consumes an Adapter, it reads:
- The Seam’s declared
must_use_adapters - Those Adapters’ Manifests
- Each Adapter’s
interface_contractsentries - The
concrete_patternfor the Adapter’s language binding
From that, the Stitcher knows what code to write. The Contract is the structured input that makes the Stitcher’s task bounded rather than exploratory.
Related
- Capability — the feature-declaration counterpart
- Slot — where Contracts are required
- Manifest — where Contracts are declared
- Adapter — what implements Contracts