How to use the OME Python SDK (Verified Memory)
The OME Python SDK (osyra-ome) contains two different kinds of
capability:
- Offline receipt verification is implemented and runnable from an authorized source install. It needs no server or network.
- The
memory.*gRPC methods have protocol implementations, but the supported customer route through Edge is not released.
The current source contract is the osyra-ome==1.0.0 pre-release.
Prerequisites
- Python 3.11+.
- An authorized checkout while package publication remains release-gated.
- For offline verification, the exact detached preimage, 64-byte signature, and the signer's real 32-byte public trust anchor obtained out of band.
- For future network calls, an Edge-issued bearer token and the authoritative IAM workspace UUID.
Step 1 — Install
Contributors can install the checked-out source:
python -m pip install -e "$OSYRA_OME_SDK_CHECKOUT"Set OSYRA_OME_SDK_CHECKOUT to the real
AP00013-osyra-ome-sdk-python checkout first.
After the private release gate clears, authenticated internal consumers will also be able to install the exact pre-release from CodeArtifact:
python -m pip install --index-url \
https://osyra-273863930653.d.codeartifact.us-east-1.amazonaws.com/pypi/osyra-pypi/simple/ \
osyra-ome==1.0.0There is no anonymous public install today. Verify the authorized install:
python -c "import osyra_ome; print(osyra_ome.__version__)"Expected output:
1.0.0Step 2 — Validate tenancy and construct a client
The authoritative workspace value is a UUID from IAM. Parse it before handing it to the SDK; the current Python model itself only checks that the string is non-empty.
import os
import uuid
from osyra_ome import OmeClient
workspace_id = str(uuid.UUID(os.environ["OSYRA_OME_WORKSPACE"]))
client = OmeClient(
target="api.osyra.ai:443",
token=os.environ["OSYRA_OME_TOKEN"],
workspace_id=workspace_id,
)
# No network call is made by construction.
client.close()Prefer a context manager when a supported route becomes available:
with OmeClient(
target="api.osyra.ai:443",
token=os.environ["OSYRA_OME_TOKEN"],
workspace_id=workspace_id,
) as client:
... # future supported network workConstructor parameters:
| Parameter | Type | Current behavior |
|---|---|---|
| target | str | Required host:port. The intended customer boundary is api.osyra.ai:443. |
| token | str \| None | Bearer token attached as authorization metadata. |
| workspace_id | str \| None | Requested tenancy binding. Parse the authoritative IAM value as a UUID before construction. |
| workspace_tier | str \| None | Deprecated compatibility input; not sent on the wire. Edge derives tier. |
| timeout_seconds | float | Per-call deadline; default 30.0. |
| insecure | bool | Disables TLS. Use only with an exact loopback development target. |
| channel_options | list[tuple[str, object]] \| None | Advanced gRPC options. |
OmeAsyncClient accepts the same inputs and supports async with. Its network
methods have the same release and wire-mismatch constraints as the synchronous
client.
Step 3 — Construct a service-valid Claim
A claim ID must be a caller-supplied RFC 9562 UUIDv7. Do not fall back to UUIDv4. The Python model validates the 16-byte width but does not validate the version and variant bits, so validate them explicitly:
import hashlib
import os
import time
import uuid
from osyra_ome import Claim, ClaimKind
def require_uuidv7(name: str) -> uuid.UUID:
value = uuid.UUID(os.environ[name])
if value.version != 7 or value.variant != uuid.RFC_4122:
raise ValueError(f"{name} must be an RFC 9562 UUIDv7")
return value
workspace_id = str(uuid.UUID(os.environ["OSYRA_OME_WORKSPACE"]))
claim_id = require_uuidv7("OSYRA_OME_CLAIM_ID")
memory_body = os.environ["OSYRA_OME_BODY"].encode("utf-8")
claim = Claim(
id=claim_id.bytes,
workspace_id=workspace_id,
subject_id=os.environ["OSYRA_OME_SUBJECT_DID"],
parents=(),
issuer_did=os.environ["OSYRA_OME_ISSUER_DID"],
content_hash=hashlib.sha256(memory_body).digest(),
embedding_hash=b"\x00" * 32,
kind=ClaimKind.ASSERTION,
ts=int(time.time() * 1000),
body=memory_body,
)The signed Form-B commitment has exactly these nine canonical short keys:
ws, id, sub, par, iss, ch, eh, kn, tsThe opaque body is outside that preimage and is bound transitively by
ch = SHA-256(body).
| Python field | Signed key | Current SDK/contract requirement |
|---|---|---|
| workspace_id | ws | Authoritative IAM workspace UUID; must equal authenticated workspace context. |
| id | id | Exactly 16 bytes with UUIDv7 version and RFC variant bits. |
| subject_id | sub | The Python model requires a non-empty subject identifier; the proto itself permits an empty subject. |
| parents | par | Each parent is a 16-byte UUIDv7. |
| issuer_did | iss | Canonical, authorized W3C DID. |
| content_hash | ch | Exactly 32 bytes; SHA-256 of the body. |
| embedding_hash | eh | Exactly 32 bytes; all-zero means no embedding. |
| kind | kn | V1 claim-kind enum. |
| ts | ts | Unix milliseconds. |
Why the network write is not shown
client.memory.write_claim(claim) and write_claim_signed(claim) build a real
SignAndInsert request, but they are not a supported customer flow today:
- The public Edge bridge and required SDK → Edge → AP00011 acceptance lane have not passed.
- The Python request sends no
signer_key_ref; AP00011 requires a non-empty signer reference. Edge must resolve and inject workspace signer custody. - Even if a write succeeds in an internal rig, the returned
encoded_cboris the full SignedClaim envelope while the SDK labels it as the detached preimage. Live write → offline verify and signature-bound verify-on-read are therefore blocked.
The optional idempotency_key argument exists and is limited to 1–128
characters, but it does not remove any of these blockers.
Step 4 — Verify caller-supplied evidence offline
Use the public verify_receipt export with evidence from a trusted evidence
channel. Do not use an in-band signer_pub as the trust anchor.
import base64
import os
from osyra_ome import verify_receipt
def required_b64(name: str, expected_len: int | None = None) -> bytes:
value = base64.b64decode(os.environ[name], validate=True)
if expected_len is not None and len(value) != expected_len:
raise ValueError(f"{name} must decode to {expected_len} bytes")
return value
preimage = required_b64("OSYRA_OME_PREIMAGE_B64")
signature = required_b64("OSYRA_OME_SIGNATURE_B64", 64)
trusted_pub = required_b64("OSYRA_OME_TRUSTED_PUB_B64", 32)
ok = verify_receipt(preimage, signature, trusted_pub)
print("valid" if ok else "signature mismatch")OSYRA_OME_TRUSTED_PUB_B64 must come from your real published workspace key
or another trust registry you already trust. It must not come from the receipt
being verified or from SDK testdata.
The return/error contract is:
True: the signature verifies over the exact supplied Form-B bytes under the supplied trust anchor.False: a genuine Ed25519 verify-false over a well-formed claim preimage.OmeWireFormatError: malformed/non-canonical CBOR, wrong Form-B shape, or wrong domain-separation tag.OmeVerifyError: malformed signature or public-key material.
Local crypto exercise, not an authenticity proof
The following example is useful for learning and KAT work. It uses the public
cbor2 dependency rather than the SDK's private _kernel package. The fixed
claim ID is the UUIDv7 vector from RFC 9562 Appendix A.6; never reuse it for a
network insert. The workspace still comes from your real IAM environment.
import hashlib
import os
import uuid
import cbor2
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from osyra_ome import verify_receipt
workspace_id = str(uuid.UUID(os.environ["OSYRA_OME_WORKSPACE"]))
kat_id = uuid.UUID("017f22e2-79b0-7cc3-98c4-dc0c0c07398f")
assert kat_id.version == 7 and kat_id.variant == uuid.RFC_4122
body = os.environ["OSYRA_OME_BODY"].encode("utf-8")
claim_map = {
"ws": workspace_id,
"id": kat_id.bytes,
"sub": os.environ["OSYRA_OME_SUBJECT_DID"],
"par": [],
"iss": os.environ["OSYRA_OME_ISSUER_DID"],
"ch": hashlib.sha256(body).digest(),
"eh": b"\x00" * 32,
"kn": 1,
"ts": 1735689600000,
}
preimage = cbor2.dumps(
["osyra-ome-claim-v1", claim_map],
canonical=True,
)
sk = Ed25519PrivateKey.generate()
exercise_key = sk.public_key().public_bytes(
encoding=serialization.Encoding.Raw,
format=serialization.PublicFormat.Raw,
)
signature = sk.sign(preimage)
assert verify_receipt(preimage, signature, exercise_key) is True
tampered_map = {
**claim_map,
"ch": hashlib.sha256(body + b"!").digest(),
}
tampered_preimage = cbor2.dumps(
["osyra-ome-claim-v1", tampered_map],
canonical=True,
)
assert verify_receipt(tampered_preimage, signature, exercise_key) is False
# The exact size depends on the real workspace and DID string lengths.
print(f"preimage={len(preimage)} signature={len(signature)} public_key={len(exercise_key)}")This proves byte integrity and possession of the generated private key. It does not prove a production issuer identity because the exercise key was not trusted before the receipt existed.
Step 5 — Read and erase cautiously
get_claim(claim_id) returns a metadata projection and always sets
Claim.body == b"". get_claim_body(claim_id) is the body-bearing RPC.
The default get_claim_body(..., verify_on_read=True) requires a detached
Form-B preimage, signature, and trusted key. The current live write response
does not supply that preimage in the shape the SDK expects, so a live
write-to-verified-read flow is blocked. Passing verify_on_read=False
returns transport-supplied body bytes without cryptographic authenticity; do
not describe that result as verified memory.
The tombstone method is a real protocol mapping:
from osyra_ome import TombstoneReasonCode
# Inside a future supported, open client context:
# claim_id must already be validated as UUIDv7 by your application.
receipt = client.memory.tombstone(
claim_id.hex,
reason_code=TombstoneReasonCode.GDPR_ART17_DSAR,
reason_detail="", # never put PII here
)This call is not customer-runnable until the Edge route passes. Also note that the current SDK's internal claim-ID parser checks only “hex decodes to 16 bytes”; it does not validate UUIDv7 version/variant bits. Validate UUIDv7 before calling. A successful service response contains the post-redaction root, era index, redaction time, audit correlation ID, and sequence; the SDK never fabricates one.
Current API status
| Surface | Status |
|---|---|
| verify_receipt(...) / client.verify.receipt(...) | Wired local crypto; requires detached Form-B bytes and a caller-trusted key. |
| memory.write_claim(...) | Protocol implementation; customer Edge route pending; signer injection pending; PRO/ENTERPRISE only. |
| memory.write_claim_signed(...) | Protocol implementation, but its encoded_cbor projection is incompatible with the detached verifier today. |
| memory.get_claim(...) | Metadata projection; no body or signed evidence. |
| memory.get_claim_body(...) | Body RPC exists; signature-bound default is blocked for live write output by the envelope/preimage mismatch. |
| memory.tombstone(...) | Protocol implementation; customer Edge route pending. |
| memory.batch_write/export_bundle/import_bundle | Raise NotImplementedError. |
| proof.*, witness.*, verify.bundle_manifest/proof/witness | Raise NotImplementedError in the Python SDK. |
Error handling
All SDK exceptions inherit from OmeError:
from osyra_ome import (
OmeAuthError,
OmeBodyUnavailableError,
OmeError,
OmePolicyError,
OmeTransportError,
OmeVerifyError,
OmeWireFormatError,
OmeWorkspaceError,
)
try:
ok = verify_receipt(preimage, signature, trusted_pub)
except (OmeVerifyError, OmeWireFormatError) as exc:
print(f"evidence rejected: [{exc.code}] {exc.message}")
except OmeError as exc:
print(f"OME failure: [{exc.code}] {exc.message}")A call on a closed client raises a plain RuntimeError, which is distinct from
a transport failure.
This guide documents the exact osyra-ome 1.0.0 pre-release implementation
and the current AP00011 service wire contract as verified on 2026-07-23.