Skip to main content
The official Python SDK for QWED.

Installation

pip install qwed

Quick start

from qwed_sdk import QWEDClient

client = QWEDClient(api_key="qwed_your_key")

# Basic verification
result = client.verify("Is 2+2=4?")
print(result.verified)  # True
print(result.status)    # "VERIFIED"
As of v5.0.0, the status field may return INCONCLUSIVE, BLOCKED, or UNKNOWN in addition to VERIFIED and ERROR. Natural-language math queries return INCONCLUSIVE when the inner engine succeeds, because the LLM translation step is non-deterministic. See the trust boundary documentation for details.

Async client

from qwed_sdk import QWEDAsyncClient
import asyncio

async def main():
    async with QWEDAsyncClient(api_key="qwed_...") as client:
        result = await client.verify("2+2=4")
        print(result.verified)

asyncio.run(main())

Methods

verify(query)

Auto-detect and verify any claim.
result = client.verify("What is 15% of 200?")

verify_math(expression)

Verify mathematical expressions.
result = client.verify_math("x**2 + 2*x + 1 = (x+1)**2")

verify_logic(query)

Verify logical constraints (QWED-Logic DSL).
result = client.verify_logic("(AND (GT x 5) (LT y 10))")
print(result.model)  # {"x": 6, "y": 9}

verify_code(code, language)

Check code for security vulnerabilities.
result = client.verify_code(code, language="python")
for vuln in result.vulnerabilities:
    print(f"{vuln.severity}: {vuln.message}")

verify_sql(query, schema_ddl, dialect)

Validate SQL queries against a schema.
result = client.verify_sql(
    query="SELECT * FROM users WHERE id = 1",
    schema_ddl="CREATE TABLE users (id INT, name TEXT)",
    dialect="postgresql"
)

verify_fact(claim, context)

New in v4.0.0
Verify factual claims against a provided context. Includes client-side PII pre-check.
result = client.verify_fact(
    claim="The company was founded in 2020",
    context="Acme Corp was established in 2020 in San Francisco."
)
print(result.verified)  # True

verify_stats(query, file_path)

New in v4.0.0
Verify statistical claims against CSV data.
result = client.verify_stats(
    query="The average salary is above 50000",
    file_path="data.csv"
)

verify_consensus(query, mode, min_confidence)

New in v4.0.0
Multi-engine consensus verification.
result = client.verify_consensus(
    query="The square root of 144 is 12",
    mode="high",
    min_confidence=0.8
)
print(result.verified)     # True
print(result.confidence)   # 0.95
ParameterTypeDefaultDescription
querystrClaim to verify
modestr"single"single, high, or maximum
min_confidencefloat0.8Minimum confidence threshold

verify_image(image_path, claim)

New in v4.0.0
Verify claims about image content.
result = client.verify_image(
    image_path="photo.jpg",
    claim="This image contains a cat"
)

verify_batch(items)

Verify multiple items at once.
results = client.verify_batch([
    {"query": "2+2=4", "type": "math"},
    {"query": "3*3=9", "type": "math"},
])
print(results.summary.success_rate)
For math items, supply equality claims (e.g., "x + x = 2*x") to receive proof results. Non-equality expressions (e.g., "x + x") are returned as simplification-only results with is_valid: false and status: "SIMPLIFIED" — they are not reported as verified.

Verification cache

qwed_sdk.cache.VerificationCache is the persistent SQLite-backed cache for verification results. It reduces LLM cost on repeated queries. Cache entries are context-bound. A hit requires an exact match of both the normalized query and the trust-bound CacheContext. A mismatch on any context dimension is a deterministic miss. The cache never falls back to a query-only match. This prevents cross-provider, cross-model, cross-policy, and cross-tenant replay of VERIFIED results.

CacheContext

Every get() and set() call requires a CacheContext. All fields participate in the cache key.
FieldTypeRequiredDescription
providerstryesProvider or API endpoint identifier (e.g., "openai").
modelstryesModel or deployment name (e.g., "gpt-4o").
policy_versionstryesVerifier policy version string (e.g., "v1").
tenant_idOptional[str]noTenant or session scope identifier.
env_fingerprintOptional[str]noEnvironment or configuration fingerprint for extra binding.

Usage

from qwed_sdk.cache import CacheContext, VerificationCache

cache = VerificationCache()  # defaults to ~/.qwed/cache, TTL 24h

ctx = CacheContext(
    provider="openai",
    model="gpt-4o",
    policy_version="v1",
    tenant_id="tenant-alpha",
)

# Cache miss on first call
result = cache.get("Is 2+2=4?", ctx)         # None

# Populate the cache for this (query, context) pair
cache.set("Is 2+2=4?", {"verified": True, "value": 4}, ctx)

# Same query, same context → hit
cache.get("Is 2+2=4?", ctx)                  # {"verified": True, "value": 4}

# Same query, different provider → deterministic miss
ctx_other = CacheContext(provider="anthropic", model="claude-opus-4-5", policy_version="v1")
cache.get("Is 2+2=4?", ctx_other)            # None

Miss conditions

cache.get(query, context) returns None when any of the following holds:
  • No entry exists for this (query, context) pair.
  • The stored entry has expired (TTL, default 24 hours).
  • The stored context fingerprint does not match context (replay guard).
  • The entry uses the legacy v1 schema. The cache never returns legacy rows.

Constructor options

VerificationCache(cache_dir: Optional[str] = None, ttl: int = 86400)
  • cache_dir — Directory for the SQLite database. Defaults to ~/.qwed/cache.
  • ttl — Time-to-live in seconds. Defaults to 24 hours.
get() and set() require a CacheContext argument as of the May 17, 2026 release. Calls that omit the context raise TypeError. See the changelog entry for migration details.

CLI

# Verify
qwed verify "2+2=4"

# Verify logic
qwed verify-logic "(AND (GT x 5) (LT y 10))"

# Verify code file
qwed verify-code -f script.py

# Batch verify
qwed batch -f queries.json

Verification cache

qwed_sdk.cache provides a context-bound SQLite cache for verification results. A cache hit requires an exact match of both the normalized query and the trust-bound CacheContext. Any mismatch on a context dimension yields a deterministic miss — the cache never crosses trust boundaries. The cache also ignores legacy entries that lack a context fingerprint.
from qwed_sdk.cache import CacheContext, VerificationCache

ctx = CacheContext(
    provider="openai",
    model="gpt-4o",
    policy_version="v1",
    tenant_id="tenant-alpha",       # optional
    env_fingerprint="sha256-...",   # optional
)

cache = VerificationCache()

cache.get("2+2", ctx)              # None (miss)
cache.set("2+2", {"verified": True}, ctx)
cache.get("2+2", ctx)              # {"verified": True}

# Different provider — deterministic miss (replay prevention)
ctx2 = CacheContext(provider="claude", model="claude-opus-4-5", policy_version="v1")
cache.get("2+2", ctx2)             # None

CacheContext

Trust-bound context dimensions required for every cache operation. All fields participate in the cache key; omitting or changing any field causes a deterministic cache miss.
provider
str
required
Provider or API endpoint identifier (for example, "openai", "claude").
model
str
required
Model or deployment name (for example, "gpt-4o").
policy_version
str
required
Verifier policy version string (for example, "v1").
tenant_id
Optional[str]
default:"None"
Tenant or session scope identifier. Use to prevent cross-tenant replay.
env_fingerprint
Optional[str]
default:"None"
Environment or config fingerprint for additional binding.

VerificationCache(cache_dir=None, ttl=86400)

cache_dir
Optional[str]
default:"~/.qwed/cache"
Directory for the SQLite cache database.
ttl
int
default:"86400"
Time-to-live in seconds (default: 24 hours). get() treats entries older than ttl as a miss and deletes them on access.
The cache caps total entries at MAX_ENTRIES = 1000. When set() grows the table past the cap, set() evicts the least-recently-accessed entries.

get(query, context)

Return the cached result for (query, context), or None on miss. get() returns None when:
  • No entry exists for the (query, context) pair.
  • The entry has expired (older than ttl).
  • The stored context fingerprint does not match context (defence-in-depth replay guard).
query
str
required
The verification query string. Normalized (lowercased, whitespace-collapsed) before hashing.
context
CacheContext
required
Trust-bound context that must match exactly. Omitting this argument raises TypeError.
result
Optional[Dict[str, Any]]
The cached result dict, or None on any miss.

set(query, result, context)

Store a verification result bound to (query, context). The composite primary key (key, context_fingerprint) keeps identical queries under different contexts as independent entries.
query
str
required
The verification query string.
result
Dict[str, Any]
required
Verification result to cache. set() serializes this dict as JSON.
context
CacheContext
required
Trust-bound context to bind this entry to.

clear()

Remove all cached entries and reset stats.

get_stats()

Return a CacheStats dataclass with hits, misses, total_entries, cache_size_bytes, and a hit_rate property. Print a formatted summary of cache statistics to stdout. Uses ANSI colors when colorama is installed.
Breaking change (Issue #187). get() and set() now require a CacheContext argument. Calls like cache.get("2+2") or cache.set("2+2", result) raise TypeError. The on-disk schema is cache_v2 with composite PRIMARY KEY (key, context_fingerprint). The cache never returns entries from the legacy v1 cache table.

Guards

The SDK includes security guards for protecting AI agent pipelines:
from qwed_sdk.guards import (
    RAGGuard,
    ExfiltrationGuard,
    MCPPoisonGuard,
    SelfInitiatedCoTGuard,
    SovereigntyGuard,
    SystemGuard,
    ConfigGuard,
)

# Prevent RAG hallucinations from wrong document chunks
rag_guard = RAGGuard(max_drm_rate="1/10")
result = rag_guard.verify_retrieval_context(
    target_document_id="contract_v2",
    retrieved_chunks=chunks
)

# Block data exfiltration to unauthorized endpoints
exfil_guard = ExfiltrationGuard(allowed_endpoints=["https://api.openai.com"])
result = exfil_guard.verify_outbound_call(
    destination_url=url,
    payload=data
)

# Detect poisoned MCP tool definitions
mcp_guard = MCPPoisonGuard()
result = mcp_guard.verify_tool_definition(tool_schema)

# Block dangerous shell commands (v4.0.0)
sys_guard = SystemGuard()
result = sys_guard.verify_shell_command("rm -rf /")

# Detect plaintext secrets in config (v4.0.0)
cfg_guard = ConfigGuard()
result = cfg_guard.verify_config_safety(config_data)
See the SDK Guards reference for complete documentation.

Environment variables

VariableDescription
QWED_API_KEYAPI key
QWED_BASE_URLAPI base URL