ClawID — Agent KYC. Verify autonomous AI agent credentials in three lines.
Project description
clawid-sdk
Agent KYC. Verify autonomous AI agent credentials in three lines.
import clawid_sdk_sdk
result = clawid_sdk.verify(token)
if result.valid:
print(result.agent_id, "owned by", result.tenant_id)
That's it. Three lines. Free forever for verifiers. No key, no contract.
What is this?
ClawID is the trust layer for autonomous AI agents and the services they touch. Every agent carries a Claw — a cryptographically signed credential that binds the agent to its owner, declares the owner's policy (the leash), and produces a tamper-evident receipt of every action. This SDK is what services use to verify a Claw on the way in.
When an AI agent calls your API, you want to know:
- Who's behind it? →
result.tenant_id,result.agent_id - What did the owner permit? →
result.leash - Can the owner kill it? → yes;
result.statusreflects current revocation state - Is there a record of the attempt? → yes; every check-in lands in a hash-chained audit log on both sides
One round-trip, four answers. Free forever for verifiers.
Install
pip install clawid-sdk
Python 3.10+. Two dependencies: httpx and pyjwt[crypto].
Use
The common case
import clawid_sdk
result = clawid_sdk.verify(token)
if not result.valid:
return reject(result.status, result.reason)
# Now you know who this is.
print(f"Agent {result.agent_id} owned by {result.tenant_id}")
print(f"Leash: {result.leash}")
When you want to configure things
from clawid_sdk import Claw
claw = Claw(
hub_url="https://api.holdtheleash.id", # defaults to this
jwks_ttl=300, # cache the hub's pubkey for 5 minutes
timeout=5.0, # per-request timeout
)
result = claw.verify(token)
Async
result = await clawid_sdk.verify_async(token)
Offline mode (signature + expiry only, no live revocation check)
result = clawid_sdk.verify(token, mode="offline")
Use when latency matters more than catching a revoke within ~30s. The signature check
still uses the cached JWKS, so it's accurate; you just won't see a revoke immediately.
Suited for very high-throughput verifiers who poll /v1/verify on a schedule out of band.
Web-framework integration
The SDK is framework-agnostic by design. A FastAPI middleware looks like:
from fastapi import FastAPI, HTTPException, Request, Depends
import clawid_sdk
app = FastAPI()
def claw_required(request: Request) -> clawid.VerifyResult:
auth = request.headers.get("Authorization", "")
token = auth.removeprefix("Bearer ").strip()
if not token:
raise HTTPException(401, "missing Claw")
result = clawid_sdk.verify(token)
if not result.valid:
raise HTTPException(401, f"{result.status.value}: {result.reason}")
return result
@app.post("/charge")
def charge(amount: float, agent: clawid.VerifyResult = Depends(claw_required)):
if amount > agent.leash["spend_ceiling"]:
raise HTTPException(403, "amount exceeds agent's leash")
return {"agent_id": agent.agent_id, "charged": amount}
What the result tells you
VerifyResult is a dataclass. if result: is shorthand for if result.valid:.
@dataclass
class VerifyResult:
valid: bool # True iff the Claw is currently usable
status: VerifyStatus # ACTIVE | REVOKED | EXPIRED | INVALID | UNKNOWN
reason: str | None # human-readable reason
jti: str | None # JWT id of this Claw (stable receipt key)
agent_id: str | None # who the agent is
tenant_id: str | None # who owns the agent
leash: dict | None # the owner's policy: spend cap, surfaces, hours...
agent_pubkey_pem: str | None # for proof-of-possession on signed actions
issued_at: int | None
expires_at: int | None
payload: dict | None # raw decoded JWS payload, for custom claims
VerifyStatus:
| Status | Means |
|---|---|
ACTIVE |
Claw is valid and live; owner has not revoked it. |
REVOKED |
Owner hit the kill switch. Deny the request. |
EXPIRED |
The exp claim is in the past. Agent needs a fresh Claw. |
INVALID |
Signature didn't verify, malformed, unknown issuer, etc. |
UNKNOWN |
Hub returned a status this SDK version doesn't recognize. Treat as INVALID. |
What's the leash?
result.leash
# {
# "spend_ceiling": 50.0,
# "allowed_surfaces": ["stripe.com", "openai.com"],
# "active_start_hour": 9,
# "active_end_hour": 17,
# "escalate_over": 25.0,
# "auto_revoke_off_leash": True,
# }
You can use the leash to short-circuit policy decisions on your side — for example,
refuse the request if amount > leash["spend_ceiling"] before doing any expensive work.
How the verify path works
clawid_sdk.verify(token)
│
┌─────────────────┴─────────────────┐
▼ ▼
Offline (JWS) Online (revocation)
│ │
1. Fetch JWKS from 1. POST /v1/verify
/.well-known/jwks.json with the token
(cached for jwks_ttl) 2. Hub responds with
2. Verify EdDSA signature live revocation status
3. Check exp / iss / required + structural detail
claims
If signature is bad → INVALID
If exp in past → EXPIRED
Otherwise: status: ACTIVE / REVOKED
online mode → run the right path
offline mode → return ACTIVE
The hub's signing key is in cloud KMS. We never see your verify traffic if you stay in offline mode after the first JWKS fetch.
Errors
ClawError is raised only for infrastructure problems (the hub is unreachable, JWKS is
malformed). Verification failures — bad signature, expired, revoked — never raise; they
return a VerifyResult with valid=False and a status that describes what happened.
import clawid_sdk
try:
result = clawid_sdk.verify(token)
except clawid_sdk.ClawError as e:
# Hub is down or JWKS is unreachable. Decide based on your trust posture
# — typically: fail closed.
return reject_with_503(str(e))
if not result.valid:
# Bad/expired/revoked Claw. Tell the agent's owner why.
return reject_with_401(result.status, result.reason)
Vendor onboarding
Verification is permissionless. You don't need a key, an account, or a contract to call
clawid_sdk.verify(...). It's free forever. That's the whole network effect.
If you want to appear in the Verified Vendors directory — and get the matching audit-chain visibility on your side of every check-in to your domain — apply at holdtheleash.id/vendors (KYB-gated: entity + domain ownership + live service + signed TOS). Listing is free; promotional placement is a separate paid surface.
Versioning
clawid-sdk follows SemVer. The VerifyResult shape is stable within
a major; new optional fields are minor; field removals or behavior changes are major.
payload always carries the full decoded JWS for forward-compatibility with new claims.
License
Apache License 2.0. Copyright © 2026 Project Black Box LLC.
Links
- Product: holdtheleash.id
- Dashboard: app.holdtheleash.id
- Issues: github.com/projectblackboxllc/claw-sdk-python/issues
- JS SDK: github.com/projectblackboxllc/claw-sdk-js (coming alongside this one)
- Spec: github.com/projectblackboxllc/claw-spec (coming next)
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 clawid_sdk-0.3.0.tar.gz.
File metadata
- Download URL: clawid_sdk-0.3.0.tar.gz
- Upload date:
- Size: 22.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
98db4387d73508e542d0dae5fdda24b885f3f6299bddcc4440e52ec4fa80615a
|
|
| MD5 |
bac53a5485cb65af25be1f64fd265988
|
|
| BLAKE2b-256 |
704c6c219b280917a6ce1e3a1d1958986f6a700b86c7fdfe6181d9b259d0cc31
|
File details
Details for the file clawid_sdk-0.3.0-py3-none-any.whl.
File metadata
- Download URL: clawid_sdk-0.3.0-py3-none-any.whl
- Upload date:
- Size: 20.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d2b58b91c380e9ec8ff9bfa2b8962bdaec96b1ad2ac50981c624d5b22b0c5f65
|
|
| MD5 |
3e5692de1a5351105f39c3f2c09bcffe
|
|
| BLAKE2b-256 |
7b9dc292032c5383e582537c69a006864474ebaba104b08f847cf05e160c1922
|