Skip to main content

Axon Python Runtime

axon-runtime-sdk is the Python distribution of the canonical Axon runtime model; its stable import namespace is axon_sdk. It exposes descriptor-bound invocation, admission, receipt proof, streaming, bidi sessions, provider binding, and the reference LocalRuntime.

The protocol has one invocation shape:

invoke(caller, callee, ability, subject, nonce, causal_context, args) -> receipt

Every public dispatch binds an exact AbilityDescriptorRef. The receipt closes the same seven-field invocation with descriptor, implementation, authority, input, output, and causal proof facts.

Install

pip install axon-runtime-sdk

The runtime facade loads a target-specific Dendrite native bridge. Release artifacts may supply that bridge as package data; source checkouts can select an explicit bridge with:

export AXON_DENDRITE_BRIDGE_LIB=/absolute/path/libaxon_dendrite_bridge.so

Descriptor-Bound Invocation

The native bridge accepts a complete request signed by caller-owned code. Create the envelope and signature with DescriptorBoundInvocationRequest.signed or bind an external signature with DescriptorBoundInvocationDraft; the bridge never receives the signing key.

from axon_sdk import DendriteBridge
from axon_sdk.invocation import DescriptorBoundInvocationRequest


def dispatch(bridge: DendriteBridge, request: DescriptorBoundInvocationRequest,
             request_id: str) -> dict:
    return bridge.invoke_descriptor_bound(
        request,
        request_id=request_id,
        content_type="application/json",
        timeout_ms=30000,
    )

The request owns caller, callee, subject, exact descriptor reference, nonce, causal context, payload bytes and signature. Its payload must match the signed digest. The receiving runtime verifies the caller signature and admission policy. LocalRuntime parent handles and supervisor options are rejected rather than silently discarded. Transport responses do not replace independent receipt verification with trusted identity keys.

The historical session-signing shorthand (SidecarTransport with DendriteSigningConfig, including decorator-based calls) does not match the current native contract. Supplying signing keys to DendriteBridge now fails before library loading; use the complete unary request above. The historical shorthand remains pending migration; complete requests also support server-stream and bidi.

Provider Binding

AbilityDescriptor, AbilityImpl, and ProviderBinding are generic runtime contracts. A binding is valid only when the descriptor and implementation refer to the same exact descriptor version.

from axon_sdk import AbilityDescriptor, AbilityImpl, ProviderBinding
from axon_sdk.invocation import sha256

descriptor_ref = (
    "easynet:///r/example/ability/example.runtime.documents.summarize"
    "@descriptor.documents.v1#aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!invoke"
)

descriptor = AbilityDescriptor(
    descriptor_ref=descriptor_ref,
    descriptor_version="descriptor.documents.v1",
    schema_hash=sha256(b"documents-schema-v1"),
)
implementation = AbilityImpl(
    descriptor_ref=descriptor_ref,
    impl_hash=sha256(b"python-provider-v1"),
    runtime_env="python;provider=documents-v1",
)


async def summarize(context):
    return context.payload


binding = ProviderBinding(
    descriptor=descriptor,
    implementation=implementation,
    handler=summarize,
)

LocalRuntime.bind_provider(binding) is the canonical in-process registration path. LocalRuntime.register_ability(...) constructs the same binding object for callers that already hold the three components separately.

Streams And Bidi

  • StreamSource, StreamSink, and LoopbackStream provide bounded credit, monotonic cancellation, and one terminal frame.
  • DendriteServerStream exposes incremental server-stream reads.
  • DendriteSignedBidiStream carries typed stream descriptors and opaque content frames without interpreting downstream content.
  • EventStream resumes invocation observation from a sequence offset.

For a complete externally signed server-stream request, use bridge.stream_descriptor_bound(request, request_id=..., content_type=...). Unary and server-stream carriers preserve the same signed envelope and payload. Use the returned DendriteServerStream as a context manager so that normal completion, early exit and exceptions release the native handle:

with bridge.stream_descriptor_bound(
    request,
    request_id="caller-owned-stream-request-id",
    content_type="application/json",
    chunk_timeout_ms=1000,
    chunk_buffer_size=64,
) as stream:
    for protocol_chunk in stream:
        consume(protocol_chunk)

The iterator returns native transport chunk bytes. Decoding and independent receipt verification remain the caller's responsibility. An older library without stream read/close capability is rejected before stream allocation.

bridge.bidi_descriptor_bound(request, request_id=..., content_type=..., streams=[SignedBidiStreamDescriptor(...)]) uses the same complete signed opening, with explicit stream descriptors and bounded request/chunk buffers. DendriteSignedBidiStream.close() sends EOF while allowing receipt reads; release() disposes the native stream and abandons unread frames. Context exit always releases resources, including after EOF or an exception. For graceful completion, send EOF, drain the terminal receipt, then release. Receipt frames preserve the native admission or terminal receipt in receipt and expose terminal. Terminal delivery ends iteration and marks the native handle already released; calling release() afterward is harmless. Receipt projection does not verify signatures: use independently trusted identity pins. Missing or ambiguous canonical receipt slots are rejected.

A failed or unacknowledged send leaves the sending direction in a failed state. Later sends and EOF attempts raise the retained error without replaying the operation. Receiving terminal evidence and releasing resources remain available. Only acknowledged EOF is reported as idempotent success; concurrent EOF/close calls are serialized. This does not establish whether an unacknowledged remote operation took effect.

The v1 frame chain is not independent origin authentication. Use authenticated transport and trusted TLS terminators as described in the InvokeBidi security boundary.

Runtime Process

start_server() connects to an existing Axon runtime or starts a local reference runtime. Its ServerHandle owns an explicit process state and stops only processes it created.

from axon_sdk import start_server

with start_server() as runtime:
    print(runtime.endpoint)

Verification

From this directory:

python -m pytest
python -m black --check axon_sdk tests examples
python -m ruff check axon_sdk tests examples
python -m mypy axon_sdk
python -m compileall -q axon_sdk tests examples

The RF-1 boundary test scans the public exports, package source, examples, and package metadata to prevent product-owned modules or lifecycle APIs from returning to the canonical SDK.

Source release scope

This distribution is a deliberately bounded public SDK, not a source release of every EasyNet control-plane service, research mechanism, or evaluation asset. The release-scope statement explains the staged policy. It does not restrict the Apache-2.0 rights granted for files actually included in this distribution.

Native HTTPS trust

Pass an explicit public PEM CA bundle when opening an HTTPS native session:

from pathlib import Path
from axon_sdk import DendriteBridge

bridge = DendriteBridge(
    endpoint="https://runtime.example.org:50051",
    tls_ca_pem=Path("runtime-ca.pem").read_text(encoding="utf-8"),
)

The same tls_ca_pem keyword is exposed by SidecarTransport and the ability_call decorator; their signing shorthand remains subject to the contract limitation above. SidecarTransport preserves it when reopening the bridge, including through its reconnect callback. The CA configures transport trust; it is not an invocation identity, signing key or authority grant.

This requires a native bridge build supporting tls_ca_pem (introduced in Axon source commit 5f739034). Native code owns certificate parsing, the 64 KiB limit and endpoint-hostname verification. An older bridge or invalid trust configuration fails; the SDK does not retry without the CA or downgrade HTTPS. No field is sent when the option is unspecified. Existing HTTP endpoints remain unprotected; TLS termination remains a trust boundary for streamed data.

Explicit live native TLS check

After uv sync --extra dev in sdk/python, build the current native library from the repository root:

cargo build --locked --manifest-path core/runtime-rs/dendrite-bridge/Cargo.toml

Set AXON_PYTHON_SDK_EXECUTABLE to the absolute SDK virtual-environment Python path and AXON_NATIVE_BRIDGE_TEST_LIB to the absolute library just built (libaxon_dendrite_bridge.dylib on macOS, .so on Linux). Then run:

cargo test --locked --manifest-path core/runtime-rs/dendrite-bridge/Cargo.toml \
  common::session_tls_tests::python_native_tls_rpc_preserves_signed_request \
  -- --ignored --exact

This explicit test starts a bounded TLS probe, launches the real Python facade and native library, checks the actual RPC request, and rejects wrong CA and hostname. The receiver uses the canonical Rust signature verifier with an independently pinned test caller public key. Changed signature, payload and caller identity are rejected at authentication. Valid signatures reach a deliberate policy denial; this does not prove permission to execute, replay protection or receipt verification. It runs only when explicitly selected because it requires the Python environment and native build.

Explicit live runtime execution check

With the same Python and freshly built native library environment variables, run from the repository root:

cargo test --locked --manifest-path sdk/rust/Cargo.toml --features grpc \
  --test python_native_execution python_executes_and_verifies_runtime_receipts \
  -- --ignored --exact

This launches Python against a real canonical Rust LocalRuntime through the native bridge and a test-only tonic service. It checks exact binary echo output, independently verifies admission and terminal signatures against a pinned test callee key, checks invocation/output bindings, and rejects receipt tampering. Unary exposes receipt endpoints rather than every lifecycle receipt, so this check does not verify the complete intervening hash chain. The fixture uses loopback HTTP and an explicit permissive test policy; it does not establish production authorization, external causal ancestry, or released-package support. The explicit prerequisites keep this test out of the default Rust test run.

Server-stream proof boundary

stream_descriptor_bound currently returns raw protobuf chunks. Receiving those bytes or verifying the terminal receipt does not verify every progress payload. The server-stream receipt scope records the current implementation, a reproducible substitution characterization, and the unfulfilled protocol transcript-binding obligation. Full stream proof verification remains pending.

Pending event-reader cleanup

EventStream.close() stops observation without cancelling the provider. When an event read is waiting, the runtime owns both the condition wait and the close-signal wait. On either completion or cancellation of the reader task, it cancels and joins those waits before leaving the condition context. This ordering lets asyncio.Condition.wait() reacquire its lock before the context releases it, avoiding leaked wait tasks and blocked provider completion.

tests/test_event_reader_close.py exercises explicit close and reader-task cancellation with a parked provider and checks that the owned wait tasks retire. These are single-event-loop source checks; they do not certify cross-thread access, installed-wheel behavior or process-crash recovery.

Complete-request Client forwarding

Client.invoke_descriptor_bound and SidecarTransport.invoke_descriptor_bound accept the canonical caller-signed request and delegate to the native bridge. Configure the SidecarTransport without signing; the caller constructs and signs explicit executor, subject, nonce and causal facts before forwarding.

with SidecarTransport(endpoint=endpoint, library_path=library_path) as transport:
    response = Client(transport).invoke_descriptor_bound(
        request, request_id="document-review",
        content_type="application/octet-stream", timeout_ms=3000,
    )

A bound ability(...) must match the signed request; principal(...) cannot override its subject. Custom transports must provide the same optional method or Client raises an explicit configuration error. Responses and native failure receipt evidence are preserved for independent verification. This method does not retry invocations. Concurrent initialization/reconnect and other lifecycle surfaces require separate acceptance; this unary evidence does not prove them.

The existing ability/payload call/call_raw paths still require session signing and infer callee from ability. They are unsupported native signed-call paths with the current native schema. An ability URI does not identify its executor. Use the complete request above or the direct bridge entrypoint. See the native entrypoint matrix.

The explicit python_exchanges_complete_signed_bidi_through_native Rust integration exercises an installed local Python wheel against the canonical loopback bidi service and a pinned native library. It checks one binary input plus EOF, actual progress/output, invalid-signature and replay rejection, and independently pinned admission and success/failure terminal receipts, including nonce/output binding and tamper rejection. Unary bridge/Client regression passes alongside it. A subsequent coordinated candidate run also passed all eight explicit native selections, including Python bidi. These local results do not establish registry installation, TLS deployment or complete transcript proof.

python_streams_complete_signed_requests_through_native additionally exercises the installed wheel's complete-request server stream. Python returns exact raw protobuf chunks to Rust's shared verifier, which checks progress bytes, order, success/failure terminal output and independently pinned endpoint receipt signatures with identity, nonce and output bindings. Wrong signer/replay are rejected. The candidate gate now requires this exact test alongside Python unary/bidi. The rebuilt nine-selection candidate run also passed, including this exact stream test. Endpoint receipts do not establish a complete signed stream transcript.

Metadata

Release files for axon-runtime-sdk 0.205.34

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for axon-runtime-sdk 0.205.34
File Size Uploaded
axon_runtime_sdk-0.205.34.tar.gz 2.3 MB Details

Built distributions (wheels)

Table of built distributions (wheels) for axon-runtime-sdk 0.205.34
File
axon_runtime_sdk-0.205.34-py3-none-win_amd64.whl Python 3 none Windows x86-64 Details
axon_runtime_sdk-0.205.34-py3-none-manylinux_2_17_x86_64.whl Python 3 none Linux glibc 2.17+ x86-64 Details
axon_runtime_sdk-0.205.34-py3-none-manylinux_2_17_aarch64.whl Python 3 none Linux glibc 2.17+ ARM64 Details
axon_runtime_sdk-0.205.34-py3-none-macosx_11_0_arm64.whl Python 3 none macOS 11.0+ ARM64 Details
axon_runtime_sdk-0.205.34-py3-none-macosx_10_12_x86_64.whl Python 3 none macOS 10.12+ x86-64 Details

Total release size: 14.7 MB

Release files / axon_runtime_sdk-0.205.34.tar.gz

Download URL axon_runtime_sdk-0.205.34.tar.gz
Size 2.3 MB
Tags Source
SHA-256 checksum
How to use checksums
c2fa5d044cf694f5cdc6f00fe5b42da4fccfea2ad41305f5f98da12c2b366fa3
BLAKE2b-256 checksum
How to use checksums
de165604ad7464fbb487941919e7363b3f5dcba457a6008ae8a68528fb4004ac
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / axon_runtime_sdk-0.205.34-py3-none-win_amd64.whl

Download URL axon_runtime_sdk-0.205.34-py3-none-win_amd64.whl
Size 2.2 MB
Tags Python 3 Windows x86-64
SHA-256 checksum
How to use checksums
b7b1e9741ee0189958d5d07bc0619f2fd2251e8ef97886669b372a7c23c28b3a
BLAKE2b-256 checksum
How to use checksums
600c5a2e511a4881cbde81eb6dc0f5d81f6641b481e13fe051c31bfe6fb91518
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / axon_runtime_sdk-0.205.34-py3-none-manylinux_2_17_x86_64.whl

Download URL axon_runtime_sdk-0.205.34-py3-none-manylinux_2_17_x86_64.whl
Size 2.8 MB
Tags Linux glibc 2.17+ x86-64 Python 3
SHA-256 checksum
How to use checksums
19119227c435b5774e8697c743fe50a3b4a2945aa4651fcbdfd1b287d14846fc
BLAKE2b-256 checksum
How to use checksums
6e5e78d319c69473766a2d4a872e49bc31339381a767e19a7cf971111224f60a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / axon_runtime_sdk-0.205.34-py3-none-manylinux_2_17_aarch64.whl

Download URL axon_runtime_sdk-0.205.34-py3-none-manylinux_2_17_aarch64.whl
Size 2.7 MB
Tags Linux glibc 2.17+ ARM64 Python 3
SHA-256 checksum
How to use checksums
e0199c6e1185d11132a0a47b17a2d85cf93777dc69718c05b9cbf3f9ceb4d963
BLAKE2b-256 checksum
How to use checksums
da012acc5284b5734bb3480e4b1267263869f2d63ae77eae0570010562fc7505
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / axon_runtime_sdk-0.205.34-py3-none-macosx_11_0_arm64.whl

Download URL axon_runtime_sdk-0.205.34-py3-none-macosx_11_0_arm64.whl
Size 2.3 MB
Tags Python 3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
d83042bcf99486f8b7d2a1cc1d075876dc32a97f3a494a9442ab8092e53b55bc
BLAKE2b-256 checksum
How to use checksums
5129665189a882da50d24b495a86ce85cab511242d36801cbdabd817ee11cfeb
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / axon_runtime_sdk-0.205.34-py3-none-macosx_10_12_x86_64.whl

Download URL axon_runtime_sdk-0.205.34-py3-none-macosx_10_12_x86_64.whl
Size 2.4 MB
Tags Python 3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
23cb3c49097f8824b44cf68f08c33c058a44881e262f2be978c5a809c6271172
BLAKE2b-256 checksum
How to use checksums
0b721a71ff6967b1a17dbe130d4d4ac4c885c26c5307e5849435bbe06b0ad410
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release history Release notifications | RSS feed

This release

0.205.34 This release

6 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page