Python client library for the Instructeer API.
Instructeer provides deterministic guardrails for LLM pipelines — no ML inference, no probabilistic scores. The same input always produces the same output.
- SQLGuard — AST-based SQL risk analysis. Blocks dangerous or expensive queries before they reach your database.
- PIIGuard — Regex and lexicon-based PII detection. Prevents sensitive data from leaking through prompts or logs.
pip install instructeerRequires Python 3.11+.
All requests require an API key. Get yours at instructeer.com.
Pass the key directly or set the INSTRUCTEER_API_KEY environment variable:
# macOS / Linux
export INSTRUCTEER_API_KEY=rg_...
# Windows (cmd)
set INSTRUCTEER_API_KEY=rg_...
# Windows (PowerShell)
$env:INSTRUCTEER_API_KEY="rg_..."from instructeer.guards import SQLGuard
# api_key = os.environ["INSTRUCTEER_API_KEY"]
sql = SQLGuard(api_key="rg_...")
result = sql.analyze("SELECT * FROM users WHERE id = 1")
print(result.allowed) # True
print(result.severity) # "low"
print(result.issues) # []{ "allowed": true, "severity": "low", "issues": [] }Block a query based on the result:
generated_sql = "DELETE FROM users"
result = sql.analyze(generated_sql)
# Block on high severity only (allowed is False)
if not result.allowed:
raise ValueError(f"Query blocked: {result.issues[0].message}")
# Block on medium and high severity
if result.severity in ("medium", "high"):
raise ValueError(f"Query blocked: {result.issues[0].message}"){
"allowed": false,
"severity": "high",
"issues": [
{ "rule": "dml_no_where", "severity": "high", "message": "DELETE without WHERE clause would affect all rows" }
]
}Defaults to "postgres". Supported values:
postgres · mysql · bigquery · tsql · oracle · snowflake · databricks · sqlite · hive · mariadb
result = sql.analyze("SELECT TOP 10 * FROM users", dialect="tsql")| Field | Type | Description |
|---|---|---|
allowed |
bool |
False when a high-severity issue is detected |
severity |
str |
"low", "medium", or "high" |
issues |
list[Issue] |
Each issue has rule, message, and severity |
from instructeer.guards import PIIGuard
# api_key = os.environ["INSTRUCTEER_API_KEY"]
pii = PIIGuard(api_key="rg_...")
result = pii.detect_all("Alice's SSN is 123-45-6789 and email is alice@example.com")
print(result.summary.total) # 2
print(result.summary.max_severity) # "high"
for d in result.detections:
print(d.entity_type, d.value, d.confidence){
"detections": [
{ "entity_type": "US_SSN", "value": "123-45-6789", "confidence": 1.0, "severity": "high" },
{ "entity_type": "EMAIL_ADDRESS", "value": "alice@example.com", "confidence": 1.0, "severity": "medium" }
],
"summary": {
"total": 2,
"max_severity": "high",
"by_type": { "US_SSN": 1, "EMAIL_ADDRESS": 1 },
"by_severity": { "high": 1, "medium": 1 }
}
}result = pii.detect_email("Reach out at hello@example.com")
result = pii.detect_ssn("Patient SSN: 078-05-1120")
result = pii.detect_card("Charged to 4111 1111 1111 1111")
result = pii.detect_phone("Call 800-555-0199")Available: detect_email · detect_phone · detect_ssn · detect_card · detect_bank · detect_iban · detect_ip · detect_url · detect_date · detect_dob · detect_dl · detect_passport · detect_address · detect_person
result = pii.detect_all(
text,
detectors=["email", "ssn", "card"],
min_confidence=0.8,
confidence_thresholds={"US_ADDRESS": 0.7},
use_default_thresholds=True,
)DetectResponse
| Field | Type | Description |
|---|---|---|
detections |
list[Detection] |
All detected PII spans |
summary |
DetectionSummary |
Aggregate counts and severity roll-up |
Detection
| Field | Type | Description |
|---|---|---|
entity_type |
str |
e.g. "EMAIL_ADDRESS", "US_SSN", "CREDIT_CARD" |
value |
str |
The matched text |
start |
int |
Start character offset |
end |
int |
End character offset |
severity |
str |
"low", "medium", or "high" |
confidence |
float |
Detection confidence (0.0–1.0) |
extra |
dict | None |
Additional detector-specific metadata |
DetectionSummary
| Field | Type | Description |
|---|---|---|
total |
int |
Total number of detections |
max_severity |
str | None |
Highest severity with confidence ≥ 0.3 |
by_type |
dict[str, int] |
Count per entity type |
by_severity |
dict[str, int] |
Count per severity level |
import asyncio
from instructeer.guards import AsyncSQLGuard, AsyncPIIGuard
async def main():
async with AsyncSQLGuard(api_key="rg_...") as sql:
result = await sql.analyze("DROP TABLE users")
async with AsyncPIIGuard(api_key="rg_...") as pii:
result = await pii.detect_all("SSN: 123-45-6789")
asyncio.run(main())from instructeer import (
AuthenticationError,
PermissionDeniedError,
RateLimitError,
UnprocessableEntityError,
APIConnectionError,
APITimeoutError,
APIError,
)
try:
result = sql.analyze(query)
except AuthenticationError:
...
except PermissionDeniedError:
...
except RateLimitError as e:
print(e.status_code) # 429
except UnprocessableEntityError:
...
except APITimeoutError:
...
except APIConnectionError:
...
except APIError as e:
print(e.status_code)| Parameter | Default | Description |
|---|---|---|
api_key |
env INSTRUCTEER_API_KEY |
Your Instructeer API key |
base_url |
https://api.instructeer.com |
Override for self-hosted deployments |
timeout |
30.0 |
Request timeout in seconds |
max_retries |
2 |
Retries on 429 and 5xx with exponential backoff |
MIT