Official Shield SDK for Python
Project description
Shield Python SDK
Official Python SDK for Shield ??tamper-evident session recording for online business transactions.
Installation
pip install shield-python==0.5.0
Quick Start
import shield
client = shield.Client(api_key="sk_live_your_api_key")
# Create a session
session = client.sessions.create(title="Contract Negotiation with Acme Corp")
session_id = session["id"]
# Record events
client.events.create(
session_id=session_id,
event_type="shield.party.joined",
actor="agent@example.com",
data={"role": "listing_agent", "name": "Jane Smith"},
)
client.events.create(
session_id=session_id,
event_type="shield.content.uploaded",
actor="agent@example.com",
data={"filename": "purchase_agreement.pdf"},
)
client.events.create(
session_id=session_id,
event_type="shield.agreement.signed",
actor="buyer@example.com",
data={"document": "purchase_agreement.pdf"},
)
# Verify session integrity
result = client.verify.session(session_id)
print(result["valid"]) # True
# Export session
pdf_bytes = client.sessions.export(session_id, format="pdf")
with open("audit_trail.pdf", "wb") as f:
f.write(pdf_bytes)
Recording AI Agent Evidence
import hashlib
# Hash content locally — never send raw prompts or outputs to Shield
prompt_hash = hashlib.sha256(my_prompt.encode()).hexdigest()
output_hash = hashlib.sha256(agent_output.encode()).hexdigest()
event = client.agent.log_action(
session_id,
"shield.content.submitted",
agent_id="agt-unique-identifier",
agent_name="gpt-4o",
agent_provider="OpenAI",
principal_user_id="alice@example.com",
prompt_hash=prompt_hash, # bare 64-char lowercase hex
output_hash=output_hash,
)
At least one of agent_id or agent_name is required. Hash fields
(prompt_hash, input_hash, output_hash) must be bare 64-character
lowercase SHA-256 hex digests (no prefix). Values of incorrect format or
length raise ShieldError.
Recording Agent Action Evidence
For browser-automation and tool-call agents, use the typed action helpers. These record what the agent did — Shield does not judge whether the decision was correct.
import hashlib
# Hash screenshots/DOM locally — never upload raw images or HTML to Shield
screenshot_before_hash = hashlib.sha256(screenshot_bytes).hexdigest()
screenshot_after_hash = hashlib.sha256(after_bytes).hexdigest()
# Record a click
client.agent.action_clicked(
session_id,
agent_id="agt-browser-001",
principal_user_id="alice@example.com",
target_url="https://app.example.com/checkout",
element_selector="#confirm-order",
element_text="Confirm Order",
screenshot_before_hash=screenshot_before_hash, # bare 64-char hex — do not include the sha256 prefix plus colon
screenshot_after_hash=screenshot_after_hash,
risk_level="medium",
)
# Record a tool call
client.agent.action_tool_called(
session_id,
agent_id="agt-001",
tool_call_id="call_abc123",
action_type="search_web",
result="success",
)
# Record a confirmed payment (amount + currency + approval required)
client.agent.action_payment_confirmed(
session_id,
agent_id="agt-001",
principal_user_id="alice@example.com",
amount=299.99,
currency="USD",
human_approval_event_id="evt-approval-abc", # or pass authority_scope=["payment:execute"]
)
Action helpers available:
| Method | Event type |
|---|---|
agent.action_clicked |
shield.agent.action.clicked |
agent.action_submitted |
shield.agent.action.submitted |
agent.action_tool_called |
shield.agent.action.tool_called |
agent.action_payment_confirmed |
shield.agent.action.payment_confirmed |
All helpers accept keyword arguments that are passed as top-level request body fields. The SDK validates that screenshot_before_hash, screenshot_after_hash, dom_before_hash, and dom_after_hash are bare 64-character lowercase SHA-256 hex digests. Values beginning with the sha256 prefix plus colon are rejected before any request is made.
Payment actions additionally require amount (float), currency (str), and either human_approval_event_id or an authority_scope list containing a payment permission string ("payment" or "pay:"). Validation is enforced server-side.
For additional agent action types not covered by the helpers above, use agent.log_action directly:
client.agent.log_action(
session_id,
"shield.agent.action.navigated",
agent_id="agt-001",
target_url="https://app.example.com/dashboard",
)
Evidence Artifact References
When an AI agent captures screenshots, DOM snapshots, or I/O traces, you can record a tamper-evident reference to each artifact. Shield seals the uri + sha256 into the hash chain — proving the file was not changed later.
Shield does not store raw artifact bytes in v1. Upload to your own storage first, then pass the URI and SHA-256 hash here.
import hashlib
# 1. Capture and hash the artifact locally
screenshot_bytes = page.screenshot() # your browser/tool
sha256 = hashlib.sha256(screenshot_bytes).hexdigest()
# 2. Upload to your S3 bucket (your responsibility — Shield does not upload)
uri = "s3://my-company-evidence/session-123/screenshot-before.png"
# ... your upload code ...
# 3. Record the tamper-evident reference in Shield
shield.agent.action_clicked(
session_id,
agent_id="agt-browser-001",
actor="agt-browser-001",
element_selector="#confirm-order",
evidence_artifacts=[{
"artifact_type": "screenshot_before", # required
"sha256": sha256, # required — bare 64-char lowercase hex, no "sha256:" prefix
"uri": uri, # optional
"storage_provider": "customer_s3", # optional
"content_type": "image/png", # optional
"size_bytes": len(screenshot_bytes), # optional
}],
)
Allowed artifact_type values: screenshot_before, screenshot_after, dom_before, dom_after, input, output, trace, receipt, other
Allowed storage_provider values: customer_s3, customer_r2, customer_gcs, customer_azure_blob, shield_storage, external
Allowed uri schemes: http://, https://, s3://, gs://, azure://, r2://
Required per artifact: artifact_type (from allowlist) and sha256 (bare 64-char lowercase hex, no prefix)
HMAC Authentication
For enhanced security, provide an HMAC secret to sign every request:
client = shield.Client(
api_key="sk_live_your_api_key",
hmac_secret="your_hmac_secret",
)
When an HMAC secret is configured, the SDK computes a signature for each request:
X-Shield-Timestamp— Unix timestamp of the requestX-Shield-Nonce— unique single-use value, sealed into the signatureX-Shield-Signature— HMAC-SHA256 of{timestamp}.{nonce}.{METHOD}.{request_uri}.{SHA256(body)}
The server validates these headers to ensure requests have not been tampered with or replayed.
Flask Integration
from flask import Flask, request, jsonify
import shield
app = Flask(__name__)
client = shield.Client(api_key="sk_live_your_api_key")
@app.route("/sessions", methods=["POST"])
def create_session():
data = request.get_json()
session = client.sessions.create(title=data["title"])
# Record who created the session
client.events.create(
session_id=session["id"],
event_type="shield.session.created",
actor=data["user_email"],
)
return jsonify(session), 201
@app.route("/sessions/<session_id>/upload", methods=["POST"])
def upload_document(session_id):
file = request.files["file"]
# ... save file logic ...
client.events.create(
session_id=session_id,
event_type="shield.content.uploaded",
actor=request.headers.get("X-User-Email"),
data={"filename": file.filename},
)
return jsonify({"status": "uploaded"}), 200
@app.route("/sessions/<session_id>/sign", methods=["POST"])
def sign_agreement(session_id):
data = request.get_json()
client.events.create(
session_id=session_id,
event_type="shield.agreement.signed",
actor=data["signer_email"],
data={"document": data["document_name"]},
)
return jsonify({"status": "signed"}), 200
FastAPI Integration
from fastapi import FastAPI, UploadFile, Header
from pydantic import BaseModel
import shield
app = FastAPI()
client = shield.Client(
api_key="sk_live_your_api_key",
hmac_secret="your_hmac_secret",
)
class CreateSessionRequest(BaseModel):
title: str
user_email: str
class SignRequest(BaseModel):
signer_email: str
document_name: str
@app.post("/sessions")
async def create_session(body: CreateSessionRequest):
session = client.sessions.create(title=body.title)
client.events.create(
session_id=session["id"],
event_type="shield.session.created",
actor=body.user_email,
)
return session
@app.post("/sessions/{session_id}/upload")
async def upload_document(
session_id: str,
file: UploadFile,
x_user_email: str = Header(...),
):
# ... save file logic ...
client.events.create(
session_id=session_id,
event_type="shield.content.uploaded",
actor=x_user_email,
data={"filename": file.filename},
)
return {"status": "uploaded"}
@app.post("/sessions/{session_id}/sign")
async def sign_agreement(session_id: str, body: SignRequest):
client.events.create(
session_id=session_id,
event_type="shield.agreement.signed",
actor=body.signer_email,
data={"document": body.document_name},
)
return {"status": "signed"}
@app.get("/sessions/{session_id}/verify")
async def verify_session(session_id: str):
return client.verify.session(session_id)
Event Types Reference
Shield Standard Event Taxonomy v1.0 — 40 event types across 8 categories:
Party Events
| Event Type | Description |
|---|---|
shield.party.joined |
A party joined the session |
shield.party.left |
A party left the session |
shield.party.identity.verified |
Party identity was verified |
shield.party.identity.failed |
Party identity verification failed |
shield.party.role.assigned |
A role was assigned to a party |
Session Events
| Event Type | Description |
|---|---|
shield.session.created |
Session was created |
shield.session.opened |
Session was opened |
shield.session.closed |
Session was closed |
shield.session.expired |
Session expired |
shield.session.archived |
Session was archived |
Content Events
| Event Type | Description |
|---|---|
shield.content.uploaded |
Content was uploaded |
shield.content.viewed |
Content was viewed |
shield.content.downloaded |
Content was downloaded |
shield.content.deleted |
Content was deleted |
shield.content.hash.verified |
Content hash was verified |
shield.content.submitted |
Content or analysis was submitted by an AI agent |
Negotiation Events
| Event Type | Description |
|---|---|
shield.negotiation.terms.proposed |
Terms were proposed |
shield.negotiation.terms.accepted |
Terms were accepted |
shield.negotiation.terms.rejected |
Terms were rejected |
shield.negotiation.terms.modified |
Terms were modified |
shield.negotiation.terms.expired |
Terms expired |
shield.negotiation.message.sent |
Negotiation message sent |
shield.negotiation.message.read |
Negotiation message read |
Agreement Events
| Event Type | Description |
|---|---|
shield.agreement.drafted |
Agreement was drafted |
shield.agreement.reviewed |
Agreement was reviewed |
shield.agreement.approved |
Agreement was approved |
shield.agreement.signed |
Agreement was signed |
shield.agreement.countersigned |
Agreement was countersigned |
shield.agreement.voided |
Agreement was voided |
shield.agreement.reached |
Agreement was reached |
Access Events
| Event Type | Description |
|---|---|
shield.access.granted |
Access was granted |
shield.access.revoked |
Access was revoked |
shield.access.attempted |
Access was attempted |
shield.access.denied |
Access was denied |
Disclosure Events
| Event Type | Description |
|---|---|
shield.disclosure.presented |
Disclosure was presented |
shield.disclosure.acknowledged |
Disclosure was acknowledged |
shield.disclosure.declined |
Disclosure was declined |
Evidence Events
| Event Type | Description |
|---|---|
shield.evidence.exported |
Evidence was exported |
shield.evidence.verified |
Evidence was verified |
shield.evidence.tampered_detected |
Evidence tampering was detected |
Agent Action Events (use with agent.log_action or action helpers)
| Event Type | Description |
|---|---|
shield.agent.action.navigated |
Agent navigated to a URL |
shield.agent.action.clicked |
Agent clicked a UI element |
shield.agent.action.input_filled |
Agent filled a form input |
shield.agent.action.submitted |
Agent submitted a form |
shield.agent.action.confirmed |
Agent confirmed an action |
shield.agent.action.payment_initiated |
Agent initiated a payment — requires amount, currency, and approval/scope |
shield.agent.action.payment_confirmed |
Agent confirmed a payment — requires amount, currency, and approval/scope |
shield.agent.action.tool_called |
Agent called a tool or function |
shield.agent.action.human_approval_requested |
Agent requested human approval |
shield.agent.action.human_approval_granted |
Human approved the agent's pending action |
Versioning & API compatibility
This SDK follows Semantic Versioning.
- Pre-1.0 (current): minor-version bumps may ship breaking changes. Pin the full version in
requirements.txt. - 1.0 and later: the public API is stable within a major version. Breaking changes require a major-version bump.
The Shield HTTP API is versioned at the URL path (/api/v1). This SDK targets /api/v1 and will not transparently follow a server-side version bump — a new server major version will be delivered as a new SDK major version so callers opt in explicitly.
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 shield_python-0.5.0.tar.gz.
File metadata
- Download URL: shield_python-0.5.0.tar.gz
- Upload date:
- Size: 19.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e2378d2984c0acc26d9abc8993eac55281a2538b31c0b71bd8af8f02bedb28ae
|
|
| MD5 |
ef0e2b73d8491a9069ea20f198431389
|
|
| BLAKE2b-256 |
ec1e333d9e7fb50420b6bb82cd665078d6f7b51858a61c1938abbffb5de5cd99
|
File details
Details for the file shield_python-0.5.0-py3-none-any.whl.
File metadata
- Download URL: shield_python-0.5.0-py3-none-any.whl
- Upload date:
- Size: 15.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4c99dfd4aa9fe09c8ae1df15f881f9aef7826f6fc20fd6ff5ef340c8a6cad69a
|
|
| MD5 |
d7dec1de4212b4f23f74cb250b0cfbfc
|
|
| BLAKE2b-256 |
929cf4ca69c86d4c52a2c8f851c45254fa3763a838d8b506bb4b306cdeda341e
|