Developer quickstart

Add Warden before an action

Scan untrusted output immediately before a model, tool, wallet, or outbound request uses it. Handle ALLOW, SANITIZE, and BLOCK explicitly.

Recommended: local Python guard

  1. 0–1 minPlace the boundary

    Identify the untrusted text immediately before a model, tool, wallet, or outbound request consumes it.

  2. 1–2 minInstall from source

    Use the repository packages below; no PyPI or npm publication is claimed.

  3. 2–4 minGate all three decisions

    ALLOW uses the original under caller policy, SANITIZE uses only the returned transformed text after review, and BLOCK stops the action.

  4. 4–5 minProve failure behavior

    Exercise BLOCK plus a timeout before shipping; enforcement should fail closed.

Install the Python service and SDK from this repository. The package currently named warden-guard on PyPI is unrelated, so Warden does not publish a PyPI install command here.

python -m pip install -e . -e sdk/python

Python local enforcement — recommended

Local mode runs WardenEngine in the caller's process. It has no network dependency or hosted quota, fails closed, returns sanitized text for SANITIZE, and raises WardenBlocked for BLOCK.

from warden_guard import WardenClient

safe = WardenClient(local=True, fail_open=False).guard(untrusted_text)
Hosted Python and TypeScript SDK modes

Python hosted free default

WardenClient() calls /api/demo/scan with fail_open=True. That route is best-effort telemetry, not enforcement: the current default quota is 20 requests per minute per IP, depth is forced to fast, payloads are truncated to 4,000 characters, and hosted latency includes network round-trip time.

warden = WardenClient()  # hosted free default; fail_open=True
result = warden.scan(untrusted_text)

TypeScript hosted client from source

The @warden/guard package under sdk/ts is source-built; Warden does not claim it is published to npm. Install the locked development dependencies, run its tests, and compile it from the repository with Node 20.19+ (the built zero-dependency runtime itself declares Node 18+):

cd sdk/ts
npm ci
npm test
npm run build
import { WardenClient } from "@warden/guard";

const warden = new WardenClient(); // hosted free default; failOpen: true
const result = await warden.scan(untrustedText);

This client has no local TypeScript scanner engine. Its default free hosted path is best-effort: network, timeout, and HTTP failures become an ALLOW result when failOpen: true. Setting failOpen: false makes those hosted failures throw; it does not move detection in-process.

Five-minute acceptance check: a known attack must raise WardenBlocked locally, a SANITIZE result must replace the original text, and a simulated hosted failure must never reach an action when fail_open=False or failOpen: false.

  1. 01Receive

    Keep the source payload inert.

  2. 02Scan

    Send it to the selected Warden surface.

  3. 03Decide

    Handle the typed scan decision or audit report explicitly.

  4. 04Act

    Use the permitted payload or review the audit findings.

Normalized marketplace catalog

Choose the service used by every hosted example

UNKNOWN Service catalog not requested.

Service
Catalog not available
Service ID
Not established
Price
Not established
Network
Not established
Endpoint
Not established

Implementation surfaces

Use one boundary, not five competing flows

Arrow keys move between tabs. The selected hosted examples update from the committed catalog; local MCP remains intentionally separate from the paid service.

OnchainOS / agent operator

Delegate a reviewable marketplace task

The operator still reviews task creation, the x402 spend, the returned result, completion, and any feedback.

Catalog-backed prompt not available.

No integration example copied.

Framework adapters

Put the same local guard inside your framework.

These Python adapters are source-installed optional extras. Each example uses local, fail-closed enforcement before untrusted text reaches the next component.

LangChainRetrieval to prompt

Insert the runnable between retrieval and the prompt. BLOCK raises WardenBlocked; SANITIZE forwards only the returned transformed text. Caller policy still decides whether to continue.

from warden_guard import WardenClient
from warden_guard.langchain_guard import WardenGuardRunnable

guard = WardenGuardRunnable(WardenClient(local=True, fail_open=False))
chain = retriever | guard | prompt | model
LlamaIndexNode postprocessor

The node postprocessor drops BLOCKed nodes and replaces SANITIZEd LLM-visible content while excluding the original metadata.

from warden_guard import WardenClient
from warden_guard.llamaindex_guard import WardenNodePostprocessor

guard = WardenNodePostprocessor(WardenClient(local=True, fail_open=False))
engine = index.as_query_engine(node_postprocessors=[guard])
FastAPI / ASGIRequest middleware

The middleware short-circuits BLOCK with HTTP 400. Its default extractor replays a sanitized body; a custom extractor blocks SANITIZE because it cannot safely rewrite the original body.

from fastapi import FastAPI
from warden_guard import WardenClient, WardenGuard

app = FastAPI()
app.add_middleware(
    WardenGuard,
    client=WardenClient(local=True, fail_open=False),
)
Framework-neutral TextGuardSingle-input guard

TextGuard and AsyncTextGuard expose the same strict one-input boundary without a framework dependency.

from warden_guard import TextGuard, WardenClient

guard = TextGuard(WardenClient(local=True, fail_open=False))
safe_text = guard(untrusted_text)
Production failure, retry, privacy, and wallet policy

Decide failure, retry, privacy, and wallet policy before launch.

Failure mode
Fail open vs. fail closed

The free hosted SDK defaults to fail open and uses a timeout of 8 seconds, so transport failures become ALLOW. That mode is telemetry, not enforcement. Use local fail_open=False or hosted failOpen: false when failure must stop the action.

Request lifecycle
Timeouts and retries

The direct paid examples use 30 seconds. Bound any retry before the downstream action. Do not automatically retry a paid replay; first determine settlement state, fetch fresh 402 terms, and validate endpoint, network, asset, amount, and recipient again.

Data boundary
Privacy, secrets, and wallet boundary

Send only payloads and audit targets you are authorized to process. Keep secrets out of request bodies and logs. A wallet layer constructs and signs payment; server or agent code receives only PAYMENT-SIGNATURE. Never ship it in browser code.

Only one payload reaches the action

ALLOW

Use the original payload. No implemented detector fired; this is not proof of safety.

SANITIZE

Require a string sanitized_payload and use that value instead of the original.

BLOCK

Stop the action and surface the recommendation for operator review.