Skip to main content

Tork Governance Python SDK

On-device AI governance with PII detection, redaction, and local audit receipts.

PyPI version Python 3.9+ License: MIT

Installation

pip install tork-governance

With optional framework support:

pip install tork-governance[langchain]
pip install tork-governance[fastapi]
pip install tork-governance[all]

Quick Start

from tork_governance import Tork

tork = Tork()

# Detect and redact PII
result = tork.govern("My SSN is 123-45-6789 and email is john@example.com")

print(result.output)  # "My SSN is [SSN_REDACTED] and email is [EMAIL_REDACTED]"
print(result.pii.types)  # ['ssn', 'email']
print(result.receipt.receipt_id)  # Locally-generated receipt ID

Regional PII Detection (v1.1)

Activate country-specific and industry-specific PII patterns with the optional region and industry parameters:

from tork_governance import Tork

tork = Tork()

# UAE regional detection — Emirates ID, +971 phone, PO Box
result = tork.govern(
    "Emirates ID: 784-1234-1234567-1",
    region=["ae"]
)

# Multi-region + industry
result = tork.govern(
    "Aadhaar: 1234 5678 9012, ICD-10: J45.20",
    region=["in"],
    industry="healthcare"
)

# Available regions: AU, US, GB, EU, AE, SA, NG, IN, JP, CN, KR, BR
# Available industries: healthcare, finance, legal

Supported AI Frameworks (67 Adapters)

LLM Provider SDKs

  • OpenAI SDK - Direct OpenAI API governance with streaming
  • Anthropic SDK - Claude API governance
  • Google Gemini - Gemini API with multi-modal support
  • AWS Bedrock - Bedrock with Claude, Titan, Llama support
  • Azure OpenAI - Azure OpenAI Service governance
  • Cohere SDK - Chat, embed, rerank, classify governance
  • Mistral SDK - Mistral AI chat and embeddings governance
  • Groq SDK - Groq LPU chat and audio transcription governance
  • Together AI SDK - Together AI chat, completions, and embeddings governance
  • Replicate SDK - Replicate model run and predictions governance
  • LocalAI - Local OpenAI-compatible LLM governance
  • LM Studio - LM Studio local inference governance
  • GPT4All - GPT4All local LLM governance
  • PrivateGPT - PrivateGPT private document AI governance

LLM Orchestration

  • LangChain - Chain and agent governance
  • LlamaIndex - Query engine and retriever governance
  • Semantic Kernel - Microsoft SK filters and plugins
  • Haystack - Pipeline and document processor governance
  • LiteLLM - Unified interface for 100+ LLMs
  • vLLM - High-throughput LLM serving
  • Ollama - Local LLM governance

Agent Frameworks

  • CrewAI - Multi-agent crew governance
  • AutoGen - Microsoft AutoGen agent governance
  • OpenAI Agents SDK - Function calling governance
  • SuperAGI - Autonomous agent governance
  • MetaGPT - Multi-agent role governance
  • BabyAGI - Task-driven agent governance
  • AgentGPT - Goal-oriented agent governance

Structured Output & Guardrails

  • Pydantic AI - Type-safe AI with governance
  • Instructor - Structured outputs governance
  • DSPy - Stanford DSPy module governance
  • Guidance - Microsoft Guidance governance
  • LMQL - Query language governance
  • Outlines - Structured generation governance
  • Marvin - AI function governance
  • Guardrails AI - Validator integration
  • NeMo Guardrails - NVIDIA Colang integration
  • Rebuff - Prompt injection detection with governance
  • LLM Guard - Input/output scanning with governance

AI Development Frameworks

  • Mirascope - Decorator-based LLM call governance
  • Magentic - @prompt decorator governance
  • txtai - Embeddings and pipeline governance
  • ChatDev - Multi-agent software development governance
  • CAMEL - Multi-agent role-playing governance

Visual Builders & Platforms

  • Flowise - Visual workflow governance
  • Langflow - Visual LangChain governance
  • Dify - Low-code AI platform governance

Vector Databases

  • ChromaDB - AI-native vector DB governance
  • Pinecone - Managed vector DB governance
  • Weaviate - Vector search governance
  • Qdrant - Vector similarity governance
  • Milvus - Scalable vector DB governance

LLM Observability

  • LangSmith - LangChain tracing governance
  • Langfuse - LLM analytics governance
  • Phoenix - Arize Phoenix observability
  • Helicone - LLM monitoring governance
  • Weights & Biases - Experiment tracking governance
  • Arize - ML observability governance
  • Portkey - AI gateway governance
  • PromptLayer - Prompt management governance
  • Humanloop - Prompt optimization governance

Protocols

  • MCP - Model Context Protocol governance

Web Frameworks

  • FastAPI - Middleware and dependency injection
  • Django - Middleware integration
  • Flask - Extension and decorator support
  • Starlette - ASGI middleware
  • Tornado - RequestHandler mixin and middleware
  • Pyramid - Tween and middleware governance
  • Sanic - Async request/response middleware

Framework Examples

LiteLLM - Unified LLM Interface

from tork_governance.adapters.litellm import TorkLiteLLMProxy, govern_completion

# Option 1: Governed proxy client
proxy = TorkLiteLLMProxy()
response = proxy.completion(
    model="gpt-3.5-turbo",
    messages=[{"role": "user", "content": "My SSN is 123-45-6789"}]
)

# Option 2: One-off governed completion
response = govern_completion(
    model="gpt-3.5-turbo",
    messages=[{"role": "user", "content": "My email is john@example.com"}]
)

Ollama - Local LLM Governance

from tork_governance.adapters.ollama import TorkOllamaClient, govern_generate

# Governed Ollama client
client = TorkOllamaClient()
response = client.generate(
    model="llama2",
    prompt="My phone number is 555-123-4567"
)
print(response["response"])  # PII redacted

# Chat with governance
response = client.chat(
    model="llama2",
    messages=[{"role": "user", "content": "My SSN is 123-45-6789"}]
)

ChromaDB - Vector Database Governance

from tork_governance.adapters.chromadb import TorkChromaClient

# Governed ChromaDB client
client = TorkChromaClient()
collection = client.get_or_create_collection("my_docs")

# Documents are governed before storage
collection.add(
    documents=["User John has SSN 123-45-6789"],
    ids=["doc1"]
)

# Query results are governed before returning
results = collection.query(query_texts=["Find user data"])

LangChain Integration

from langchain.llms import OpenAI
from tork_governance.adapters.langchain import TorkCallbackHandler

llm = OpenAI(callbacks=[TorkCallbackHandler()])
response = llm("My credit card is 4111-1111-1111-1111")
# PII automatically redacted in prompts and responses

FastAPI Middleware

from fastapi import FastAPI
from tork_governance.adapters.fastapi import TorkFastAPIMiddleware

app = FastAPI()
app.add_middleware(TorkFastAPIMiddleware)

@app.post("/chat")
async def chat(message: str):
    # Request body is automatically governed
    return {"response": message}

PII Detection

Tork.govern() and Tork.scan_tool_result() run one of two on-device PII detectors, chosen by TorkConfig.detector, the Tork(detector=...) constructor kwarg, or the TORK_PII_DETECTOR environment variable (constructor kwarg wins, then the env var, then the default):

detector Default? Type vocabulary Checksum validation
"regional" Yes 44 types across US/AU/EU/UK + universal/financial/healthcare/biometric (tork_governance.detectors.pii_patterns) Yes, on the types that have one (SSN, credit card, IBAN, TFN, NHS, ABN, Medicare, NINO, routing number, NPI, DEA) — a lookalike that fails its checksum is not flagged
"basic" No — opt in 10 types: ssn, credit_card, email, phone, address, ip_address, date_of_birth, passport, drivers_license, bank_account No
from tork_governance import Tork

# Default: the wider, checksum-validated regional detector
tork = Tork()
result = tork.govern("IBAN: DE89370400440532013000")
print(result.pii.types)  # ['iban']

# Opt back into the original 10-type detector
basic_tork = Tork(detector="basic")
# ...or: TorkConfig(detector="basic"), or `TORK_PII_DETECTOR=basic` in the environment

Wider vocabulary than the JS SDK. @torknetwork/sdk (JS) implements only the 10 basic types above — it has no regional detector. A Python govern()/scan_tool_result() result's pii.types (or tool_result_scan receipt block finding types) may therefore contain labels with no JS-SDK equivalent, e.g. "iban", "tfn", "nhs_uk". Don't assume the two SDKs' outputs are directly comparable without accounting for this — use detector="basic" (or TORK_PII_DETECTOR=basic) on the Python side to match the JS SDK's exact 10-type vocabulary and behavior byte-for-byte.

Full list of regional types by category, generated from PIIDetector(regions=['all']).get_supported_types():

Category Types
US (6) driver_license_us, ein, itin, passport_us, phone_us, ssn
Australia (5) abn, acn, medicare_au, phone_au, tfn
EU (5) french_ssn, german_id, iban, phone_eu, vat_eu
UK (4) nhs_uk, nino_uk, postcode_uk, sort_code_uk
Universal (8) credit_card, date_of_birth, email, ip_address, ipv6_address, mac_address, phone_generic, url_with_pii
Financial (6) bank_account, card_expiry, crypto_address, cvv, routing_number, swift_bic
Healthcare (7) cpt_code, dea_number, health_plan_id, icd_code, mrn, npi, patient_id
Biometric (3) biometric_id, face_id, fingerprint_id

Removed regional types (0.26.1). The regional PIIType enum previously declared five types with no backing pattern anywhere in pii_patterns.py — they were listed in get_supported_types()'s vocabulary but could never actually be matched. Each was resolved individually:

  • name, addressremoved. Free-text personal names and postal addresses can't be reliably matched with a regex; that needs an NER model, which this detector doesn't have. A low-precision regex here would flag ordinary prose as PII (or miss most real addresses/names), which is worse than not claiming the type at all.
  • ssn_no_dashesremoved. The existing ssn pattern's separators are already optional (\d{3}[-\s]?\d{2}[-\s]?\d{4}), so it already matches unformatted 9-digit input under the ssn label. A second type for the identical span wouldn't add detection coverage — worse, PIIDetector.redact()'s reversed-replacement loop assumes matches don't share a span, and two same-span matches corrupt its output (confirmed today, rarely, when a bare 9-digit number happens to pass both the ssn and tfn checksums — see test_pii_type_parity.py). Adding ssn_no_dashes would have turned that from a rare coincidence into a routine occurrence on every unformatted SSN.
  • phone_generic, url_with_piiadded a real pattern. Both are reliable, keyword-gated heuristics in the same style already used elsewhere in this file (bank_account, mrn, patient_id): phone_generic matches a Phone:/Tel:/ Mobile:/Cell:-labeled number outside any region-specific format, validated against E.164 digit-count bounds (7–15 digits); url_with_pii matches a URL whose query string carries a PII-indicative parameter (email=, ssn=, token=, api_key=, password=, etc).

tests/test_pii_type_parity.py enforces, with no exceptions list, that every declared PIIType in both the basic and regional enums has a backing pattern — this class of bug (declared-but-unmatched type) can't reoccur silently for either detector.

Compliance Support

  • GDPR - EU data protection
  • HIPAA - Healthcare (18 PHI identifiers)
  • PCI-DSS - Payment card data
  • SOC 2 - Security controls
  • CCPA/CPRA - California privacy
  • FERPA - Education records
  • GLBA - Financial privacy
  • COPPA - Children's privacy

Receipts & Attestation

Every govern() call locally mints a receipt, entirely on-device. This happens every time, regardless of network access, and doesn't depend on whether a server was ever reached:

result = tork.govern("Sensitive data here")

receipt = result.receipt
print(receipt.receipt_id)    # Locally-generated identifier
print(receipt.timestamp)     # ISO 8601 timestamp
print(receipt.input_hash)    # SHA-256 of input
print(receipt.output_hash)   # SHA-256 of output
print(receipt.policy_version)  # Applied policy version

If you supply an api_key (via Tork(api_key=...) or TorkConfig), govern() additionally attempts to report the decision to tork.network as a separate server attestation. This is optional, asynchronous, and best-effort:

  • It runs on a background thread — govern() never blocks on it.
  • The network call (and its one retry) can fail; nothing about the local decision above is affected either way.
  • Check result.report.attempted and .succeeded before treating a decision as anchored on the server — don't assume success just because reporting was attempted.
  • On success, result.report.receipt_id is the server's receipt ID, a different value from the local receipt.receipt_id above.
report = result.report
print(report.attempted)   # Whether reporting was attempted (api_key configured)
print(report.succeeded)   # Whether the server actually persisted the attestation
print(report.receipt_id)  # Server-side receipt ID, only set once succeeded
print(report.reason)      # Why it hasn't succeeded (or its current status)

# Block until the background attempt settles, if you need the confirmed
# outcome before proceeding — most callers don't need this.
report.wait(timeout=5)

Scanning tool results

A tool result returned by an MCP server — or any external system you do not control — is untrusted input that is about to be appended to a model's context. Tork.scan_tool_result() scans it first, on-device, for PII and prompt injection:

from tork_governance import Tork

tork = Tork()
outcome = tork.scan_tool_result(
    "lookup_customer",
    tool_result,                       # whatever the server returned
    "mcp://crm.internal/customers",
    block_on_injection=True,
)

if outcome.blocked:
    print(outcome.reason)              # do not append anything
else:
    append_to_context(outcome.sanitized)  # PII masked in place

outcome.findings
# [ToolResultFinding(kind='pii', type='email', count=1, location='$.content[0].text'),
#  ToolResultFinding(kind='injection', type='heuristic:instruction_override', count=1, location='$.content[0].text')]

There is also a standalone scan_tool_result(tool_name, payload, server_uri=None, **options) function with the same signature (minus the receipt) that returns an object with sanitized, findings, blocked, and reason, and produces no receipt.

  • PII uses the same on-device detector as govern() — same patterns, same redaction labels. Matches are masked in place; the payload structure is otherwise unchanged, and a clean payload comes back untouched (same object identity, not just equal).
  • Injection detection is heuristic. A conservative pattern set (tork-injection-heuristics-v1) covering instruction-override phrases, role reassignment, and exfiltration URLs. Every injection finding is typed heuristic:<name> because that is exactly what it is: a regex match over untrusted text, with false positives and false negatives, not a verified determination. Without block_on_injection, matches are reported and the result is still returned; with it, sanitized is None so no masked copy can be appended by accident.
  • Zero network calls. The scan is pure and synchronous. The payload never leaves the machine, whether or not an api_key is configured.
  • Recorded on the receipt as counts only. receipt.tool_result_scan carries attested_by: 'client', capture_mode: 'edge', the tool name and server URI, counts by kind and type, the blocked flag, and the SDK version. It never carries the payload, a matched value, or a location path.

This is a client-side, client-attested control. The scan runs in your process, and the receipt says so: Tork did not execute it and cannot verify it ran at all — the same honest boundary as every other edge attestation this SDK produces. Gateway-side enforcement, where a caller cannot skip the scan, is a separate and later control. Do not read a tool_result_scan block as proof that every tool result reaching a model was scanned; read it as a record of the scans a caller chose to run and report.

Configuration

from tork_governance import Tork, TorkConfig

tork = Tork(
    config=TorkConfig(
        policy_version="1.0.0",
        default_action="redact",  # or "allow", "deny"
        custom_patterns={
            "employee_id": r"EMP-\d{6}"
        }
    )
)

Documentation

License

MIT License - see LICENSE for details.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

tork_governance-0.26.1.tar.gz (287.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

tork_governance-0.26.1-py3-none-any.whl (243.6 kB view details)

Uploaded Python 3

File details

Details for the file tork_governance-0.26.1.tar.gz.

File metadata

  • Download URL: tork_governance-0.26.1.tar.gz
  • Upload date:
  • Size: 287.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.1

File hashes

Hashes for tork_governance-0.26.1.tar.gz
Algorithm Hash digest
SHA256 5f10f15b6dabeb74cdbc683a98d301efa7a8ce885aadc7a74c455fb8bf5255d5
MD5 8fb3dd487b3de9dc0736397aa41e3048
BLAKE2b-256 46380ef99ac9e2436bc8b0f53b5a34014e5befff706b981fe6411b184d527210

See more details on using hashes here.

File details

Details for the file tork_governance-0.26.1-py3-none-any.whl.

File metadata

File hashes

Hashes for tork_governance-0.26.1-py3-none-any.whl
Algorithm Hash digest
SHA256 6443408db97639359db0ade2c8b2f25519b584109c6042d8710c24aeac3e216f
MD5 de90deba07ab2e051021d78670325f65
BLAKE2b-256 9896256d282fffeff2f80e028f2ae3232e631e4ac157ab96deaf7043e3a30043

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.26.1 This release

2 files

0.24.0

2 files

0.23.0

2 files

0.22.0

2 files

0.20.0

2 files

0.19.0

2 files

0.17.0

2 files

0.16.0

2 files

0.14.0

2 files

0.13.0

2 files

0.12.0

2 files

0.11.0

2 files

0.10.0

2 files

0.9.0

2 files

0.8.1

2 files

0.8.0

2 files

0.7.0

2 files

0.6.0

2 files

0.5.0

2 files

0.4.0

2 files

0.3.0

2 files

0.2.0

2 files

0.1.0

2 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