Composable guardrails for OpenAI-compatible clients and native PyTorch generation.
OpenWarden wraps clients and models you already use. It intercepts supported generation calls, evaluates their input and output, and either returns the original response object or raises an explicit guard exception.
pip install openwarden
Quick Start
from openai import OpenAI
from openwarden import GuardMode, GuardedOpenAI, WardenConfig
from openwarden.guards.regex import RegexSecretGuard
client = GuardedOpenAI(
OpenAI(),
guard=RegexSecretGuard(),
config=WardenConfig(
mode=GuardMode.BOTH,
fail_open=False,
),
)
response = client.responses.create(
model="your-generation-model",
instructions="You are concise and helpful.",
input="Explain Python decorators with a simple example.",
)
print(response.output_text)
Allowed calls return the original OpenAI SDK object. Blocked calls raise
GuardViolation.
Supported Surfaces
- Synchronous
OpenAIand asynchronousAsyncOpenAIclients. responses.create(...)andchat.completions.create(...).- Native PyTorch or Transformers
model.generate(...). - Input-only, output-only, both, and disabled modes.
- Block, redact, rewrite, annotate, and log-only enforcement actions.
- Deterministic guards, guard pipelines, and prompted guard models.
- Per-call overrides and context-managed overrides.
- RAG retrieval, context injection, and grounding extension points.
- Trace IDs, decisions, latencies, and optional
GuardedResultmetadata. - Fail-open and fail-closed operation.
Unsupported SDK resources pass through to the wrapped client unchanged.
Guard Models
ModelPromptGuard can call a dedicated policy model through any compatible
OpenAI endpoint:
import os
from openai import OpenAI
from openwarden import GuardMode, GuardedOpenAI, WardenConfig
from openwarden.guards.base import ModelPromptGuard
raw_client = OpenAI()
guard = ModelPromptGuard(
raw_client,
model=os.environ["GUARD_MODEL"],
api="chat_completions",
require_json=True,
)
client = GuardedOpenAI(
raw_client,
guard=guard,
config=WardenConfig(mode=GuardMode.BOTH, fail_open=False),
)
Provider-specific generation parameters can be passed through
create_kwargs.
Direct PyTorch Generation
OpenWarden does not import or pin PyTorch or Transformers. It composes around compatible objects from the versions selected by your application:
from transformers import AutoModelForCausalLM, AutoTokenizer
from openwarden import GuardMode, GuardedPyTorch, WardenConfig
from openwarden.guards.regex import RegexSecretGuard
model_id = "your-org/your-generation-model"
tokenizer = AutoTokenizer.from_pretrained(model_id)
raw_model = AutoModelForCausalLM.from_pretrained(model_id, device_map="auto")
model = GuardedPyTorch(
raw_model,
tokenizer=tokenizer,
guard=RegexSecretGuard(),
config=WardenConfig(mode=GuardMode.BOTH, fail_open=False),
)
inputs = tokenizer("Explain decorators.", return_tensors="pt").to(raw_model.device)
output = model.generate(**inputs, max_new_tokens=200)
Allowed calls return the original tensor or Transformers generation object.
PyTorchPromptGuard can run a separate policy model locally.
Guard Decisions
Custom guards subclass BaseGuard and return structured decisions:
from openwarden import BaseGuard, GuardDecision
class CompanyPolicyGuard(BaseGuard):
def check_input(self, context):
if "confidential" in context.request.text().lower():
return GuardDecision.block(
"Confidential content cannot leave this boundary",
categories=("data_policy",),
)
return GuardDecision.allow()
Configuration
from openwarden import GuardAction, GuardMode, WardenConfig
config = WardenConfig(
mode=GuardMode.BOTH,
input_action=GuardAction.BLOCK,
output_action=GuardAction.BLOCK,
fail_open=False,
timeout_seconds=10,
)
Streaming is conservative by default. When output guarding is enabled,
stream=True raises UnsupportedStreamingModeError rather than exposing
tokens before the complete response can be evaluated.
Documentation
Security
OpenWarden is an application-layer policy boundary. It does not replace
authorization, provider safety systems, deterministic access controls, or
secure secret storage. Keep retrieval authorization in the data layer and use
fail_open=False where enforcement is required.
Please report vulnerabilities according to the security policy. Do not open public issues containing credentials, private prompts, customer data, or model output.
Development
python -m pip install -e ".[dev]"
ruff check openwarden tests examples scripts
python -m pytest -q
python -m build
python -m twine check dist/*
See the contribution guide before submitting changes.
License
OpenWarden is available under the MIT License.
Release files for openwarden 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| openwarden-0.1.0.tar.gz | 207.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| openwarden-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 239.3 kB
Release files / openwarden-0.1.0.tar.gz
| Download URL | openwarden-0.1.0.tar.gz |
|---|---|
| Size | 207.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
0d79b6d42511778b7b93756ec90ad46bd1b931221a7f9b6bd77b23f0666f92bb
|
|
BLAKE2b-256 checksum How to use checksums |
4975306889f9b6a29ae642f2294ba3f9af06842647facbf8c42f83f1ff997823
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.5
|
Release files / openwarden-0.1.0-py3-none-any.whl
| Download URL | openwarden-0.1.0-py3-none-any.whl |
|---|---|
| Size | 32.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
d6279ed2c86551f4c07714866735570af27594bf6d00602de4a1b7e1c2214814
|
|
BLAKE2b-256 checksum How to use checksums |
05a534bdf1ab49ad3cb9165c3a997c1ff439d1bee94d45a948a00b003e9af12b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.5
|