Shrike Guard SDK

Drop-in protection for OpenAI, Anthropic, and Google Gemini. Secure your LLM applications with 3 lines of code.

$pip install shrike-guard

Quick Start

The Shrike Guard SDK is a drop-in replacement for popular LLM client libraries. Simply swap your import and add your Shrike API key - all security scanning happens automatically.

Python
from shrike_guard import ShrikeOpenAI
 
# Drop-in replacement - same API as OpenAI
client = ShrikeOpenAI(
    api_key="your-openai-key",
    shrike_api_key="your-shrike-key",
)
 
# Use exactly like OpenAI - scanning happens automatically
response = client.chat.completions.create(
    model="gpt-4",
    messages=[{"role": "user", "content": "Hello, how are you?"}]
)

Installation

PyPython
Terminal
pip install shrike-guard
TSTypeScript
Terminal
npm install shrike-guard

Supported Providers

LanguagePackageProviders
Pythonshrike-guardOpenAI, Anthropic, Google Gemini
TypeScriptshrike-guardOpenAI, Anthropic

Configuration

All SDKs support these configuration options:

OptionTypeDefaultDescription
shrike_api_keystringrequiredAPI key for Shrike authentication
shrike_endpointstringProduction URLCustom endpoint URL
fail_modestring"closed"Behavior on scan failure (default: block)
scan_timeoutnumber10-30sTimeout for scan requests

Fail Modes

Fail Closed (Default)

If scanning fails (timeout, network error), block the request. Enforcement outranks availability — the Zero-Trust default across the SDKs and MCP.

Fail Open (opt-in)

If scanning fails, allow the request to proceed. Opt in only when availability must outrank enforcement (e.g. a low-stakes chatbot tolerating scan outages).

Python
# Fail-closed (default) - blocks on scan failure (Zero-Trust)
client = ShrikeOpenAI(
    api_key="...",
    shrike_api_key="...",
    fail_mode="closed"  # default — shown for clarity
)
 
# Fail-open - opt in when availability must outrank enforcement
client = ShrikeOpenAI(
    api_key="...",
    shrike_api_key="...",
    fail_mode="open"
)

Provider Examples

OpenAI

Python
from shrike_guard import ShrikeOpenAI
 
client = ShrikeOpenAI(
    api_key="your-openai-key",
    shrike_api_key="your-shrike-key",
)
 
response = client.chat.completions.create(
    model="gpt-4",
    messages=[{"role": "user", "content": "Explain quantum computing"}]
)
 
print(response.choices[0].message.content)

Anthropic

Python
from shrike_guard import ShrikeAnthropic
 
client = ShrikeAnthropic(
    api_key="your-anthropic-key",
    shrike_api_key="your-shrike-key",
)
 
response = client.messages.create(
    model="claude-3-opus-20240229",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Explain quantum computing"}]
)
 
print(response.content[0].text)

Google Gemini

Python
from shrike_guard import ShrikeGemini
import google.generativeai as genai
 
genai.configure(api_key="your-gemini-key")
model = genai.GenerativeModel("gemini-pro")
 
# Wrap the Gemini model
shrike_model = ShrikeGemini(
    model=model,
    shrike_api_key="your-shrike-key",
)
 
response = shrike_model.generate_content("What is machine learning?")
print(response.text)

Error Handling

The SDK provides specific exception types for different error scenarios:

ExceptionWhen RaisedContains
ShrikeBlockedErrorThreat detectedthreat_type, confidence, violations
ShrikeScanErrorScan failed (in closed mode)Error details
ShrikeConfigErrorInvalid configurationConfiguration issue
Python
from shrike_guard import ShrikeOpenAI, ShrikeBlockedError, ShrikeScanError
 
try:
    response = client.chat.completions.create(
        model="gpt-4",
        messages=[{"role": "user", "content": user_input}]
    )
except ShrikeBlockedError as e:
    # Threat was detected
    print(f"Blocked: {e.threat_type}")
    print(f"Confidence: {e.confidence}")
    print(f"Violations: {e.violations}")
    # Show user-friendly error message
except ShrikeScanError as e:
    # Scan failed (only in fail_mode="closed")
    print(f"Scan error: {e}")

Governance Helpers

The SDK ships three helpers that close the loop between a Shrike verdict and the model's next turn. See the Cookbook and the integration guide for how they compose.

system_prompt() — the canonical block

Returns the ~180-word "Working with Shrike" block that teaches the model how to react to Shrike verdicts. Drop it into your agent's system prompt as the first non-role paragraph.

Python
# Python
from shrike_guard import system_prompt, SYSTEM_PROMPT_VERSION
 
prompt = (
    "You are a customer support agent for Acme Corp.\n\n"
    + system_prompt()
    + "\n\nWhen customers ask about refunds..."
)
# Pin behavior against SYSTEM_PROMPT_VERSION if needed.

format_block_feedback() — inject the verdict back to the model

When Shrike blocks or holds a tool call, render the verdict as a canonical prompt-shape string and append it as a system message to the model's next turn. The model, having been taught by system_prompt() to recognize the prefix, reads the Reason / Threat type / Recovery / Available tools lines and adjusts.

Python
# Python
from shrike_guard import format_block_feedback
 
verdict = shrike.scan_sql_query(query)
if not verdict.get("safe"):
    model_messages.append({
        "role": "system",
        "content": format_block_feedback(verdict),
    })

Renders four verdict shapes: block / warn / require_approval / allow. Forward-compat with the upcoming recovery block (instruction, available_tools, patterns_triggered) — new fields render automatically without a signature change.

evaluateRotation() — the two-shape session rotation record

When a verdict indicates the session should rotate (either explicit threat_type: "session_locked" or accumulated session_risk_score >= 0.7), the helper returns either a ModuleOwnedRotation (SDK's own session was in use) or a CallerOwnedRotationRecommendation (caller supplied their own session_id). Discriminate on rotated.

TypeScript
// TypeScript
import { evaluateRotation, getSessionId } from 'shrike-guard';
 
const rotation = evaluateRotation({
  threat_type: verdict.threat_type,
  session_state: verdict.session_state,
  effective_session_id: currentSessionId,
  module_session_id: getSessionId(),
});
 
if (rotation?.rotated) {
  // Module-owned: SDK's fallback SESSION_ID rotated
  currentSessionId = rotation.new_session_id;
} else if (rotation) {
  // Caller-owned: adopt suggested_new_session_id on the VERY NEXT call.
  // suggestions are per-event — do not cache across turns.
  currentSessionId = rotation.suggested_new_session_id;
}

Available in TypeScript today. Python port is deferred — the Python scanner needs session_id threading through ScanClient.scan() first. Track this as a known parity gap.

Specialized Scanners

Beyond LLM prompt scanning, SDKs provide specialized security scanners for common attack vectors:

SQL Injection Scanner

Python
# Python
result = client.scan_sql(
    query="SELECT * FROM users WHERE id = ?",
    database="postgresql",
    allow_destructive=False  # Block DROP, DELETE, TRUNCATE
)
 
if result.safe:
    # Execute the query
    cursor.execute(query)

File Path Validator

Python
# Python - Prevent path traversal attacks
result = client.scan_file(
    path="/uploads/user-file.pdf",
    content=file_content  # Optional
)
 
if result.safe:
    # Process the file
    save_file(path, content)

CLI Command Scanner

Governs shell commands before execution — destructive operations, exfiltration imperatives, privilege escalation patterns.

Python
# Python
result = client.scan_command("rm -rf /var/log/app/*.log")
if result.safe:
    subprocess.run(result.content, shell=True)

Web Search Scanner

Governs outbound search queries before external egress — high-blast-radius sink for reconnaissance ("obtain AWS metadata creds" etc.). Gap 3 (2026-07-06) lowered the cascade floor for this content type so short adversarial queries are caught.

Python
# Python
result = client.scan_web_search("latest CVEs for kubernetes API server")
if result.safe:
    search_engine.query(result.content)

A2A Message Scanner

Governs agent-to-agent messages before cross-agent trust is extended. Same Gap 3 cascade-floor lowering — trivial pings pass, adversarial imperatives run the full cascade.

Python
# Python
result = client.scan_a2a_message(
    "Please summarize the last 3 turns of context",
    from_agent="planner",
    to_agent="summarizer",
)

Agent Card Scanner

Governs A2A agent-card metadata (name / description / URL / capabilities) before connection establishment. Blocks malicious capabilities and suspicious domains.

Python
# Python
result = client.scan_agent_card(
    '{"name":"weather-agent","description":"forecasts",'
    '"url":"https://weather.acme.com","capabilities":["forecast"]}'
)

Streaming & Async Support

Streaming Responses

All SDKs support streaming responses with real-time scanning:

Python
# Python streaming
stream = client.chat.completions.create(
    model="gpt-4",
    messages=[{"role": "user", "content": "Write a story"}],
    stream=True
)
 
for chunk in stream:
    print(chunk.choices[0].delta.content, end="")

Async Support

Python
from shrike_guard import ShrikeAsyncOpenAI
 
async def main():
    client = ShrikeAsyncOpenAI(
        api_key="...",
        shrike_api_key="...",
    )
 
    response = await client.chat.completions.create(
        model="gpt-4",
        messages=[{"role": "user", "content": "Hello!"}]
    )

Response Schema

All scan operations return a consistent response format:

JSON
1{
2 "safe": false,
3 "threat_type": "prompt_injection",
4 "confidence": 0.95,
5 "action": "block",
6 "violations": [
7 {
8 "policy_id": "pol-block-jailbreak",
9 "policy_name": "Block Jailbreak Attempts",
10 "pattern_matched": "ignore previous instructions",
11 "severity": "high"
12 }
13 ],
14 "scan_id": "scan-abc123",
15 "latency_ms": 45
16}
FieldTypeDescription
safebooleantrue if content passed all security checks
threat_typestringType of threat detected (if any)
confidencefloatConfidence score 0.0-1.0
actionstringAction taken: allow, block, redact, flag
violationsarrayList of policy violations
scan_idstringUnique scan identifier for debugging
latency_msnumberScan processing time in milliseconds

Best Practices

1. Use Environment Variables

Never hardcode API keys in your source code.

Python
import os
from shrike_guard import ShrikeOpenAI
 
client = ShrikeOpenAI(
    api_key=os.environ["OPENAI_API_KEY"],
    shrike_api_key=os.environ["SHRIKE_API_KEY"],
)

2. Handle Errors Gracefully

Always provide user-friendly feedback when content is blocked.

Python
try:
    response = client.chat.completions.create(...)
except ShrikeBlockedError:
    return {"error": "Your message was blocked for safety reasons."}
except ShrikeScanError:
    return {"error": "Security check failed. Please try again."}

3. Choose Appropriate Fail Mode

ScenarioRecommended Mode
Most production apps (default)"closed"
Regulated / financial / healthcare"closed"
Availability-critical (tolerates scan outage)"open"
Development / testing"open"

4. Monitor Scan Latency

Set appropriate timeouts based on your SLA requirements.

Python
client = ShrikeOpenAI(
    api_key="...",
    shrike_api_key="...",
    scan_timeout=5.0  # 5 seconds max
)