Skip to main content

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

Two request modes

Server-derived (the production path) — the server lists the change set from the repository:

result = client.authorize_change_set(
    derivation="server",
    context={"repository": "owner/repo", "base": "main", "head": "feature", "operation": "merge"},
)

Caller-supplied artifacts — you assemble the complete base→head set yourself:

result = client.authorize_change_set(
    artifacts=[{"id": "api", "type": "openapi", "before": old_yaml, "after": new_yaml}],
    context={"operation": "merge"},
)

The two are mutually exclusive. Python cannot express that as a type-level union the way the TypeScript SDK does, so it is a runtime guard: mixing them raises a ValueError that names the rule, before any HTTP call. For an ATOMIC-profile grant, pass state_nonce= from your executor's state-challenge alongside include_execution_grant=True.

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 / NoneNone 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.3.0

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

Source distribution (sdist)

Source distribution for coderifts-sdk 3.3.0
File Size Uploaded
coderifts_sdk-3.3.0.tar.gz 26.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for coderifts-sdk 3.3.0
File Interpreter ABI Platform
coderifts_sdk-3.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 45.5 kB

Release files / coderifts_sdk-3.3.0.tar.gz

Download URL coderifts_sdk-3.3.0.tar.gz
Size 26.2 kB
Tags Source
SHA-256 checksum
How to use checksums
4be63426d41bbb4acdf38013523598b1c2183ea84850355032cdf6d4cf05fce3
BLAKE2b-256 checksum
How to use checksums
adc5464a7ceaeec640d3263b3af6330bfebeefca73de06d9adea24f4050c8867
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.3.0-py3-none-any.whl

Download URL coderifts_sdk-3.3.0-py3-none-any.whl
Size 19.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
f3f0d6479be2b2280f2d36a2184a0d2bf993cc82a3423bbbdc3fe07f6626a1ad
BLAKE2b-256 checksum
How to use checksums
615afa526238ad83ff1fbdbbd22f01c72cd48af060e12a7f988e6636204bfeab
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.9.6

Release history Release notifications | RSS feed

3.8.2

2 release files

3.8.1

2 release files

3.8.0

2 release files

3.7.0

2 release files

3.6.0

2 release files

3.5.0

2 release files

This release

3.3.0 This release

2 release files

3.2.0

2 release files

3.0.0

2 release files

2.0.0

2 release files

1.0.1

2 release files

1.0.0

2 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