The Thessor SDK — cryptographic AI decision accountability
Project description
Thessor Python SDK
Cryptographic accountability for AI decisions. Seals decisions into tamper-evident, Ed25519-signed envelopes and verifies them — without ever requiring you to send PHI to Thessor.
v0.2.0 · Python ≥ 3.11 · zero third-party dependencies
Install
pip install thessor
Quick start
from thessor import Client
client = Client(api_key="thsr_...")
result = client.seal(
decision_id="dec-001",
model_id="cnds-classifier-v3",
model_version="3.2.1",
timestamp="2026-06-19T10:00:00Z",
input_hash="sha256:...",
output={"label": "approved"},
confidence_score=0.97,
policy_version="policy-2026-Q2",
payload={"finding": "..."},
)
print(result.envelope_id, result.verify_url)
verification = client.verify(result.envelope_id)
assert verification.valid
PHI never has to leave your environment
Use hash_patient_id() to turn a patient ID into a one-way SHA-256 hash
before it ever leaves your systems, and pass the hash as patient_id_hash
in attestations:
from thessor import hash_patient_id
result = client.seal(
...,
attestations={"patient_id_hash": hash_patient_id(patient.mrn)},
)
Thessor stores and seals only the hash. canonicalize() and sha256_hex()
are also exposed for fully offline, trustless verification with no API call
(client.verify_direct supports this flow).
API reference
Sealing decisions
client.seal(...) → SealResult
Seal a decision into a tamper-evident, Ed25519-signed envelope.
result = client.seal(
decision_id="dec-001", # caller-supplied stable ID
model_id="cnds-classifier-v3",
model_version="3.2.1",
timestamp="2026-06-19T10:00:00Z",
input_hash="sha256:abc123", # SHA-256 of the canonical input
output={"label": "approved"},
confidence_score=0.97,
policy_version="policy-2026-Q2",
payload={"finding": "..."}, # extra context (not sealed, not sent)
attestations={ # optional: sealed regulatory metadata
"regulatory_frameworks": ["fda_pccp", "eu_ai_act_high_risk"],
"clinician_npi": "1234567890",
"patient_id_hash": hash_patient_id(patient.mrn),
},
sync=True, # default: block until envelope is written
)
# result.envelope_id, result.canonical_hash, result.signature, result.verify_url
sync=False queues the seal and returns immediately (status "pending").
Poll with get_seal_status(seal_id) or use seal_and_wait().
client.seal_with_rationale(...) → SealWithRationaleResult
Seal a decision and immediately seal its rationale record in one call.
result = client.seal_with_rationale(
# all seal() fields:
decision_id="dec-002",
model_id="cnds-classifier-v3",
model_version="3.2.1",
timestamp="2026-06-19T10:00:00Z",
input_hash="sha256:abc123",
output={"label": "approved"},
confidence_score=0.97,
policy_version="policy-2026-Q2",
payload={},
# rationale fields:
confidence_distribution={"approved": 0.97, "denied": 0.03},
salient_inputs={"age": 0.42, "risk_score": 0.81},
policy_logic_applied={"rule": "threshold_0.85", "version": "v3"},
human_oversight_action="clinician_confirmed",
human_operator_id_hash=sha256_hex(b"npi:1234567890"),
)
print(result.envelope_id) # shortcut to result.seal.envelope_id
print(result.rationale_id)
print(result.rationale_hash)
client.seal_agent_decision(...) → dict
Seal an agent tool call without setting up ThessorMCPMiddleware directly.
Works with any agent framework (LangChain, AutoGen, custom orchestrators).
Raw inputs and outputs are never sent — only their SHA-256 hashes.
envelope = client.seal_agent_decision(
tool_name="search_formulary",
tool_input={"drug_name": "metformin", "plan_id": "BCBS-HMO"},
tool_output={"formulary_match": True, "tier": 2},
model_id="gpt-4o",
model_version="2024-11-20",
agent_id_hash=sha256_hex(b"agent:workflow-v1"),
confidence=0.95,
policy_version="formulary-policy-v2",
parent_decision_id=prior_envelope_id, # chains to parent decision
)
print(envelope["envelope_id"])
client.seal_and_wait(...) → SealResult
Queue an async seal and block until it completes or times out.
result = client.seal_and_wait(
poll_interval=0.5,
timeout=30.0,
decision_id="dec-003",
... # same kwargs as seal()
)
client.get_seal_status(seal_id) → SealResult
Poll the status of an async seal (seal(sync=False)).
Verification
client.verify(envelope_id) → VerifyResult
Fetch verification metadata for a sealed envelope.
v = client.verify(result.envelope_id)
print(v.valid, v.canonical_hash, v.regulatory_context)
client.verify_with_payload(envelope_id, payload) → VerifyResult
Verify that a payload matches the sealed envelope's hash and signature.
client.verify_direct(payload, signature_hex, public_key_hex) → VerifyResult
Fully trustless, offline verification — no envelope lookup, no DB. Useful for auditors who only have the envelope contents and the published Thessor public key.
Outcomes and consequence chains
client.seal_outcome(outcome_id, model_id, outcome_type, payload) → SealResult
Seal an outcome envelope to later link to a decision.
client.link(decision_envelope_id, outcome_envelope_id, causal_claim) → dict
Causally link a decision envelope to an outcome envelope.
client.get_chain(decision_envelope_id) → ChainResult
Fetch the full consequence chain (decision + linked outcomes) for a decision envelope.
Population attestation
client.attest_population(...) → dict
Post a sealed aggregate performance attestation for a model version over a defined time window. Required for GMLP, EU AI Act post-market surveillance, ISO 42001, and FDA PCCP total-lifecycle monitoring.
attestation = client.attest_population(
model_version="ct-lung-v4.1.0",
period_start="2026-01-01T00:00:00Z",
period_end="2026-03-31T23:59:59Z",
site_identifier_hash=sha256_hex(b"site:hospital-a"),
decision_count=1000,
confirmed_count=400,
true_positive_count=180,
false_positive_count=20,
true_negative_count=190,
false_negative_count=10,
drift_flag=False,
regulatory_frameworks=["fda_pccp", "gmlp_principle_7"],
)
print(attestation["attestation_id"])
print(attestation["sensitivity"]) # 0.947
print(attestation["specificity"]) # 0.905
Offline audit export
client.export_packet(decision_id) → dict
Fetch the signed, self-verifying offline audit packet for a decision — a
single JSON bundle containing the decision envelope, replay record, rationale,
consequence chain, population context, and Merkle checkpoint. Every nested
record carries its own signature; the export_signature seals the entire
bundle. A regulator can verify it offline without Thessor infrastructure.
packet = client.export_packet(envelope_id)
# packet["export_signature"] seals every field
client.export_to_file(decision_id, filepath) → dict
Fetch the audit packet and write it to filepath as pretty-printed JSON.
Returns the packet dict as well.
packet = client.export_to_file(envelope_id, "/tmp/audit-dec-001.json")
MCP middleware
For agent frameworks using the Model Context Protocol, use
ThessorMCPMiddleware to seal every tool call automatically:
from thessor import ThessorMCPMiddleware, sha256_hex
middleware = ThessorMCPMiddleware(
thessor_client=client,
model_id="claude-sonnet-4-6",
model_version="20250620",
agent_id_hash=sha256_hex(b"agent:my-workflow-v1"),
)
# Seal a tool call manually:
envelope = middleware.seal_tool_call(
"lookup_icd10",
tool_input={"description": "type 2 diabetes"},
tool_output={"code": "E11", "description": "Type 2 diabetes mellitus"},
confidence=0.99,
parent_decision_id=prior_envelope_id,
)
# Or use the decorator to seal every call automatically:
@middleware.seal_mcp_tool
def search_formulary(tool_input: dict) -> dict:
return {"tier": 2, "covered": True}
result = search_formulary({"drug_name": "metformin"})
# → tool runs, output sealed, result returned unchanged
seal_tool_call_async() is also available for async contexts.
Error handling
All API errors raise a subclass of ThessorError:
from thessor import AuthError, ValidationError, RateLimitError, NotFoundError
try:
client.seal(...)
except ValidationError as exc:
print(exc.field_errors) # structured per-field validation errors
except AuthError:
print("check your API key")
except RateLimitError:
print("back off and retry later")
except NotFoundError:
print("envelope not found")
429 and 5xx responses are retried automatically with exponential backoff (0.5 s, 1 s, 2 s). 4xx errors are raised immediately.
Changelog
0.2.0
Client.seal_with_rationale()— seal + rationale in one callClient.seal_agent_decision()— agent sealing without MCP setupClient.attest_population()— population performance attestationThessorMCPMiddleware— MCP-native agent decision sealing- Model classes (
SealResult,SealWithRationaleResult,VerifyResult,ChainResult) now exported from the top-level package - Version bump to 0.2.0
0.1.0
- Initial release:
Client,FHIRConnector,DICOMSRConnector,ATNAConnector,HL7Connector, PHI-safe hashing utilities,export_packet,export_to_file
Releasing
To publish a new version to PyPI:
- Bump version in
sdk/pyproject.toml,sdk/thessor/__init__.py, andsdk/VERSION git add sdk/git commit -m "release: SDK v0.x.x"git tag sdk-v0.x.xgit push origin main --tags
GitHub Actions will build and push to PyPI automatically.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file thessor-0.2.0.tar.gz.
File metadata
- Download URL: thessor-0.2.0.tar.gz
- Upload date:
- Size: 36.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5d50afb81fdd79e7cd3c50e8f85a04461d6bb16a629bab273bb21a3193660117
|
|
| MD5 |
6504e23ccae8fa8328a689cbc2d3a227
|
|
| BLAKE2b-256 |
d0267d1072c1364492713d5a89742c8315bd3cfd8abc614b219083ffff1bce71
|
Provenance
The following attestation bundles were made for thessor-0.2.0.tar.gz:
Publisher:
publish-sdk.yml on SOLOMONTHESSOR/thessor-api
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
thessor-0.2.0.tar.gz -
Subject digest:
5d50afb81fdd79e7cd3c50e8f85a04461d6bb16a629bab273bb21a3193660117 - Sigstore transparency entry: 1964316040
- Sigstore integration time:
-
Permalink:
SOLOMONTHESSOR/thessor-api@e58e8f701ed4fed7f13bf69b6ef131d785b51812 -
Branch / Tag:
refs/tags/sdk-v0.2.0 - Owner: https://github.com/SOLOMONTHESSOR
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-sdk.yml@e58e8f701ed4fed7f13bf69b6ef131d785b51812 -
Trigger Event:
push
-
Statement type:
File details
Details for the file thessor-0.2.0-py3-none-any.whl.
File metadata
- Download URL: thessor-0.2.0-py3-none-any.whl
- Upload date:
- Size: 32.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4c4ad0e04853f02f02c4cd0c55423c0a34c0ec180d2c3e02d2b8944cb71f2597
|
|
| MD5 |
6a07b8f494932810fec472c83ce59b6b
|
|
| BLAKE2b-256 |
d196d3fe72a8c949100a55b329e4c960fd6370f3ab1136156d78f139065006a3
|
Provenance
The following attestation bundles were made for thessor-0.2.0-py3-none-any.whl:
Publisher:
publish-sdk.yml on SOLOMONTHESSOR/thessor-api
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
thessor-0.2.0-py3-none-any.whl -
Subject digest:
4c4ad0e04853f02f02c4cd0c55423c0a34c0ec180d2c3e02d2b8944cb71f2597 - Sigstore transparency entry: 1964316239
- Sigstore integration time:
-
Permalink:
SOLOMONTHESSOR/thessor-api@e58e8f701ed4fed7f13bf69b6ef131d785b51812 -
Branch / Tag:
refs/tags/sdk-v0.2.0 - Owner: https://github.com/SOLOMONTHESSOR
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-sdk.yml@e58e8f701ed4fed7f13bf69b6ef131d785b51812 -
Trigger Event:
push
-
Statement type: