Post-quantum execution boundary enforcement for AI agents, APIs, and distributed systems
Project description
kavach
Post-quantum execution boundary enforcement for AI agents, APIs, and distributed systems. Python SDK.
Kavach separates possession of credentials from permission to act. Every action passes through a gate that evaluates identity, policy, drift, and invariants before producing a verdict. All evaluation runs in compiled Rust via PyO3; this package is the idiomatic Python wrapper.
Action attempted ──▶ Gate (identity · policy · drift · invariants) ──▶ Permit / Refuse / Invalidate
Install
pip install kavach-sdk
Wheels are published as abi3. A single wheel per platform covers CPython 3.10, 3.11, 3.12, and every future Python. Linux x86_64/aarch64, macOS x86_64/arm64, and Windows x64 are supported.
60-second quickstart
from kavach import ActionContext, Gate
# Policy as a native Python dict. No separate config format to learn.
POLICY = {
"policies": [
{
"name": "agent_small_refunds",
"effect": "permit",
"conditions": [
{"identity_kind": "agent"},
{"action": "issue_refund"},
{"param_max": {"field": "amount", "max": 1000.0}},
],
},
],
}
gate = Gate.from_dict(
POLICY,
invariants=[("hard_cap", "amount", 50_000.0)],
)
ctx = ActionContext(
principal_id="agent-bot",
principal_kind="agent",
action_name="issue_refund",
params={"amount": 500.0},
)
verdict = gate.evaluate(ctx)
if verdict.is_permit:
print("permit", verdict.token_id)
else:
print(f"blocked: [{verdict.code}] {verdict.evaluator}: {verdict.reason}")
A policy set with no matching permit Refuses by default. There is no implicit allow.
Loading a policy
The recommended surface for Python is a native dict (admin UI submissions, database rows, feature flags):
gate = Gate.from_dict(policy_dict) # native dict (recommended)
gate = Gate.from_json_string(json_string) # JSON over the wire
gate = Gate.from_json_file("kavach.json") # JSON file on disk
For operator-owned config that lives in git and is hand-edited, use TOML:
gate = Gate.from_toml(toml_string) # operator-edited TOML
gate = Gate.from_file("kavach.toml") # TOML file on disk
Typo'd field names ({"idnetity_kind": "agent"}) raise ValueError in every loader instead of being silently dropped, so a misspelled condition cannot quietly weaken a policy. The full TOML workflow (rendered in Rust, Python, and Node) lives at docs/guides/toml-policies.md.
Decorator
from kavach import guarded
@guarded(gate, action="issue_refund", param_fields={"amount": "amount"})
async def issue_refund(order_id: str, amount: float):
return {"status": "refunded", "order_id": order_id, "amount": amount}
result = await issue_refund(
"ORD-123", 500.0,
_principal_id="bot", _principal_kind="agent",
)
Both async and sync functions are supported; the decorator returns the matching wrapper shape. Only numeric parameters are forwarded to the gate (the policy and invariant evaluators operate on numeric thresholds).
Feature surface
Signed permit tokens (PqTokenSigner)
When a PqTokenSigner is attached to a gate, every Permit verdict carries an ML-DSA-65 (or ML-DSA-65 + Ed25519 hybrid) signed envelope. Downstream services verify independently.
from kavach import Gate, PqTokenSigner, PermitToken
signer = PqTokenSigner.generate_hybrid()
gate = Gate.from_dict(POLICY, token_signer=signer)
verdict = gate.evaluate(...)
if verdict.is_permit:
token = PermitToken(
token_id=verdict.permit_token.token_id,
evaluation_id=verdict.permit_token.evaluation_id,
issued_at=verdict.permit_token.issued_at,
expires_at=verdict.permit_token.expires_at,
action_name=verdict.permit_token.action_name,
)
assert signer.verify(token, verdict.permit_token.signature)
Hybrid (generate_hybrid) signs with both ML-DSA-65 and Ed25519; a hybrid verifier rejects PQ-only envelopes as a signature-downgrade guard.
Key pairs
from kavach import KavachKeyPair
kp = KavachKeyPair.generate() # no expiry
kp = KavachKeyPair.generate_with_expiry(3600) # 1-hour lifetime
assert not kp.is_expired
bundle = kp.public_keys() # PublicKeyBundle, safe to share
Signed audit chain
Append-only, tamper-evident audit log. verify rejects tampered entries, wrong keys, and mode mismatches (e.g., a PQ-only verifier on a hybrid chain, which is a silent downgrade).
from kavach import AuditEntry, SignedAuditChain
chain = SignedAuditChain(kp, hybrid=True)
chain.append(AuditEntry(
principal_id="agent-bot",
action_name="issue_refund",
verdict="permit",
verdict_detail="within policy",
))
chain.verify(kp.public_keys())
# Portable JSONL for off-node storage:
blob = chain.export_jsonl()
SignedAuditChain.verify_jsonl(blob, kp.public_keys())
Secure channel
Hybrid-encrypted, PQ-signed byte channel between two peers. Sealed payloads are opaque; ship them over any transport.
from kavach import SecureChannel
alice, bob = KavachKeyPair.generate(), KavachKeyPair.generate()
alice_ch = SecureChannel(alice, bob.public_keys())
bob_ch = SecureChannel(bob, alice.public_keys())
sealed = alice_ch.send_signed(b"hello bob", context_id="greeting")
plaintext = bob_ch.receive_signed(sealed, expected_context_id="greeting")
assert plaintext == b"hello bob"
Replay, cross-context, and wrong-recipient attacks all fail closed.
Public key directory
from kavach import PublicKeyDirectory, DirectoryTokenVerifier
# Root-signed manifest on disk (tamper-evident):
signing_key = KavachKeyPair.generate()
manifest = signing_key.build_signed_manifest([bundle_a, bundle_b])
Path("directory.json").write_bytes(manifest)
directory = PublicKeyDirectory.from_signed_file(
"directory.json",
root_ml_dsa_verifying_key=signing_key.public_keys().ml_dsa_verifying_key,
)
verifier = DirectoryTokenVerifier(directory, hybrid=True)
verifier.verify(token, signed_envelope) # raises on tamper/miss/downgrade
In-memory (PublicKeyDirectory.in_memory([...])) and unsigned-file variants are also available.
Geo drift (tolerant mode)
Same-country IP hops become Warnings instead of Violations when you provide lat/lon and a threshold:
from kavach import ActionContext, GeoLocation
gate = Gate.from_dict(POLICY, geo_drift_max_km=500.0)
verdict = gate.evaluate(ActionContext(
principal_id="u", principal_kind="user",
action_name="view_profile",
ip="2.3.4.5",
session_id="sess-1",
current_geo=GeoLocation("IN", city="Chennai", latitude=13.08, longitude=80.27),
origin_geo =GeoLocation("IN", city="Bangalore", latitude=12.97, longitude=77.59),
))
Missing geo with a threshold set still fails closed. The SDK does not silently bypass.
Policy hot reload
gate.reload(...) accepts a TOML string; it raises ValueError on parse error and leaves the previous good set in place. See docs/guides/toml-policies.md for the full reload workflow (including the file-watcher pattern and the empty-TOML kill switch).
gate.reload(new_policy_toml) # parse error raises, previous set preserved
Multi-replica (Redis) (experimental)
The Rust-level integration tests for
kavach-redispass, and the Python SDK exposesRedisRateLimitStore/RedisSessionStore/RedisInvalidationBroadcasteras classes, but the end-to-end multi-replica story has not yet been validated through the consumer-test harness. Early adopters can wire this up; treat it as a reference rather than a production guarantee. Thorough validation is tracked in the project roadmap.
Rate limits and invalidation broadcast move to Redis so every replica agrees:
from kavach import (
Gate, RedisRateLimitStore, RedisInvalidationBroadcaster,
spawn_invalidation_listener,
)
REDIS_URL = "redis://127.0.0.1:6379"
rate_store = RedisRateLimitStore(REDIS_URL)
broadcaster = RedisInvalidationBroadcaster(REDIS_URL, channel="kavach:invalidation")
gate = Gate.from_dict(POLICY, rate_store=rate_store, broadcaster=broadcaster)
handle = spawn_invalidation_listener(broadcaster, lambda scope: None)
# handle.abort() on shutdown
Redis outages fail closed: a dropped record refuses the action; a dropped count collapses the rate-limit condition to default-deny. Full wiring lives in docs/guides/distributed.md.
Observe mode
Roll out incrementally: log verdicts without blocking.
gate = Gate.from_dict(POLICY, observe_only=True)
What's in the Rust engine
Every evaluate() call crosses FFI into compiled Rust. The Python layer is pure wrappers. The engine implements:
- Policy: a small, fixed condition vocabulary (
identity_kind,action,param_max,rate_limit,time_windowwith optional timezone, etc.) expressed as a Python dict, JSON, or operator-edited TOML. - Drift detectors: IP / geo, session age, device, behavior.
- Invariants: hard per-action limits that cannot be overridden by policy.
- Post-quantum crypto: ML-DSA-65, ML-KEM-768, Ed25519, X25519, ChaCha20-Poly1305.
- Fail-closed: any evaluator error, store failure, or broadcast issue errs on the side of Refuse.
License
Elastic License 2.0. Source-available; free to use, embed, and modify for any purpose, including commercially. You may not offer Kavach itself as a hosted or managed service that competes with SarthiAI. See the LICENSE file for the full text.
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 Distributions
Built Distributions
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 kavach_sdk-0.1.0-cp310-abi3-win_amd64.whl.
File metadata
- Download URL: kavach_sdk-0.1.0-cp310-abi3-win_amd64.whl
- Upload date:
- Size: 1.7 MB
- Tags: CPython 3.10+, Windows x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9dca5d94824eee71bc9a4fa8b9d0bddd4f4731db0f62aa03aaaec58d6a5c5d0e
|
|
| MD5 |
bc056be725264968bbdc1cf0e82633e6
|
|
| BLAKE2b-256 |
b7e6c272aba4b030f17b776651e6e4108a9cc4f9b17351f1c115fbe6360f4170
|
Provenance
The following attestation bundles were made for kavach_sdk-0.1.0-cp310-abi3-win_amd64.whl:
Publisher:
publish-pypi.yml on SarthiAI/Kavach
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
kavach_sdk-0.1.0-cp310-abi3-win_amd64.whl -
Subject digest:
9dca5d94824eee71bc9a4fa8b9d0bddd4f4731db0f62aa03aaaec58d6a5c5d0e - Sigstore transparency entry: 1343042603
- Sigstore integration time:
-
Permalink:
SarthiAI/Kavach@3b1a9b384a0cad8b23e642455b397bf5c9904f93 -
Branch / Tag:
refs/tags/py-v0.1.0 - Owner: https://github.com/SarthiAI
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@3b1a9b384a0cad8b23e642455b397bf5c9904f93 -
Trigger Event:
push
-
Statement type:
File details
Details for the file kavach_sdk-0.1.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: kavach_sdk-0.1.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 2.1 MB
- Tags: CPython 3.10+, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0213f885778ac06bd3fabc2ac1d881ed30aa88154e00c52af4efdb9f322e0073
|
|
| MD5 |
83263f5b5a273991381f44ccd351c369
|
|
| BLAKE2b-256 |
d5a957828618e5b2027e89cb694eea90e1a254067cacb7539b52d4c94a8df776
|
Provenance
The following attestation bundles were made for kavach_sdk-0.1.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:
Publisher:
publish-pypi.yml on SarthiAI/Kavach
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
kavach_sdk-0.1.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl -
Subject digest:
0213f885778ac06bd3fabc2ac1d881ed30aa88154e00c52af4efdb9f322e0073 - Sigstore transparency entry: 1343042621
- Sigstore integration time:
-
Permalink:
SarthiAI/Kavach@3b1a9b384a0cad8b23e642455b397bf5c9904f93 -
Branch / Tag:
refs/tags/py-v0.1.0 - Owner: https://github.com/SarthiAI
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@3b1a9b384a0cad8b23e642455b397bf5c9904f93 -
Trigger Event:
push
-
Statement type:
File details
Details for the file kavach_sdk-0.1.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.
File metadata
- Download URL: kavach_sdk-0.1.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
- Upload date:
- Size: 2.2 MB
- Tags: CPython 3.10+, manylinux: glibc 2.17+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
22a50596883dc29931d8e2e135c0c3485b275141d3fbd4f05ecc40fb001fabaa
|
|
| MD5 |
5a2f721a30791c9f817e4b3985265b62
|
|
| BLAKE2b-256 |
406317361b705a11f54c4a962a955b78c39b1653561ed2789b71624926de9691
|
Provenance
The following attestation bundles were made for kavach_sdk-0.1.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:
Publisher:
publish-pypi.yml on SarthiAI/Kavach
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
kavach_sdk-0.1.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl -
Subject digest:
22a50596883dc29931d8e2e135c0c3485b275141d3fbd4f05ecc40fb001fabaa - Sigstore transparency entry: 1343042634
- Sigstore integration time:
-
Permalink:
SarthiAI/Kavach@3b1a9b384a0cad8b23e642455b397bf5c9904f93 -
Branch / Tag:
refs/tags/py-v0.1.0 - Owner: https://github.com/SarthiAI
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@3b1a9b384a0cad8b23e642455b397bf5c9904f93 -
Trigger Event:
push
-
Statement type:
File details
Details for the file kavach_sdk-0.1.0-cp310-abi3-macosx_11_0_arm64.whl.
File metadata
- Download URL: kavach_sdk-0.1.0-cp310-abi3-macosx_11_0_arm64.whl
- Upload date:
- Size: 1.9 MB
- Tags: CPython 3.10+, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c2538484ca24a425b77bf050a62518b702113625e2c9283fa82af54dd8c77038
|
|
| MD5 |
a1ea1e7e60bd53456433127a9a3eff76
|
|
| BLAKE2b-256 |
cafef361a53a409c0af2f57723de2ac02f5b4eb421e7c4b907317ec1e2490bce
|
Provenance
The following attestation bundles were made for kavach_sdk-0.1.0-cp310-abi3-macosx_11_0_arm64.whl:
Publisher:
publish-pypi.yml on SarthiAI/Kavach
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
kavach_sdk-0.1.0-cp310-abi3-macosx_11_0_arm64.whl -
Subject digest:
c2538484ca24a425b77bf050a62518b702113625e2c9283fa82af54dd8c77038 - Sigstore transparency entry: 1343042646
- Sigstore integration time:
-
Permalink:
SarthiAI/Kavach@3b1a9b384a0cad8b23e642455b397bf5c9904f93 -
Branch / Tag:
refs/tags/py-v0.1.0 - Owner: https://github.com/SarthiAI
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@3b1a9b384a0cad8b23e642455b397bf5c9904f93 -
Trigger Event:
push
-
Statement type: