coderifts-sdk
Python SDK for CodeRifts — API governance for AI agents.
v3.2.0 (ID75) closes REST method parity with @coderifts/sdk 3.3.0.
Decision Spec v2 still requires top-level preflight_mode on preflight.
PyPI publishes are a separate, manual flow (do not twine upload from this
checkout). Offline Ed25519 verification is not in this package (requests
only) — use @coderifts/sdk, coderifts-app, or receipt-verifier.
Surface vs TypeScript SDK
| Capability | Python | TypeScript 3.3.0 | Notes |
|---|---|---|---|
preflight_change_set / analyze_change_set / authorize_change_set |
yes | preflightChangeSet / analyzeChangeSet / authorizeChangeSet |
POST /api/v1/preflight |
verify_receipt |
yes | verifyReceipt |
POST /api/v1/verify-receipt |
get_decision_details |
yes | getDecisionDetails |
POST /api/v1/decisions/lookup |
preflight_check |
yes (3.2.0) | preflightCheck |
POST /api/v1/agent/preflight |
diff |
yes (3.2.0) | diff |
POST /api/v1/diff |
score_mcp |
yes (3.2.0) | scoreMcp |
POST /api/v1/agent-readiness-score |
get_ledger |
yes (3.2.0) | getLedger |
GET /api/v1/ledger (from_ → query from) |
simulate_policy |
yes (3.2.0) | simulatePolicy |
POST /api/v1/policy-simulator |
explain_decision |
yes (3.2.0) | explainDecision |
client-side; no HTTP |
how_to_unblock |
yes (3.2.0) | howToUnblock |
client-side; no HTTP |
readDecision |
no | readDecision |
Guard helper — TS-only by design (agent-guard / tool-table). |
verifyExecutionGrant |
no | verifyExecutionGrant |
Offline Ed25519. Python has no crypto dep; helpers compute_scope_hash / receipt_digest / after_payload_canonical only. |
| waiver / deploy-gate / publish-gate | no | no | Not on the TS client. Not invented here. |
| MCP client | no | no | Out of scope. |
Installation
pip install coderifts-sdk
Requires Python 3.9+ and requests.
Quick start
from coderifts import CodeRifts, CodeRiftsError
client = CodeRifts(api_key="cr_live_...")
preflight_change_set / analyze_change_set / authorize_change_set
Required keyword-only preflight_mode='analyze'|'authorize' (Decision Spec v2;
server returns HTTP 400 if omitted). Prefer the wrappers so the two meanings
cannot be mixed.
Branch on execution_action (proceed signal, authorize). Closed set:
CONTINUE | CONTINUE_WITH_MONITORING | REQUEST_APPROVAL | STOP.
Unrecognised → treat as STOP. Use decision for the explanation label.
Analyze is informational (risk-only), not permission.
v2 fields on authorize: receipt_kind (operation_authorization | NONE),
chain_receipt, optional execution_grant, blast_radius (counts, not a score).
before = open("openapi-before.json").read()
after = open("openapi-after.json").read()
artifacts = [
{
"id": "spec-main",
"type": "openapi",
"before": before,
"after": after,
}
]
# Risk-only
risk = client.analyze_change_set(artifacts=artifacts)
print(risk.analysis_outcome, risk.receipt_kind) # receipt_kind == "NONE"
# Operation-bound authorize (requires context.operation; may mint a receipt)
result = client.authorize_change_set(
artifacts=artifacts,
context={
"operation": "merge",
"environment": "staging",
},
include_execution_grant=True, # opt-in cr.exec.v1 grant
)
print(result.execution_action) # e.g. "CONTINUE"
print(result.decision) # e.g. "ALLOW"
print(result.receipt_kind) # "operation_authorization" | "NONE"
print(result.breaking_changes) # integer count, not a list
print(getattr(result, "execution_grant", None)) # grant token when opted in
print(getattr(result, "blast_radius", None))
token = result.chain_receipt
decision_id = result.decision_result.decision_id
verify_receipt
A valid signature is not authorization. currently_authorized is
True / False / None — None means authorization was not evaluated.
Expiry uses 30s clock-skew leeway (CLOCK_SKEW_LEEWAY_MS); 0s for destructive
operations in production when the intended context declares them. The SDK does
not compare expiry locally — the server does.
This is a REST verify. Offline grant verification is TS/app/receipt-verifier.
# Cryptographic check only
check = client.verify_receipt(token=token)
print(check.valid, check.status)
print(check.currently_authorized) # often None without intent context
# With intent + the body-bound decision envelope for full authorization
authz = client.verify_receipt(
token=token,
operation="merge",
environment="staging",
target_id=result.decision_result.artifact_digest,
fingerprint=result.verdict_fingerprint,
decision_result=result.decision_result.to_dict(),
)
print(authz.currently_authorized) # True / False once evaluable
print(getattr(authz, "authz_status", None))
Grant helpers (no Ed25519):
from coderifts import compute_scope_hash, receipt_digest
print(receipt_digest(token))
print(compute_scope_hash("merge", "sha256:tgt", after))
get_decision_details
Look up a stored decision by decision_id or fingerprint.
stored = client.get_decision_details(decision_id=decision_id)
print(stored.execution_action)
print(stored.decision)
print(stored.meta.source)
Other REST methods (TS parity)
client.diff(before=before, after=after)
client.score_mcp(manifest={"tools": []})
client.get_ledger(repo="acme/api", from_="2026-01-01", limit=20)
client.simulate_policy(policy_yaml="rules: []", old_spec=before, new_spec=after)
Error handling
from coderifts import CodeRifts, ApiError, AuthError, RateLimitError, CodeRiftsError
try:
client.authorize_change_set(artifacts=[...], context={"operation": "merge"})
except AuthError as e:
print("auth", e.message)
except RateLimitError as e:
print("rate limit", e.message)
except ApiError as e:
print(e.status_code, e.message)
except CodeRiftsError as e:
print(e.code, e.message)
Response access
Return values are thin wrappers around the JSON object:
result.decision # attribute
result["decision"] # item
"decision" in result # membership
result.to_dict() # full dict
result.decision_result.decision_id # nested dicts wrap too
License
MIT
Release files for coderifts-sdk 3.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| coderifts_sdk-3.2.0.tar.gz | 22.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| coderifts_sdk-3.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 39.5 kB
Release files / coderifts_sdk-3.2.0.tar.gz
| Download URL | coderifts_sdk-3.2.0.tar.gz |
|---|---|
| Size | 22.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
df5146538f40fe9d64859ae8e13313c4c3d9e7459292b40f248055869bac0631
|
|
BLAKE2b-256 checksum How to use checksums |
fb6201dde3e262c5ada012160c4fa3ce3e8c21ab643c5f8bc0a7b1c05c1bc6d7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.9.6
|
Release files / coderifts_sdk-3.2.0-py3-none-any.whl
| Download URL | coderifts_sdk-3.2.0-py3-none-any.whl |
|---|---|
| Size | 17.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
73fe83814c75fca2fff100ba9861224315a412b32ad21259f303b6ebe6d2a722
|
|
BLAKE2b-256 checksum How to use checksums |
b78532c966627c6fd062f4ad3788879d24b5a7e08d336f70cb9f5e81690f5df8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.9.6
|