Whiteout AI Governance SDK
Wrap AI API calls with Whiteout policy enforcement. Three lines of code to add governance to any Python AI application.
Install
pip install whiteout-ai
Custom AI Apps: AppGuard (0.2+)
For your own LLM applications registered under Integrations → Custom AI Apps. Authenticates with the app key from the setup wizard, with no registration step, and checks both the prompt and the model's reply.
pip install "whiteout-ai>=0.2"
export WHITEOUT_APP_KEY=wo_app_prod_...
export WHITEOUT_BASE_URL=https://api.whiteout.groovysec.com # the default
from openai import OpenAI
from whiteout_ai import AppGuard, WhiteoutBlockedError
guard = AppGuard()
client = guard.openai(OpenAI()) # or guard.anthropic(Anthropic())
try:
reply = client.chat.completions.create(
model="gpt-5", messages=messages,
whiteout={"end_user": user.id}, # optional; never sent to OpenAI
)
except WhiteoutBlockedError as e:
print(e.stage, e.reason, e.violated_policies) # stage: "input" or "output"
The wrapped client is the same object with chat.completions.create (or
messages.create) governed. Everything else passes straight through.
What gets scanned. By default this is the latest user message. Pass
scan=["user", "system", "context", "tool"] to the constructor, or per call via
whiteout={"scan": [...]}, to also catch sensitive data in system prompts,
retrieved documents (context=) and tool results.
Checking without a wrapper:
d = guard.check_input(messages, context=retrieved_docs, model="gpt-5", provider="openai")
reply = call_your_model(messages)
guard.check_output(d.evaluation_id, reply) # raises WhiteoutBlockedError on block
Streaming. stream=True works for both providers.
stream_mode |
Behaviour |
|---|---|
"buffered" (default) |
The whole response is held until the output check passes, so nothing flagged reaches the user. |
"passthrough" |
Chunks are yielded as they arrive, with a check every check_every characters (default 2000) plus a final check. It stops at the first flagged checkpoint. Text already shown cannot be retracted, so use buffered mode where you enforce. |
Fail behaviour. If Whiteout is unreachable, or the key is revoked (logged at
ERROR), the SDK applies your policy group's fail behaviour from
GET /v1/guard/config. That setting is cached for 5 minutes and revalidated with an ETag.
Pass fail_open=True/False to override it. With no config yet, the SDK fails open.
Async. AsyncAppGuard has the same surface (await guard.check_input(...),
guard.openai(AsyncOpenAI()), async for over streams). Use it as
async with AsyncAppGuard() as guard: so pending background checks drain on exit.
LangChain.
from whiteout_ai.langchain import WhiteoutCallbackHandler # pip install "whiteout-ai[langchain]"
llm = ChatOpenAI(callbacks=[WhiteoutCallbackHandler(AppGuard())])
A block raises out of the chain. Streaming chains are checked when the completion finishes.
Other options:
block_output=Falsemakes output checks fire-and-forget (observe the reply without blocking it).send_events([...])reports calls after the fact (observe-only, batched).timeoutsets the request timeout in seconds (default 10).
No code changes: auto-instrumentation (0.3+)
pip install "whiteout-ai[auto]"
export WHITEOUT_APP_KEY=wo_app_prod_...
whiteout-ai run python app.py # or: whiteout-ai run -- gunicorn app:server
whiteout-ai check # key set? which clients will be governed?
In a container where you can't change the start command, put the bootstrap on the path instead:
PYTHONPATH="$(whiteout-ai bootstrap-path)". It runs any sitecustomize you already have.
What gets governed:
openai: chat completions and the Responses API, sync and async.anthropic:messages.create, sync and async.messages.stream()is checked on input, and its final text is recorded.- boto3
bedrock-runtime: Converse and InvokeModel (input and output) and the streaming variants (input). This runs through botocore's event system.
A library is patched when your app imports it, so there's no startup cost for clients you don't use.
Environment variables:
| Variable | Values |
|---|---|
WHITEOUT_MODE |
enforce (default) or observe. Observe checks and records but never raises. |
WHITEOUT_STREAM_MODE |
Stream mode for governed calls |
WHITEOUT_SCAN |
Which parts of the call to scan |
WHITEOUT_INCLUDE / WHITEOUT_EXCLUDE |
openai, anthropic, bedrock |
WHITEOUT_DISABLE=1 |
Turns it off completely |
Limits: raw HTTP calls to a model API aren't seen. If a declared model host is called without Guard events, the AI Footprint still flags it.
Prompt injection: quarantine (0.3+)
When your org has Prompt Injection Defense on, a tool result or system prompt carrying instructions can be quarantined. Wrapped clients, and auto-instrumentation, replace that turn with a short notice before the model sees it. Tool calls stay paired, and your own objects are never changed.
Context documents you send as context= can't be rewritten inside your prompt, so drop them yourself:
d = guard.check_input(messages, context=docs, scan=["user", "context"])
docs = d.clean_context(docs) # the documents Whiteout didn't quarantine
Replies are checked for injected instructions too. If your org blocks such content, check_output blocks.
The employee's own policies (0.3+)
If the app is set to the employee's own policies in the admin console, pass the signed-in employee's OIDC id_token. Whiteout then applies their group's policies, just as it does in ChatGPT:
guard.check_input(messages, user_token=session["id_token"])
client.chat.completions.create(model=..., messages=..., whiteout={"user_token": session["id_token"]})
Infrastructure workloads: WhiteoutGuard
WhiteoutGuard is unchanged. It uses an enrollment token and the /infra-agent routes,
and suits workloads enrolled as infrastructure resources.
Quick Start
from whiteout_ai import WhiteoutGuard
guard = WhiteoutGuard(
token="whiteout_enroll_...",
backend_url="https://your-org.api.whiteout.groovysec.com",
)
# Option 1: Evaluate a prompt directly
result = guard.evaluate(
prompt="Summarize this patient record...",
ai_provider="openai",
model="gpt-4o",
)
# result = {"decision": "block", "reason": "Contains PHI", ...}
# Option 2: Wrap an OpenAI call
import openai
response = guard.wrap(
openai.chat.completions.create,
model="gpt-4o",
messages=[{"role": "user", "content": "Hello world"}],
)
# Option 3: Catch blocked prompts
from whiteout_ai import WhiteoutBlockedError
try:
guard.evaluate(prompt="SSN 123-45-6789")
except WhiteoutBlockedError as e:
print(f"Blocked: {e.reason}")
print(f"Policies: {e.violated_policies}")
Configuration
| Parameter | Required | Default | Description |
|---|---|---|---|
token |
Yes | - | Enrollment token from Whiteout admin |
backend_url |
Yes | - | Your org's Whiteout API URL |
fail_open |
No | True |
Allow calls when backend unreachable |
timeout |
No | 10.0 |
Backend call timeout (seconds) |
mode |
No | sdk |
Deployment mode identifier |
Features
- Automatic provider detection (OpenAI, Anthropic, Google, Mistral)
- Fast checks cached locally (provider block, model allowlist)
- Remote compliance evaluation for content policies
- Output governance (response scanning in background)
- Fail-open by default (never breaks your app)
- Thread-safe
Metadata
Release files for whiteout-ai 0.3.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| whiteout_ai-0.3.1.tar.gz | 8.6 MB | With provenance | Details for whiteout_ai-0.3.1.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| whiteout_ai-0.3.1-py3-none-any.whl | Python 3 | none | any | Details for whiteout_ai-0.3.1-py3-none-any.whl |
Total release size: 8.7 MB
Release files / whiteout_ai-0.3.1.tar.gz
| Download URL | whiteout_ai-0.3.1.tar.gz |
|---|---|
| Size | 8.6 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
199b6d73451c554ea436f14bc034f119ada7907925febcab06c4198e191c0c01
|
|
BLAKE2b-256 checksum How to use checksums |
99adc80f9fc3a3f8d6bcab1bedc669368009499e769b7161473c8cdcaa77e167
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 28, 2026.
Transparency logRelease files / whiteout_ai-0.3.1-py3-none-any.whl
| Download URL | whiteout_ai-0.3.1-py3-none-any.whl |
|---|---|
| Size | 38.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
038255e403f7a3eb6eadd14addd51811e7e2a4e4af79859c60d8a83bde9ff8f6
|
|
BLAKE2b-256 checksum How to use checksums |
88c1375c0ac5242902d2a787e16be39445effa9e6340799ed1335d9083ba51c2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 28, 2026.
Transparency logSecurity for whiteout-ai 0.3.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for whiteout_ai-0.3.1.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 28, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.