Skip to main content

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

Metadata

Release files for trusys 0.1.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for trusys 0.1.2
File Size Uploaded
trusys-0.1.2.tar.gz 71.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for trusys 0.1.2
File Interpreter ABI Platform
trusys-0.1.2-py3-none-any.whl Python 3 none any Details

Total release size: 145.6 kB

Release files / trusys-0.1.2.tar.gz

Download URL trusys-0.1.2.tar.gz
Size 71.6 kB
Tags Source
SHA-256 checksum
How to use checksums
b85b090267a8c95ecccb27ce236fbd5d154048ae36cf71780132a621cb150826
BLAKE2b-256 checksum
How to use checksums
5406cf7cf38d5b25e68ad4b930975eb699e64d0c9a19d222d77c2707b425d642
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.3

Release files / trusys-0.1.2-py3-none-any.whl

Download URL trusys-0.1.2-py3-none-any.whl
Size 74.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
5ee97721ab971ee008da37ec10611249462b3353612c58805fc753cb0c729491
BLAKE2b-256 checksum
How to use checksums
0faa15eac7506082c888c7c94f61d5ad3d76ee18df664e6bbced44b624414212
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.3

Release history Release notifications | RSS feed

This release

0.1.2 This release

2 release files

0.1.1

2 release files

0.1.0

2 release 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