A person signs off a completion contract before the action runs. It states what "done" means for one action: the outcome, the evidence that proves it, and the results that must never appear. The runtime checks the provider against it.
A contract is immutable, versioned, and hashable, so nobody moves the goalposts after a run. Every receipt records the contract id, version, and hash. A contract is data. Code interprets it and holds no provider rule, so a new service ships without a runtime change.
Where does a contract come from?
In words
- The prompt and the context go into the compiler.
- The compiler returns the steps, the evidence for each step, and the postconditions.
- A part that no contract can check is marked REQUIRES_REVIEW.
- You confirm the contract before it verifies anything.
Provely compiles it from the task. You pass the agent prompt, the context and the tools. The compiler returns the steps, the evidence, the correlation keys and the negative postconditions. You confirm the result before it runs.
A part of the task that no contract can check is marked REQUIRES_REVIEW, and it is never dropped in silence. Read intent compilation.
In words
- Intent: what the user asked for.
- Action: what the agent attempted.
- Acknowledgement: what the provider returned.
- Outcome: the observable state in the provider.
- Completion: the outcome satisfies the contract.
What does a contract contain?
Twelve members. Four of them decide a verdict: the completion conditions, the negative conditions, the correlation keys, and the evidence policy. The rest bound how long the runtime waits and which provider versions the semantics hold for.
Explain: every member, with a Stripe example
| Member | Purpose | Example |
|---|---|---|
intent | What the user asked for, and the input schema. | Refund the charge to the customer. |
subject | The real-world thing the contract talks about. | stripe.refund identified by $action.result.id. |
action | The effect class and the idempotency rule. | money.refund with Idempotency-Key: $operation.id. |
correlation | How evidence ties to this exact operation. | Match the refund id from the action response. |
evidence_policy | The channels and the minimum evidence level. | Readback at E2, event at E3, independent channel required. |
completion.all_of | The positive postconditions. Every one must hold. | status eq succeeded, amount eq $input.amount_cents. |
negative_conditions.any_of | The false-success blockers. One gives CONTRADICTED. | More than one refund for this operation. |
verdict_map | Observed state to verdict, before completion. | pending gives PENDING. failed gives FAILED. |
timing | Poll interval, backoff, deadline, stale-read window. | Poll on an interval, and stop at a deadline. |
on_timeout | The verdict when the deadline passes. VERIFIED is never allowed. | UNVERIFIABLE, escalated to a person. |
valid_for | The provider API versions the semantics are proven for. | >=2025-03-31. |
overlays | Version differences as a merge patch. One contract, no copies. | The 2026-08-26 overlay adds requires_action. |
What does a refund contract look like?
schema_version: '1.0.0'
id: acme.refund.completed
version: 1.0.0
service: acme
completion_level: completed
title: Acme Payments returned the money to the buyer.
intent:
statement: Return the payment to the buyer.
subject:
type: acme.refund
identity: { refund_ref: $action.result.ref }
action:
canonical_effect: money.refund
idempotency: { strategy: idempotency_key, key: $operation.id, header: Acme-Request-Key }
correlation:
strategies:
- { name: resource_id, assurance: strong, required: true,
keys: [{ name: refund_ref, source: $action.result.ref }] }
evidence_policy:
minimum_evidence_level: E2
require_independent_channel: true
channels:
- { name: ledger_lookup, evidence_level: E2, independence: provider_readback,
verifier: { name: http, version: '^1' } }
completion:
all_of:
- { id: refund_settled, path: $observed.ledger_lookup.settlement,
operator: eq, expected: settled, evidence: [ledger_lookup] }
- { id: refund_value_matches, path: $observed.ledger_lookup.value_minor,
operator: eq, expected: $input.value_minor, evidence: [ledger_lookup] }
negative_conditions:
any_of:
- { id: second_refund_seen, class: duplicate_side_effect, reason_code: duplicate_refund,
path: $observed.ledger_lookup.refunds_for_operation, operator: gt, expected: 1,
evidence: [ledger_lookup] }
timing: { poll_interval_ms: 30000, timeout_ms: 172800000 }
on_timeout: { result: UNVERIFIABLE, reason_code: evidence_unavailable_before_timeout,
escalate_to_human_review: true }
valid_for: { provider_api_versions: ['>=2026-01-01'] }
Acme Payments is a fictional provider. The example shows the format, and no signed package holds it. The Stripe refund contract page states what the signed Stripe contract promises.
Why are completion levels separate contracts?
Because a service makes more than one promise. Resend accepts, sends, and delivers an email as three events. Each level is one contract, so an agent cannot upgrade the promise it made.
resend.email.accepted,resend.email.sent,resend.email.delivered, andresend.email.bouncedare four contracts.shopify.refund.createdandshopify.refund.financially_completedare two contracts, because a Refund object does not prove money moved.stripe.refund.createdandstripe.refund.succeededare two contracts, becausependingis notsucceeded.
Which rules does the schema enforce?
The loader refuses a contract that could produce a false VERIFIED. Seven rules do that work, and each one fails the document when it loads, not during a run.
Explain: the seven rules the loader enforces
- Every condition names an evidence channel that the contract declares.
- A channel cannot claim a level above its path. A reading of the action response is E1 at most.
- A weak correlation strategy states a time window. An Official contract needs one strong strategy.
- A PENDING result on timeout must escalate to a person. An operation always ends.
verdict_mapandon_timeoutcan never give VERIFIED. Only the completion block can.- An overlay adds a condition. It cannot remove one, change the identity, or weaken the evidence policy.
- The document rejects an unknown member with a clear error.
The published schema is completion-contract.schema.json, JSON Schema draft 2020-12, in the @provely/core package.
Source: Provely core schemas · retrieved 2026-09-05
How does composition work?
A contract can use other contracts as sub-contracts. The runtime combines their verdicts with frozen precedence rules. One CONTRADICTED component contradicts the whole. One PENDING component keeps the whole PENDING. VERIFIED needs every component VERIFIED.
Can I write a contract by hand?
Yes. The schema and the loader are public. The Integration Compiler writes the Official contracts, because it records provenance and runs the conformance matrix.