Skip to main content

A modular Python library for AI guardrails with input/output scanning capabilities

Project description

TruGuard

A Python library for AI guardrails. Configure your guardrails in the Trusys portal; in your application you run truguard init (or set credentials), call TruGuard.init(), then use the built-in input and output scanners. No manual scanner configuration in code — everything is managed from console.trusys.ai.

Features

  • Portal-driven configuration: Define input and output guardrails in the Trusys Console; your app receives config automatically.
  • Static input and output guards: Use TruGuard.input_guard and TruGuard.output_guard to scan prompts and model responses.
  • No code-level scanner setup: Scanners (regex, blocklist, PII, content safety, etc.) are configured in the portal, not in your codebase.
  • Parallel execution: Scanners run concurrently for better performance.
  • Flexible actions: Fix, mask, filter, fail, or ignore violations based on portal settings.
  • Async support: Full async/await for I/O-bound scanning.

Installation

pip install trusys

Optional Dependencies

For PII (Personally Identifiable Information) detection when enabled in the portal:

pip install trusys[pii]
python -m spacy download en_core_web_lg

Quick Start

1. Configure guardrails in the Trusys portal

  1. Go to https://console.trusys.ai and sign in.
  2. Create or select an application.
  3. Configure input and output guardrails (e.g. blocklists, PII, content safety, prompt injection).
  4. Copy your Application ID and API key for the next step.

2. Initialize TruGuard in your project

Configure your Application ID and API key by setting these environment variables:

  • TRUSYS_APPLICATION_ID – from the Trusys portal
  • TRUSYS_API_KEY – from the Trusys portal

3. Use the input and output guards in code

Call TruGuard.init() once at application startup (e.g. in main or when your app loads). Then use the static input and output guards to scan content.

from trusys import TruGuard

# One-time init at startup (uses TRUSYS_APPLICATION_ID and TRUSYS_API_KEY)
TruGuard.init()

# Scan user input (e.g. before sending to the LLM)
input_result = TruGuard.input_guard.scan(content={"prompt": "Hello world!"})
if not input_result.passed:
    # Handle violations (e.g. block request or apply fixes)
    for v in input_result.all_violations:
        print(f"Input violation: {v.message}")
    raise ValueError("Input failed guardrails")

# ... call your LLM ...

# Scan model output (e.g. before returning to the user)
output_result = TruGuard.output_guard.scan(
    content={"prompt": "user prompt", "response": "model response"}
)
if not output_result.passed:
    for v in output_result.all_violations:
        print(f"Output violation: {v.message}")
    raise ValueError("Output failed guardrails")

# Use output_result.final_content for the (possibly fixed) response if needed

Async usage

import asyncio
from trusys import TruGuard

TruGuard.init()

async def main():
    input_result = await TruGuard.input_guard.scan_async(content={"prompt": "Hello!"})
    print(f"Input passed: {input_result.passed}")

    output_result = await TruGuard.output_guard.scan_async(
        content={"prompt": "Hi", "response": "Hi there!"}
    )
    print(f"Output passed: {output_result.passed}")

asyncio.run(main())

Init options

You can pass credentials and options explicitly instead of (or in addition to) environment variables:

TruGuard.init(
    application_id="your-application-id",
    api_key="your-api-key",
    application_version="1.0.0",   # optional
    environment="production",      # optional: dev, staging, prod
    metadata={"service": "chat"},  # optional: attached to all result uploads
    batch_interval=60.0,           # seconds between result uploads (default 60)
    batch_count=100,               # max results per batch (default 100)
    debug_print=False,            # set True only for debugging (adds latency)
)

Guardrail configuration is fetched from the Trusys API at init and refreshed periodically in the background. No manual scanner configuration is required in your code.

Metadata (init + per-scan)

You can attach metadata at init (app-wide) and per scan (e.g. conversation_id, session_id). Scan-level metadata is merged with init metadata; duplicate keys are overridden by the scan value. The merged metadata is included in result uploads to the backend.

# Init with app-level metadata
TruGuard.init(
    application_id="...",
    api_key="...",
    metadata={"environment": "prod", "service": "chat"},
)

# Per-scan metadata: merged with init metadata for this scan
input_result = TruGuard.input_guard.scan(
    content={"prompt": "Hello"},
    metadata={"conversation_id": "conv-123", "session_id": "sess-456"},
)
# Uploaded result includes: environment, service, conversation_id, session_id

# Same for async
output_result = await TruGuard.output_guard.scan_async(
    content={"prompt": "Hi", "response": "Hi there!"},
    metadata={"conversation_id": "conv-123"},
)

Action types

When a scanner finds a violation, the action is determined by your portal configuration. Supported actions:

Action Behavior
fix Apply the scanner’s suggested fix (e.g. mask PII with entity labels).
mask Replace detected content with ****.
encrypt Replace with format-preserving encryption (FPE).
filter Remove or replace problematic content.
fail Raise ScanFailedError (scan fails).
ignore Log and allow content through unchanged.

Format-preserving encryption (FPE) uses the FF1/FFX algorithm. Set the TRUSYS_FPE_KEY environment variable if you need a custom encryption key. Decrypt with:

from trusys.actions.builtin import decrypt_text

original = decrypt_text(encrypted_text, entity_type="PHONE_NUMBER")

Result inspection

result = TruGuard.input_guard.scan(content={"prompt": "test"})

print(result.passed)
print(result.total_execution_time_ms)

for scan_result in result.results:
    print(f"{scan_result.scanner_name}: {'PASS' if scan_result.passed else 'FAIL'}")
    for v in scan_result.violations:
        print(f"  - [{v.severity.value}] {v.message}")

all_violations = result.all_violations
failed_scanners = result.failed_scanners

if result.final_content:
    print("Modified content:", result.final_content)

Error handling

When the action is fail

If a scanner is configured with on_fail="fail" in the portal and that scanner finds a violation, the library raises ScanFailedError instead of returning an AggregatedResult. Your code can catch this exception to handle the failure (e.g. block the request, return an error to the user, or log and retry).

Exception attributes:

Attribute Description
scanner_name Name of the scanner that failed.
violations List of Violation objects (rule, severity, message, metadata such as matched_text).
message Human-readable summary (e.g. "Scan failed with N violation(s)").
aggregated_result Full AggregatedResult for the run (all scanner results, timing). Set by the library when re-raising; useful if you need full details when handling the error.

Result is always saved. Before re-raising, the library queues the failed result and flushes it to the Trusys backend. So the failure is recorded even if your application does not catch the exception and exits — you do not need to catch the exception solely to “save” the result.

Sync example:

from trusys.exceptions import ScanFailedError

try:
    result = TruGuard.input_guard.scan(content={"prompt": "user input"})
    # Use result as needed (result.passed, result.final_content, etc.)
except ScanFailedError as e:
    print(f"Guardrail failed: {e.scanner_name}")
    for v in e.violations:
        print(f"  - {v.message}")
    # Optional: use full result (e.g. for logging or custom reporting)
    if e.aggregated_result:
        print(f"Failed scanners: {e.aggregated_result.failed_scanners}")
    raise  # or return an error response, etc.

Async example:

from trusys.exceptions import ScanFailedError

try:
    result = await TruGuard.input_guard.scan_async(content={"prompt": "user input"})
except ScanFailedError as e:
    print(f"Guardrail failed: {e.scanner_name}, violations: {len(e.violations)}")
    raise

Other errors

from trusys.exceptions import ScanFailedError, ScannerTimeoutError

try:
    result = TruGuard.input_guard.scan(content={"prompt": "content"})
except ScanFailedError as e:
    print(f"Scan failed: {e.scanner_name}")
    print(f"Violations: {e.violations}")
except ScannerTimeoutError as e:
    print(f"Scanner {e.scanner_name} timed out after {e.timeout}s")

Environment variables

Variable Description
TRUSYS_APPLICATION_ID Application ID from console.trusys.ai (required for init).
TRUSYS_API_KEY API key from the Trusys portal (required for init).
TRUSYS_APPLICATION_VERSION Optional application version.
TRUSYS_ENVIRONMENT Optional environment (e.g. dev, staging, prod).
TRUSYS_BATCH_INTERVAL Seconds between batch uploads (default 60).
TRUSYS_BATCH_COUNT Max results per batch (default 100).
TRUSYS_DEBUG_PRINT Set to true for debug logging (adds latency).
TRUSYS_FPE_KEY Optional key for format-preserving encryption.
TRUSYS_API_HOST Backend API host (default https://backend.trusys.ai).
TRUSYS_GUARDRAILS_HOST Guardrails API host (default https://guard-api.trusys.ai).

Examples

  • Guardrail flow: examples/guardrail_flow_example.py – init, then one input scan and one output scan.

Run it (with TRUSYS_APPLICATION_ID and TRUSYS_API_KEY set):

python examples/guardrail_flow_example.py

Development

Install dev dependencies

pip install -e ".[dev]"

Run tests

pytest

Run tests with coverage

pytest --cov=trusys --cov-report=html

Type checking

mypy trusys

Linting

ruff check trusys

License

MIT License

Project details


Download files

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

Source Distribution

trusys-0.1.1.tar.gz (67.5 kB view details)

Uploaded Source

Built Distribution

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

trusys-0.1.1-py3-none-any.whl (65.4 kB view details)

Uploaded Python 3

File details

Details for the file trusys-0.1.1.tar.gz.

File metadata

  • Download URL: trusys-0.1.1.tar.gz
  • Upload date:
  • Size: 67.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.9

File hashes

Hashes for trusys-0.1.1.tar.gz
Algorithm Hash digest
SHA256 70bf0407054f32ca2d7c3e3f504d576f261e197878f227bd710058ac1279073e
MD5 1afcb92bf8cf36c65805621c0b6c77bc
BLAKE2b-256 9158ff02b0c796980818c5bc56183d5387464f04821bb58f3f18c62f867e8a96

See more details on using hashes here.

File details

Details for the file trusys-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: trusys-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 65.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.9

File hashes

Hashes for trusys-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 f93e701a03fdf3efbc93d38ef6bbcfdc3b2f1780fb36ea80d8ab0217585ecf1a
MD5 85adf827003ec3d9878d085a354d08e6
BLAKE2b-256 4d93aa4f0c88fff36881ad7ce313d959f2c4383de31e3089fb80afea7adfdcbf

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page