APIs
Each sub-API is a small class over the sharedTransport (python/parmana/config/transport.py, an ABC), one module per concern under python/parmana/api/. Every class’s docstring lists what it explicitly does not do — the same convention used in the TypeScript SDK.
ExecutionApi
execute() runs the transaction through encode() (python/parmana/serialization/encoder.py) first, converting the dataclass’s snake_case fields to the camelCase JSON the Runtime expects, and decodes the response back into ExecutionTrustRecord via response_model=.
VerificationApi
ReplayApi
ReplayApi.replay() — both call POST /replay and type the result as the flat {business_transaction_id, trust_record_hash, verified} shape. See REST API → Replay for what this endpoint actually checks (a hash comparison, not deterministic policy re-evaluation via the replay package).
ReceiptApi
generate() exists. Neither SDK has a method for GET /receipt/latest/:id — see REST API → Receipt.
TransactionApi
TransactionApi one-for-one, aside from naming (page_size vs. pageSize, per each language’s convention).
TrustRecordApi
TrustRecordApi exactly.
PolicyApi
validate() takes and returns a plain dict — there’s no PolicyReference/Policy dataclass involved at all, unlike TypeScript’s PolicyApi.validate() which is typed against the Policy interface from @parmana/policy. Functionally equivalent (the server only reads policyId/policyVersion off the body either way), just untyped on the Python side.
Models
python/parmana/models/ defines one @dataclass(frozen=True) per domain concept. Field names are snake_case Python equivalents of the same camelCase fields used by the Runtime and by the TypeScript SDK’s models — encode()/decode() (python/parmana/serialization/) convert between the two automatically using regex-based case conversion, both directions.
| Model | File | TypeScript equivalent |
|---|---|---|
Authority | authority.py | Authority |
Authorization | authorization.py | Authorization |
Intent | intent.py | Intent |
BusinessTransaction, BusinessTransactionMetadata | business_transaction.py | BusinessTransaction, BusinessTransactionMetadata |
Decision, Execution | execution.py | Decision, Execution |
Override | override.py | Override |
PolicyReference | policy.py | PolicyReference |
Receipt | receipt.py | Receipt |
ReplayResult | replay_result.py (also duplicated verbatim in replay.py, unused) | ReplayResult |
ExecutionTrustRecord | trust_record.py | ExecutionTrustRecord |
Verification | verification.py | Verification |
models/replay.py, which defines a byte-for-byte identical ReplayResult dataclass to models/replay_result.py — replay_api.py imports from replay_result.py, so replay.py’s copy is unused dead code, not a second, different result type.
Only
Authority, Authorization, Intent, PolicyReference, BusinessTransaction, BusinessTransactionMetadata, Verification, Receipt, ReplayResult, and ExecutionTrustRecord are re-exported from the top-level parmana package (python/parmana/__init__.py). Execution, Decision, and Override are not — import them from parmana.models.execution / parmana.models.override directly.Override has the same drift as TypeScript
python/parmana/models/override.py uses authority_id, matching the TypeScript SDK’s (also drifted) field name — but the canonical domain type (packages/shared/src/domain/override.ts) actually has approved_by/approvedBy, plus an optional justification neither SDK models at all. See TypeScript SDK → Models for the full comparison. Since neither SDK — nor the REST API — exposes any way to create or fetch an Override today (see Guides → Human Override), this drift has no observable effect yet.
Timestamps are handled better than in TypeScript
decode() (python/parmana/serialization/decoder.py) parses every datetime-typed field with datetime.fromisoformat(value.replace("Z", "+00:00")), so timestamps really do arrive as Python datetime objects. This is a genuine advantage over the TypeScript SDK, whose models declare fields as Date but never actually construct one — see TypeScript SDK → Models.
Errors
Python’s error hierarchy is much smaller than TypeScript’s, and behaves differently:| Class | code | Raised when |
|---|---|---|
ApiError | API_ERROR (base) | Never raised directly. |
NetworkError | NETWORK_ERROR | requests.exceptions.RequestException (python/parmana/transport/http_transport.py). |
RuntimeError | RUNTIME_ERROR | Any non-2xx HTTP response. |
Related
ParmanaClient
The facade composing these APIs.
TypeScript SDK
The equivalent TypeScript surface, for comparison.
Error Model (REST API)
What the server actually returns on failure.
Concepts
The domain concepts these models represent.