1.2.0-rc.1 / Agreements and authority

Free exchange

Direct and delegated agreements, protected delivery, reporting and revocation.

This 1.2.0-draft.3 profile implements a bounded free exchange over real HTTPS. The legacy odexa_ref server and CLI remain draft-2; the separate installed odexa-current entry point and quickstart compose the draft-3 APIs without test fixtures. No global version switch or subclass relabels the legacy implementation. This profile is included in the implementation candidate.

An originator may host its own agreement service or appoint a separate provider with exactly the same free wire contracts. Both paths have been exercised by an independent Node client against the Python implementation. No payment module, spending mandate, billing provider or commercial provider account participates in this exchange. A provider’s appointment is an operational capability scoped by the origin, not ownership of the originator’s assets.

Components and trusted interfaces

profiles.free_service.FreeAgreementService exposes dispatch(method, path, headers, body) and returns (status, headers, exact_body_bytes). Construct it with a FreeStore, explicit publisher/service/issuer/delegation binding, service base URL, signing key, exact human terms, current-authority transport/history and a trusted live UTC clock. Provision local agent, gateway and administrative credentials through provision_client; this trusted setup method is not public registration or proof of a person’s legal authority. Separate roles use separate credentials and keys. Random client secrets and opaque tokens require at least 256 bits of generated entropy; the durable store retains their hashes.

The wire contracts specify closed fields and semantic correlations. The store persists exact offers, acceptance payloads/JWS, original receipts, state transitions, status statements, intake records and authority decisions. The publisher independently serves /odexa.json and /odexa-service.json. A provider does not publish authoritative copies at its own origin. Current documents are acquired over certificate-verified HTTPS and checked against durable origin history for every new authorized operation, including in direct mode.

All routes are beneath the exact configured tenant base_url:

Route Role and behavior
POST offers Agent requests exact resource/actions/purposes, principal and access/use windows; emits an unsigned offer pinned to exact policy, authority and human terms
POST agreements Agent sends an ES256 acceptance; commits a single original signed receipt atomically
POST tokens Owner agent obtains a short-lived opaque token for an active agreement
POST introspect Separately provisioned publisher gateway requests one exact delivery admission
GET agreements/{id}/receipt Owner agent, gateway or admin retrieves the original historical receipt
GET agreements/{id}/status Authenticated authorized reader receives a newly signed current status
POST agreements/{id}/revoke Owner agent or admin stops future access; exact command retry returns the original statement
POST events Authenticated agent or gateway submits a signed source-qualified report bound to an existing agreement
GET contexts/{sha256hex} Public immutable exact context bytes, fetched without client credentials

Current authority outages and withdrawals fail closed. Authenticated historical receipt, acceptance and already-recorded event retries can return their exact original evidence during an outage; these paths create no new token, admission or permission. Introspection uses one request ID once; replay is rejected rather than reusing a previous access decision. Tokens are not idempotent bearer delivery: a retried token request creates a new short-lived token only after the same current checks.

Acceptance, deadlines and policy changes

An offer lives for 60 seconds and is issued only if that full period fits the current authority, key, delegation and policy validity. Acceptance binds its exact bytes, client, principal, service, nonce and explicit intent. The accepted payload is the idempotency value; an alternate ES256 encoding of the same authenticated payload returns the original receipt. A different payload under the same idempotency key conflicts; an offer cannot be accepted twice under a different key.

Any exact policy or authority byte change before first acceptance makes the offer stale. Later token issuance and admission also require the accepted policy digest to remain current. Thus a policy edit stops future access under these agreements until a new offer is accepted. Original receipts and original use-window terms remain retained; this does not claim that already acquired copies can be recalled. Authority may rotate while a policy stays the same, provided the current service, capabilities, scope and keys authorize the new operation.

The service samples its live clock after acquiring the SQLite write lock, checks current origin history and repeats operational authorization before commit. Separate final predicates reject an acceptance past its original offer deadline, a newly expired access window, an expired token/admission or an active status statement whose access has expired. A two-second signing delay that crosses offer expiry causes rollback rather than late acceptance. These are local commit guarantees bounded by the retained remote observation, not globally atomic remote revocation.

The original receipt is the initial version-1 acceptance proof. Signed status generation is lazy. status_history retains the first observed statement for each lifecycle version; status_attestations retains every emitted exact signed status, even when polling does not change the lifecycle version. Polling never invents a transition. Revoked and expired agreements cannot become active again.

Publisher gateway and evidence boundary

profiles.free_gateway.FreeGateway is a separate publisher component with its own private durable journal and scoped gateway credential. admit(token, resource_url=..., actions=..., purposes=...) checks publisher authority, sends introspection only to the appointed service/tenant, and checks fresh publisher authority again after the reply. It validates the full response binding and persists an admission before returning its request ID. A trusted guard runs after TLS immediately before transmitting a bearer token and the gateway credential.

The host HTTP adapter must call begin_delivery(request_id) immediately before protected response headers/body. This checks current retained history, observation age and access expiry, and atomically consumes that admission once. The host calls finish_delivery after its write/flush, with the actual reported byte count, representation digest and completion flag. The supplied adapter in the TLS tests performs that sequence with an actual protected response. Cached bodies require a new admission too.

The journal distinguishes admitted, in_flight, sent and partial. A crash leaves an unresolved entry; restart neither retries a consumed admission nor invents a completed delivery. Tokens and client secrets are absent from this journal. Completion timestamps cannot precede delivery start. The journal trusts its local HTTP adapter’s observations: successful writes do not prove remote consumption or downstream AI use. It is neither a signed portable export nor a complete registry of every ingress to an organisation.

The service can verify gateway event signatures and bind a delivery report to its exact recorded admission, including chronology. The optional gateway reporter now atomically retains a signed terminal outcome and durable outbox, then publishes it to the appointed collector with authenticated acknowledgement/retry recovery. The host explicitly schedules its bounded drain; there is no hidden background worker. The independent wire run sends a separate signed client-reported retrieval only after receiving actual protected bytes. A valid signature authenticates the reporter and exact claim, not the truth of arbitrary downstream claims.

Reproduce and inspect

To reproduce the wire checks, first extract the source as described in the quickstart. Use Python 3.12 or later with the declared requirements and Node.js 24. Run from the extracted source/ directory:

ODEXA_NODE="$(command -v node)" ODEXA_FREE_REPORT_DIR=verification/local-free-run \
  python -m unittest discover -s tests -p 'test_free*.py' -v
node --test verification/test_free_client.mjs

The Python suite creates two local HTTPS origins with an explicitly trusted ephemeral CA. It exercises the same contract in direct and delegated modes; the provider receives no request in the direct independent-client run. Real asset delivery, signed self-report, exact retry, status, revocation, outage/withdrawal and deadline failures are tested. Private fixture keys/configuration remain in temporary private directories. verification/free-client.mjs is a separate Node implementation; its signature rejection tests are distinct from successful wire interoperability checks.

For an existing prepared test deployment, run the independent client with node verification/free-client.mjs --config /private/path/config.json --outdir /path/report. Its config names publisherOrigin, serviceId, baseUrl, optional delegationId, caFile, agent (clientId, principalId, password, keyId, reporterId, privateJwk), exact request, accessSeconds, useSeconds, expectedTermsDigest, and includeResource. It performs a destructive-to-that-test-agreement self-revocation at the end. Reports exclude private configuration and tokens.

This free-flow Node client does not demonstrate every Agent Core duty: it verifies policy/terms and reports its tested retrieval, but does not exercise every attribution/display, continuing storage, training or derived-output duty. The additive storage-session profile has its own explicit signed selection, collection and durable runtime; it is not automatically enabled by the ordinary CLI. Paid agreement/gateway integration and bounded free evidence archives are implemented separately. Paid/asset portability, fresh-agreement provider/key handover and declared coverage accounting retain their own scoped evidence, as do the independent paid client and independent native asset client. See current validation and release status for the combined record and publication gates.

Odexa / Protocol explorer

This page. Your terms.

Inspect this website’s published policy and see how a proposed use is evaluated.

Current pagehttps://odexa.io/releases/1.2.0-rc.1/docs/wire-profile/
Loading policy…

Published JSON
Open JSON

This is a local policy check, not a signed agreement or proof of agent compliance. Other published licences and applicable rights still apply. How policy evaluation works →

Odexa / Get in touch

Start a conversation.

Tell us what you have in mind. We’ll respond where we can.

We use these details to review and respond to your enquiry. Please leave out confidential information. Submitting does not subscribe you to marketing. Privacy policy.