Skip to main content

Emet SDK for Python

PyPI Python CI License

Emet checks the claims an AI agent makes against the evidence behind them: the tool results and data the agent actually received. emet-sdk sends your agent's turns to Emet from the OpenTelemetry GenAI spans your framework already emits. There is no second instrumentation to maintain.

Early release. The API may change before 1.0; every change is in the changelog.

Quick start

You need an Emet account, a key for a development Application, and the External ID of the Team your users belong to.

uv add emet-sdk  # or: pip install emet-sdk
import emet_sdk
from pydantic_ai import Agent

# Once, at startup, after your own tracing setup (such as logfire.configure())
emet_sdk.configure(
    service_name="support-agent",
    on_delivery=emet_sdk.write_delivery_file(".emet/last-delivery.json"),
)
Agent.instrument_all()


@app.post("/chat")
async def chat(body: ChatIn, user=Depends(current_user)):
    # Take these from your server's own auth and storage, never from the request body
    thread = await threads.get_for_user(user, body.thread_id)
    with emet_sdk.turn(tenant_ref=user.team_external_id, conversation_id=thread.id, user=user.email):
        result = await agent.run(body.message)
    return result.output

Set EMET_APPLICATION_KEY in the app's environment. In production that is your host's secret settings; locally, load your .env the way your app already does, for example with uvicorn --env-file .env or python-dotenv. Without the key, the app logs "Emet is off" once and runs as before.

emet-cli can do this setup with your coding agent, and tells you whether a turn reached Emet whole.

How it works

  • Adds, never replaces. configure() adds one span processor to your app's TracerProvider, and creates a provider only when the app has none. Logfire, Datadog or any other exporter keeps receiving the same spans, with the same sampling.
  • Opt in per turn. Only spans that start inside turn() are sent. Other agents, HTTP calls and database queries are not.
  • Nothing written onto your spans. The tenant, conversation and user stay inside the SDK. They never reach your other exporters, and never travel to downstream services as baggage.
  • Never in your way. Turns are built and sent on a background thread, and the SDK never raises into your app.

DESIGN.md has the details: how a turn is collected, built into Emet's envelope, split and sent.

What is sent, and what never leaves

Emet needs the content of a turn to check it: the user's question, each model call's messages, and each tool call's arguments and result. Before anything leaves the process:

  • Secrets are redacted from every string: keys and tokens of common providers (OpenAI, Anthropic, AWS, GitHub, GitLab, Slack, Stripe, Google, npm), bearer tokens, JWTs, passwords in URLs, assignments such as DB_PASSWORD=..., values under keys such as password or api_key, and your Emet key itself. Redaction is best effort; tell us about a pattern it misses.
  • The system prompt travels as a SHA-256 hash, never as text.
  • Images and files sent inline are replaced by their type, size and digest.
  • Errors carry their message, never the stack trace.
  • Span attributes are limited to an allowlist of GenAI fields; framework dumps such as Pydantic AI's message history are dropped.

The user you pass to turn(), usually their email, is stored on the trace so Emet can show usage per person.

Reference

configure(*, service_name=None, on_delivery=None, endpoint="https://app.emet.so") Adds Emet to the global TracerProvider. Call once at startup; later calls do nothing. service_name names the app in Emet. on_delivery receives each turn's delivery result on the SDK's thread. endpoint takes only production or a localhost address, for testing against Emet on your machine.
turn(tenant_ref, conversation_id, user=None) A context manager or decorator, sync or async, around one turn of your agent. tenant_ref is the External ID of the Team in Emet; conversation_id is your app's own thread id; user is who asked.
flush(timeout=10.0) -> bool Waits until every finished turn is sent; returns False when the timeout ran out first. Call it before a short-lived process exits. The SDK also flushes for up to 5 seconds at exit.
write_delivery_file(path) An on_delivery callback that saves the latest result to a file, for emet-cli check --last. Its folder must exist.
EMET_APPLICATION_KEY The key, read from the environment when configure() runs.

The delivery result reports each turn as sent, stopped or skipped, with the reason, the trace and conversation ids, span and batch counts, whether the turn matched a Team (unattributed) or arrived after Emet closed it (late), and any tools Emet found missing arguments or results. A turn is captured when it was sent whole, attributed, on time and with no gaps. The result never holds the key, the tenant, the user or any content.

Compatibility

Supported
Python 3.10 to 3.14
OpenTelemetry SDK 1.27 or later
Pydantic AI 2.63 tested in CI, on Python 3.11 or later

Google ADK is planned. A TypeScript SDK will follow the same design.

Contributing and security

See CONTRIBUTING.md for development and releases, and SECURITY.md to report a vulnerability privately. Everyone taking part follows the Code of Conduct.

License

Apache-2.0

Metadata

Release files for emet-sdk 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for emet-sdk 0.1.1
File Size Uploaded Provenance Actions
emet_sdk-0.1.1.tar.gz 152.0 kB With provenance Details for emet_sdk-0.1.1.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for emet-sdk 0.1.1
File Interpreter ABI Platform Actions
emet_sdk-0.1.1-py3-none-any.whl Python 3 none any Details for emet_sdk-0.1.1-py3-none-any.whl

Total release size: 181.5 kB

Release files / emet_sdk-0.1.1.tar.gz

Download URL emet_sdk-0.1.1.tar.gz
Size 152.0 kB
Tags Source
SHA-256 checksum
How to use checksums
a9ef043729489da97f841151099fdcd7a0d152f6d4cb32a2708a1f301956f5b8
BLAKE2b-256 checksum
How to use checksums
08e844b43a0367b3ca7b465c724a9b394394b016c097b129d598390ee4743003
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 30, 2026.

Transparency log

Release files / emet_sdk-0.1.1-py3-none-any.whl

Download URL emet_sdk-0.1.1-py3-none-any.whl
Size 29.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
39acc2da0e48d48b19270767f9626f0a635412d056a414c50e24813edb68cdb6
BLAKE2b-256 checksum
How to use checksums
52b91930ec757bb9adbc460335e95ae9bd0d78b83b158616cf70347306680ece
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 30, 2026.

Transparency log

Security for emet-sdk 0.1.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for emet_sdk-0.1.1.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 30, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page