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.
Metadata
Release files for strands-tealtiger 0.2.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 | |
|---|---|---|---|
| strands_tealtiger-0.2.1.tar.gz | 5.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| strands_tealtiger-0.2.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 9.9 kB
Release files / strands_tealtiger-0.2.1.tar.gz
| Download URL | strands_tealtiger-0.2.1.tar.gz |
|---|---|
| Size | 5.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
65bcbbdb15b3897f617d4550e6f209ee7be9aa1c9b2960d06d9b17e4a60fad4b
|
|
BLAKE2b-256 checksum How to use checksums |
0a95421e526321a954ac9ccaf2d57fc33281ff928e8a6861b2864d7166c4d203
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.2
|
Release files / strands_tealtiger-0.2.1-py3-none-any.whl
| Download URL | strands_tealtiger-0.2.1-py3-none-any.whl |
|---|---|
| Size | 4.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
b6b531a1d6418b4efaa15e3f0da99ea7671e95b958576e11d5ea111713b0b264
|
|
BLAKE2b-256 checksum How to use checksums |
00e2a7e41b94107d822c0506282d5028e1079ef7a49656e32ac68e8910270f20
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.2
|