strands-tealtiger
Deterministic governance plugin for Strands Agents — tool allowlists, PII/secret detection, prompt injection defense, cost budgets, and kill switches.
No LLM in the governance path. No external server. <2ms per evaluation.
Installation
pip install strands-tealtiger
📖 Full documentation: docs.tealtiger.ai/integrations/strands
Quick Start
from strands import Agent
from strands_tools import calculator
from strands_tealtiger import TealTigerPlugin
agent = Agent(
tools=[calculator],
plugins=[TealTigerPlugin(
mode="ENFORCE",
allowed_tools=["calculator"],
budget_limit=5.0,
)]
)
agent("What is 42 * 17?")
Usage
Tool Allowlist + Blocklist
Control which tools the agent can call:
from strands_tealtiger import TealTigerPlugin
governance = TealTigerPlugin(
mode="ENFORCE",
allowed_tools=["search", "read_*"], # Glob patterns
blocked_tools=["delete_*", "rm_*"], # Always denied (overrides allowlist)
)
PII Detection
Block tool calls containing sensitive data:
governance = TealTigerPlugin(
mode="ENFORCE",
pii_categories=["ssn", "credit_card", "email", "phone"],
)
Prompt Injection Defense
Detect adversarial inputs in tool arguments:
governance = TealTigerPlugin(
mode="ENFORCE",
detect_injection=True,
injection_threshold=0.8, # Higher = fewer false positives
)
Detects: instruction override, DAN/jailbreak, developer mode, system prompt override, delimiter injection, XML tag injection, fake system messages.
Cost Budget
Hard-stop when session cost exceeds the limit:
governance = TealTigerPlugin(
mode="ENFORCE",
budget_limit=5.0, # $5 max per session
cost_per_call=0.003, # Estimated cost per tool call
)
Kill Switch
Freeze all tool calls immediately — no policy can override:
governance = TealTigerPlugin(mode="ENFORCE")
# Later, when something goes wrong:
governance.freeze() # All tool calls blocked instantly
governance.unfreeze() # Resume normal governance
Secret Detection
Block tool calls containing API keys, tokens, or credentials:
governance = TealTigerPlugin(
mode="ENFORCE",
detect_secrets=True, # Default: True
)
Catches: OpenAI keys (sk-...), GitHub tokens (ghp_...), AWS keys (AKIA...), Slack tokens, generic API keys, PEM private keys.
Governance Modes
| Mode | Behavior | Use Case |
|---|---|---|
ENFORCE |
Block violations via event.cancel_tool |
Production |
MONITOR |
Evaluate policies, log decisions, allow all through | Staging / shadow |
OBSERVE |
Skip evaluation, track cost only | Initial rollout |
# Start with OBSERVE in staging
governance = TealTigerPlugin(mode="OBSERVE")
# Promote to MONITOR to see what would be blocked
governance = TealTigerPlugin(mode="MONITOR")
# Enforce in production
governance = TealTigerPlugin(mode="ENFORCE")
Audit Trail
Every evaluation produces a structured GovernanceDecision:
for decision in governance.decisions:
print(
f"[{decision.action}] {decision.tool_name} "
f"— {decision.reason_codes} "
f"(risk={decision.risk_score}, {decision.evaluation_time_ms:.2f}ms)"
)
Fields:
| Field | Type | Description |
|---|---|---|
decision_id |
str |
UUID for correlation |
action |
str |
ALLOW or DENY |
mode |
str |
ENFORCE, MONITOR, or OBSERVE |
tool_name |
str |
Tool that was evaluated |
reason |
str |
Human-readable reason |
reason_codes |
list[str] |
Machine-readable codes |
risk_score |
int |
0–100 |
cost_tracked |
float |
Cost for this call |
cumulative_cost |
float |
Session total |
evaluation_time_ms |
float |
Governance latency |
Multi-Agent (Swarm / Graph)
Works in multi-agent patterns — attach to individual agents:
from strands import Agent
from strands.multiagent import Swarm
from strands_tealtiger import TealTigerPlugin
researcher = Agent(
name="researcher",
tools=[search],
plugins=[TealTigerPlugin(
mode="ENFORCE",
allowed_tools=["search"],
budget_limit=3.0,
)]
)
writer = Agent(
name="writer",
tools=[write_file],
plugins=[TealTigerPlugin(
mode="ENFORCE",
allowed_tools=["write_file"],
pii_categories=["ssn", "credit_card"],
)]
)
swarm = Swarm([researcher, writer])
Complete Example
import asyncio
from strands import Agent, tool
from strands_tealtiger import TealTigerPlugin
@tool
def search(query: str) -> str:
"""Search the web."""
return f"Results for: {query}"
@tool
def send_email(to: str, body: str) -> str:
"""Send an email."""
return f"Sent to {to}"
@tool
def delete_database(table: str) -> str:
"""Delete a database table."""
return f"Deleted {table}"
# Configure governance
governance = TealTigerPlugin(
mode="ENFORCE",
allowed_tools=["search", "send_email"],
blocked_tools=["delete_*"],
pii_categories=["ssn", "credit_card", "email"],
detect_secrets=True,
detect_injection=True,
budget_limit=5.0,
cost_per_call=0.003,
on_decision=lambda d: print(f" [{d.action}] {d.tool_name}: {d.reason_codes}"),
)
agent = Agent(
system_prompt="You are a helpful research assistant.",
tools=[search, send_email, delete_database],
plugins=[governance],
)
# This works (search is allowed)
agent("Search for AI governance frameworks")
# This is DENIED (delete_database is in blocklist)
agent("Delete the users table")
# Post-run analysis
print(f"\nTotal decisions: {len(governance.decisions)}")
print(f"Denied: {governance.deny_count}")
print(f"Session cost: ${governance.total_cost:.4f}")
Comparison with Agent Control
| Agent Control (Galileo) | TealTiger | |
|---|---|---|
| Architecture | External server + Docker required | In-process, zero infrastructure |
| Latency | Network round-trip per evaluation | <2ms in-process |
| Dependencies | Galileo SaaS for AI evaluators | None — stdlib only |
| Determinism | LLM-as-judge (Luna-2) | Pure regex/pattern matching |
| Offline/air-gap | Requires server connectivity | Works fully offline |
| Lambda/serverless | Cold start penalty for server connection | Zero cold start overhead |
| Cost | Paid AI evaluations | Free, Apache 2.0 |
API Reference
TealTigerPlugin
| Parameter | Type | Default | Description |
|---|---|---|---|
mode |
str |
"ENFORCE" |
Governance mode |
allowed_tools |
list[str] | None |
None |
Glob patterns for permitted tools |
blocked_tools |
list[str] | None |
[] |
Explicit deny-list |
pii_categories |
list[str] | None |
[] |
PII types to detect |
detect_secrets |
bool |
True |
Enable secret detection |
detect_injection |
bool |
True |
Enable injection detection |
injection_threshold |
float |
0.7 |
Confidence threshold for injection |
budget_limit |
float | None |
None |
Max session cost (USD) |
cost_per_call |
float |
0.002 |
Estimated cost per tool call |
on_decision |
callable | None |
None |
Callback for each decision |
Methods
| Method | Description |
|---|---|
freeze() |
Activate kill switch |
unfreeze() |
Deactivate kill switch |
reset() |
Clear session state |
Properties
| Property | Type | Description |
|---|---|---|
decisions |
list[GovernanceDecision] |
All decisions this session |
total_cost |
float |
Cumulative cost |
deny_count |
int |
Number of denials |
is_frozen |
bool |
Kill switch status |
License
Apache-2.0 — see LICENSE.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file strands_tealtiger-0.1.0.tar.gz.
File metadata
- Download URL: strands_tealtiger-0.1.0.tar.gz
- Upload date:
- Size: 5.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.14.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
412f32d93e791eb9b03062e699dfd39be98209ce46a364ecb450f9a05a8f9fd8
|
|
| MD5 |
d73868ca7a0dd995c714881d13db6dae
|
|
| BLAKE2b-256 |
64ca55a3702da9b41bc2e62b59865aec5b9db2c4ad23bd38019197c42b34e87d
|
File details
Details for the file strands_tealtiger-0.1.0-py3-none-any.whl.
File metadata
- Download URL: strands_tealtiger-0.1.0-py3-none-any.whl
- Upload date:
- Size: 4.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.14.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
65b7a6da9b9323bed94b81461d92a9fb9aa10fd5a416811acfbd9c9ea2582921
|
|
| MD5 |
43d2ffb27fa228f2574e3fd583c94778
|
|
| BLAKE2b-256 |
f63037fc6544d0bc7fd1f3eaa521ac3f0bba82e97f0f8c9c522b72e3f741e573
|