Shrike Guard SDK
Drop-in protection for OpenAI, Anthropic, and Google Gemini. Secure your LLM applications with 3 lines of code.
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.
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
pip install shrike-guardnpm install shrike-guardSupported Providers
| Language | Package | Providers |
|---|---|---|
| Python | shrike-guard | OpenAI, Anthropic, Google Gemini |
| TypeScript | shrike-guard | OpenAI, Anthropic |
Configuration
All SDKs support these configuration options:
| Option | Type | Default | Description |
|---|---|---|---|
shrike_api_key | string | required | API key for Shrike authentication |
shrike_endpoint | string | Production URL | Custom endpoint URL |
fail_mode | string | "closed" | Behavior on scan failure (default: block) |
scan_timeout | number | 10-30s | Timeout 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).
# 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
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
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
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:
| Exception | When Raised | Contains |
|---|---|---|
ShrikeBlockedError | Threat detected | threat_type, confidence, violations |
ShrikeScanError | Scan failed (in closed mode) | Error details |
ShrikeConfigError | Invalid configuration | Configuration issue |
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
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
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
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
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 - 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
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
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
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
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 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
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:
| 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 | } |
| Field | Type | Description |
|---|---|---|
safe | boolean | true if content passed all security checks |
threat_type | string | Type of threat detected (if any) |
confidence | float | Confidence score 0.0-1.0 |
action | string | Action taken: allow, block, redact, flag |
violations | array | List of policy violations |
scan_id | string | Unique scan identifier for debugging |
latency_ms | number | Scan processing time in milliseconds |
Best Practices
1. Use Environment Variables
Never hardcode API keys in your source code.
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.
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
| Scenario | Recommended 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.
client = ShrikeOpenAI(
api_key="...",
shrike_api_key="...",
scan_timeout=5.0 # 5 seconds max
)Resources
Company
- Shrike
- Dallas, TX
- info@shrikesecurity.com