Binding Contracts And Roadmap
AHRI_TRE_RS is designed so language bindings stay thin. Bindings should expose the application services through stable interface contracts; they should not create a second domain model, a second persistence format, or a second control plane for each client language.
ADR-0005 sets the repository boundary for those bindings. Full Python, Julia, and R package implementations live in separate repositories:
| Language | External repository seed |
|---|---|
| Python | ahri-tre-py |
| Julia | ahri-tre-jl |
| R | ahri-tre-r |
This Rust workspace owns the public protocol, stable C ABI, Client bootstrap runtime, runtime artifacts, package manifests, compatibility fixtures, and wrapper-author contract. The language repositories own package code, language-specific CI, publication, documentation, dataframe ergonomics, and ongoing host-language issue tracking. The shared Binding Repository Seed Contract is the handoff contract each external repository consumes.
Shared Boundary Model
| Concern | Binding contract |
|---|---|
| In-memory tabular boundary | Apache Arrow RecordBatch values |
| Persisted analytical datasets | Parquet |
| Binary tabular transport | Arrow IPC stream or file |
| Command, status, and metadata responses | JSON over HTTP |
| Client dataframes | Local language representations only |
The Rust workspace treats Arrow as the neutral tabular boundary. Python, Julia,
and R users may naturally work with pandas, Polars, Julia DataFrame, Arrow.jl
tables, tibbles, or R data.frame values, but those are binding-local
representations. They are adapters around the shared Arrow, Parquet, Arrow IPC,
and JSON contracts rather than canonical wire or storage models.
This keeps the Rust service independent of any single client dataframe library and lets each binding choose idiomatic conversion points without changing the core workflow semantics.
Implemented Foundation
The binding foundation currently exists below the language wrapper layer:
ahri_tre_tabularowns reusable ArrowRecordBatchvalidation, Parquet read/write helpers, Arrow IPC helpers, and AHRI_TRE Arrow metadata handling.ahri_tre_appowns workflow-facing services that bindings should call through a stable lower-level interface instead of reimplementing workflows.ahri_tre_protocol,ahri_tre_daemon, andahri_tre_cliprovide the local JSON/control-plane direction over app workflows. The final JSON-over-HTTP service remains roadmap work.ahri_tre_ffi_cexposes the stable C protocol-adapter ABI: startup introspection, immutable Client bootstrap selection, opaque client/session/result handles, authenticated Trusted-runtime protocol JSON execution, response JSON access, optional attached payload access, and matching cleanup functions. It intentionally exposes no local daemon lifecycle or transport overrides and is not one C function per workflow.ahri_tre_python,ahri_tre_julia, andahri_tre_rare scaffold crates retained only as transitional workspace placeholders and compatibility shims. Their exported Rust functions are not public language APIs and should not grow into package implementations in this repository.
C ABI First
The stable C ABI is the implemented language-neutral low-level interface. It defines:
- opaque handles for sessions and result objects
- explicit memory ownership and cleanup rules
- stable error and diagnostic envelopes
- JSON control-plane payload exchange for commands and metadata
- Arrow IPC or file-oriented handles for tabular payloads
- smoke tests proving the ABI is usable outside Rust
The C ABI is stable enough for Python, Julia, and R wrappers to share. The wrappers can focus on idiomatic packaging and dataframe conversion rather than each binding discovering its own unsafe Rust boundary.
Wrapper and C ABI compatibility checks should use Protocol version
compatibility, not the Rust crate version, Rust package version, C ABI library
identity, or host-language package version. Local installations expose that
contract through ahri-tre version --format json: the JSON version field
identifies the CLI executable package, C ABI startup introspection identifies
the loaded shared library and ABI surface, each language package has its own
ecosystem version, and protocol.current plus protocol.compatibility
identify the public control-plane contract the executable speaks.
Wrapper authors can inspect the same JSON payload contract through
ahri-tre schema list --format json and ahri-tre schema get <schema-id> --format json. The protocol schema IDs, such as
protocol.response-envelope.v2, protocol.dataset.catalog.v2, and
protocol.semantic-model.catalog.v2, are the binding-facing DTO contract for
control-plane responses. They are useful for generated typed result objects,
contract fixtures, and cross-language smoke tests, while Arrow IPC and Parquet
remain the data-plane contracts for tabular payloads.
Backlog: P1.21 Build stable C ABI.
Language Wrapper Roadmap
| Binding | Current status | Intended first useful surface |
|---|---|---|
| Python | External seed repository plus transitional scaffold crate | ahri-tre-py consumes staged runtime artifacts, implements the wrapper API, and runs contract smoke tests outside this workspace. |
| Julia | External seed repository plus transitional scaffold crate | ahri-tre-jl consumes staged runtime artifacts, implements the wrapper API, and runs contract smoke tests outside this workspace. |
| R | External seed repository plus transitional scaffold crate | ahri-tre-r consumes staged runtime artifacts, implements the wrapper API, and runs contract smoke tests outside this workspace. |
| C | First stable generic protocol adapter | Generated header, startup introspection, client/session/result lifecycle, response JSON and optional payload access, ownership rules, and smoke tests. |
The first useful Rust-workspace outcome for each host language is a seed and contract handoff: artifact discovery, protocol compatibility checks, managed runtime lifecycle coverage, generic protocol JSON execution, safe diagnostics, payload handling, and smoke fixtures. Full host-language APIs, dataframe conversion matrices, package-manager checks, documentation sites, CI matrices, and publication workflows belong in the external binding repositories.
C ABI Wrapper Author Contract
The stable C ABI is the layer Python, Julia, R, and other wrappers should bind
to before exposing idiomatic host-language APIs. Wrapper startup should inspect
the loaded library with ahri_tre_abi_version() and
ahri_tre_library_version(), then decide behavioral compatibility from
ahri_tre_protocol_version(),
ahri_tre_protocol_compatibility_minimum(),
ahri_tre_protocol_compatibility_maximum(), and
ahri_tre_protocol_compatibility_rule(). Wrappers should fail fast when their
required protocol support is outside that range; package and crate versions are
support metadata, not the protocol compatibility contract.
The ABI owns unsafe-boundary lifecycle only. Client handles wrap adapter state,
session handles wrap selected session context, and result handles own protocol
response JSON plus any attached payload descriptors or bytes. Borrowed response
JSON, payload descriptor strings, and borrowed byte views stay valid only until
the owning result handle is freed. Owned string and byte copies must be released
with ahri_tre_string_free() and ahri_tre_bytes_free() respectively.
Daemon-backed data-plane outputs use those result-owned payload accessors for
Arrow IPC bytes and descriptor-only export artifacts; runtime target paths and
lake internals are not wrapper-facing data.
Cleanup functions accept NULL as a no-op. Double-free, freeing foreign
pointers, freeing with the wrong function, freeing copied bytes with the wrong
length, and concurrent mutation or cleanup of the same handle are caller
errors. First-stable same-handle concurrent use is not thread-safe unless a
future ABI symbol explicitly documents otherwise.
Wrapper construction accepts only optional Client bootstrap selection. A wrapper passes an explicit projected document through client_bootstrap_path or leaves it NULL for /etc/ahri-tre/client.toml. Construction validates Deployment identity, Trusted-runtime origin, and TLS trust before returning the opaque handle. Profiles are server-discovered and selected by logical identifier. Explicit selection failures do not fall back. Wrappers must not reintroduce endpoint, local daemon, binary override, never-start, or auto-start configuration above ABI v2.
Workflow semantics stay in public protocol envelopes. C callers submit
serialized protocol request JSON with ahri_tre_client_execute_protocol_json()
or ahri_tre_session_execute_protocol_json() and read the returned protocol
response JSON from the result handle. Python, Julia, and R packages may add
typed convenience functions above that generic layer, but those functions
should generate protocol requests and parse protocol responses rather than
depending on a workflow-specific C ABI.
New TRE workflow semantics must land in ahri_tre_app and
ahri_tre_protocol first. A language wrapper may expose a convenient host API
only after the behavior is available through the shared protocol contract.
The dedicated book chapter Stable C ABI explains the ABI’s
functioning and wrapper-author contract in more detail. The generated header
and minimal C examples live in crates/ahri_tre_ffi_c.
External Python, Julia, and R repositories must also follow the shared Binding Repository Seed Contract. That contract is the discoverable handoff for ADR-0005: it defines the runtime artifact layout, manifest discovery rules, protocol compatibility checks, Client bootstrap policy, C ABI ownership rules, redaction expectations, payload handling, development overrides, and representative smoke scenarios that every language repository should share.
Backlog:
- P2.8 Python binding repository handoff
- P2.9 Julia binding repository handoff
- P2.10 R binding repository handoff
- P2.11 Build and test release matrix
Binding Rules
Bindings should preserve the same architectural boundaries as the Rust workspace:
- domain types remain free of runtime database, lake, or OAuth handles
- application workflows remain the semantic source of truth
- PostgreSQL metadata access remains behind the libpq-based adapter
- DuckDB, DuckLake, and Lake location logic remain behind the lake adapter
- OAuth/OIDC behavior stays separate from libpq wiring
- JSON control-plane responses remain machine-readable and stable
- dataframe conversion happens at the edge of each language binding
These rules are especially important while the binding crates are still scaffolds. A thin wrapper is allowed to make AHRI_TRE convenient in a host language; it is not allowed to bypass governance, provenance, datastore session, or lake semantics.
Protocol 2 cutover
Current source clients require protocol 2.0.0 (minimum and maximum), independently
of C ABI 2 and package 0.11.0. Match a source-built library and CLI by
revision and artifact digest; old released runtime artifacts do not acquire v2
support through a package-version comparison. Read streaming results through the
verified empty completion using the existing content-transfer API.
The Rust Python/R/Julia crates and bindings/ folders are placeholders. ADR-0005
seed directories under tmp/ are absent in this checkout; no new host-language
wrapper or native artifact publication is claimed. The implemented Python ctypes
qualification consumer uses the exported C functions and protocol introspection.
External packages must adopt these same references, Session semantics and stream
ownership before declaring support for a v2 runtime artifact.