Enkrypt AI Python SDK
A Python SDK with Guardrails, Code of Conduct Policies, Endpoints (Models), Deployments, AI Proxy, Datasets, Red Team, Skill Scanner, etc. functionality for API interactions.
See documentation at https://docs.enkryptai.com/libraries/python/introduction
See https://pypi.org/project/enkryptai-sdk
Start a red team run
import os
from enkryptai_sdk import RedTeamClient, RTModelConfig, RTRedteamRequest
client = RedTeamClient(api_key=os.environ["ENKRYPTAI_API_KEY"])
run = client.run_redteam(RTRedteamRequest(
target=RTModelConfig.hosted(
endpoint="https://api.openai.com/v1/chat/completions",
api_key=os.environ["OPENAI_API_KEY"],
model_name="gpt-4o",
),
risk_categories={"safety_harm": {"attack_config": ["basic"]}},
run_name="nightly probe",
))
print(run.run_id) # rt-<uuid> -- save this
print(client.run_url(run.run_id)) # watch it in the dashboard
A run takes anywhere from about half an hour to several hours, so starting it
and reading it are usually different sittings. run_id is all you need to pick
it back up from a fresh process:
status = client.wait_for_run(run.run_id, on_progress=print)
report = client.get_run_results(run.run_id)
wait_for_run has no timeout by default and interrupting it does nothing to
the run. For a live feed instead of polling, client.iter_run_events(run_id)
yields decoded events and reconnects on its own, resuming where it left off —
which matters, because a run that lasts hours will outlive its connection.
One run, three id spellings.
rt-<uuid>is what the endpoints want; the bare uuid (job_id_for(run_id), also onstatus.job_id) is what relay logs and compliance reports use. And a finished run reportsFinishedfrom one endpoint andcompletedfrom another —status.stateandstatus.is_terminalfold both into one.
Against a model on your own machine
Same script, one different target — plus a bridge (see below):
target=RTModelConfig.via_relay(
bridge_id="my-laptop",
endpoint="http://localhost:11434/v1/chat/completions",
model_name="llama3",
),
Relay bridge
The SDK also ships the Enkrypt Sentry Relay bridge: a tiny
in-network process that lets red-team jobs running in Enkrypt's cloud
reach an LLM that lives inside your private network -- without opening
any inbound ports. The bridge is pure network plumbing: it does no
LLM work itself, just maintains one outbound WSS connection to
api.enkryptai.com:443, receives OpenAI-shaped chat.completions
requests over it, forwards them to your local LLM, and pushes the
response back. (Industry analogues for the same role are Twingate /
Zscaler Connector and Cloudflare's tunnel.)
Availability: the public relay route is currently enabled in Enkrypt's dev environment only. Confirm with your Enkrypt contact which URL your bridge should dial before rolling it out — pointed at an environment where the route is absent, the bridge does not fail loudly, it just reconnect-loops.
One-command start
pip install enkryptai-sdk
export ENKRYPT_API_KEY=<your-enkrypt-api-key>
enkryptai-relay --bridge-id my-laptop --target http://localhost:11434
Two required values, and no user id: the gateway authenticates your API
key and tells the relay whose bridge this is. The bridge id is the value
you also pass as bridge_id on the red-team target — it is the one value
the two sides must agree on.
Every flag has an environment-variable equivalent, which is what you want under systemd, docker or k8s. Flags win when both are set:
export RELAY_BRIDGE_ID=my-laptop
export ENKRYPT_API_KEY=<your-enkrypt-api-key>
export TARGET_BASE_URL=http://localhost:11434 # your local LLM
# Optional:
# export BRIDGE_HOOKS_MODULE=my_company.relay_hooks # custom translation
# export RELAY_TARGET_ALLOWED_HOSTS=local-llm.corp # host allow-list
enkryptai-relay
Run enkryptai-relay --help for the full list. Prefer ENKRYPT_API_KEY
over --api-key, which lands in your shell history.
Keep the bridge up for the whole run: a red team run lasts from about half an hour to several hours, and if the bridge drops the run pauses and eventually fails. Run it as a service, not in the terminal you are about to close.
Programmatic API
from enkryptai_sdk import RelayBridge
RelayBridge(
bridge_id="my-laptop",
api_key="<your-enkrypt-api-key>",
target_base_url="http://localhost:11434",
).run()
Arguments are keyword-only — positional construction raises
TypeError rather than silently rebinding fields.
Translation hooks (non-OpenAI local LLMs)
The relay wire format is OpenAI chat.completions end-to-end. If your
local LLM doesn't already speak OpenAI (Anthropic, Bedrock, Vertex,
proprietary shape, ...) write a Python module that exports two
coroutines and point BRIDGE_HOOKS_MODULE at its dotted path:
async def before_request(payload: dict) -> dict:
return translate_openai_to_local(payload)
async def after_response(local_response: dict) -> dict:
return translate_local_to_openai(local_response)
The bridge validates inputs/outputs against the official openai SDK
Pydantic types at both boundaries, so a buggy hook surfaces as a
structured error to the red-team worker instead of corrupted traffic.
Nothing about your local LLM's shape has to be known by, or deployed to,
Enkrypt's cloud.
A worked OpenAI ↔ Anthropic Messages API example ships inside the
SDK at enkryptai_sdk.relay.examples.hooks_example. Either point the
bridge at it directly (smoke test) or copy it into your own repo to
edit:
# Smoke test (no copy):
export BRIDGE_HOOKS_MODULE=enkryptai_sdk.relay.examples.hooks_example
enkryptai-relay
# Or, copy the template next to your own code:
python -c "from enkryptai_sdk.relay.examples import copy_example; \
copy_example('hooks_example.py', './my_hooks.py')"
export BRIDGE_HOOKS_MODULE=my_hooks
PYTHONPATH=. enkryptai-relay
A bridge.env.example env-file template ships alongside it and can
be copied the same way (copy_example('bridge.env.example', './bridge.env')). See
src/enkryptai_sdk/relay/examples/README.md
for the full list.
Turning the relay on for a run
Routing is switched on by the red-team request, not by the bridge.
RTModelConfig.via_relay builds that target for you:
from enkryptai_sdk import RTModelConfig
target = RTModelConfig.via_relay(
bridge_id="my-laptop", # == --bridge-id
endpoint="https://local-llm.corp/v1/chat/completions", # as the bridge sees it
model_name="their-internal-model",
# Credentials your local LLM needs. They go here, never in api_key --
# the bridge is what authenticates to your LLM, so passing api_key raises.
target_headers={"Authorization": "Bearer customer-side-internal-key"},
)
which serialises to the wire shape below. Write it by hand if you prefer:
{
"target": {
"endpoint": "https://local-llm.corp/v1/chat/completions",
"api_key": "",
"model_name": "their-internal-model",
"connect_via_relay": true,
"metadata": {
"relay": {
"bridge_id": "my-laptop",
"target_endpoint": "https://local-llm.corp/v1/chat/completions",
"model_name": "their-internal-model"
}
}
},
"risk_categories": { "safety_harm": { "attack_config": { "basic": {} } } }
}
metadata.relay.bridge_id, metadata.relay.target_endpoint and
metadata.relay.model_name are all required; target.api_key may be
empty because the bridge is what authenticates to your LLM (put those
credentials in metadata.relay.target_headers). Note that
connect_via_relay stays at the root of the target — only the relay
block itself lives under metadata. A bare target.relay block is the
older spelling and is still accepted, so existing integrations keep
working; write target.metadata.relay in new ones. Ready-to-send bodies
with a field-by-field reference are in
docs/relay/examples/.
Further reading
docs/relay/ covers the architecture and config
reference (README), how to run both sides on one
laptop (LOCAL_TESTING), deploying the
cloud side (INFRA_RUNBOOK), and why the
relay is shaped this way (DESIGN).
Scan an agent skill
The Skill Scanner checks an agent "skill" (a directory in a git repo) for
security threats. Submitting is asynchronous — you get a scan_id back and
poll it; a scan typically takes 30-90 seconds.
import os
from enkryptai_sdk import SkillScannerClient
client = SkillScannerClient(api_key=os.getenv("ENKRYPTAI_API_KEY"))
queued = client.scan({
"git_url": "https://github.com/affaan-m/ECC.git",
"skill_path": ".agents/skills/api-design",
# Recommended: pins the checkout, and lets an identical repeat scan come
# back from cache instead of re-running the scanner.
"commit": "2bc924aa11bb22cc33dd44ee55ff6677889900aa",
})
print(queued.scan_id, queued.status) # -> "...", "queued"
# Blocks until the scan is done (default budget 15 min, polls every 5s).
record = client.wait_for_scan(queued.scan_id)
if record.succeeded:
print(record.verdict, record.risk_level, record.findings_count, record.stars)
print(client.get_report(record.scan_id)) # the full skill-sentinel report
else:
print("scan failed:", record.error)
# Your own scans, newest first.
for item in client.list_scans(status="succeeded", limit=10).items:
print(item.scan_id, item.repo, item.skill_name, item.verdict)
Two things worth knowing before you build on it:
- You see your organization's scans. The gateway derives the owning
identity from your API key. For an org or project key that is the
organization, so every member sees every scan the org has run, whichever
project their key belongs to; an individual account sees its own. A scan
belonging to a different organization is a
403. There is deliberately nouser_emailparameter to pass — sending one is a400. - A failed scan is a result, not an exception.
wait_for_scanreturns the record for afailedscan withrecord.errorexplaining why; only running out of time raises (SkillScannerTimeoutError).
force=True on scan() bypasses the dedup cache and forces a fresh scan.
Copyright, License and Terms of Use
© 2025 Enkrypt AI. All rights reserved.
Enkrypt AI software is provided under a proprietary license. Unauthorized use, reproduction, or distribution of this software or any portion of it is strictly prohibited.
Terms of Use: https://www.enkryptai.com/terms-and-conditions
Enkrypt AI and the Enkrypt AI logo are trademarks of Enkrypt AI, Inc.
Release files for enkryptai-sdk 1.0.40
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| enkryptai_sdk-1.0.40.tar.gz | 188.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| enkryptai_sdk-1.0.40-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 305.9 kB
Release files / enkryptai_sdk-1.0.40.tar.gz
| Download URL | enkryptai_sdk-1.0.40.tar.gz |
|---|---|
| Size | 188.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
4eabf6d71a6ec44722ee079d26ee7ff2dd5d5ff4f8beab6131e76a58b81e38f1
|
|
BLAKE2b-256 checksum How to use checksums |
f7e36b003e057026108cdb8e6e3be5252dfb7004e271862cb3518fc81b0438c4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.16
|
Release files / enkryptai_sdk-1.0.40-py3-none-any.whl
| Download URL | enkryptai_sdk-1.0.40-py3-none-any.whl |
|---|---|
| Size | 117.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
e1f3363ede93ebfc0626f30427008143b873de610df14c9a7be8889d447dce6b
|
|
BLAKE2b-256 checksum How to use checksums |
4195a11d24fe5feb176335f7633cd3278df4302967095d6506df0fe49f2c7d72
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.16
|